add teamschats to m365 backup

tests will arrive in a later PR
This commit is contained in:
ryanfkeepers 2024-01-23 14:34:43 -07:00
parent 9831fb8f91
commit 7d9d0e04cc
7 changed files with 110 additions and 72 deletions

View File

@ -13,7 +13,10 @@ import (
"github.com/alcionai/corso/src/internal/m365/service/groups"
"github.com/alcionai/corso/src/internal/m365/service/onedrive"
"github.com/alcionai/corso/src/internal/m365/service/sharepoint"
"github.com/alcionai/corso/src/internal/m365/service/teamschats"
"github.com/alcionai/corso/src/internal/m365/support"
"github.com/alcionai/corso/src/internal/operations/inject"
"github.com/alcionai/corso/src/pkg/account"
bupMD "github.com/alcionai/corso/src/pkg/backup/metadata"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/count"
@ -22,9 +25,31 @@ import (
"github.com/alcionai/corso/src/pkg/filters"
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/selectors"
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
)
type backupHandler interface {
produceBackupCollectionser
}
type produceBackupCollectionser interface {
ProduceBackupCollections(
ctx context.Context,
bpc inject.BackupProducerConfig,
ac api.Client,
creds account.M365Config,
su support.StatusUpdater,
counter *count.Bus,
errs *fault.Bus,
) (
collections []data.BackupCollection,
excludeItems *prefixmatcher.StringSetMatcher,
canUsePreviousBackup bool,
err error,
)
}
// ---------------------------------------------------------------------------
// Data Collections
// ---------------------------------------------------------------------------
@ -63,67 +88,40 @@ func (ctrl *Controller) ProduceBackupCollections(
canUsePreviousBackup bool
)
var handler backupHandler
switch service {
case path.ExchangeService:
colls, excludeItems, canUsePreviousBackup, err = exchange.ProduceBackupCollections(
ctx,
bpc,
ctrl.AC,
ctrl.credentials,
ctrl.UpdateStatus,
counter,
errs)
if err != nil {
return nil, nil, false, err
}
handler = exchange.NewBackup()
case path.OneDriveService:
colls, excludeItems, canUsePreviousBackup, err = onedrive.ProduceBackupCollections(
ctx,
bpc,
ctrl.AC,
ctrl.credentials,
ctrl.UpdateStatus,
counter,
errs)
if err != nil {
return nil, nil, false, err
}
handler = onedrive.NewBackup()
case path.SharePointService:
colls, excludeItems, canUsePreviousBackup, err = sharepoint.ProduceBackupCollections(
ctx,
bpc,
ctrl.AC,
ctrl.credentials,
ctrl.UpdateStatus,
counter,
errs)
if err != nil {
return nil, nil, false, err
}
handler = sharepoint.NewBackup()
case path.GroupsService:
colls, excludeItems, err = groups.ProduceBackupCollections(
ctx,
bpc,
ctrl.AC,
ctrl.credentials,
ctrl.UpdateStatus,
counter,
errs)
if err != nil {
return nil, nil, false, err
}
handler = groups.NewBackup()
// canUsePreviousBacukp can be always returned true for groups as we
// return a tombstone collection in case the metadata read fails
canUsePreviousBackup = true
case path.TeamsChatsService:
handler = teamschats.NewBackup()
default:
return nil, nil, false, clues.Wrap(clues.NewWC(ctx, service.String()), "service not supported")
}
colls, excludeItems, canUsePreviousBackup, err = handler.ProduceBackupCollections(
ctx,
bpc,
ctrl.AC,
ctrl.credentials,
ctrl.UpdateStatus,
counter,
errs)
if err != nil {
return nil, nil, false, err
}
for _, c := range colls {
// kopia doesn't stream Items() from deleted collections,
// and so they never end up calling the UpdateStatus closer.
@ -153,25 +151,27 @@ func (ctrl *Controller) IsServiceEnabled(
return sharepoint.IsServiceEnabled(ctx, ctrl.AC.Sites(), resourceOwner)
case path.GroupsService:
return groups.IsServiceEnabled(ctx, ctrl.AC.Groups(), resourceOwner)
case path.TeamsChatsService:
return teamschats.IsServiceEnabled(ctx, ctrl.AC.Users(), resourceOwner)
}
return false, clues.Wrap(clues.NewWC(ctx, service.String()), "service not supported")
}
func verifyBackupInputs(sels selectors.Selector, cachedIDs []string) error {
func verifyBackupInputs(sel selectors.Selector, cachedIDs []string) error {
var ids []string
switch sels.Service {
switch sel.Service {
case selectors.ServiceExchange, selectors.ServiceOneDrive:
// Exchange and OneDrive user existence now checked in checkServiceEnabled.
return nil
case selectors.ServiceSharePoint, selectors.ServiceGroups:
case selectors.ServiceSharePoint, selectors.ServiceGroups, selectors.ServiceTeamsChats:
ids = cachedIDs
}
if !filters.Contains(ids).Compare(sels.ID()) {
return clues.Stack(core.ErrNotFound).With("selector_protected_resource", sels.DiscreteOwner)
if !filters.Contains(ids).Compare(sel.ID()) {
return clues.Stack(core.ErrNotFound).With("selector_protected_resource", sel.ID())
}
return nil

View File

@ -139,7 +139,7 @@ func (suite *DataCollectionIntgSuite) TestExchangeDataCollection() {
Selector: sel,
}
collections, excludes, canUsePreviousBackup, err := exchange.ProduceBackupCollections(
collections, excludes, canUsePreviousBackup, err := exchange.NewBackup().ProduceBackupCollections(
ctx,
bpc,
suite.ac,
@ -309,7 +309,7 @@ func (suite *DataCollectionIntgSuite) TestSharePointDataCollection() {
Selector: sel,
}
collections, excludes, canUsePreviousBackup, err := sharepoint.ProduceBackupCollections(
collections, excludes, canUsePreviousBackup, err := sharepoint.NewBackup().ProduceBackupCollections(
ctx,
bpc,
suite.ac,

View File

@ -19,9 +19,17 @@ import (
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
)
type exchangeBackup struct{}
// NewBackup provides a struct that matches standard apis
// across m365/service handlers.
func NewBackup() *exchangeBackup {
return &exchangeBackup{}
}
// ProduceBackupCollections returns a DataCollection which the caller can
// use to read mailbox data out for the specified user
func ProduceBackupCollections(
func (exchangeBackup) ProduceBackupCollections(
ctx context.Context,
bpc inject.BackupProducerConfig,
ac api.Client,

View File

@ -33,7 +33,15 @@ import (
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
)
func ProduceBackupCollections(
type groupsBackup struct{}
// NewBackup provides a struct that matches standard apis
// across m365/service handlers.
func NewBackup() *groupsBackup {
return &groupsBackup{}
}
func (groupsBackup) ProduceBackupCollections(
ctx context.Context,
bpc inject.BackupProducerConfig,
ac api.Client,
@ -41,10 +49,10 @@ func ProduceBackupCollections(
su support.StatusUpdater,
counter *count.Bus,
errs *fault.Bus,
) ([]data.BackupCollection, *prefixmatcher.StringSetMatcher, error) {
) ([]data.BackupCollection, *prefixmatcher.StringSetMatcher, bool, error) {
b, err := bpc.Selector.ToGroupsBackup()
if err != nil {
return nil, nil, clues.Wrap(err, "groupsDataCollection: parsing selector")
return nil, nil, true, clues.Wrap(err, "groupsDataCollection: parsing selector")
}
var (
@ -65,7 +73,7 @@ func ProduceBackupCollections(
bpc.ProtectedResource.ID(),
api.CallConfig{})
if err != nil {
return nil, nil, clues.WrapWC(ctx, err, "getting group")
return nil, nil, true, clues.WrapWC(ctx, err, "getting group")
}
bc := backupCommon{ac, bpc, creds, group, sitesPreviousPaths, su}
@ -128,7 +136,7 @@ func ProduceBackupCollections(
counter,
errs)
if err != nil {
return nil, nil, err
return nil, nil, true, err
}
collections = append(collections, baseCols...)
@ -142,7 +150,7 @@ func ProduceBackupCollections(
su,
counter)
if err != nil {
return nil, nil, err
return nil, nil, true, err
}
collections = append(collections, md)
@ -151,7 +159,7 @@ func ProduceBackupCollections(
logger.Ctx(ctx).Infow("produced collections", "stats", counter.Values())
return collections, globalItemIDExclusions.ToReader(), el.Failure()
return collections, globalItemIDExclusions.ToReader(), true, el.Failure()
}
type backupCommon struct {

View File

@ -22,7 +22,15 @@ import (
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
)
func ProduceBackupCollections(
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,

View File

@ -20,7 +20,15 @@ import (
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
)
func ProduceBackupCollections(
type sharePointBackup struct{}
// NewBackup provides a struct that matches standard apis
// across m365/service handlers.
func NewBackup() *sharePointBackup {
return &sharePointBackup{}
}
func (sharePointBackup) ProduceBackupCollections(
ctx context.Context,
bpc inject.BackupProducerConfig,
ac api.Client,

View File

@ -22,7 +22,15 @@ import (
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
)
func ProduceBackupCollections(
type teamsChatsBackup struct{}
// NewBackup provides a struct that matches standard apis
// across m365/service handlers.
func NewBackup() *teamsChatsBackup {
return &teamsChatsBackup{}
}
func (teamsChatsBackup) ProduceBackupCollections(
ctx context.Context,
bpc inject.BackupProducerConfig,
ac api.Client,
@ -30,10 +38,10 @@ func ProduceBackupCollections(
su support.StatusUpdater,
counter *count.Bus,
errs *fault.Bus,
) ([]data.BackupCollection, *prefixmatcher.StringSetMatcher, error) {
) ([]data.BackupCollection, *prefixmatcher.StringSetMatcher, bool, error) {
b, err := bpc.Selector.ToTeamsChatsBackup()
if err != nil {
return nil, nil, clues.WrapWC(ctx, err, "parsing selector")
return nil, nil, true, clues.WrapWC(ctx, err, "parsing selector")
}
var (
@ -98,7 +106,7 @@ func ProduceBackupCollections(
counter,
errs)
if err != nil {
return nil, nil, err
return nil, nil, true, err
}
collections = append(collections, baseCols...)
@ -108,7 +116,7 @@ func ProduceBackupCollections(
logger.Ctx(ctx).Infow("produced collections", "stats", counter.Values())
return collections, nil, clues.Stack(el.Failure()).OrNil()
return collections, nil, true, clues.Stack(el.Failure()).OrNil()
}
type backupCommon struct {
@ -126,9 +134,7 @@ func backupChats(
counter *count.Bus,
errs *fault.Bus,
) ([]data.BackupCollection, error) {
var (
colls []data.BackupCollection
)
var colls []data.BackupCollection
progressMessage := observe.MessageWithCompletion(
ctx,