Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Commit

Permalink
Split backups by (resource owner, service) at CLI layer (#1609)
Browse files Browse the repository at this point in the history
## Description

Sketch of how to split backups by (resource owner, service) for exchange. Needs more support from selectors package to be complete.

## Type of change

<!--- Please check the type of change your PR introduces: --->
- [x] 🌻 Feature
- [ ] 🐛 Bugfix
- [ ] 🗺️ Documentation
- [ ] 🤖 Test
- [ ] 💻 CI/Deployment
- [ ] 🐹 Trivial/Minor

## Issue(s)

* closes #1505

## Test Plan

<!-- How will this be tested prior to merging.-->
- [x] 💪 Manual
- [ ] ⚡ Unit test
- [ ] 💚 E2E
  • Loading branch information
ashmrtn authored Nov 30, 2022
1 parent c4333ad commit 27d0980
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 29 deletions.
55 changes: 46 additions & 9 deletions src/cli/backup/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package backup
import (
"context"

"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
Expand All @@ -19,6 +20,7 @@ import (
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/repository"
"github.com/alcionai/corso/src/pkg/selectors"
"github.com/alcionai/corso/src/pkg/services/m365"
"github.com/alcionai/corso/src/pkg/store"
)

Expand Down Expand Up @@ -270,27 +272,62 @@ func createExchangeCmd(cmd *cobra.Command, args []string) error {

sel := exchangeBackupCreateSelectors(user, exchangeData)

bo, err := r.NewBackup(ctx, sel)
users, err := m365.UserIDs(ctx, acct)
if err != nil {
return Only(ctx, errors.Wrap(err, "Failed to initialize Exchange backup"))
return Only(ctx, errors.Wrap(err, "Failed to retrieve M365 users"))
}

err = bo.Run(ctx)
if err != nil {
return Only(ctx, errors.Wrap(err, "Failed to run Exchange backup"))
var (
errs *multierror.Error
bIDs []model.StableID
)

for _, scope := range sel.DiscreteScopes(users) {
for _, selUser := range scope.Get(selectors.ExchangeUser) {
opSel := selectors.NewExchangeBackup()
opSel.Include([]selectors.ExchangeScope{scope.DiscreteCopy(selUser)})

bo, err := r.NewBackup(ctx, opSel.Selector)
if err != nil {
errs = multierror.Append(errs, errors.Wrapf(
err,
"Failed to initialize Exchange backup for user %s",
scope.Get(selectors.ExchangeUser),
))

continue
}

err = bo.Run(ctx)
if err != nil {
errs = multierror.Append(errs, errors.Wrapf(
err,
"Failed to run Exchange backup for user %s",
scope.Get(selectors.ExchangeUser),
))

continue
}

bIDs = append(bIDs, bo.Results.BackupID)
}
}

bu, err := r.Backup(ctx, bo.Results.BackupID)
bups, err := r.Backups(ctx, bIDs)
if err != nil {
return Only(ctx, errors.Wrap(err, "Unable to retrieve backup results from storage"))
}

bu.Print(ctx)
backup.PrintAll(ctx, bups)

if e := errs.ErrorOrNil(); e != nil {
return Only(ctx, e)
}

return nil
}

func exchangeBackupCreateSelectors(userIDs, data []string) selectors.Selector {
func exchangeBackupCreateSelectors(userIDs, data []string) *selectors.ExchangeBackup {
sel := selectors.NewExchangeBackup()

if len(data) == 0 {
Expand All @@ -310,7 +347,7 @@ func exchangeBackupCreateSelectors(userIDs, data []string) selectors.Selector {
}
}

return sel.Selector
return sel
}

func validateExchangeBackupCreateFlags(userIDs, data []string) error {
Expand Down
57 changes: 47 additions & 10 deletions src/cli/backup/onedrive.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package backup
import (
"context"

"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
Expand All @@ -18,6 +19,7 @@ import (
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/repository"
"github.com/alcionai/corso/src/pkg/selectors"
"github.com/alcionai/corso/src/pkg/services/m365"
"github.com/alcionai/corso/src/pkg/store"
)

Expand Down Expand Up @@ -192,22 +194,57 @@ func createOneDriveCmd(cmd *cobra.Command, args []string) error {

sel := oneDriveBackupCreateSelectors(user)

bo, err := r.NewBackup(ctx, sel)
users, err := m365.UserIDs(ctx, acct)
if err != nil {
return Only(ctx, errors.Wrap(err, "Failed to initialize OneDrive backup"))
return Only(ctx, errors.Wrap(err, "Failed to retrieve M365 users"))
}

err = bo.Run(ctx)
if err != nil {
return Only(ctx, errors.Wrap(err, "Failed to run OneDrive backup"))
var (
errs *multierror.Error
bIDs []model.StableID
)

for _, scope := range sel.DiscreteScopes(users) {
for _, selUser := range scope.Get(selectors.OneDriveUser) {
opSel := selectors.NewOneDriveBackup()
opSel.Include([]selectors.OneDriveScope{scope.DiscreteCopy(selUser)})

bo, err := r.NewBackup(ctx, opSel.Selector)
if err != nil {
errs = multierror.Append(errs, errors.Wrapf(
err,
"Failed to initialize OneDrive backup for user %s",
scope.Get(selectors.OneDriveUser),
))

continue
}

err = bo.Run(ctx)
if err != nil {
errs = multierror.Append(errs, errors.Wrapf(
err,
"Failed to run OneDrive backup for user %s",
scope.Get(selectors.OneDriveUser),
))

continue
}

bIDs = append(bIDs, bo.Results.BackupID)
}
}

bu, err := r.Backup(ctx, bo.Results.BackupID)
bups, err := r.Backups(ctx, bIDs)
if err != nil {
return errors.Wrap(err, "Unable to retrieve backup results from storage")
return Only(ctx, errors.Wrap(err, "Unable to retrieve backup results from storage"))
}

bu.Print(ctx)
backup.PrintAll(ctx, bups)

if e := errs.ErrorOrNil(); e != nil {
return Only(ctx, e)
}

return nil
}
Expand All @@ -220,11 +257,11 @@ func validateOneDriveBackupCreateFlags(users []string) error {
return nil
}

func oneDriveBackupCreateSelectors(users []string) selectors.Selector {
func oneDriveBackupCreateSelectors(users []string) *selectors.OneDriveBackup {
sel := selectors.NewOneDriveBackup()
sel.Include(sel.Users(users))

return sel.Selector
return sel
}

// ------------------------------------------------------------------------------------------------
Expand Down
57 changes: 47 additions & 10 deletions src/cli/backup/sharepoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package backup
import (
"context"

"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
Expand All @@ -18,6 +19,7 @@ import (
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/repository"
"github.com/alcionai/corso/src/pkg/selectors"
"github.com/alcionai/corso/src/pkg/services/m365"
"github.com/alcionai/corso/src/pkg/store"
)

Expand Down Expand Up @@ -181,22 +183,57 @@ func createSharePointCmd(cmd *cobra.Command, args []string) error {

sel := sharePointBackupCreateSelectors(site)

bo, err := r.NewBackup(ctx, sel)
sites, err := m365.Sites(ctx, acct)
if err != nil {
return Only(ctx, errors.Wrap(err, "Failed to initialize SharePoint backup"))
return Only(ctx, errors.Wrap(err, "Failed to retrieve SharePoint sites"))
}

err = bo.Run(ctx)
if err != nil {
return Only(ctx, errors.Wrap(err, "Failed to run SharePoint backup"))
var (
errs *multierror.Error
bIDs []model.StableID
)

for _, scope := range sel.DiscreteScopes(sites) {
for _, selSite := range scope.Get(selectors.SharePointSite) {
opSel := selectors.NewSharePointBackup()
opSel.Include([]selectors.SharePointScope{scope.DiscreteCopy(selSite)})

bo, err := r.NewBackup(ctx, opSel.Selector)
if err != nil {
errs = multierror.Append(errs, errors.Wrapf(
err,
"Failed to initialize SharePoint backup for site %s",
scope.Get(selectors.SharePointSite),
))

continue
}

err = bo.Run(ctx)
if err != nil {
errs = multierror.Append(errs, errors.Wrapf(
err,
"Failed to run SharePoint backup for site %s",
scope.Get(selectors.SharePointSite),
))

continue
}

bIDs = append(bIDs, bo.Results.BackupID)
}
}

bu, err := r.Backup(ctx, bo.Results.BackupID)
bups, err := r.Backups(ctx, bIDs)
if err != nil {
return errors.Wrap(err, "Unable to retrieve backup results from storage")
return Only(ctx, errors.Wrap(err, "Unable to retrieve backup results from storage"))
}

bu.Print(ctx)
backup.PrintAll(ctx, bups)

if e := errs.ErrorOrNil(); e != nil {
return Only(ctx, e)
}

return nil
}
Expand All @@ -209,11 +246,11 @@ func validateSharePointBackupCreateFlags(sites []string) error {
return nil
}

func sharePointBackupCreateSelectors(sites []string) selectors.Selector {
func sharePointBackupCreateSelectors(sites []string) *selectors.SharePointBackup {
sel := selectors.NewSharePointBackup()
sel.Include(sel.Sites(sites))

return sel.Selector
return sel
}

// ------------------------------------------------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions src/internal/connector/graph_connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ func NewGraphConnector(ctx context.Context, acct account.Account, r resource) (*

gc.graphService = *aService

// TODO(ashmrtn): When selectors only encapsulate a single resource owner that
// is not a wildcard don't populate users or sites when making the connector.
// For now this keeps things functioning if callers do pass in a selector like
// "*" instead of.
if r == AllResources || r == Users {
if err = gc.setTenantUsers(ctx); err != nil {
return nil, errors.Wrap(err, "retrieving tenant user list")
Expand Down
11 changes: 11 additions & 0 deletions src/pkg/services/m365/m365.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,14 @@ func GetEmailAndUserID(ctx context.Context, m365Account account.Account) (map[st

return gc.Users, nil
}

// Sites returns a list of SharePoint sites in the specified M365 tenant
// TODO: Implement paging support
func Sites(ctx context.Context, m365Account account.Account) ([]string, error) {
gc, err := connector.NewGraphConnector(ctx, m365Account, connector.Sites)
if err != nil {
return nil, errors.Wrap(err, "could not initialize M365 graph connection")
}

return gc.GetSites(), nil
}

0 comments on commit 27d0980

Please sign in to comment.