add teamschats to m365 backup
tests will arrive in a later PR
This commit is contained in:
parent
9831fb8f91
commit
7d9d0e04cc
@ -13,7 +13,10 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/m365/service/groups"
|
"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/onedrive"
|
||||||
"github.com/alcionai/corso/src/internal/m365/service/sharepoint"
|
"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/internal/operations/inject"
|
||||||
|
"github.com/alcionai/corso/src/pkg/account"
|
||||||
bupMD "github.com/alcionai/corso/src/pkg/backup/metadata"
|
bupMD "github.com/alcionai/corso/src/pkg/backup/metadata"
|
||||||
"github.com/alcionai/corso/src/pkg/control"
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
"github.com/alcionai/corso/src/pkg/count"
|
"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/filters"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
"github.com/alcionai/corso/src/pkg/selectors"
|
"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"
|
"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
|
// Data Collections
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -63,67 +88,40 @@ func (ctrl *Controller) ProduceBackupCollections(
|
|||||||
canUsePreviousBackup bool
|
canUsePreviousBackup bool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var handler backupHandler
|
||||||
|
|
||||||
switch service {
|
switch service {
|
||||||
case path.ExchangeService:
|
case path.ExchangeService:
|
||||||
colls, excludeItems, canUsePreviousBackup, err = exchange.ProduceBackupCollections(
|
handler = exchange.NewBackup()
|
||||||
ctx,
|
|
||||||
bpc,
|
|
||||||
ctrl.AC,
|
|
||||||
ctrl.credentials,
|
|
||||||
ctrl.UpdateStatus,
|
|
||||||
counter,
|
|
||||||
errs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
case path.OneDriveService:
|
case path.OneDriveService:
|
||||||
colls, excludeItems, canUsePreviousBackup, err = onedrive.ProduceBackupCollections(
|
handler = onedrive.NewBackup()
|
||||||
ctx,
|
|
||||||
bpc,
|
|
||||||
ctrl.AC,
|
|
||||||
ctrl.credentials,
|
|
||||||
ctrl.UpdateStatus,
|
|
||||||
counter,
|
|
||||||
errs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
case path.SharePointService:
|
case path.SharePointService:
|
||||||
colls, excludeItems, canUsePreviousBackup, err = sharepoint.ProduceBackupCollections(
|
handler = sharepoint.NewBackup()
|
||||||
ctx,
|
|
||||||
bpc,
|
|
||||||
ctrl.AC,
|
|
||||||
ctrl.credentials,
|
|
||||||
ctrl.UpdateStatus,
|
|
||||||
counter,
|
|
||||||
errs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
case path.GroupsService:
|
case path.GroupsService:
|
||||||
colls, excludeItems, err = groups.ProduceBackupCollections(
|
handler = groups.NewBackup()
|
||||||
ctx,
|
|
||||||
bpc,
|
|
||||||
ctrl.AC,
|
|
||||||
ctrl.credentials,
|
|
||||||
ctrl.UpdateStatus,
|
|
||||||
counter,
|
|
||||||
errs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// canUsePreviousBacukp can be always returned true for groups as we
|
case path.TeamsChatsService:
|
||||||
// return a tombstone collection in case the metadata read fails
|
handler = teamschats.NewBackup()
|
||||||
canUsePreviousBackup = true
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, nil, false, clues.Wrap(clues.NewWC(ctx, service.String()), "service not supported")
|
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 {
|
for _, c := range colls {
|
||||||
// kopia doesn't stream Items() from deleted collections,
|
// kopia doesn't stream Items() from deleted collections,
|
||||||
// and so they never end up calling the UpdateStatus closer.
|
// 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)
|
return sharepoint.IsServiceEnabled(ctx, ctrl.AC.Sites(), resourceOwner)
|
||||||
case path.GroupsService:
|
case path.GroupsService:
|
||||||
return groups.IsServiceEnabled(ctx, ctrl.AC.Groups(), resourceOwner)
|
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")
|
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
|
var ids []string
|
||||||
|
|
||||||
switch sels.Service {
|
switch sel.Service {
|
||||||
case selectors.ServiceExchange, selectors.ServiceOneDrive:
|
case selectors.ServiceExchange, selectors.ServiceOneDrive:
|
||||||
// Exchange and OneDrive user existence now checked in checkServiceEnabled.
|
// Exchange and OneDrive user existence now checked in checkServiceEnabled.
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
case selectors.ServiceSharePoint, selectors.ServiceGroups:
|
case selectors.ServiceSharePoint, selectors.ServiceGroups, selectors.ServiceTeamsChats:
|
||||||
ids = cachedIDs
|
ids = cachedIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
if !filters.Contains(ids).Compare(sels.ID()) {
|
if !filters.Contains(ids).Compare(sel.ID()) {
|
||||||
return clues.Stack(core.ErrNotFound).With("selector_protected_resource", sels.DiscreteOwner)
|
return clues.Stack(core.ErrNotFound).With("selector_protected_resource", sel.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -139,7 +139,7 @@ func (suite *DataCollectionIntgSuite) TestExchangeDataCollection() {
|
|||||||
Selector: sel,
|
Selector: sel,
|
||||||
}
|
}
|
||||||
|
|
||||||
collections, excludes, canUsePreviousBackup, err := exchange.ProduceBackupCollections(
|
collections, excludes, canUsePreviousBackup, err := exchange.NewBackup().ProduceBackupCollections(
|
||||||
ctx,
|
ctx,
|
||||||
bpc,
|
bpc,
|
||||||
suite.ac,
|
suite.ac,
|
||||||
@ -309,7 +309,7 @@ func (suite *DataCollectionIntgSuite) TestSharePointDataCollection() {
|
|||||||
Selector: sel,
|
Selector: sel,
|
||||||
}
|
}
|
||||||
|
|
||||||
collections, excludes, canUsePreviousBackup, err := sharepoint.ProduceBackupCollections(
|
collections, excludes, canUsePreviousBackup, err := sharepoint.NewBackup().ProduceBackupCollections(
|
||||||
ctx,
|
ctx,
|
||||||
bpc,
|
bpc,
|
||||||
suite.ac,
|
suite.ac,
|
||||||
|
|||||||
@ -19,9 +19,17 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
"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
|
// ProduceBackupCollections returns a DataCollection which the caller can
|
||||||
// use to read mailbox data out for the specified user
|
// use to read mailbox data out for the specified user
|
||||||
func ProduceBackupCollections(
|
func (exchangeBackup) ProduceBackupCollections(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
bpc inject.BackupProducerConfig,
|
bpc inject.BackupProducerConfig,
|
||||||
ac api.Client,
|
ac api.Client,
|
||||||
|
|||||||
@ -33,7 +33,15 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
"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,
|
ctx context.Context,
|
||||||
bpc inject.BackupProducerConfig,
|
bpc inject.BackupProducerConfig,
|
||||||
ac api.Client,
|
ac api.Client,
|
||||||
@ -41,10 +49,10 @@ func ProduceBackupCollections(
|
|||||||
su support.StatusUpdater,
|
su support.StatusUpdater,
|
||||||
counter *count.Bus,
|
counter *count.Bus,
|
||||||
errs *fault.Bus,
|
errs *fault.Bus,
|
||||||
) ([]data.BackupCollection, *prefixmatcher.StringSetMatcher, error) {
|
) ([]data.BackupCollection, *prefixmatcher.StringSetMatcher, bool, error) {
|
||||||
b, err := bpc.Selector.ToGroupsBackup()
|
b, err := bpc.Selector.ToGroupsBackup()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, clues.Wrap(err, "groupsDataCollection: parsing selector")
|
return nil, nil, true, clues.Wrap(err, "groupsDataCollection: parsing selector")
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -65,7 +73,7 @@ func ProduceBackupCollections(
|
|||||||
bpc.ProtectedResource.ID(),
|
bpc.ProtectedResource.ID(),
|
||||||
api.CallConfig{})
|
api.CallConfig{})
|
||||||
if err != nil {
|
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}
|
bc := backupCommon{ac, bpc, creds, group, sitesPreviousPaths, su}
|
||||||
@ -128,7 +136,7 @@ func ProduceBackupCollections(
|
|||||||
counter,
|
counter,
|
||||||
errs)
|
errs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
collections = append(collections, baseCols...)
|
collections = append(collections, baseCols...)
|
||||||
@ -142,7 +150,7 @@ func ProduceBackupCollections(
|
|||||||
su,
|
su,
|
||||||
counter)
|
counter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
collections = append(collections, md)
|
collections = append(collections, md)
|
||||||
@ -151,7 +159,7 @@ func ProduceBackupCollections(
|
|||||||
|
|
||||||
logger.Ctx(ctx).Infow("produced collections", "stats", counter.Values())
|
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 {
|
type backupCommon struct {
|
||||||
|
|||||||
@ -22,7 +22,15 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
"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,
|
ctx context.Context,
|
||||||
bpc inject.BackupProducerConfig,
|
bpc inject.BackupProducerConfig,
|
||||||
ac api.Client,
|
ac api.Client,
|
||||||
|
|||||||
@ -20,7 +20,15 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
"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,
|
ctx context.Context,
|
||||||
bpc inject.BackupProducerConfig,
|
bpc inject.BackupProducerConfig,
|
||||||
ac api.Client,
|
ac api.Client,
|
||||||
|
|||||||
@ -22,7 +22,15 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
"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,
|
ctx context.Context,
|
||||||
bpc inject.BackupProducerConfig,
|
bpc inject.BackupProducerConfig,
|
||||||
ac api.Client,
|
ac api.Client,
|
||||||
@ -30,10 +38,10 @@ func ProduceBackupCollections(
|
|||||||
su support.StatusUpdater,
|
su support.StatusUpdater,
|
||||||
counter *count.Bus,
|
counter *count.Bus,
|
||||||
errs *fault.Bus,
|
errs *fault.Bus,
|
||||||
) ([]data.BackupCollection, *prefixmatcher.StringSetMatcher, error) {
|
) ([]data.BackupCollection, *prefixmatcher.StringSetMatcher, bool, error) {
|
||||||
b, err := bpc.Selector.ToTeamsChatsBackup()
|
b, err := bpc.Selector.ToTeamsChatsBackup()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, clues.WrapWC(ctx, err, "parsing selector")
|
return nil, nil, true, clues.WrapWC(ctx, err, "parsing selector")
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -98,7 +106,7 @@ func ProduceBackupCollections(
|
|||||||
counter,
|
counter,
|
||||||
errs)
|
errs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
collections = append(collections, baseCols...)
|
collections = append(collections, baseCols...)
|
||||||
@ -108,7 +116,7 @@ func ProduceBackupCollections(
|
|||||||
|
|
||||||
logger.Ctx(ctx).Infow("produced collections", "stats", counter.Values())
|
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 {
|
type backupCommon struct {
|
||||||
@ -126,9 +134,7 @@ func backupChats(
|
|||||||
counter *count.Bus,
|
counter *count.Bus,
|
||||||
errs *fault.Bus,
|
errs *fault.Bus,
|
||||||
) ([]data.BackupCollection, error) {
|
) ([]data.BackupCollection, error) {
|
||||||
var (
|
var colls []data.BackupCollection
|
||||||
colls []data.BackupCollection
|
|
||||||
)
|
|
||||||
|
|
||||||
progressMessage := observe.MessageWithCompletion(
|
progressMessage := observe.MessageWithCompletion(
|
||||||
ctx,
|
ctx,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user