| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 | package mainimport (	"encoding/json"	"errors"	"net/http"	"path/filepath"	"strings"	"imuslab.com/arozos/mod/disk/hybridBackup"	user "imuslab.com/arozos/mod/user"	prout "imuslab.com/arozos/mod/prouter")func backup_init() {	//Register HybridBackup storage restore endpoints	router := prout.NewModuleRouter(prout.RouterOption{		AdminOnly:   false,		UserHandler: userHandler,		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {			sendErrorResponse(w, "Permission Denied")		},	})	//Register API endpoints	router.HandleFunc("/system/backup/listRestorable", backup_listRestorable)	router.HandleFunc("/system/backup/restoreFile", backup_restoreSelected)	router.HandleFunc("/system/backup/snapshotSummary", backup_renderSnapshotSummary)	router.HandleFunc("/system/backup/listAll", backup_listAllBackupDisk)	//Register settings	registerSetting(settingModule{		Name:         "Backup Disks",		Desc:         "All backup disk in the system",		IconPath:     "img/system/backup.svg",		Group:        "Disk",		StartDir:     "SystemAO/disk/backup/backups.html",		RequireAdmin: true,	})}//List all backup disk infofunc backup_listAllBackupDisk(w http.ResponseWriter, r *http.Request) {	//Get all fsh from the system	runningBackupTasks := []*hybridBackup.BackupTask{}	//Render base storage pool	for _, fsh := range baseStoragePool.Storages {		if fsh.Hierarchy == "backup" {			task, err := baseStoragePool.HyperBackupManager.GetTaskByBackupDiskID(fsh.UUID)			if err != nil {				continue			}			runningBackupTasks = append(runningBackupTasks, task)		}	}	//Render group storage pool	for _, pg := range permissionHandler.PermissionGroups {		for _, fsh := range pg.StoragePool.Storages {			task, err := pg.StoragePool.HyperBackupManager.GetTaskByBackupDiskID(fsh.UUID)			if err != nil {				continue			}			runningBackupTasks = append(runningBackupTasks, task)		}	}	type backupDrive struct {		DiskUID             string //The backup disk UUID		DiskName            string // The Backup disk name		ParentUID           string //Parent disk UID		ParentName          string //Parent disk name		BackupMode          string //The backup mode of the drive		LastBackupCycleTime int64  //Last backup timestamp		BackupCycleCount    int64  //How many backup cycle has proceeded since the system startup		Error               bool   //If there are error occured in the last cycle		ErrorMessage        string //If there are any error msg	}	backupDrives := []*backupDrive{}	for _, task := range runningBackupTasks {		diskFsh, diskErr := GetFsHandlerByUUID(task.DiskUID)		parentFsh, parentErr := GetFsHandlerByUUID(task.ParentUID)		//Check for error in getting FS Handler		if diskErr != nil || parentErr != nil {			sendErrorResponse(w, "Unable to get backup task info from backup disk: "+task.DiskUID)			return		}		thisBackupDrive := backupDrive{			DiskUID:             diskFsh.UUID,			DiskName:            diskFsh.Name,			ParentUID:           parentFsh.UUID,			ParentName:          parentFsh.Name,			BackupMode:          task.Mode,			LastBackupCycleTime: task.LastCycleTime,			BackupCycleCount:    task.CycleCounter,			Error:               task.PanicStopped,			ErrorMessage:        task.ErrorMessage,		}		backupDrives = append(backupDrives, &thisBackupDrive)	}	js, _ := json.Marshal(backupDrives)	sendJSONResponse(w, string(js))}//Generate a snapshot summary for vrootfunc backup_renderSnapshotSummary(w http.ResponseWriter, r *http.Request) {	//Get user accessiable storage pools	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)	if err != nil {		sendErrorResponse(w, "User not logged in")		return	}	//Get Backup disk ID from request	bdid, err := mv(r, "bdid", true)	if err != nil {		sendErrorResponse(w, "Invalid backup disk ID given")		return	}	//Get target snapshot name from request	snapshot, err := mv(r, "snapshot", true)	if err != nil {		sendErrorResponse(w, "Invalid snapshot name given")		return	}	//Get fsh from the id	fsh, err := GetFsHandlerByUUID(bdid)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	//Get parent disk hierarcy	parentDiskID, err := userinfo.HomeDirectories.HyperBackupManager.GetParentDiskIDByRestoreDiskID(fsh.UUID)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	parentFsh, err := GetFsHandlerByUUID(parentDiskID)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	//Get task by the backup disk id	task, err := userinfo.HomeDirectories.HyperBackupManager.GetTaskByBackupDiskID(fsh.UUID)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	if task.Mode == "version" {		//Generate snapshot summary		var summary *hybridBackup.SnapshotSummary		if parentFsh.Hierarchy == "user" {			s, err := task.GenerateSnapshotSummary(snapshot, &userinfo.Username)			if err != nil {				sendErrorResponse(w, err.Error())				return			}			summary = s		} else {			s, err := task.GenerateSnapshotSummary(snapshot, nil)			if err != nil {				sendErrorResponse(w, err.Error())				return			}			summary = s		}		js, _ := json.Marshal(summary)		sendJSONResponse(w, string(js))	} else {		sendErrorResponse(w, "Unable to genreate snapshot summary: Backup mode is not snapshot")		return	}}//Restore a given filefunc backup_restoreSelected(w http.ResponseWriter, r *http.Request) {	//Get user accessiable storage pools	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)	if err != nil {		sendErrorResponse(w, "User not logged in")		return	}	//Get Backup disk ID from request	bdid, err := mv(r, "bdid", true)	if err != nil {		sendErrorResponse(w, "Invalid backup disk ID given")		return	}	//Get fsh from the id	fsh, err := GetFsHandlerByUUID(bdid)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	//Get the relative path for the restorable file	relpath, err := mv(r, "relpath", true)	if err != nil {		sendErrorResponse(w, "Invalid relative path given")		return	}	//Pick the correct HybridBackup Manager	targetHybridBackupManager, err := backup_pickHybridBackupManager(userinfo, fsh.UUID)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	//Handle restore of the file	err = targetHybridBackupManager.HandleRestore(fsh.UUID, relpath, &userinfo.Username)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	type RestoreResult struct {		RestoreDiskID       string		TargetDiskID        string		RestoredVirtualPath string	}	result := RestoreResult{		RestoreDiskID: fsh.UUID,	}	//Get access path for this file	parentDiskId, err := targetHybridBackupManager.GetParentDiskIDByRestoreDiskID(fsh.UUID)	if err != nil {		//Unable to get parent disk ID???	} else {		//Get the path of the parent disk		parentDiskHandler, err := GetFsHandlerByUUID(parentDiskId)		if err == nil {			//Join the result to create a virtual path			assumedRestoreRealPath := filepath.ToSlash(filepath.Join(parentDiskHandler.Path, relpath))			restoreVpath, err := userinfo.RealPathToVirtualPath(assumedRestoreRealPath)			if err == nil {				result.RestoredVirtualPath = restoreVpath			}			result.TargetDiskID = parentDiskId		}	}	js, _ := json.Marshal(result)	sendJSONResponse(w, string(js))}//As one user might be belongs to multiple groups, check which storage pool is this disk ID owned by and return its corect backup maangerfunc backup_pickHybridBackupManager(userinfo *user.User, diskID string) (*hybridBackup.Manager, error) {	//Filter out the :/ if it exists in the disk ID	if strings.Contains(diskID, ":") {		diskID = strings.Split(diskID, ":")[0]	}	//Get all backup managers that this user ac can access	userpg := userinfo.GetUserPermissionGroup()	if userinfo.HomeDirectories.ContainDiskID(diskID) {		return userinfo.HomeDirectories.HyperBackupManager, nil	}	//Extract the backup Managers	for _, pg := range userpg {		if pg.StoragePool.ContainDiskID(diskID) {			return pg.StoragePool.HyperBackupManager, nil		}	}	return nil, errors.New("Disk ID not found in any storage pool this user can access")}//Generate and return a restorable reportfunc backup_listRestorable(w http.ResponseWriter, r *http.Request) {	//Get user accessiable storage pools	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)	if err != nil {		sendErrorResponse(w, "User not logged in")		return	}	//Get Vroot ID from request	vroot, err := mv(r, "vroot", true)	if err != nil {		sendErrorResponse(w, "Invalid vroot given")		return	}	//Get fsh from the id	fsh, err := GetFsHandlerByUUID(vroot)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	//Get all backup managers that this user ac can access	targetBackupManager, err := backup_pickHybridBackupManager(userinfo, vroot)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	//Get the user's storage pool and list restorable by the user's storage pool access	restorableReport, err := targetBackupManager.ListRestorable(fsh.UUID)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	//Get and check if the parent disk has a user Hierarcy	paretnfsh, err := GetFsHandlerByUUID(restorableReport.ParentUID)	if err != nil {		sendErrorResponse(w, err.Error())		return	}	result := hybridBackup.RestorableReport{		ParentUID:       restorableReport.ParentUID,		RestorableFiles: []*hybridBackup.RestorableFile{},	}	if paretnfsh.Hierarchy == "user" {		//The file system is user based. Filter out those file that is not belong to this user		for _, restorableFile := range restorableReport.RestorableFiles {			if restorableFile.IsSnapshot {				//Is snapshot. Always allow access				result.RestorableFiles = append(result.RestorableFiles, restorableFile)			} else {				//Is file				fileAbsPath := filepath.Join(fsh.Path, restorableFile.RelpathOnDisk)				_, err := userinfo.RealPathToVirtualPath(fileAbsPath)				if err != nil {					//Cannot translate this file. That means the file is not owned by this user				} else {					//Can translate the path.					result.RestorableFiles = append(result.RestorableFiles, restorableFile)				}			}		}	} else {		result = restorableReport	}	js, _ := json.Marshal(result)	sendJSONResponse(w, string(js))}
 |