centralize folder creation and permission setting for OneDrive restore (#2468)
## Description Rearrange how folder permissions are restored. Instead of restoring them when reading the meta file in the parent folder restore them when iterating through the collection itself. This solution leans more heavily on the idea of having a map[folder path]->folder permissions and uses that to lookup what to restore Folder permissions are still read and added to the map as they are encountered ## Does this PR need a docs update or release note? - [ ] ✅ Yes, it's included - [ ] 🕐 Yes, but in a later PR - [x] ⛔ No ## Type of change - [x] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Test - [ ] 💻 CI/Deployment - [ ] 🧹 Tech Debt/Cleanup ## Issue(s) * #2447 ## Test Plan - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
b174c632b7
commit
6b6f684119
@ -58,6 +58,45 @@ func getParentPermissions(
|
|||||||
return parentPerms, nil
|
return parentPerms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getParentAndCollectionPermissions(
|
||||||
|
drivePath *path.DrivePath,
|
||||||
|
collectionPath path.Path,
|
||||||
|
permissions map[string][]UserPermission,
|
||||||
|
restorePerms bool,
|
||||||
|
) ([]UserPermission, []UserPermission, error) {
|
||||||
|
if !restorePerms {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
parentPerms []UserPermission
|
||||||
|
colPerms []UserPermission
|
||||||
|
)
|
||||||
|
|
||||||
|
// Only get parent permissions if we're not restoring the root.
|
||||||
|
if len(drivePath.Folders) > 0 {
|
||||||
|
parentPath, err := collectionPath.Dir()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, clues.Wrap(err, "getting parent path")
|
||||||
|
}
|
||||||
|
|
||||||
|
parentPerms, err = getParentPermissions(parentPath, permissions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, clues.Wrap(err, "getting parent permissions")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(ashmrtn): For versions after this pull the permissions from the
|
||||||
|
// current collection with Fetch().
|
||||||
|
colPerms, err = getParentPermissions(collectionPath, permissions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, clues.Wrap(err, "getting collection permissions")
|
||||||
|
}
|
||||||
|
|
||||||
|
return parentPerms, colPerms, nil
|
||||||
|
}
|
||||||
|
|
||||||
// RestoreCollections will restore the specified data collections into OneDrive
|
// RestoreCollections will restore the specified data collections into OneDrive
|
||||||
func RestoreCollections(
|
func RestoreCollections(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
@ -94,24 +133,12 @@ func RestoreCollections(
|
|||||||
|
|
||||||
// Iterate through the data collections and restore the contents of each
|
// Iterate through the data collections and restore the contents of each
|
||||||
for _, dc := range dcs {
|
for _, dc := range dcs {
|
||||||
var (
|
|
||||||
parentPerms []UserPermission
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
if opts.RestorePermissions {
|
|
||||||
parentPerms, err = getParentPermissions(dc.FullPath(), parentPermissions)
|
|
||||||
if err != nil {
|
|
||||||
errUpdater(dc.FullPath().String(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
metrics, folderPerms, permissionIDMappings, canceled = RestoreCollection(
|
metrics, folderPerms, permissionIDMappings, canceled = RestoreCollection(
|
||||||
ctx,
|
ctx,
|
||||||
backupVersion,
|
backupVersion,
|
||||||
service,
|
service,
|
||||||
dc,
|
dc,
|
||||||
parentPerms,
|
parentPermissions,
|
||||||
OneDriveSource,
|
OneDriveSource,
|
||||||
dest.ContainerName,
|
dest.ContainerName,
|
||||||
deets,
|
deets,
|
||||||
@ -150,7 +177,7 @@ func RestoreCollection(
|
|||||||
backupVersion int,
|
backupVersion int,
|
||||||
service graph.Servicer,
|
service graph.Servicer,
|
||||||
dc data.RestoreCollection,
|
dc data.RestoreCollection,
|
||||||
parentPerms []UserPermission,
|
parentPermissions map[string][]UserPermission,
|
||||||
source driveSource,
|
source driveSource,
|
||||||
restoreContainerName string,
|
restoreContainerName string,
|
||||||
deets *details.Builder,
|
deets *details.Builder,
|
||||||
@ -189,8 +216,25 @@ func RestoreCollection(
|
|||||||
"origin", dc.FullPath().Folder(),
|
"origin", dc.FullPath().Folder(),
|
||||||
"destination", restoreFolderElements)
|
"destination", restoreFolderElements)
|
||||||
|
|
||||||
|
parentPerms, colPerms, err := getParentAndCollectionPermissions(
|
||||||
|
drivePath,
|
||||||
|
dc.FullPath(),
|
||||||
|
parentPermissions,
|
||||||
|
restorePerms)
|
||||||
|
if err != nil {
|
||||||
|
errUpdater(directory.String(), err)
|
||||||
|
return metrics, folderPerms, permissionIDMappings, false
|
||||||
|
}
|
||||||
|
|
||||||
// Create restore folders and get the folder ID of the folder the data stream will be restored in
|
// Create restore folders and get the folder ID of the folder the data stream will be restored in
|
||||||
restoreFolderID, err := CreateRestoreFolders(ctx, service, drivePath.DriveID, restoreFolderElements)
|
restoreFolderID, permissionIDMappings, err := createRestoreFoldersWithPermissions(
|
||||||
|
ctx,
|
||||||
|
service,
|
||||||
|
drivePath.DriveID,
|
||||||
|
restoreFolderElements,
|
||||||
|
parentPerms,
|
||||||
|
colPerms,
|
||||||
|
permissionIDMappings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errUpdater(directory.String(), errors.Wrapf(err, "failed to create folders %v", restoreFolderElements))
|
errUpdater(directory.String(), errors.Wrapf(err, "failed to create folders %v", restoreFolderElements))
|
||||||
return metrics, folderPerms, permissionIDMappings, false
|
return metrics, folderPerms, permissionIDMappings, false
|
||||||
@ -272,7 +316,7 @@ func RestoreCollection(
|
|||||||
service,
|
service,
|
||||||
drivePath.DriveID,
|
drivePath.DriveID,
|
||||||
itemID,
|
itemID,
|
||||||
parentPerms,
|
colPerms,
|
||||||
meta.Permissions,
|
meta.Permissions,
|
||||||
permissionIDMappings,
|
permissionIDMappings,
|
||||||
)
|
)
|
||||||
@ -288,40 +332,16 @@ func RestoreCollection(
|
|||||||
// RestoreOp, so we still need to handle them in some way.
|
// RestoreOp, so we still need to handle them in some way.
|
||||||
continue
|
continue
|
||||||
} else if strings.HasSuffix(name, DirMetaFileSuffix) {
|
} else if strings.HasSuffix(name, DirMetaFileSuffix) {
|
||||||
trimmedName := strings.TrimSuffix(name, DirMetaFileSuffix)
|
|
||||||
folderID, err := createRestoreFolder(
|
|
||||||
ctx,
|
|
||||||
service,
|
|
||||||
drivePath.DriveID,
|
|
||||||
trimmedName,
|
|
||||||
restoreFolderID,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
errUpdater(itemData.UUID(), err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !restorePerms {
|
if !restorePerms {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := getMetadata(itemData.ToReader())
|
metaReader := itemData.ToReader()
|
||||||
if err != nil {
|
meta, err := getMetadata(metaReader)
|
||||||
errUpdater(itemData.UUID(), err)
|
metaReader.Close()
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
permissionIDMappings, err = restorePermissions(
|
|
||||||
ctx,
|
|
||||||
service,
|
|
||||||
drivePath.DriveID,
|
|
||||||
folderID,
|
|
||||||
parentPerms,
|
|
||||||
meta.Permissions,
|
|
||||||
permissionIDMappings,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errUpdater(itemData.UUID(), err)
|
errUpdater(itemData.UUID(), clues.Wrap(err, "folder metadata"))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,29 +378,43 @@ func RestoreCollection(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a folder with its permissions
|
// createRestoreFoldersWithPermissions creates the restore folder hierarchy in
|
||||||
func createRestoreFolder(
|
// the specified drive and returns the folder ID of the last folder entry in the
|
||||||
|
// hierarchy. Permissions are only applied to the last folder in the hierarchy.
|
||||||
|
// Passing nil for the permissions results in just creating the folder(s).
|
||||||
|
func createRestoreFoldersWithPermissions(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
service graph.Servicer,
|
service graph.Servicer,
|
||||||
driveID, folder, parentFolderID string,
|
driveID string,
|
||||||
) (string, error) {
|
restoreFolders []string,
|
||||||
folderItem, err := createItem(ctx, service, driveID, parentFolderID, newItem(folder, true))
|
parentPermissions []UserPermission,
|
||||||
|
folderPermissions []UserPermission,
|
||||||
|
permissionIDMappings map[string]string,
|
||||||
|
) (string, map[string]string, error) {
|
||||||
|
id, err := CreateRestoreFolders(ctx, service, driveID, restoreFolders)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrapf(
|
return "", permissionIDMappings, err
|
||||||
err,
|
|
||||||
"failed to create folder %s/%s. details: %s", parentFolderID, folder,
|
|
||||||
support.ConnectorStackErrorTrace(err),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Ctx(ctx).Debugf("Resolved %s in %s to %s", folder, parentFolderID, *folderItem.GetId())
|
permissionIDMappings, err = restorePermissions(
|
||||||
|
ctx,
|
||||||
|
service,
|
||||||
|
driveID,
|
||||||
|
id,
|
||||||
|
parentPermissions,
|
||||||
|
folderPermissions,
|
||||||
|
permissionIDMappings)
|
||||||
|
|
||||||
return *folderItem.GetId(), nil
|
return id, permissionIDMappings, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// createRestoreFolders creates the restore folder hierarchy in the specified drive and returns the folder ID
|
// CreateRestoreFolders creates the restore folder hierarchy in the specified
|
||||||
// of the last folder entry in the hierarchy
|
// drive and returns the folder ID of the last folder entry in the hierarchy.
|
||||||
func CreateRestoreFolders(ctx context.Context, service graph.Servicer, driveID string, restoreFolders []string,
|
func CreateRestoreFolders(
|
||||||
|
ctx context.Context,
|
||||||
|
service graph.Servicer,
|
||||||
|
driveID string,
|
||||||
|
restoreFolders []string,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
driveRoot, err := service.Client().DrivesById(driveID).Root().Get(ctx, nil)
|
driveRoot, err := service.Client().DrivesById(driveID).Root().Get(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -69,7 +69,7 @@ func RestoreCollections(
|
|||||||
backupVersion,
|
backupVersion,
|
||||||
service,
|
service,
|
||||||
dc,
|
dc,
|
||||||
[]onedrive.UserPermission{}, // Currently permission data is not stored for sharepoint
|
map[string][]onedrive.UserPermission{}, // Currently permission data is not stored for sharepoint
|
||||||
onedrive.OneDriveSource,
|
onedrive.OneDriveSource,
|
||||||
dest.ContainerName,
|
dest.ContainerName,
|
||||||
deets,
|
deets,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user