diff --git a/CHANGELOG.md b/CHANGELOG.md index 28c4d2de3..b93597507 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Fixed issue where repository connect progress bar was clobbering backup/restore operation output. -- Fixed issue where a `backup create exchange` produced one backup record per data type. +- Issue where repository connect progress bar was clobbering backup/restore operation output. +- Issue where a `backup create exchange` produced one backup record per data type. +- Specifying multiple users in a onedrive backup (ex: `--user a,b,c`) now properly delimits the input along the commas. ### Known Issues diff --git a/src/cli/backup/onedrive.go b/src/cli/backup/onedrive.go index e94338cfd..29c18d7e7 100644 --- a/src/cli/backup/onedrive.go +++ b/src/cli/backup/onedrive.go @@ -83,7 +83,7 @@ func addOneDriveCommands(cmd *cobra.Command) *cobra.Command { c.Use = c.Use + " " + oneDriveServiceCommandCreateUseSuffix c.Example = oneDriveServiceCommandCreateExamples - fs.StringArrayVar(&user, + fs.StringSliceVar(&user, utils.UserFN, nil, "Backup OneDrive data by user ID; accepts '"+utils.Wildcard+"' to select all users. (required)") options.AddOperationFlags(c) diff --git a/src/internal/connector/onedrive/drive.go b/src/internal/connector/onedrive/drive.go index 904e5dd41..55e1ead53 100644 --- a/src/internal/connector/onedrive/drive.go +++ b/src/internal/connector/onedrive/drive.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "strings" + "time" msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core" msdrive "github.com/microsoftgraph/msgraph-sdk-go/drive" @@ -100,7 +101,11 @@ func siteDrives(ctx context.Context, service graph.Servicer, site string) ([]mod } func userDrives(ctx context.Context, service graph.Servicer, user string) ([]models.Driveable, error) { - var hasDrive bool + var ( + hasDrive bool + numberOfRetries = 3 + r models.DriveCollectionResponseable + ) hasDrive, err := hasDriveLicense(ctx, service, user) if err != nil { @@ -112,15 +117,30 @@ func userDrives(ctx context.Context, service graph.Servicer, user string) ([]mod return make([]models.Driveable, 0), nil // no license } - r, err := service.Client().UsersById(user).Drives().Get(ctx, nil) - if err != nil { - if strings.Contains(support.ConnectorStackErrorTrace(err), userDoesNotHaveDrive) { - logger.Ctx(ctx).Debugf("User %s does not have a drive", user) - return make([]models.Driveable, 0), nil // no license + // Retry Loop for Drive retrieval. Request can timeout + for i := 0; i <= numberOfRetries; i++ { + r, err = service.Client().UsersById(user).Drives().Get(ctx, nil) + if err != nil { + detailedError := support.ConnectorStackErrorTrace(err) + if strings.Contains(detailedError, userDoesNotHaveDrive) { + logger.Ctx(ctx).Debugf("User %s does not have a drive", user) + return make([]models.Driveable, 0), nil // no license + } + + if strings.Contains(detailedError, "context deadline exceeded") && i < numberOfRetries { + time.Sleep(time.Duration(3*(i+1)) * time.Second) + continue + } + + return nil, errors.Wrapf( + err, + "failed to retrieve user drives. user: %s, details: %s", + user, + detailedError, + ) } - return nil, errors.Wrapf(err, "failed to retrieve user drives. user: %s, details: %s", - user, support.ConnectorStackErrorTrace(err)) + break } logger.Ctx(ctx).Debugf("Found %d drives for user %s", len(r.GetValue()), user)