Add functions used for restore to existing service-level handlers (#4687)
This continues the push towards having service-level handlers that know how to perform different operations. It adds the helper functions that will be used during restore operations to the existing handler code This logic is not currently used nor does this PR change the restore call path --- #### 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 - [ ] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Supportability/Tests - [ ] 💻 CI/Deployment - [x] 🧹 Tech Debt/Cleanup #### Issue(s) * #4254 #### Test Plan - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
dbdd3f236c
commit
51f44c2988
@ -21,13 +21,13 @@ func (ctrl *Controller) NewServiceHandler(
|
|||||||
|
|
||||||
switch service {
|
switch service {
|
||||||
case path.OneDriveService:
|
case path.OneDriveService:
|
||||||
return onedrive.NewOneDriveHandler(opts), nil
|
return onedrive.NewOneDriveHandler(opts, ctrl.AC, ctrl.resourceHandler), nil
|
||||||
|
|
||||||
case path.SharePointService:
|
case path.SharePointService:
|
||||||
return sharepoint.NewSharePointHandler(opts), nil
|
return sharepoint.NewSharePointHandler(opts, ctrl.AC, ctrl.resourceHandler), nil
|
||||||
|
|
||||||
case path.GroupsService:
|
case path.GroupsService:
|
||||||
return groups.NewGroupsHandler(opts), nil
|
return groups.NewGroupsHandler(opts, ctrl.AC, ctrl.resourceHandler), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, clues.New("unrecognized service").
|
return nil, clues.New("unrecognized service").
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
package resource
|
package resource
|
||||||
|
|
||||||
|
import "github.com/alcionai/clues"
|
||||||
|
|
||||||
|
var ErrNoResourceLookup = clues.New("missing resource lookup client")
|
||||||
|
|
||||||
type Category string
|
type Category string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/data"
|
"github.com/alcionai/corso/src/internal/data"
|
||||||
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
||||||
"github.com/alcionai/corso/src/internal/m365/collection/groups"
|
"github.com/alcionai/corso/src/internal/m365/collection/groups"
|
||||||
|
"github.com/alcionai/corso/src/internal/m365/resource"
|
||||||
"github.com/alcionai/corso/src/internal/operations/inject"
|
"github.com/alcionai/corso/src/internal/operations/inject"
|
||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"github.com/alcionai/corso/src/pkg/control"
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
@ -17,20 +18,33 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/logger"
|
"github.com/alcionai/corso/src/pkg/logger"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ inject.ServiceHandler = &baseGroupsHandler{}
|
var _ inject.ServiceHandler = &groupsHandler{}
|
||||||
|
|
||||||
func NewGroupsHandler(
|
func NewGroupsHandler(
|
||||||
opts control.Options,
|
opts control.Options,
|
||||||
) *baseGroupsHandler {
|
apiClient api.Client,
|
||||||
return &baseGroupsHandler{
|
resourceGetter idname.GetResourceIDAndNamer,
|
||||||
opts: opts,
|
) *groupsHandler {
|
||||||
backupDriveIDNames: idname.NewCache(nil),
|
return &groupsHandler{
|
||||||
backupSiteIDWebURL: idname.NewCache(nil),
|
baseGroupsHandler: baseGroupsHandler{
|
||||||
|
opts: opts,
|
||||||
|
backupDriveIDNames: idname.NewCache(nil),
|
||||||
|
backupSiteIDWebURL: idname.NewCache(nil),
|
||||||
|
},
|
||||||
|
apiClient: apiClient,
|
||||||
|
resourceGetter: resourceGetter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// baseGroupsHandler
|
||||||
|
// ========================================================================== //
|
||||||
|
|
||||||
|
// baseGroupsHandler contains logic for tracking data and doing operations
|
||||||
|
// (e.x. export) that don't require contact with external M356 services.
|
||||||
type baseGroupsHandler struct {
|
type baseGroupsHandler struct {
|
||||||
opts control.Options
|
opts control.Options
|
||||||
|
|
||||||
@ -134,3 +148,39 @@ func (h *baseGroupsHandler) ProduceExportCollections(
|
|||||||
|
|
||||||
return ec, el.Failure()
|
return ec, el.Failure()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// groupsHandler
|
||||||
|
// ========================================================================== //
|
||||||
|
|
||||||
|
// groupsHandler contains logic for handling data and performing operations
|
||||||
|
// (e.x. restore) regardless of whether they require contact with external M365
|
||||||
|
// services or not.
|
||||||
|
type groupsHandler struct {
|
||||||
|
baseGroupsHandler
|
||||||
|
apiClient api.Client
|
||||||
|
resourceGetter idname.GetResourceIDAndNamer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *groupsHandler) IsServiceEnabled(
|
||||||
|
ctx context.Context,
|
||||||
|
resourceID string,
|
||||||
|
) (bool, error) {
|
||||||
|
// TODO(ashmrtn): Move free function implementation to this function.
|
||||||
|
res, err := IsServiceEnabled(ctx, h.apiClient.Groups(), resourceID)
|
||||||
|
return res, clues.Stack(err).OrNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *groupsHandler) PopulateProtectedResourceIDAndName(
|
||||||
|
ctx context.Context,
|
||||||
|
resourceID string, // Can be either ID or name.
|
||||||
|
ins idname.Cacher,
|
||||||
|
) (idname.Provider, error) {
|
||||||
|
if h.resourceGetter == nil {
|
||||||
|
return nil, clues.StackWC(ctx, resource.ErrNoResourceLookup)
|
||||||
|
}
|
||||||
|
|
||||||
|
pr, err := h.resourceGetter.GetResourceIDAndNameFrom(ctx, resourceID, ins)
|
||||||
|
|
||||||
|
return pr, clues.Wrap(err, "identifying resource owner").OrNil()
|
||||||
|
}
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/export"
|
"github.com/alcionai/corso/src/pkg/export"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ExportUnitSuite struct {
|
type ExportUnitSuite struct {
|
||||||
@ -96,7 +97,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections_messages() {
|
|||||||
|
|
||||||
stats := data.ExportStats{}
|
stats := data.ExportStats{}
|
||||||
|
|
||||||
ecs, err := NewGroupsHandler(control.DefaultOptions()).
|
ecs, err := NewGroupsHandler(control.DefaultOptions(), api.Client{}, nil).
|
||||||
ProduceExportCollections(
|
ProduceExportCollections(
|
||||||
ctx,
|
ctx,
|
||||||
int(version.Backup),
|
int(version.Backup),
|
||||||
@ -196,7 +197,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections_libraries() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewGroupsHandler(control.DefaultOptions())
|
handler := NewGroupsHandler(control.DefaultOptions(), api.Client{}, nil)
|
||||||
handler.CacheItemInfo(dii)
|
handler.CacheItemInfo(dii)
|
||||||
|
|
||||||
stats := data.ExportStats{}
|
stats := data.ExportStats{}
|
||||||
|
|||||||
@ -5,35 +5,58 @@ import (
|
|||||||
|
|
||||||
"github.com/alcionai/clues"
|
"github.com/alcionai/clues"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common/idname"
|
||||||
"github.com/alcionai/corso/src/internal/data"
|
"github.com/alcionai/corso/src/internal/data"
|
||||||
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
||||||
|
"github.com/alcionai/corso/src/internal/m365/resource"
|
||||||
"github.com/alcionai/corso/src/internal/operations/inject"
|
"github.com/alcionai/corso/src/internal/operations/inject"
|
||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"github.com/alcionai/corso/src/pkg/control"
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
"github.com/alcionai/corso/src/pkg/export"
|
"github.com/alcionai/corso/src/pkg/export"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ inject.ServiceHandler = &baseOnedriveHandler{}
|
var _ inject.ServiceHandler = &onedriveHandler{}
|
||||||
|
|
||||||
func NewOneDriveHandler(
|
func NewOneDriveHandler(
|
||||||
opts control.Options,
|
opts control.Options,
|
||||||
) *baseOnedriveHandler {
|
apiClient api.Client,
|
||||||
return &baseOnedriveHandler{
|
resourceGetter idname.GetResourceIDAndNamer,
|
||||||
opts: opts,
|
) *onedriveHandler {
|
||||||
|
return &onedriveHandler{
|
||||||
|
baseOneDriveHandler: baseOneDriveHandler{
|
||||||
|
opts: opts,
|
||||||
|
backupDriveIDNames: idname.NewCache(nil),
|
||||||
|
},
|
||||||
|
apiClient: apiClient,
|
||||||
|
resourceGetter: resourceGetter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type baseOnedriveHandler struct {
|
// ========================================================================== //
|
||||||
opts control.Options
|
// baseOneDriveHandler
|
||||||
|
// ========================================================================== //
|
||||||
|
|
||||||
|
// baseOneDriveHandler contains logic for tracking data and doing operations
|
||||||
|
// (e.x. export) that don't require contact with external M356 services.
|
||||||
|
type baseOneDriveHandler struct {
|
||||||
|
opts control.Options
|
||||||
|
backupDriveIDNames idname.CacheBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *baseOnedriveHandler) CacheItemInfo(v details.ItemInfo) {}
|
func (h *baseOneDriveHandler) CacheItemInfo(v details.ItemInfo) {
|
||||||
|
if v.OneDrive == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.backupDriveIDNames.Add(v.OneDrive.DriveID, v.OneDrive.DriveName)
|
||||||
|
}
|
||||||
|
|
||||||
// ProduceExportCollections will create the export collections for the
|
// ProduceExportCollections will create the export collections for the
|
||||||
// given restore collections.
|
// given restore collections.
|
||||||
func (h *baseOnedriveHandler) ProduceExportCollections(
|
func (h *baseOneDriveHandler) ProduceExportCollections(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
backupVersion int,
|
backupVersion int,
|
||||||
exportCfg control.ExportConfig,
|
exportCfg control.ExportConfig,
|
||||||
@ -65,3 +88,39 @@ func (h *baseOnedriveHandler) ProduceExportCollections(
|
|||||||
|
|
||||||
return ec, el.Failure()
|
return ec, el.Failure()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// onedriveHandler
|
||||||
|
// ========================================================================== //
|
||||||
|
|
||||||
|
// onedriveHandler contains logic for handling data and performing operations
|
||||||
|
// (e.x. restore) regardless of whether they require contact with external M365
|
||||||
|
// services or not.
|
||||||
|
type onedriveHandler struct {
|
||||||
|
baseOneDriveHandler
|
||||||
|
apiClient api.Client
|
||||||
|
resourceGetter idname.GetResourceIDAndNamer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *onedriveHandler) IsServiceEnabled(
|
||||||
|
ctx context.Context,
|
||||||
|
resourceID string,
|
||||||
|
) (bool, error) {
|
||||||
|
// TODO(ashmrtn): Move free function implementation to this function.
|
||||||
|
res, err := IsServiceEnabled(ctx, h.apiClient.Users(), resourceID)
|
||||||
|
return res, clues.Stack(err).OrNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *onedriveHandler) PopulateProtectedResourceIDAndName(
|
||||||
|
ctx context.Context,
|
||||||
|
resourceID string, // Can be either ID or name.
|
||||||
|
ins idname.Cacher,
|
||||||
|
) (idname.Provider, error) {
|
||||||
|
if h.resourceGetter == nil {
|
||||||
|
return nil, clues.StackWC(ctx, resource.ErrNoResourceLookup)
|
||||||
|
}
|
||||||
|
|
||||||
|
pr, err := h.resourceGetter.GetResourceIDAndNameFrom(ctx, resourceID, ins)
|
||||||
|
|
||||||
|
return pr, clues.Wrap(err, "identifying resource owner").OrNil()
|
||||||
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/export"
|
"github.com/alcionai/corso/src/pkg/export"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ExportUnitSuite struct {
|
type ExportUnitSuite struct {
|
||||||
@ -341,7 +342,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections() {
|
|||||||
|
|
||||||
stats := data.ExportStats{}
|
stats := data.ExportStats{}
|
||||||
|
|
||||||
ecs, err := NewOneDriveHandler(control.DefaultOptions()).
|
ecs, err := NewOneDriveHandler(control.DefaultOptions(), api.Client{}, nil).
|
||||||
ProduceExportCollections(
|
ProduceExportCollections(
|
||||||
ctx,
|
ctx,
|
||||||
int(version.Backup),
|
int(version.Backup),
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/common/idname"
|
"github.com/alcionai/corso/src/internal/common/idname"
|
||||||
"github.com/alcionai/corso/src/internal/data"
|
"github.com/alcionai/corso/src/internal/data"
|
||||||
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
||||||
|
"github.com/alcionai/corso/src/internal/m365/resource"
|
||||||
"github.com/alcionai/corso/src/internal/operations/inject"
|
"github.com/alcionai/corso/src/internal/operations/inject"
|
||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"github.com/alcionai/corso/src/pkg/control"
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
@ -15,25 +16,38 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/logger"
|
"github.com/alcionai/corso/src/pkg/logger"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ inject.ServiceHandler = &baseSharepointHandler{}
|
var _ inject.ServiceHandler = &sharepointHandler{}
|
||||||
|
|
||||||
func NewSharePointHandler(
|
func NewSharePointHandler(
|
||||||
opts control.Options,
|
opts control.Options,
|
||||||
) *baseSharepointHandler {
|
apiClient api.Client,
|
||||||
return &baseSharepointHandler{
|
resourceGetter idname.GetResourceIDAndNamer,
|
||||||
opts: opts,
|
) *sharepointHandler {
|
||||||
backupDriveIDNames: idname.NewCache(nil),
|
return &sharepointHandler{
|
||||||
|
baseSharePointHandler: baseSharePointHandler{
|
||||||
|
opts: opts,
|
||||||
|
backupDriveIDNames: idname.NewCache(nil),
|
||||||
|
},
|
||||||
|
apiClient: apiClient,
|
||||||
|
resourceGetter: resourceGetter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type baseSharepointHandler struct {
|
// ========================================================================== //
|
||||||
|
// baseSharePointHandler
|
||||||
|
// ========================================================================== //
|
||||||
|
|
||||||
|
// baseSharePointHandler contains logic for tracking data and doing operations
|
||||||
|
// (e.x. export) that don't require contact with external M356 services.
|
||||||
|
type baseSharePointHandler struct {
|
||||||
opts control.Options
|
opts control.Options
|
||||||
backupDriveIDNames idname.CacheBuilder
|
backupDriveIDNames idname.CacheBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *baseSharepointHandler) CacheItemInfo(v details.ItemInfo) {
|
func (h *baseSharePointHandler) CacheItemInfo(v details.ItemInfo) {
|
||||||
// Old versions would store SharePoint data as OneDrive.
|
// Old versions would store SharePoint data as OneDrive.
|
||||||
switch {
|
switch {
|
||||||
case v.SharePoint != nil:
|
case v.SharePoint != nil:
|
||||||
@ -46,7 +60,7 @@ func (h *baseSharepointHandler) CacheItemInfo(v details.ItemInfo) {
|
|||||||
|
|
||||||
// ProduceExportCollections will create the export collections for the
|
// ProduceExportCollections will create the export collections for the
|
||||||
// given restore collections.
|
// given restore collections.
|
||||||
func (h *baseSharepointHandler) ProduceExportCollections(
|
func (h *baseSharePointHandler) ProduceExportCollections(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
backupVersion int,
|
backupVersion int,
|
||||||
exportCfg control.ExportConfig,
|
exportCfg control.ExportConfig,
|
||||||
@ -88,3 +102,39 @@ func (h *baseSharepointHandler) ProduceExportCollections(
|
|||||||
|
|
||||||
return ec, el.Failure()
|
return ec, el.Failure()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// sharepointHandler
|
||||||
|
// ========================================================================== //
|
||||||
|
|
||||||
|
// sharepointHandler contains logic for handling data and performing operations
|
||||||
|
// (e.x. restore) regardless of whether they require contact with external M365
|
||||||
|
// services or not.
|
||||||
|
type sharepointHandler struct {
|
||||||
|
baseSharePointHandler
|
||||||
|
apiClient api.Client
|
||||||
|
resourceGetter idname.GetResourceIDAndNamer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *sharepointHandler) IsServiceEnabled(
|
||||||
|
ctx context.Context,
|
||||||
|
resourceID string,
|
||||||
|
) (bool, error) {
|
||||||
|
// TODO(ashmrtn): Move free function implementation to this function.
|
||||||
|
res, err := IsServiceEnabled(ctx, h.apiClient.Sites(), resourceID)
|
||||||
|
return res, clues.Stack(err).OrNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *sharepointHandler) PopulateProtectedResourceIDAndName(
|
||||||
|
ctx context.Context,
|
||||||
|
resourceID string, // Can be either ID or name.
|
||||||
|
ins idname.Cacher,
|
||||||
|
) (idname.Provider, error) {
|
||||||
|
if h.resourceGetter == nil {
|
||||||
|
return nil, clues.StackWC(ctx, resource.ErrNoResourceLookup)
|
||||||
|
}
|
||||||
|
|
||||||
|
pr, err := h.resourceGetter.GetResourceIDAndNameFrom(ctx, resourceID, ins)
|
||||||
|
|
||||||
|
return pr, clues.Wrap(err, "identifying resource owner").OrNil()
|
||||||
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/export"
|
"github.com/alcionai/corso/src/pkg/export"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ExportUnitSuite struct {
|
type ExportUnitSuite struct {
|
||||||
@ -125,7 +126,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewSharePointHandler(control.DefaultOptions())
|
handler := NewSharePointHandler(control.DefaultOptions(), api.Client{}, nil)
|
||||||
handler.CacheItemInfo(test.itemInfo)
|
handler.CacheItemInfo(test.itemInfo)
|
||||||
|
|
||||||
stats := data.ExportStats{}
|
stats := data.ExportStats{}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user