ryanfkeepers 7d9d0e04cc add teamschats to m365 backup
tests will arrive in a later PR
2024-01-23 14:34:43 -07:00

167 lines
4.4 KiB
Go

package onedrive
import (
"context"
"fmt"
"github.com/alcionai/clues"
"github.com/alcionai/corso/src/internal/common/prefixmatcher"
"github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/internal/m365/collection/drive"
"github.com/alcionai/corso/src/internal/m365/support"
"github.com/alcionai/corso/src/internal/observe"
"github.com/alcionai/corso/src/internal/operations/inject"
"github.com/alcionai/corso/src/internal/version"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/count"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/logger"
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
)
type oneDriveBackup struct{}
// NewBackup provides a struct that matches standard apis
// across m365/service handlers.
func NewBackup() *oneDriveBackup {
return &oneDriveBackup{}
}
func (oneDriveBackup) ProduceBackupCollections(
ctx context.Context,
bpc inject.BackupProducerConfig,
ac api.Client,
creds account.M365Config,
su support.StatusUpdater,
counter *count.Bus,
errs *fault.Bus,
) ([]data.BackupCollection, *prefixmatcher.StringSetMatcher, bool, error) {
odb, err := bpc.Selector.ToOneDriveBackup()
if err != nil {
return nil, nil, false, clues.WrapWC(ctx, err, "parsing selector")
}
var (
el = errs.Local()
tenantID = creds.AzureTenantID
categories = map[path.CategoryType]struct{}{}
collections = []data.BackupCollection{}
ssmb = prefixmatcher.NewStringSetBuilder()
odcs []data.BackupCollection
canUsePreviousBackup bool
)
// for each scope that includes oneDrive items, get all
for _, scope := range odb.Scopes() {
if el.Failure() != nil {
break
}
logger.Ctx(ctx).Debug("creating OneDrive collections")
nc := drive.NewCollections(
drive.NewUserDriveBackupHandler(ac.Drives(), bpc.ProtectedResource.ID(), scope),
tenantID,
bpc.ProtectedResource,
su,
bpc.Options,
counter)
progressMessage := observe.MessageWithCompletion(
ctx,
observe.ProgressCfg{
Indent: 1,
CompletionMessage: func() string { return fmt.Sprintf("(found %d files)", nc.NumFiles) },
},
path.FilesCategory.HumanString())
defer close(progressMessage)
odcs, canUsePreviousBackup, err = nc.Get(ctx, bpc.MetadataCollections, ssmb, errs)
if err != nil {
el.AddRecoverable(ctx, clues.Stack(err).Label(fault.LabelForceNoBackupCreation))
}
categories[scope.Category().PathType()] = struct{}{}
collections = append(collections, odcs...)
}
mcs, err := migrationCollections(bpc, tenantID, su, counter)
if err != nil {
return nil, nil, false, err
}
collections = append(collections, mcs...)
if len(collections) > 0 {
baseCols, err := graph.BaseCollections(
ctx,
collections,
tenantID,
bpc.ProtectedResource.ID(),
path.OneDriveService,
categories,
su,
counter,
errs)
if err != nil {
return nil, nil, false, err
}
collections = append(collections, baseCols...)
}
logger.Ctx(ctx).Infow("produced collections", "stats", counter.Values())
return collections, ssmb.ToReader(), canUsePreviousBackup, el.Failure()
}
// adds data migrations to the collection set.
func migrationCollections(
bpc inject.BackupProducerConfig,
tenant string,
su support.StatusUpdater,
counter *count.Bus,
) ([]data.BackupCollection, error) {
// assume a version < 0 implies no prior backup, thus nothing to migrate.
if version.IsNoBackup(bpc.LastBackupVersion) {
return nil, nil
}
if bpc.LastBackupVersion >= version.All8MigrateUserPNToID {
return nil, nil
}
counter.Inc(count.RequiresUserPnToIDMigration)
// unlike exchange, which enumerates all folders on every
// backup, onedrive needs to force the owner PN -> ID migration
mc, err := path.BuildPrefix(
tenant,
bpc.ProtectedResource.ID(),
path.OneDriveService,
path.FilesCategory)
if err != nil {
return nil, clues.Wrap(err, "creating user id migration path")
}
mpc, err := path.BuildPrefix(
tenant,
bpc.ProtectedResource.Name(),
path.OneDriveService,
path.FilesCategory)
if err != nil {
return nil, clues.Wrap(err, "creating user name migration path")
}
mgn, err := graph.NewPrefixCollection(mpc, mc, su, counter)
if err != nil {
return nil, clues.Wrap(err, "creating migration collection")
}
return []data.BackupCollection{mgn}, nil
}