Wire up GraphConnector <-> BackupOp item exclude list (#2245)

## Description

Return an item exclude list from GraphConnector to BackupOp. BackupOp does not yet pass this to kopia wrapper.

Returned list is set to nil (eventually) by all components so even if this were wired to kopia wrapper it wouldn't change the current behavior of the system

## 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)

* #2243

merge after:
* #2143 

## Test Plan

- [ ] 💪 Manual
- [x]  Unit test
- [ ] 💚 E2E
This commit is contained in:
ashmrtn 2023-01-30 11:44:06 -08:00 committed by GitHub
parent 03642c517f
commit 2458508969
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 73 additions and 46 deletions

View File

@ -6,6 +6,7 @@ import (
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/exp/maps"
"github.com/alcionai/corso/src/internal/connector/discovery" "github.com/alcionai/corso/src/internal/connector/discovery"
"github.com/alcionai/corso/src/internal/connector/discovery/api" "github.com/alcionai/corso/src/internal/connector/discovery/api"
@ -35,27 +36,27 @@ func (gc *GraphConnector) DataCollections(
sels selectors.Selector, sels selectors.Selector,
metadata []data.Collection, metadata []data.Collection,
ctrlOpts control.Options, ctrlOpts control.Options,
) ([]data.Collection, error) { ) ([]data.Collection, map[string]struct{}, error) {
ctx, end := D.Span(ctx, "gc:dataCollections", D.Index("service", sels.Service.String())) ctx, end := D.Span(ctx, "gc:dataCollections", D.Index("service", sels.Service.String()))
defer end() defer end()
err := verifyBackupInputs(sels, gc.GetUsers(), gc.GetSiteIDs()) err := verifyBackupInputs(sels, gc.GetUsers(), gc.GetSiteIDs())
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
serviceEnabled, err := checkServiceEnabled(ctx, gc.Owners.Users(), path.ServiceType(sels.Service), sels.DiscreteOwner) serviceEnabled, err := checkServiceEnabled(ctx, gc.Owners.Users(), path.ServiceType(sels.Service), sels.DiscreteOwner)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
if !serviceEnabled { if !serviceEnabled {
return []data.Collection{}, nil return []data.Collection{}, nil, nil
} }
switch sels.Service { switch sels.Service {
case selectors.ServiceExchange: case selectors.ServiceExchange:
colls, err := exchange.DataCollections( colls, excludes, err := exchange.DataCollections(
ctx, ctx,
sels, sels,
metadata, metadata,
@ -64,7 +65,7 @@ func (gc *GraphConnector) DataCollections(
gc.UpdateStatus, gc.UpdateStatus,
ctrlOpts) ctrlOpts)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
for _, c := range colls { for _, c := range colls {
@ -79,13 +80,13 @@ func (gc *GraphConnector) DataCollections(
} }
} }
return colls, nil return colls, excludes, nil
case selectors.ServiceOneDrive: case selectors.ServiceOneDrive:
return gc.OneDriveDataCollections(ctx, sels, ctrlOpts) return gc.OneDriveDataCollections(ctx, sels, ctrlOpts)
case selectors.ServiceSharePoint: case selectors.ServiceSharePoint:
colls, err := sharepoint.DataCollections( colls, excludes, err := sharepoint.DataCollections(
ctx, ctx,
gc.itemClient, gc.itemClient,
sels, sels,
@ -94,17 +95,17 @@ func (gc *GraphConnector) DataCollections(
gc, gc,
ctrlOpts) ctrlOpts)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
for range colls { for range colls {
gc.incrementAwaitingMessages() gc.incrementAwaitingMessages()
} }
return colls, nil return colls, excludes, nil
default: default:
return nil, errors.Errorf("service %s not supported", sels.Service.String()) return nil, nil, errors.Errorf("service %s not supported", sels.Service.String())
} }
} }
@ -182,15 +183,16 @@ func (gc *GraphConnector) OneDriveDataCollections(
ctx context.Context, ctx context.Context,
selector selectors.Selector, selector selectors.Selector,
ctrlOpts control.Options, ctrlOpts control.Options,
) ([]data.Collection, error) { ) ([]data.Collection, map[string]struct{}, error) {
odb, err := selector.ToOneDriveBackup() odb, err := selector.ToOneDriveBackup()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "oneDriveDataCollection: parsing selector") return nil, nil, errors.Wrap(err, "oneDriveDataCollection: parsing selector")
} }
var ( var (
user = selector.DiscreteOwner user = selector.DiscreteOwner
collections = []data.Collection{} collections = []data.Collection{}
allExcludes = map[string]struct{}{}
errs error errs error
) )
@ -198,7 +200,7 @@ func (gc *GraphConnector) OneDriveDataCollections(
for _, scope := range odb.Scopes() { for _, scope := range odb.Scopes() {
logger.Ctx(ctx).With("user", user).Debug("Creating OneDrive collections") logger.Ctx(ctx).With("user", user).Debug("Creating OneDrive collections")
odcs, err := onedrive.NewCollections( odcs, excludes, err := onedrive.NewCollections(
gc.itemClient, gc.itemClient,
gc.credentials.AzureTenantID, gc.credentials.AzureTenantID,
user, user,
@ -209,15 +211,17 @@ func (gc *GraphConnector) OneDriveDataCollections(
ctrlOpts, ctrlOpts,
).Get(ctx) ).Get(ctx)
if err != nil { if err != nil {
return nil, support.WrapAndAppend(user, err, errs) return nil, nil, support.WrapAndAppend(user, err, errs)
} }
collections = append(collections, odcs...) collections = append(collections, odcs...)
maps.Copy(allExcludes, excludes)
} }
for range collections { for range collections {
gc.incrementAwaitingMessages() gc.incrementAwaitingMessages()
} }
return collections, errs return collections, allExcludes, errs
} }

View File

@ -99,7 +99,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestExchangeDataCollection
for _, test := range tests { for _, test := range tests {
suite.T().Run(test.name, func(t *testing.T) { suite.T().Run(test.name, func(t *testing.T) {
collections, err := exchange.DataCollections( collections, excludes, err := exchange.DataCollections(
ctx, ctx,
test.getSelector(t), test.getSelector(t),
nil, nil,
@ -108,6 +108,8 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestExchangeDataCollection
control.Options{}) control.Options{})
require.NoError(t, err) require.NoError(t, err)
assert.Empty(t, excludes)
for range collections { for range collections {
connector.incrementAwaitingMessages() connector.incrementAwaitingMessages()
} }
@ -199,9 +201,10 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invali
for _, test := range tests { for _, test := range tests {
suite.T().Run(test.name, func(t *testing.T) { suite.T().Run(test.name, func(t *testing.T) {
collections, err := connector.DataCollections(ctx, test.getSelector(t), nil, control.Options{}) collections, excludes, err := connector.DataCollections(ctx, test.getSelector(t), nil, control.Options{})
assert.Error(t, err) assert.Error(t, err)
assert.Empty(t, collections) assert.Empty(t, collections)
assert.Empty(t, excludes)
}) })
} }
} }
@ -242,7 +245,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestSharePointDataCollecti
for _, test := range tests { for _, test := range tests {
suite.T().Run(test.name, func(t *testing.T) { suite.T().Run(test.name, func(t *testing.T) {
collections, err := sharepoint.DataCollections( collections, excludes, err := sharepoint.DataCollections(
ctx, ctx,
graph.HTTPClient(graph.NoTimeout()), graph.HTTPClient(graph.NoTimeout()),
test.getSelector(), test.getSelector(),
@ -251,6 +254,8 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestSharePointDataCollecti
connector, connector,
control.Options{}) control.Options{})
require.NoError(t, err) require.NoError(t, err)
// Not expecting excludes as this isn't an incremental backup.
assert.Empty(t, excludes)
for range collections { for range collections {
connector.incrementAwaitingMessages() connector.incrementAwaitingMessages()
@ -320,9 +325,11 @@ func (suite *ConnectorCreateSharePointCollectionIntegrationSuite) TestCreateShar
sel := selectors.NewSharePointBackup(siteIDs) sel := selectors.NewSharePointBackup(siteIDs)
sel.Include(sel.Libraries([]string{"foo"}, selectors.PrefixMatch())) sel.Include(sel.Libraries([]string{"foo"}, selectors.PrefixMatch()))
cols, err := gc.DataCollections(ctx, sel.Selector, nil, control.Options{}) cols, excludes, err := gc.DataCollections(ctx, sel.Selector, nil, control.Options{})
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, cols, 1) assert.Len(t, cols, 1)
// No excludes yet as this isn't an incremental backup.
assert.Empty(t, excludes)
for _, collection := range cols { for _, collection := range cols {
t.Logf("Path: %s\n", collection.FullPath().String()) t.Logf("Path: %s\n", collection.FullPath().String())
@ -344,9 +351,11 @@ func (suite *ConnectorCreateSharePointCollectionIntegrationSuite) TestCreateShar
sel := selectors.NewSharePointBackup(siteIDs) sel := selectors.NewSharePointBackup(siteIDs)
sel.Include(sel.Lists(selectors.Any(), selectors.PrefixMatch())) sel.Include(sel.Lists(selectors.Any(), selectors.PrefixMatch()))
cols, err := gc.DataCollections(ctx, sel.Selector, nil, control.Options{}) cols, excludes, err := gc.DataCollections(ctx, sel.Selector, nil, control.Options{})
require.NoError(t, err) require.NoError(t, err)
assert.Less(t, 0, len(cols)) assert.Less(t, 0, len(cols))
// No excludes yet as this isn't an incremental backup.
assert.Empty(t, excludes)
for _, collection := range cols { for _, collection := range cols {
t.Logf("Path: %s\n", collection.FullPath().String()) t.Logf("Path: %s\n", collection.FullPath().String())

View File

@ -167,10 +167,10 @@ func DataCollections(
acct account.M365Config, acct account.M365Config,
su support.StatusUpdater, su support.StatusUpdater,
ctrlOpts control.Options, ctrlOpts control.Options,
) ([]data.Collection, error) { ) ([]data.Collection, map[string]struct{}, error) {
eb, err := selector.ToExchangeBackup() eb, err := selector.ToExchangeBackup()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "exchangeDataCollection: parsing selector") return nil, nil, errors.Wrap(err, "exchangeDataCollection: parsing selector")
} }
var ( var (
@ -181,7 +181,7 @@ func DataCollections(
cdps, err := parseMetadataCollections(ctx, metadata) cdps, err := parseMetadataCollections(ctx, metadata)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
for _, scope := range eb.Scopes() { for _, scope := range eb.Scopes() {
@ -196,13 +196,15 @@ func DataCollections(
ctrlOpts, ctrlOpts,
su) su)
if err != nil { if err != nil {
return nil, support.WrapAndAppend(user, err, errs) return nil, nil, support.WrapAndAppend(user, err, errs)
} }
collections = append(collections, dcs...) collections = append(collections, dcs...)
} }
return collections, errs // Exchange does not require adding items to the global exclude list so always
// return nil.
return collections, nil, errs
} }
func getterByType(ac api.Client, category path.CategoryType) (addedAndRemovedItemIDsGetter, error) { func getterByType(ac api.Client, category path.CategoryType) (addedAndRemovedItemIDsGetter, error) {

View File

@ -425,8 +425,10 @@ func runRestoreBackupTest(
t.Logf("Selective backup of %s\n", backupSel) t.Logf("Selective backup of %s\n", backupSel)
start = time.Now() start = time.Now()
dcs, err := backupGC.DataCollections(ctx, backupSel, nil, control.Options{}) dcs, excludes, err := backupGC.DataCollections(ctx, backupSel, nil, control.Options{})
require.NoError(t, err) require.NoError(t, err)
// No excludes yet because this isn't an incremental backup.
assert.Empty(t, excludes)
t.Logf("Backup enumeration complete in %v\n", time.Since(start)) t.Logf("Backup enumeration complete in %v\n", time.Since(start))
@ -898,8 +900,10 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames
backupSel := backupSelectorForExpected(t, test.service, expectedDests) backupSel := backupSelectorForExpected(t, test.service, expectedDests)
t.Log("Selective backup of", backupSel) t.Log("Selective backup of", backupSel)
dcs, err := backupGC.DataCollections(ctx, backupSel, nil, control.Options{}) dcs, excludes, err := backupGC.DataCollections(ctx, backupSel, nil, control.Options{})
require.NoError(t, err) require.NoError(t, err)
// No excludes yet because this isn't an incremental backup.
assert.Empty(t, excludes)
t.Log("Backup enumeration complete") t.Log("Backup enumeration complete")

View File

@ -92,19 +92,20 @@ func NewCollections(
} }
} }
// Retrieves drive data as set of `data.Collections` // Retrieves drive data as set of `data.Collections` and a set of item names to
func (c *Collections) Get(ctx context.Context) ([]data.Collection, error) { // be excluded from the upcoming backup.
func (c *Collections) Get(ctx context.Context) ([]data.Collection, map[string]struct{}, error) {
// Enumerate drives for the specified resourceOwner // Enumerate drives for the specified resourceOwner
pager, err := PagerForSource(c.source, c.service, c.resourceOwner, nil) pager, err := PagerForSource(c.source, c.service, c.resourceOwner, nil)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
retry := c.source == OneDriveSource retry := c.source == OneDriveSource
drives, err := drives(ctx, pager, retry) drives, err := drives(ctx, pager, retry)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
var ( var (
@ -133,7 +134,7 @@ func (c *Collections) Get(ctx context.Context) ([]data.Collection, error) {
c.UpdateCollections, c.UpdateCollections,
) )
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
if len(delta) > 0 { if len(delta) > 0 {
@ -185,7 +186,8 @@ func (c *Collections) Get(ctx context.Context) ([]data.Collection, error) {
collections = append(collections, metadata) collections = append(collections, metadata)
} }
return collections, nil // TODO(ashmrtn): Track and return the set of items to exclude.
return collections, nil, nil
} }
// UpdateCollections initializes and adds the provided drive items to Collections // UpdateCollections initializes and adds the provided drive items to Collections

View File

@ -454,7 +454,7 @@ func (suite *OneDriveSuite) TestOneDriveNewCollections() {
scope := selectors. scope := selectors.
NewOneDriveBackup([]string{test.user}). NewOneDriveBackup([]string{test.user}).
AllData()[0] AllData()[0]
odcs, err := NewCollections( odcs, excludes, err := NewCollections(
graph.HTTPClient(graph.NoTimeout()), graph.HTTPClient(graph.NoTimeout()),
creds.AzureTenantID, creds.AzureTenantID,
test.user, test.user,
@ -465,6 +465,8 @@ func (suite *OneDriveSuite) TestOneDriveNewCollections() {
control.Options{}, control.Options{},
).Get(ctx) ).Get(ctx)
assert.NoError(t, err) assert.NoError(t, err)
// Don't expect excludes as this isn't an incremental backup.
assert.Empty(t, excludes)
for _, entry := range odcs { for _, entry := range odcs {
assert.NotEmpty(t, entry.FullPath()) assert.NotEmpty(t, entry.FullPath())

View File

@ -31,10 +31,10 @@ func DataCollections(
serv graph.Servicer, serv graph.Servicer,
su statusUpdater, su statusUpdater,
ctrlOpts control.Options, ctrlOpts control.Options,
) ([]data.Collection, error) { ) ([]data.Collection, map[string]struct{}, error) {
b, err := selector.ToSharePointBackup() b, err := selector.ToSharePointBackup()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "sharePointDataCollection: parsing selector") return nil, nil, errors.Wrap(err, "sharePointDataCollection: parsing selector")
} }
var ( var (
@ -63,11 +63,11 @@ func DataCollections(
su, su,
ctrlOpts) ctrlOpts)
if err != nil { if err != nil {
return nil, support.WrapAndAppend(site, err, errs) return nil, nil, support.WrapAndAppend(site, err, errs)
} }
case path.LibrariesCategory: case path.LibrariesCategory:
spcs, err = collectLibraries( spcs, _, err = collectLibraries(
ctx, ctx,
itemClient, itemClient,
serv, serv,
@ -77,7 +77,7 @@ func DataCollections(
su, su,
ctrlOpts) ctrlOpts)
if err != nil { if err != nil {
return nil, support.WrapAndAppend(site, err, errs) return nil, nil, support.WrapAndAppend(site, err, errs)
} }
} }
@ -85,7 +85,7 @@ func DataCollections(
foldersComplete <- struct{}{} foldersComplete <- struct{}{}
} }
return collections, errs return collections, nil, errs
} }
func collectLists( func collectLists(
@ -134,7 +134,7 @@ func collectLibraries(
scope selectors.SharePointScope, scope selectors.SharePointScope,
updater statusUpdater, updater statusUpdater,
ctrlOpts control.Options, ctrlOpts control.Options,
) ([]data.Collection, error) { ) ([]data.Collection, map[string]struct{}, error) {
var ( var (
collections = []data.Collection{} collections = []data.Collection{}
errs error errs error
@ -152,12 +152,12 @@ func collectLibraries(
updater.UpdateStatus, updater.UpdateStatus,
ctrlOpts) ctrlOpts)
odcs, err := colls.Get(ctx) odcs, excludes, err := colls.Get(ctx)
if err != nil { if err != nil {
return nil, support.WrapAndAppend(siteID, err, errs) return nil, nil, support.WrapAndAppend(siteID, err, errs)
} }
return append(collections, odcs...), errs return append(collections, odcs...), excludes, errs
} }
type folderMatcher struct { type folderMatcher struct {

View File

@ -261,7 +261,11 @@ func produceBackupDataCollections(
closer() closer()
}() }()
return gc.DataCollections(ctx, sel, metadata, ctrlOpts) // TODO(ashmrtn): When we're ready to wire up the global exclude list return
// all values.
cols, _, errs := gc.DataCollections(ctx, sel, metadata, ctrlOpts)
return cols, errs
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------