From 9f6f13f0c57bfd4f9739667b731905dfecbce1be Mon Sep 17 00:00:00 2001 From: Scott Seago Date: Thu, 3 Nov 2022 16:21:21 -0400 Subject: [PATCH] RestoreItemAction v2 API implementation Signed-off-by: Scott Seago --- changelogs/unreleased/5569-sseago | 1 + pkg/controller/restore_controller.go | 4 +- pkg/controller/restore_controller_test.go | 8 +- pkg/plugin/clientmgmt/manager.go | 46 + pkg/plugin/clientmgmt/manager_test.go | 110 ++ .../clientmgmt/process/client_builder.go | 18 +- .../clientmgmt/process/client_builder_test.go | 18 +- .../v2/restartable_restore_item_action.go | 185 +++ .../restartable_restore_item_action_test.go | 170 +++ pkg/plugin/framework/action_resolver.go | 36 + pkg/plugin/framework/common/plugin_kinds.go | 7 +- .../v2/restore_item_action.go | 45 + .../v2/restore_item_action_client.go | 201 +++ .../v2/restore_item_action_server.go | 265 ++++ pkg/plugin/framework/server.go | 78 +- .../v2/RestoreItemAction.pb.go | 1103 +++++++++++++++++ pkg/plugin/mocks/manager.go | 48 + .../v2/RestoreItemAction.proto | 61 + .../restoreitemaction/v2/RestoreItemAction.go | 130 ++ .../velero/restore_item_action_shared.go | 34 + .../v2/restore_item_action.go | 70 ++ pkg/restore/restore.go | 18 +- pkg/restore/restore_test.go | 71 +- 23 files changed, 2649 insertions(+), 78 deletions(-) create mode 100644 changelogs/unreleased/5569-sseago create mode 100644 pkg/plugin/clientmgmt/restoreitemaction/v2/restartable_restore_item_action.go create mode 100644 pkg/plugin/clientmgmt/restoreitemaction/v2/restartable_restore_item_action_test.go create mode 100644 pkg/plugin/framework/restoreitemaction/v2/restore_item_action.go create mode 100644 pkg/plugin/framework/restoreitemaction/v2/restore_item_action_client.go create mode 100644 pkg/plugin/framework/restoreitemaction/v2/restore_item_action_server.go create mode 100644 pkg/plugin/generated/restoreitemaction/v2/RestoreItemAction.pb.go create mode 100644 pkg/plugin/proto/restoreitemaction/v2/RestoreItemAction.proto create mode 100644 pkg/plugin/velero/mocks/restoreitemaction/v2/RestoreItemAction.go create mode 100644 pkg/plugin/velero/restoreitemaction/v2/restore_item_action.go diff --git a/changelogs/unreleased/5569-sseago b/changelogs/unreleased/5569-sseago new file mode 100644 index 0000000000..876f3d75c7 --- /dev/null +++ b/changelogs/unreleased/5569-sseago @@ -0,0 +1 @@ +RestoreItemAction v2 API implementation diff --git a/pkg/controller/restore_controller.go b/pkg/controller/restore_controller.go index 9e2eb31d75..0d79647f7d 100644 --- a/pkg/controller/restore_controller.go +++ b/pkg/controller/restore_controller.go @@ -474,11 +474,11 @@ func (c *restoreController) runValidatedRestore(restore *api.Restore, info backu pluginManager := c.newPluginManager(restoreLog) defer pluginManager.CleanupClients() - actions, err := pluginManager.GetRestoreItemActions() + actions, err := pluginManager.GetRestoreItemActionsV2() if err != nil { return errors.Wrap(err, "error getting restore item actions") } - actionsResolver := framework.NewRestoreItemActionResolver(actions) + actionsResolver := framework.NewRestoreItemActionResolverV2(actions) itemSnapshotters, err := pluginManager.GetItemSnapshotters() if err != nil { diff --git a/pkg/controller/restore_controller_test.go b/pkg/controller/restore_controller_test.go index fff95340e5..19c834985e 100644 --- a/pkg/controller/restore_controller_test.go +++ b/pkg/controller/restore_controller_test.go @@ -47,7 +47,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/plugin/framework" pluginmocks "github.com/vmware-tanzu/velero/pkg/plugin/mocks" isv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/item_snapshotter/v1" - riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1" + riav2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2" pkgrestore "github.com/vmware-tanzu/velero/pkg/restore" velerotest "github.com/vmware-tanzu/velero/pkg/test" "github.com/vmware-tanzu/velero/pkg/util/logging" @@ -556,7 +556,7 @@ func TestProcessQueueItem(t *testing.T) { } if test.restore != nil { - pluginManager.On("GetRestoreItemActions").Return(nil, nil) + pluginManager.On("GetRestoreItemActionsV2").Return(nil, nil) pluginManager.On("GetItemSnapshotters").Return([]isv1.ItemSnapshotter{}, nil) pluginManager.On("CleanupClients") } @@ -861,7 +861,7 @@ type fakeRestorer struct { func (r *fakeRestorer) Restore( info pkgrestore.Request, - actions []riav1.RestoreItemAction, + actions []riav2.RestoreItemAction, snapshotLocationLister listers.VolumeSnapshotLocationLister, volumeSnapshotterGetter pkgrestore.VolumeSnapshotterGetter, ) (pkgrestore.Result, pkgrestore.Result) { @@ -873,7 +873,7 @@ func (r *fakeRestorer) Restore( } func (r *fakeRestorer) RestoreWithResolvers(req pkgrestore.Request, - resolver framework.RestoreItemActionResolver, + resolver framework.RestoreItemActionResolverV2, itemSnapshotterResolver framework.ItemSnapshotterResolver, snapshotLocationLister listers.VolumeSnapshotLocationLister, volumeSnapshotterGetter pkgrestore.VolumeSnapshotterGetter, diff --git a/pkg/plugin/clientmgmt/manager.go b/pkg/plugin/clientmgmt/manager.go index 4e3343d6a4..b00e4fbcc7 100644 --- a/pkg/plugin/clientmgmt/manager.go +++ b/pkg/plugin/clientmgmt/manager.go @@ -28,6 +28,7 @@ import ( biav2cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/backupitemaction/v2" "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process" riav1cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/restoreitemaction/v1" + riav2cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/restoreitemaction/v2" vsv1cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/volumesnapshotter/v1" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" "github.com/vmware-tanzu/velero/pkg/plugin/velero" @@ -35,6 +36,7 @@ import ( biav2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v2" isv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/item_snapshotter/v1" riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1" + riav2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2" vsv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v1" ) @@ -64,6 +66,12 @@ type Manager interface { // GetRestoreItemAction returns the restore item action plugin for name. GetRestoreItemAction(name string) (riav1.RestoreItemAction, error) + // GetRestoreItemActionsV2 returns all v2 restore item action plugins. + GetRestoreItemActionsV2() ([]riav2.RestoreItemAction, error) + + // GetRestoreItemActionV2 returns the restore item action plugin for name. + GetRestoreItemActionV2(name string) (riav2.RestoreItemAction, error) + // GetDeleteItemActions returns all delete item action plugins. GetDeleteItemActions() ([]velero.DeleteItemAction, error) @@ -302,6 +310,44 @@ func (m *manager) GetRestoreItemAction(name string) (riav1.RestoreItemAction, er return nil, fmt.Errorf("unable to get valid RestoreItemAction for %q", name) } +// GetRestoreItemActionsV2 returns all v2 restore item actions as restartableRestoreItemActions. +func (m *manager) GetRestoreItemActionsV2() ([]riav2.RestoreItemAction, error) { + list := m.registry.List(common.PluginKindRestoreItemActionV2) + + actions := make([]riav2.RestoreItemAction, 0, len(list)) + + for i := range list { + id := list[i] + + r, err := m.GetRestoreItemActionV2(id.Name) + if err != nil { + return nil, err + } + + actions = append(actions, r) + } + + return actions, nil +} + +// GetRestoreItemActionV2 returns a v2 restartableRestoreItemAction for name. +func (m *manager) GetRestoreItemActionV2(name string) (riav2.RestoreItemAction, error) { + name = sanitizeName(name) + + for _, adaptedRestoreItemAction := range riav2cli.AdaptedRestoreItemActions() { + restartableProcess, err := m.getRestartableProcess(adaptedRestoreItemAction.Kind, name) + // Check if plugin was not found + if errors.As(err, &pluginNotFoundErrType) { + continue + } + if err != nil { + return nil, err + } + return adaptedRestoreItemAction.GetRestartable(name, restartableProcess), nil + } + return nil, fmt.Errorf("unable to get valid RestoreItemActionV2 for %q", name) +} + // GetDeleteItemActions returns all delete item actions as restartableDeleteItemActions. func (m *manager) GetDeleteItemActions() ([]velero.DeleteItemAction, error) { list := m.registry.List(common.PluginKindDeleteItemAction) diff --git a/pkg/plugin/clientmgmt/manager_test.go b/pkg/plugin/clientmgmt/manager_test.go index 541613c73b..4ed74491f9 100644 --- a/pkg/plugin/clientmgmt/manager_test.go +++ b/pkg/plugin/clientmgmt/manager_test.go @@ -31,6 +31,7 @@ import ( biav2cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/backupitemaction/v2" "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process" riav1cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/restoreitemaction/v1" + riav2cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/restoreitemaction/v2" vsv1cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/volumesnapshotter/v1" "github.com/vmware-tanzu/velero/pkg/plugin/framework" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" @@ -238,6 +239,23 @@ func TestGetRestoreItemAction(t *testing.T) { ) } +func TestGetRestoreItemActionV2(t *testing.T) { + getPluginTest(t, + common.PluginKindRestoreItemActionV2, + "velero.io/pod", + func(m Manager, name string) (interface{}, error) { + return m.GetRestoreItemActionV2(name) + }, + func(name string, sharedPluginProcess process.RestartableProcess) interface{} { + return &riav2cli.RestartableRestoreItemAction{ + Key: process.KindAndName{Kind: common.PluginKindRestoreItemActionV2, Name: name}, + SharedPluginProcess: sharedPluginProcess, + } + }, + false, + ) +} + func getPluginTest( t *testing.T, kind common.PluginKind, @@ -565,6 +583,98 @@ func TestGetRestoreItemActions(t *testing.T) { } } +func TestGetRestoreItemActionsV2(t *testing.T) { + tests := []struct { + name string + names []string + newRestartableProcessError error + expectedError string + }{ + { + name: "No items", + names: []string{}, + }, + { + name: "Error getting restartable process", + names: []string{"velero.io/a", "velero.io/b", "velero.io/c"}, + newRestartableProcessError: errors.Errorf("NewRestartableProcess"), + expectedError: "NewRestartableProcess", + }, + { + name: "Happy path", + names: []string{"velero.io/a", "velero.io/b", "velero.io/c"}, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + logger := test.NewLogger() + logLevel := logrus.InfoLevel + + registry := &mockRegistry{} + defer registry.AssertExpectations(t) + + m := NewManager(logger, logLevel, registry).(*manager) + factory := &mockRestartableProcessFactory{} + defer factory.AssertExpectations(t) + m.restartableProcessFactory = factory + + pluginKind := common.PluginKindRestoreItemActionV2 + var pluginIDs []framework.PluginIdentifier + for i := range tc.names { + pluginID := framework.PluginIdentifier{ + Command: "/command", + Kind: pluginKind, + Name: tc.names[i], + } + pluginIDs = append(pluginIDs, pluginID) + } + registry.On("List", pluginKind).Return(pluginIDs) + + var expectedActions []interface{} + for i := range pluginIDs { + pluginID := pluginIDs[i] + pluginName := pluginID.Name + + registry.On("Get", pluginKind, pluginName).Return(pluginID, nil) + + restartableProcess := &restartabletest.MockRestartableProcess{} + defer restartableProcess.AssertExpectations(t) + + expected := &riav2cli.RestartableRestoreItemAction{ + Key: process.KindAndName{Kind: pluginKind, Name: pluginName}, + SharedPluginProcess: restartableProcess, + } + + if tc.newRestartableProcessError != nil { + // Test 1: error getting restartable process + factory.On("NewRestartableProcess", pluginID.Command, logger, logLevel).Return(nil, errors.Errorf("NewRestartableProcess")).Once() + break + } + + // Test 2: happy path + if i == 0 { + factory.On("NewRestartableProcess", pluginID.Command, logger, logLevel).Return(restartableProcess, nil).Once() + } + + expectedActions = append(expectedActions, expected) + } + + restoreItemActions, err := m.GetRestoreItemActionsV2() + if tc.newRestartableProcessError != nil { + assert.Nil(t, restoreItemActions) + assert.EqualError(t, err, "NewRestartableProcess") + } else { + require.NoError(t, err) + var actual []interface{} + for i := range restoreItemActions { + actual = append(actual, restoreItemActions[i]) + } + assert.Equal(t, expectedActions, actual) + } + }) + } +} + func TestGetDeleteItemAction(t *testing.T) { getPluginTest(t, common.PluginKindDeleteItemAction, diff --git a/pkg/plugin/clientmgmt/process/client_builder.go b/pkg/plugin/clientmgmt/process/client_builder.go index ffadcc95f5..2847390757 100644 --- a/pkg/plugin/clientmgmt/process/client_builder.go +++ b/pkg/plugin/clientmgmt/process/client_builder.go @@ -29,6 +29,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/plugin/framework" biav2 "github.com/vmware-tanzu/velero/pkg/plugin/framework/backupitemaction/v2" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" + riav2 "github.com/vmware-tanzu/velero/pkg/plugin/framework/restoreitemaction/v2" ) // clientBuilder builds go-plugin Clients. @@ -69,14 +70,15 @@ func (b *clientBuilder) clientConfig() *hcplugin.ClientConfig { HandshakeConfig: framework.Handshake(), AllowedProtocols: []hcplugin.Protocol{hcplugin.ProtocolGRPC}, Plugins: map[string]hcplugin.Plugin{ - string(common.PluginKindBackupItemAction): framework.NewBackupItemActionPlugin(common.ClientLogger(b.clientLogger)), - string(common.PluginKindBackupItemActionV2): biav2.NewBackupItemActionPlugin(common.ClientLogger(b.clientLogger)), - string(common.PluginKindVolumeSnapshotter): framework.NewVolumeSnapshotterPlugin(common.ClientLogger(b.clientLogger)), - string(common.PluginKindObjectStore): framework.NewObjectStorePlugin(common.ClientLogger(b.clientLogger)), - string(common.PluginKindPluginLister): &framework.PluginListerPlugin{}, - string(common.PluginKindRestoreItemAction): framework.NewRestoreItemActionPlugin(common.ClientLogger(b.clientLogger)), - string(common.PluginKindDeleteItemAction): framework.NewDeleteItemActionPlugin(common.ClientLogger(b.clientLogger)), - string(common.PluginKindItemSnapshotter): framework.NewItemSnapshotterPlugin(common.ClientLogger(b.clientLogger)), + string(common.PluginKindBackupItemAction): framework.NewBackupItemActionPlugin(common.ClientLogger(b.clientLogger)), + string(common.PluginKindBackupItemActionV2): biav2.NewBackupItemActionPlugin(common.ClientLogger(b.clientLogger)), + string(common.PluginKindVolumeSnapshotter): framework.NewVolumeSnapshotterPlugin(common.ClientLogger(b.clientLogger)), + string(common.PluginKindObjectStore): framework.NewObjectStorePlugin(common.ClientLogger(b.clientLogger)), + string(common.PluginKindPluginLister): &framework.PluginListerPlugin{}, + string(common.PluginKindRestoreItemAction): framework.NewRestoreItemActionPlugin(common.ClientLogger(b.clientLogger)), + string(common.PluginKindRestoreItemActionV2): riav2.NewRestoreItemActionPlugin(common.ClientLogger(b.clientLogger)), + string(common.PluginKindDeleteItemAction): framework.NewDeleteItemActionPlugin(common.ClientLogger(b.clientLogger)), + string(common.PluginKindItemSnapshotter): framework.NewItemSnapshotterPlugin(common.ClientLogger(b.clientLogger)), }, Logger: b.pluginLogger, Cmd: exec.Command(b.commandName, b.commandArgs...), //nolint diff --git a/pkg/plugin/clientmgmt/process/client_builder_test.go b/pkg/plugin/clientmgmt/process/client_builder_test.go index c70cf29bfa..2af2b0b740 100644 --- a/pkg/plugin/clientmgmt/process/client_builder_test.go +++ b/pkg/plugin/clientmgmt/process/client_builder_test.go @@ -29,6 +29,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/plugin/framework" biav2 "github.com/vmware-tanzu/velero/pkg/plugin/framework/backupitemaction/v2" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" + riav2 "github.com/vmware-tanzu/velero/pkg/plugin/framework/restoreitemaction/v2" "github.com/vmware-tanzu/velero/pkg/test" ) @@ -62,14 +63,15 @@ func TestClientConfig(t *testing.T) { HandshakeConfig: framework.Handshake(), AllowedProtocols: []hcplugin.Protocol{hcplugin.ProtocolGRPC}, Plugins: map[string]hcplugin.Plugin{ - string(common.PluginKindBackupItemAction): framework.NewBackupItemActionPlugin(common.ClientLogger(logger)), - string(common.PluginKindBackupItemActionV2): biav2.NewBackupItemActionPlugin(common.ClientLogger(logger)), - string(common.PluginKindVolumeSnapshotter): framework.NewVolumeSnapshotterPlugin(common.ClientLogger(logger)), - string(common.PluginKindObjectStore): framework.NewObjectStorePlugin(common.ClientLogger(logger)), - string(common.PluginKindPluginLister): &framework.PluginListerPlugin{}, - string(common.PluginKindRestoreItemAction): framework.NewRestoreItemActionPlugin(common.ClientLogger(logger)), - string(common.PluginKindDeleteItemAction): framework.NewDeleteItemActionPlugin(common.ClientLogger(logger)), - string(common.PluginKindItemSnapshotter): framework.NewItemSnapshotterPlugin(common.ClientLogger(logger)), + string(common.PluginKindBackupItemAction): framework.NewBackupItemActionPlugin(common.ClientLogger(logger)), + string(common.PluginKindBackupItemActionV2): biav2.NewBackupItemActionPlugin(common.ClientLogger(logger)), + string(common.PluginKindVolumeSnapshotter): framework.NewVolumeSnapshotterPlugin(common.ClientLogger(logger)), + string(common.PluginKindObjectStore): framework.NewObjectStorePlugin(common.ClientLogger(logger)), + string(common.PluginKindPluginLister): &framework.PluginListerPlugin{}, + string(common.PluginKindRestoreItemAction): framework.NewRestoreItemActionPlugin(common.ClientLogger(logger)), + string(common.PluginKindRestoreItemActionV2): riav2.NewRestoreItemActionPlugin(common.ClientLogger(logger)), + string(common.PluginKindDeleteItemAction): framework.NewDeleteItemActionPlugin(common.ClientLogger(logger)), + string(common.PluginKindItemSnapshotter): framework.NewItemSnapshotterPlugin(common.ClientLogger(logger)), }, Logger: cb.pluginLogger, Cmd: exec.Command(cb.commandName, cb.commandArgs...), diff --git a/pkg/plugin/clientmgmt/restoreitemaction/v2/restartable_restore_item_action.go b/pkg/plugin/clientmgmt/restoreitemaction/v2/restartable_restore_item_action.go new file mode 100644 index 0000000000..052abb99ab --- /dev/null +++ b/pkg/plugin/clientmgmt/restoreitemaction/v2/restartable_restore_item_action.go @@ -0,0 +1,185 @@ +/* +Copyright the Velero contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2 + +import ( + "github.com/pkg/errors" + + api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process" + riav1cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/restoreitemaction/v1" + "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" + "github.com/vmware-tanzu/velero/pkg/plugin/velero" + riav2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2" +) + +// AdaptedRestoreItemAction is a v1 RestoreItemAction adapted to implement the v2 API +type AdaptedRestoreItemAction struct { + Kind common.PluginKind + + // Get returns a restartable RestoreItemAction for the given name and process, wrapping if necessary + GetRestartable func(name string, restartableProcess process.RestartableProcess) riav2.RestoreItemAction +} + +func AdaptedRestoreItemActions() []AdaptedRestoreItemAction { + return []AdaptedRestoreItemAction{ + { + Kind: common.PluginKindRestoreItemActionV2, + GetRestartable: func(name string, restartableProcess process.RestartableProcess) riav2.RestoreItemAction { + return NewRestartableRestoreItemAction(name, restartableProcess) + }, + }, + { + Kind: common.PluginKindRestoreItemAction, + GetRestartable: func(name string, restartableProcess process.RestartableProcess) riav2.RestoreItemAction { + return NewAdaptedV1RestartableRestoreItemAction(riav1cli.NewRestartableRestoreItemAction(name, restartableProcess)) + }, + }, + } +} + +// RestartableRestoreItemAction is a restore item action for a given implementation (such as "pod"). It is associated with +// a restartableProcess, which may be shared and used to run multiple plugins. At the beginning of each method +// call, the RestartableRestoreItemAction asks its restartableProcess to restart itself if needed (e.g. if the +// process terminated for any reason), then it proceeds with the actual call. +type RestartableRestoreItemAction struct { + Key process.KindAndName + SharedPluginProcess process.RestartableProcess + config map[string]string +} + +// NewRestartableRestoreItemAction returns a new RestartableRestoreItemAction. +func NewRestartableRestoreItemAction(name string, sharedPluginProcess process.RestartableProcess) *RestartableRestoreItemAction { + r := &RestartableRestoreItemAction{ + Key: process.KindAndName{Kind: common.PluginKindRestoreItemActionV2, Name: name}, + SharedPluginProcess: sharedPluginProcess, + } + return r +} + +// getRestoreItemAction returns the restore item action for this RestartableRestoreItemAction. It does *not* restart the +// plugin process. +func (r *RestartableRestoreItemAction) getRestoreItemAction() (riav2.RestoreItemAction, error) { + plugin, err := r.SharedPluginProcess.GetByKindAndName(r.Key) + if err != nil { + return nil, err + } + + restoreItemAction, ok := plugin.(riav2.RestoreItemAction) + if !ok { + return nil, errors.Errorf("%T is not a RestoreItemActionV2!", plugin) + } + + return restoreItemAction, nil +} + +// getDelegate restarts the plugin process (if needed) and returns the restore item action for this RestartableRestoreItemAction. +func (r *RestartableRestoreItemAction) getDelegate() (riav2.RestoreItemAction, error) { + if err := r.SharedPluginProcess.ResetIfNeeded(); err != nil { + return nil, err + } + + return r.getRestoreItemAction() +} + +// AppliesTo restarts the plugin's process if needed, then delegates the call. +func (r RestartableRestoreItemAction) AppliesTo() (velero.ResourceSelector, error) { + delegate, err := r.getDelegate() + if err != nil { + return velero.ResourceSelector{}, err + } + + return delegate.AppliesTo() +} + +// Execute restarts the plugin's process if needed, then delegates the call. +func (r *RestartableRestoreItemAction) Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) { + delegate, err := r.getDelegate() + if err != nil { + return nil, err + } + + return delegate.Execute(input) +} + +// Progress restarts the plugin's process if needed, then delegates the call. +func (r *RestartableRestoreItemAction) Progress(operationID string, restore *api.Restore) (velero.OperationProgress, error) { + delegate, err := r.getDelegate() + if err != nil { + return velero.OperationProgress{}, err + } + + return delegate.Progress(operationID, restore) +} + +// Cancel restarts the plugin's process if needed, then delegates the call. +func (r *RestartableRestoreItemAction) Cancel(operationID string, restore *api.Restore) error { + delegate, err := r.getDelegate() + if err != nil { + return err + } + + return delegate.Cancel(operationID, restore) +} + +// AreAdditionalItemsReady restarts the plugin's process if needed, then delegates the call. +func (r *RestartableRestoreItemAction) AreAdditionalItemsReady(additionalItems []velero.ResourceIdentifier, restore *api.Restore) (bool, error) { + delegate, err := r.getDelegate() + if err != nil { + return false, err + } + + return delegate.AreAdditionalItemsReady(additionalItems, restore) +} + +type AdaptedV1RestartableRestoreItemAction struct { + V1Restartable *riav1cli.RestartableRestoreItemAction +} + +// NewAdaptedV1RestartableRestoreItemAction returns a new v1 RestartableRestoreItemAction adapted to v2 +func NewAdaptedV1RestartableRestoreItemAction(v1Restartable *riav1cli.RestartableRestoreItemAction) *AdaptedV1RestartableRestoreItemAction { + r := &AdaptedV1RestartableRestoreItemAction{ + V1Restartable: v1Restartable, + } + return r +} + +// AppliesTo delegates to the v1 AppliesTo call. +func (r *AdaptedV1RestartableRestoreItemAction) AppliesTo() (velero.ResourceSelector, error) { + return r.V1Restartable.AppliesTo() +} + +// Execute delegates to the v1 Execute call, returning an empty operationID. +func (r *AdaptedV1RestartableRestoreItemAction) Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) { + return r.V1Restartable.Execute(input) +} + +// Progress returns with an error since v1 plugins will never return an operationID, which means that +// any operationID passed in here will be invalid. +func (r *AdaptedV1RestartableRestoreItemAction) Progress(operationID string, restore *api.Restore) (velero.OperationProgress, error) { + return velero.OperationProgress{}, riav2.AsyncOperationsNotSupportedError() +} + +// Cancel just returns without error since v1 plugins don't implement it. +func (r *AdaptedV1RestartableRestoreItemAction) Cancel(operationID string, restore *api.Restore) error { + return nil +} + +// AreAdditionalItemsReady just returns true since v1 plugins don't wait for items. +func (r *AdaptedV1RestartableRestoreItemAction) AreAdditionalItemsReady(additionalItems []velero.ResourceIdentifier, restore *api.Restore) (bool, error) { + return true, nil +} diff --git a/pkg/plugin/clientmgmt/restoreitemaction/v2/restartable_restore_item_action_test.go b/pkg/plugin/clientmgmt/restoreitemaction/v2/restartable_restore_item_action_test.go new file mode 100644 index 0000000000..3c3dc1cadf --- /dev/null +++ b/pkg/plugin/clientmgmt/restoreitemaction/v2/restartable_restore_item_action_test.go @@ -0,0 +1,170 @@ +/* +Copyright 2018, 2019 the Velero contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2 + +import ( + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + "github.com/vmware-tanzu/velero/internal/restartabletest" + v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process" + "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" + "github.com/vmware-tanzu/velero/pkg/plugin/velero" + mocks "github.com/vmware-tanzu/velero/pkg/plugin/velero/mocks/restoreitemaction/v2" +) + +func TestRestartableGetRestoreItemAction(t *testing.T) { + tests := []struct { + name string + plugin interface{} + getError error + expectedError string + }{ + { + name: "error getting by kind and name", + getError: errors.Errorf("get error"), + expectedError: "get error", + }, + { + name: "wrong type", + plugin: 3, + expectedError: "int is not a RestoreItemActionV2!", + }, + { + name: "happy path", + plugin: new(mocks.RestoreItemAction), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + p := new(restartabletest.MockRestartableProcess) + defer p.AssertExpectations(t) + + name := "pod" + key := process.KindAndName{Kind: common.PluginKindRestoreItemActionV2, Name: name} + p.On("GetByKindAndName", key).Return(tc.plugin, tc.getError) + + r := NewRestartableRestoreItemAction(name, p) + a, err := r.getRestoreItemAction() + if tc.expectedError != "" { + assert.EqualError(t, err, tc.expectedError) + return + } + require.NoError(t, err) + + assert.Equal(t, tc.plugin, a) + }) + } +} + +func TestRestartableRestoreItemActionGetDelegate(t *testing.T) { + p := new(restartabletest.MockRestartableProcess) + defer p.AssertExpectations(t) + + // Reset error + p.On("ResetIfNeeded").Return(errors.Errorf("reset error")).Once() + name := "pod" + r := NewRestartableRestoreItemAction(name, p) + a, err := r.getDelegate() + assert.Nil(t, a) + assert.EqualError(t, err, "reset error") + + // Happy path + p.On("ResetIfNeeded").Return(nil) + expected := new(mocks.RestoreItemAction) + key := process.KindAndName{Kind: common.PluginKindRestoreItemActionV2, Name: name} + p.On("GetByKindAndName", key).Return(expected, nil) + + a, err = r.getDelegate() + assert.NoError(t, err) + assert.Equal(t, expected, a) +} + +func TestRestartableRestoreItemActionDelegatedFunctions(t *testing.T) { + pv := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "color": "blue", + }, + } + + input := &velero.RestoreItemActionExecuteInput{ + Item: pv, + ItemFromBackup: pv, + Restore: new(v1.Restore), + } + + output := &velero.RestoreItemActionExecuteOutput{ + UpdatedItem: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "color": "green", + }, + }, + } + + r := new(v1.Restore) + oid := "operation1" + additionalItems := []velero.ResourceIdentifier{} + restartabletest.RunRestartableDelegateTests( + t, + common.PluginKindRestoreItemActionV2, + func(key process.KindAndName, p process.RestartableProcess) interface{} { + return &RestartableRestoreItemAction{ + Key: key, + SharedPluginProcess: p, + } + }, + func() restartabletest.Mockable { + return new(mocks.RestoreItemAction) + }, + restartabletest.RestartableDelegateTest{ + Function: "AppliesTo", + Inputs: []interface{}{}, + ExpectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")}, + ExpectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")}, + }, + restartabletest.RestartableDelegateTest{ + Function: "Execute", + Inputs: []interface{}{input}, + ExpectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")}, + ExpectedDelegateOutputs: []interface{}{output, errors.Errorf("delegate error")}, + }, + restartabletest.RestartableDelegateTest{ + Function: "Progress", + Inputs: []interface{}{oid, r}, + ExpectedErrorOutputs: []interface{}{velero.OperationProgress{}, errors.Errorf("reset error")}, + ExpectedDelegateOutputs: []interface{}{velero.OperationProgress{}, errors.Errorf("delegate error")}, + }, + restartabletest.RestartableDelegateTest{ + Function: "Cancel", + Inputs: []interface{}{oid, r}, + ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")}, + ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")}, + }, + restartabletest.RestartableDelegateTest{ + Function: "AreAdditionalItemsReady", + Inputs: []interface{}{additionalItems, r}, + ExpectedErrorOutputs: []interface{}{false, errors.Errorf("reset error")}, + ExpectedDelegateOutputs: []interface{}{true, errors.Errorf("delegate error")}, + }, + ) +} diff --git a/pkg/plugin/framework/action_resolver.go b/pkg/plugin/framework/action_resolver.go index f9ad62ab5d..a03f197d0f 100644 --- a/pkg/plugin/framework/action_resolver.go +++ b/pkg/plugin/framework/action_resolver.go @@ -29,6 +29,7 @@ import ( biav2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v2" isv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/item_snapshotter/v1" riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1" + riav2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2" "github.com/vmware-tanzu/velero/pkg/util/collections" ) @@ -128,6 +129,12 @@ func NewRestoreItemActionResolver(actions []riav1.RestoreItemAction) RestoreItem } } +func NewRestoreItemActionResolverV2(actions []riav2.RestoreItemAction) RestoreItemActionResolverV2 { + return RestoreItemActionResolverV2{ + actions: actions, + } +} + func NewDeleteItemActionResolver(actions []velero.DeleteItemAction) DeleteItemActionResolver { return DeleteItemActionResolver{ actions: actions, @@ -199,6 +206,11 @@ type RestoreItemResolvedAction struct { resolvedAction } +type RestoreItemResolvedActionV2 struct { + riav2.RestoreItemAction + resolvedAction +} + type RestoreItemActionResolver struct { actions []riav1.RestoreItemAction } @@ -223,6 +235,30 @@ func (recv RestoreItemActionResolver) ResolveActions(helper discovery.Helper, lo return resolved, nil } +type RestoreItemActionResolverV2 struct { + actions []riav2.RestoreItemAction +} + +func (recv RestoreItemActionResolverV2) ResolveActions(helper discovery.Helper, log logrus.FieldLogger) ([]RestoreItemResolvedActionV2, error) { + var resolved []RestoreItemResolvedActionV2 + for _, action := range recv.actions { + resources, namespaces, selector, err := resolveAction(helper, action) + if err != nil { + return nil, err + } + res := RestoreItemResolvedActionV2{ + RestoreItemAction: action, + resolvedAction: resolvedAction{ + ResourceIncludesExcludes: resources, + NamespaceIncludesExcludes: namespaces, + Selector: selector, + }, + } + resolved = append(resolved, res) + } + return resolved, nil +} + type DeleteItemResolvedAction struct { velero.DeleteItemAction resolvedAction diff --git a/pkg/plugin/framework/common/plugin_kinds.go b/pkg/plugin/framework/common/plugin_kinds.go index c6e25e5b6c..3f567418d5 100644 --- a/pkg/plugin/framework/common/plugin_kinds.go +++ b/pkg/plugin/framework/common/plugin_kinds.go @@ -41,6 +41,9 @@ const ( // PluginKindRestoreItemAction represents a restore item action plugin. PluginKindRestoreItemAction PluginKind = "RestoreItemAction" + // PluginKindRestoreItemAction represents a v2 restore item action plugin. + PluginKindRestoreItemActionV2 PluginKind = "RestoreItemActionV2" + // PluginKindDeleteItemAction represents a delete item action plugin. PluginKindDeleteItemAction PluginKind = "DeleteItemAction" @@ -55,7 +58,8 @@ const ( // The older (adaptable) version is the key, and the value is the full list of newer // plugin kinds that are capable of adapting it. var PluginKindsAdaptableTo = map[PluginKind][]PluginKind{ - PluginKindBackupItemAction: {PluginKindBackupItemActionV2}, + PluginKindBackupItemAction: {PluginKindBackupItemActionV2}, + PluginKindRestoreItemAction: {PluginKindRestoreItemActionV2}, } // AllPluginKinds contains all the valid plugin kinds that Velero supports, excluding PluginLister because that is not a @@ -67,6 +71,7 @@ func AllPluginKinds() map[string]PluginKind { allPluginKinds[PluginKindBackupItemAction.String()] = PluginKindBackupItemAction allPluginKinds[PluginKindBackupItemActionV2.String()] = PluginKindBackupItemActionV2 allPluginKinds[PluginKindRestoreItemAction.String()] = PluginKindRestoreItemAction + allPluginKinds[PluginKindRestoreItemActionV2.String()] = PluginKindRestoreItemActionV2 allPluginKinds[PluginKindDeleteItemAction.String()] = PluginKindDeleteItemAction allPluginKinds[PluginKindItemSnapshotter.String()] = PluginKindItemSnapshotter return allPluginKinds diff --git a/pkg/plugin/framework/restoreitemaction/v2/restore_item_action.go b/pkg/plugin/framework/restoreitemaction/v2/restore_item_action.go new file mode 100644 index 0000000000..13ec1b851d --- /dev/null +++ b/pkg/plugin/framework/restoreitemaction/v2/restore_item_action.go @@ -0,0 +1,45 @@ +/* +Copyright the Velero contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2 + +import ( + plugin "github.com/hashicorp/go-plugin" + "golang.org/x/net/context" + "google.golang.org/grpc" + + "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" + protoriav2 "github.com/vmware-tanzu/velero/pkg/plugin/generated/restoreitemaction/v2" +) + +// RestoreItemActionPlugin is an implementation of go-plugin's Plugin +// interface with support for gRPC for the restore/ItemAction +// interface. +type RestoreItemActionPlugin struct { + plugin.NetRPCUnsupportedPlugin + *common.PluginBase +} + +// GRPCClient returns a RestoreItemAction gRPC client. +func (p *RestoreItemActionPlugin) GRPCClient(_ context.Context, _ *plugin.GRPCBroker, clientConn *grpc.ClientConn) (interface{}, error) { + return common.NewClientDispenser(p.ClientLogger, clientConn, newRestoreItemActionGRPCClient), nil +} + +// GRPCServer registers a RestoreItemAction gRPC server. +func (p *RestoreItemActionPlugin) GRPCServer(_ *plugin.GRPCBroker, server *grpc.Server) error { + protoriav2.RegisterRestoreItemActionServer(server, &RestoreItemActionGRPCServer{mux: p.ServerMux}) + return nil +} diff --git a/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_client.go b/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_client.go new file mode 100644 index 0000000000..92ea96e1d4 --- /dev/null +++ b/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_client.go @@ -0,0 +1,201 @@ +/* +Copyright the Velero contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2 + +import ( + "encoding/json" + + "github.com/pkg/errors" + "golang.org/x/net/context" + "google.golang.org/grpc" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + + api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" + protoriav2 "github.com/vmware-tanzu/velero/pkg/plugin/generated/restoreitemaction/v2" + "github.com/vmware-tanzu/velero/pkg/plugin/velero" + riav2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2" +) + +var _ riav2.RestoreItemAction = &RestoreItemActionGRPCClient{} + +// NewRestoreItemActionPlugin constructs a RestoreItemActionPlugin. +func NewRestoreItemActionPlugin(options ...common.PluginOption) *RestoreItemActionPlugin { + return &RestoreItemActionPlugin{ + PluginBase: common.NewPluginBase(options...), + } +} + +// RestoreItemActionGRPCClient implements the backup/ItemAction interface and uses a +// gRPC client to make calls to the plugin server. +type RestoreItemActionGRPCClient struct { + *common.ClientBase + grpcClient protoriav2.RestoreItemActionClient +} + +func newRestoreItemActionGRPCClient(base *common.ClientBase, clientConn *grpc.ClientConn) interface{} { + return &RestoreItemActionGRPCClient{ + ClientBase: base, + grpcClient: protoriav2.NewRestoreItemActionClient(clientConn), + } +} + +func (c *RestoreItemActionGRPCClient) AppliesTo() (velero.ResourceSelector, error) { + res, err := c.grpcClient.AppliesTo(context.Background(), &protoriav2.RestoreItemActionAppliesToRequest{Plugin: c.Plugin}) + if err != nil { + return velero.ResourceSelector{}, common.FromGRPCError(err) + } + + if res.ResourceSelector == nil { + return velero.ResourceSelector{}, nil + } + + return velero.ResourceSelector{ + IncludedNamespaces: res.ResourceSelector.IncludedNamespaces, + ExcludedNamespaces: res.ResourceSelector.ExcludedNamespaces, + IncludedResources: res.ResourceSelector.IncludedResources, + ExcludedResources: res.ResourceSelector.ExcludedResources, + LabelSelector: res.ResourceSelector.Selector, + }, nil +} + +func (c *RestoreItemActionGRPCClient) Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) { + itemJSON, err := json.Marshal(input.Item.UnstructuredContent()) + if err != nil { + return nil, errors.WithStack(err) + } + + itemFromBackupJSON, err := json.Marshal(input.ItemFromBackup.UnstructuredContent()) + if err != nil { + return nil, errors.WithStack(err) + } + + restoreJSON, err := json.Marshal(input.Restore) + if err != nil { + return nil, errors.WithStack(err) + } + + req := &protoriav2.RestoreItemActionExecuteRequest{ + Plugin: c.Plugin, + Item: itemJSON, + ItemFromBackup: itemFromBackupJSON, + Restore: restoreJSON, + } + + res, err := c.grpcClient.Execute(context.Background(), req) + if err != nil { + return nil, common.FromGRPCError(err) + } + + var updatedItem unstructured.Unstructured + if err := json.Unmarshal(res.Item, &updatedItem); err != nil { + return nil, errors.WithStack(err) + } + + var additionalItems []velero.ResourceIdentifier + for _, itm := range res.AdditionalItems { + newItem := velero.ResourceIdentifier{ + GroupResource: schema.GroupResource{ + Group: itm.Group, + Resource: itm.Resource, + }, + Namespace: itm.Namespace, + Name: itm.Name, + } + + additionalItems = append(additionalItems, newItem) + } + + return &velero.RestoreItemActionExecuteOutput{ + UpdatedItem: &updatedItem, + AdditionalItems: additionalItems, + SkipRestore: res.SkipRestore, + OperationID: res.OperationID, + WaitForAdditionalItems: res.WaitForAdditionalItems, + AdditionalItemsReadyTimeout: res.AdditionalItemsReadyTimeout.AsDuration(), + }, nil +} + +func (c *RestoreItemActionGRPCClient) Progress(operationID string, restore *api.Restore) (velero.OperationProgress, error) { + restoreJSON, err := json.Marshal(restore) + if err != nil { + return velero.OperationProgress{}, errors.WithStack(err) + } + req := &protoriav2.RestoreItemActionProgressRequest{ + Plugin: c.Plugin, + OperationID: operationID, + Restore: restoreJSON, + } + + res, err := c.grpcClient.Progress(context.Background(), req) + if err != nil { + return velero.OperationProgress{}, common.FromGRPCError(err) + } + + return velero.OperationProgress{ + Completed: res.Progress.Completed, + Err: res.Progress.Err, + NCompleted: res.Progress.NCompleted, + NTotal: res.Progress.NTotal, + OperationUnits: res.Progress.OperationUnits, + Description: res.Progress.Description, + Started: res.Progress.Started.AsTime(), + Updated: res.Progress.Updated.AsTime(), + }, nil +} + +func (c *RestoreItemActionGRPCClient) Cancel(operationID string, restore *api.Restore) error { + restoreJSON, err := json.Marshal(restore) + if err != nil { + return errors.WithStack(err) + } + req := &protoriav2.RestoreItemActionCancelRequest{ + Plugin: c.Plugin, + OperationID: operationID, + Restore: restoreJSON, + } + + _, err = c.grpcClient.Cancel(context.Background(), req) + if err != nil { + return common.FromGRPCError(err) + } + + return nil +} + +func (c *RestoreItemActionGRPCClient) AreAdditionalItemsReady(additionalItems []velero.ResourceIdentifier, restore *api.Restore) (bool, error) { + restoreJSON, err := json.Marshal(restore) + if err != nil { + return false, errors.WithStack(err) + } + + req := &protoriav2.RestoreItemActionItemsReadyRequest{ + Plugin: c.Plugin, + Restore: restoreJSON, + } + for _, item := range additionalItems { + req.AdditionalItems = append(req.AdditionalItems, restoreResourceIdentifierToProto(item)) + } + + res, err := c.grpcClient.AreAdditionalItemsReady(context.Background(), req) + if err != nil { + return false, common.FromGRPCError(err) + } + + return res.Ready, nil +} diff --git a/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_server.go b/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_server.go new file mode 100644 index 0000000000..db2cbeb264 --- /dev/null +++ b/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_server.go @@ -0,0 +1,265 @@ +/* +Copyright the Velero contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2 + +import ( + "encoding/json" + + "github.com/pkg/errors" + "golang.org/x/net/context" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/timestamppb" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + + api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" + proto "github.com/vmware-tanzu/velero/pkg/plugin/generated" + protoriav2 "github.com/vmware-tanzu/velero/pkg/plugin/generated/restoreitemaction/v2" + "github.com/vmware-tanzu/velero/pkg/plugin/velero" + riav2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2" +) + +// RestoreItemActionGRPCServer implements the proto-generated RestoreItemActionServer interface, and accepts +// gRPC calls and forwards them to an implementation of the pluggable interface. +type RestoreItemActionGRPCServer struct { + mux *common.ServerMux +} + +func (s *RestoreItemActionGRPCServer) getImpl(name string) (riav2.RestoreItemAction, error) { + impl, err := s.mux.GetHandler(name) + if err != nil { + return nil, err + } + + itemAction, ok := impl.(riav2.RestoreItemAction) + if !ok { + return nil, errors.Errorf("%T is not a restore item action (v2)", impl) + } + + return itemAction, nil +} + +func (s *RestoreItemActionGRPCServer) AppliesTo(ctx context.Context, req *protoriav2.RestoreItemActionAppliesToRequest) (response *protoriav2.RestoreItemActionAppliesToResponse, err error) { + defer func() { + if recoveredErr := common.HandlePanic(recover()); recoveredErr != nil { + err = recoveredErr + } + }() + + impl, err := s.getImpl(req.Plugin) + if err != nil { + return nil, common.NewGRPCError(err) + } + + resourceSelector, err := impl.AppliesTo() + if err != nil { + return nil, common.NewGRPCError(err) + } + + return &protoriav2.RestoreItemActionAppliesToResponse{ + ResourceSelector: &proto.ResourceSelector{ + IncludedNamespaces: resourceSelector.IncludedNamespaces, + ExcludedNamespaces: resourceSelector.ExcludedNamespaces, + IncludedResources: resourceSelector.IncludedResources, + ExcludedResources: resourceSelector.ExcludedResources, + Selector: resourceSelector.LabelSelector, + }, + }, nil +} + +func (s *RestoreItemActionGRPCServer) Execute(ctx context.Context, req *protoriav2.RestoreItemActionExecuteRequest) (response *protoriav2.RestoreItemActionExecuteResponse, err error) { + defer func() { + if recoveredErr := common.HandlePanic(recover()); recoveredErr != nil { + err = recoveredErr + } + }() + + impl, err := s.getImpl(req.Plugin) + if err != nil { + return nil, common.NewGRPCError(err) + } + + var ( + item unstructured.Unstructured + itemFromBackup unstructured.Unstructured + restoreObj api.Restore + ) + + if err := json.Unmarshal(req.Item, &item); err != nil { + return nil, common.NewGRPCError(errors.WithStack(err)) + } + + if err := json.Unmarshal(req.ItemFromBackup, &itemFromBackup); err != nil { + return nil, common.NewGRPCError(errors.WithStack(err)) + } + + if err := json.Unmarshal(req.Restore, &restoreObj); err != nil { + return nil, common.NewGRPCError(errors.WithStack(err)) + } + + executeOutput, err := impl.Execute(&velero.RestoreItemActionExecuteInput{ + Item: &item, + ItemFromBackup: &itemFromBackup, + Restore: &restoreObj, + }) + if err != nil { + return nil, common.NewGRPCError(err) + } + + // If the plugin implementation returned a nil updateItem (meaning no modifications), reset updatedItem to the + // original item. + var updatedItemJSON []byte + if executeOutput.UpdatedItem == nil { + updatedItemJSON = req.Item + } else { + updatedItemJSON, err = json.Marshal(executeOutput.UpdatedItem.UnstructuredContent()) + if err != nil { + return nil, common.NewGRPCError(errors.WithStack(err)) + } + } + + res := &protoriav2.RestoreItemActionExecuteResponse{ + Item: updatedItemJSON, + SkipRestore: executeOutput.SkipRestore, + OperationID: executeOutput.OperationID, + WaitForAdditionalItems: executeOutput.WaitForAdditionalItems, + AdditionalItemsReadyTimeout: durationpb.New(executeOutput.AdditionalItemsReadyTimeout), + } + + for _, item := range executeOutput.AdditionalItems { + res.AdditionalItems = append(res.AdditionalItems, restoreResourceIdentifierToProto(item)) + } + + return res, nil +} + +func (s *RestoreItemActionGRPCServer) Progress(ctx context.Context, req *protoriav2.RestoreItemActionProgressRequest) ( + response *protoriav2.RestoreItemActionProgressResponse, err error) { + defer func() { + if recoveredErr := common.HandlePanic(recover()); recoveredErr != nil { + err = recoveredErr + } + }() + + impl, err := s.getImpl(req.Plugin) + if err != nil { + return nil, common.NewGRPCError(err) + } + + var restore api.Restore + if err := json.Unmarshal(req.Restore, &restore); err != nil { + return nil, common.NewGRPCError(errors.WithStack(err)) + } + + progress, err := impl.Progress(req.OperationID, &restore) + if err != nil { + return nil, common.NewGRPCError(err) + } + + res := &protoriav2.RestoreItemActionProgressResponse{ + Progress: &proto.OperationProgress{ + Completed: progress.Completed, + Err: progress.Err, + NCompleted: progress.NCompleted, + NTotal: progress.NTotal, + OperationUnits: progress.OperationUnits, + Description: progress.Description, + Started: timestamppb.New(progress.Started), + Updated: timestamppb.New(progress.Updated), + }, + } + return res, nil +} + +func (s *RestoreItemActionGRPCServer) Cancel( + ctx context.Context, req *protoriav2.RestoreItemActionCancelRequest) ( + response *emptypb.Empty, err error) { + defer func() { + if recoveredErr := common.HandlePanic(recover()); recoveredErr != nil { + err = recoveredErr + } + }() + + impl, err := s.getImpl(req.Plugin) + if err != nil { + return nil, common.NewGRPCError(err) + } + + var restore api.Restore + if err := json.Unmarshal(req.Restore, &restore); err != nil { + return nil, common.NewGRPCError(errors.WithStack(err)) + } + + err = impl.Cancel(req.OperationID, &restore) + if err != nil { + return nil, common.NewGRPCError(err) + } + + return &emptypb.Empty{}, nil +} + +func (s *RestoreItemActionGRPCServer) AreAdditionalItemsReady(ctx context.Context, req *protoriav2.RestoreItemActionItemsReadyRequest) ( + response *protoriav2.RestoreItemActionItemsReadyResponse, err error) { + defer func() { + if recoveredErr := common.HandlePanic(recover()); recoveredErr != nil { + err = recoveredErr + } + }() + + impl, err := s.getImpl(req.Plugin) + if err != nil { + return nil, common.NewGRPCError(err) + } + + var restore api.Restore + if err := json.Unmarshal(req.Restore, &restore); err != nil { + return nil, common.NewGRPCError(errors.WithStack(err)) + } + var additionalItems []velero.ResourceIdentifier + for _, itm := range req.AdditionalItems { + newItem := velero.ResourceIdentifier{ + GroupResource: schema.GroupResource{ + Group: itm.Group, + Resource: itm.Resource, + }, + Namespace: itm.Namespace, + Name: itm.Name, + } + + additionalItems = append(additionalItems, newItem) + } + ready, err := impl.AreAdditionalItemsReady(additionalItems, &restore) + if err != nil { + return nil, common.NewGRPCError(err) + } + + res := &protoriav2.RestoreItemActionItemsReadyResponse{ + Ready: ready, + } + return res, nil +} + +func restoreResourceIdentifierToProto(id velero.ResourceIdentifier) *proto.ResourceIdentifier { + return &proto.ResourceIdentifier{ + Group: id.Group, + Resource: id.Resource, + Namespace: id.Namespace, + Name: id.Name, + } +} diff --git a/pkg/plugin/framework/server.go b/pkg/plugin/framework/server.go index d9a1af3872..e84df612af 100644 --- a/pkg/plugin/framework/server.go +++ b/pkg/plugin/framework/server.go @@ -27,6 +27,7 @@ import ( biav2 "github.com/vmware-tanzu/velero/pkg/plugin/framework/backupitemaction/v2" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" + riav2 "github.com/vmware-tanzu/velero/pkg/plugin/framework/restoreitemaction/v2" "github.com/vmware-tanzu/velero/pkg/util/logging" ) @@ -75,6 +76,13 @@ type Server interface { // RegisterRestoreItemActions registers multiple restore item actions. RegisterRestoreItemActions(map[string]common.HandlerInitializer) Server + // RegisterRestoreItemActionV2 registers a v2 restore item action. Accepted format + // for the plugin name is /. + RegisterRestoreItemActionV2(pluginName string, initializer common.HandlerInitializer) Server + + // RegisterRestoreItemActionsV2 registers multiple v2 restore item actions. + RegisterRestoreItemActionsV2(map[string]common.HandlerInitializer) Server + // RegisterDeleteItemAction registers a delete item action. Accepted format // for the plugin name is /. RegisterDeleteItemAction(pluginName string, initializer common.HandlerInitializer) Server @@ -93,16 +101,17 @@ type Server interface { // server implements Server. type server struct { - log *logrus.Logger - logLevelFlag *logging.LevelFlag - flagSet *pflag.FlagSet - backupItemAction *BackupItemActionPlugin - backupItemActionV2 *biav2.BackupItemActionPlugin - volumeSnapshotter *VolumeSnapshotterPlugin - objectStore *ObjectStorePlugin - restoreItemAction *RestoreItemActionPlugin - deleteItemAction *DeleteItemActionPlugin - itemSnapshotter *ItemSnapshotterPlugin + log *logrus.Logger + logLevelFlag *logging.LevelFlag + flagSet *pflag.FlagSet + backupItemAction *BackupItemActionPlugin + backupItemActionV2 *biav2.BackupItemActionPlugin + volumeSnapshotter *VolumeSnapshotterPlugin + objectStore *ObjectStorePlugin + restoreItemAction *RestoreItemActionPlugin + restoreItemActionV2 *riav2.RestoreItemActionPlugin + deleteItemAction *DeleteItemActionPlugin + itemSnapshotter *ItemSnapshotterPlugin } // NewServer returns a new Server @@ -110,15 +119,16 @@ func NewServer() Server { log := newLogger() return &server{ - log: log, - logLevelFlag: logging.LogLevelFlag(log.Level), - backupItemAction: NewBackupItemActionPlugin(common.ServerLogger(log)), - backupItemActionV2: biav2.NewBackupItemActionPlugin(common.ServerLogger(log)), - volumeSnapshotter: NewVolumeSnapshotterPlugin(common.ServerLogger(log)), - objectStore: NewObjectStorePlugin(common.ServerLogger(log)), - restoreItemAction: NewRestoreItemActionPlugin(common.ServerLogger(log)), - deleteItemAction: NewDeleteItemActionPlugin(common.ServerLogger(log)), - itemSnapshotter: NewItemSnapshotterPlugin(common.ServerLogger(log)), + log: log, + logLevelFlag: logging.LogLevelFlag(log.Level), + backupItemAction: NewBackupItemActionPlugin(common.ServerLogger(log)), + backupItemActionV2: biav2.NewBackupItemActionPlugin(common.ServerLogger(log)), + volumeSnapshotter: NewVolumeSnapshotterPlugin(common.ServerLogger(log)), + objectStore: NewObjectStorePlugin(common.ServerLogger(log)), + restoreItemAction: NewRestoreItemActionPlugin(common.ServerLogger(log)), + restoreItemActionV2: riav2.NewRestoreItemActionPlugin(common.ServerLogger(log)), + deleteItemAction: NewDeleteItemActionPlugin(common.ServerLogger(log)), + itemSnapshotter: NewItemSnapshotterPlugin(common.ServerLogger(log)), } } @@ -190,6 +200,18 @@ func (s *server) RegisterRestoreItemActions(m map[string]common.HandlerInitializ return s } +func (s *server) RegisterRestoreItemActionV2(name string, initializer common.HandlerInitializer) Server { + s.restoreItemActionV2.Register(name, initializer) + return s +} + +func (s *server) RegisterRestoreItemActionsV2(m map[string]common.HandlerInitializer) Server { + for name := range m { + s.RegisterRestoreItemActionV2(name, m[name]) + } + return s +} + func (s *server) RegisterDeleteItemAction(name string, initializer common.HandlerInitializer) Server { s.deleteItemAction.Register(name, initializer) return s @@ -242,6 +264,7 @@ func (s *server) Serve() { pluginIdentifiers = append(pluginIdentifiers, getNames(command, common.PluginKindVolumeSnapshotter, s.volumeSnapshotter)...) pluginIdentifiers = append(pluginIdentifiers, getNames(command, common.PluginKindObjectStore, s.objectStore)...) pluginIdentifiers = append(pluginIdentifiers, getNames(command, common.PluginKindRestoreItemAction, s.restoreItemAction)...) + pluginIdentifiers = append(pluginIdentifiers, getNames(command, common.PluginKindRestoreItemActionV2, s.restoreItemActionV2)...) pluginIdentifiers = append(pluginIdentifiers, getNames(command, common.PluginKindDeleteItemAction, s.deleteItemAction)...) pluginIdentifiers = append(pluginIdentifiers, getNames(command, common.PluginKindItemSnapshotter, s.itemSnapshotter)...) @@ -250,14 +273,15 @@ func (s *server) Serve() { plugin.Serve(&plugin.ServeConfig{ HandshakeConfig: Handshake(), Plugins: map[string]plugin.Plugin{ - string(common.PluginKindBackupItemAction): s.backupItemAction, - string(common.PluginKindBackupItemActionV2): s.backupItemActionV2, - string(common.PluginKindVolumeSnapshotter): s.volumeSnapshotter, - string(common.PluginKindObjectStore): s.objectStore, - string(common.PluginKindPluginLister): NewPluginListerPlugin(pluginLister), - string(common.PluginKindRestoreItemAction): s.restoreItemAction, - string(common.PluginKindDeleteItemAction): s.deleteItemAction, - string(common.PluginKindItemSnapshotter): s.itemSnapshotter, + string(common.PluginKindBackupItemAction): s.backupItemAction, + string(common.PluginKindBackupItemActionV2): s.backupItemActionV2, + string(common.PluginKindVolumeSnapshotter): s.volumeSnapshotter, + string(common.PluginKindObjectStore): s.objectStore, + string(common.PluginKindPluginLister): NewPluginListerPlugin(pluginLister), + string(common.PluginKindRestoreItemAction): s.restoreItemAction, + string(common.PluginKindRestoreItemActionV2): s.restoreItemActionV2, + string(common.PluginKindDeleteItemAction): s.deleteItemAction, + string(common.PluginKindItemSnapshotter): s.itemSnapshotter, }, GRPCServer: plugin.DefaultGRPCServer, }) diff --git a/pkg/plugin/generated/restoreitemaction/v2/RestoreItemAction.pb.go b/pkg/plugin/generated/restoreitemaction/v2/RestoreItemAction.pb.go new file mode 100644 index 0000000000..0e041e51eb --- /dev/null +++ b/pkg/plugin/generated/restoreitemaction/v2/RestoreItemAction.pb.go @@ -0,0 +1,1103 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.14.0 +// source: restoreitemaction/v2/RestoreItemAction.proto + +package v2 + +import ( + context "context" + proto "github.com/golang/protobuf/proto" + generated "github.com/vmware-tanzu/velero/pkg/plugin/generated" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + emptypb "google.golang.org/protobuf/types/known/emptypb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type RestoreItemActionExecuteRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` + Restore []byte `protobuf:"bytes,3,opt,name=restore,proto3" json:"restore,omitempty"` + ItemFromBackup []byte `protobuf:"bytes,4,opt,name=itemFromBackup,proto3" json:"itemFromBackup,omitempty"` +} + +func (x *RestoreItemActionExecuteRequest) Reset() { + *x = RestoreItemActionExecuteRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RestoreItemActionExecuteRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RestoreItemActionExecuteRequest) ProtoMessage() {} + +func (x *RestoreItemActionExecuteRequest) ProtoReflect() protoreflect.Message { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RestoreItemActionExecuteRequest.ProtoReflect.Descriptor instead. +func (*RestoreItemActionExecuteRequest) Descriptor() ([]byte, []int) { + return file_restoreitemaction_v2_RestoreItemAction_proto_rawDescGZIP(), []int{0} +} + +func (x *RestoreItemActionExecuteRequest) GetPlugin() string { + if x != nil { + return x.Plugin + } + return "" +} + +func (x *RestoreItemActionExecuteRequest) GetItem() []byte { + if x != nil { + return x.Item + } + return nil +} + +func (x *RestoreItemActionExecuteRequest) GetRestore() []byte { + if x != nil { + return x.Restore + } + return nil +} + +func (x *RestoreItemActionExecuteRequest) GetItemFromBackup() []byte { + if x != nil { + return x.ItemFromBackup + } + return nil +} + +type RestoreItemActionExecuteResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item []byte `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` + AdditionalItems []*generated.ResourceIdentifier `protobuf:"bytes,2,rep,name=additionalItems,proto3" json:"additionalItems,omitempty"` + SkipRestore bool `protobuf:"varint,3,opt,name=skipRestore,proto3" json:"skipRestore,omitempty"` + OperationID string `protobuf:"bytes,4,opt,name=operationID,proto3" json:"operationID,omitempty"` + WaitForAdditionalItems bool `protobuf:"varint,5,opt,name=waitForAdditionalItems,proto3" json:"waitForAdditionalItems,omitempty"` + AdditionalItemsReadyTimeout *durationpb.Duration `protobuf:"bytes,6,opt,name=additionalItemsReadyTimeout,proto3" json:"additionalItemsReadyTimeout,omitempty"` +} + +func (x *RestoreItemActionExecuteResponse) Reset() { + *x = RestoreItemActionExecuteResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RestoreItemActionExecuteResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RestoreItemActionExecuteResponse) ProtoMessage() {} + +func (x *RestoreItemActionExecuteResponse) ProtoReflect() protoreflect.Message { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RestoreItemActionExecuteResponse.ProtoReflect.Descriptor instead. +func (*RestoreItemActionExecuteResponse) Descriptor() ([]byte, []int) { + return file_restoreitemaction_v2_RestoreItemAction_proto_rawDescGZIP(), []int{1} +} + +func (x *RestoreItemActionExecuteResponse) GetItem() []byte { + if x != nil { + return x.Item + } + return nil +} + +func (x *RestoreItemActionExecuteResponse) GetAdditionalItems() []*generated.ResourceIdentifier { + if x != nil { + return x.AdditionalItems + } + return nil +} + +func (x *RestoreItemActionExecuteResponse) GetSkipRestore() bool { + if x != nil { + return x.SkipRestore + } + return false +} + +func (x *RestoreItemActionExecuteResponse) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +func (x *RestoreItemActionExecuteResponse) GetWaitForAdditionalItems() bool { + if x != nil { + return x.WaitForAdditionalItems + } + return false +} + +func (x *RestoreItemActionExecuteResponse) GetAdditionalItemsReadyTimeout() *durationpb.Duration { + if x != nil { + return x.AdditionalItemsReadyTimeout + } + return nil +} + +type RestoreItemActionAppliesToRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` +} + +func (x *RestoreItemActionAppliesToRequest) Reset() { + *x = RestoreItemActionAppliesToRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RestoreItemActionAppliesToRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RestoreItemActionAppliesToRequest) ProtoMessage() {} + +func (x *RestoreItemActionAppliesToRequest) ProtoReflect() protoreflect.Message { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RestoreItemActionAppliesToRequest.ProtoReflect.Descriptor instead. +func (*RestoreItemActionAppliesToRequest) Descriptor() ([]byte, []int) { + return file_restoreitemaction_v2_RestoreItemAction_proto_rawDescGZIP(), []int{2} +} + +func (x *RestoreItemActionAppliesToRequest) GetPlugin() string { + if x != nil { + return x.Plugin + } + return "" +} + +type RestoreItemActionAppliesToResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ResourceSelector *generated.ResourceSelector `protobuf:"bytes,1,opt,name=ResourceSelector,proto3" json:"ResourceSelector,omitempty"` +} + +func (x *RestoreItemActionAppliesToResponse) Reset() { + *x = RestoreItemActionAppliesToResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RestoreItemActionAppliesToResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RestoreItemActionAppliesToResponse) ProtoMessage() {} + +func (x *RestoreItemActionAppliesToResponse) ProtoReflect() protoreflect.Message { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RestoreItemActionAppliesToResponse.ProtoReflect.Descriptor instead. +func (*RestoreItemActionAppliesToResponse) Descriptor() ([]byte, []int) { + return file_restoreitemaction_v2_RestoreItemAction_proto_rawDescGZIP(), []int{3} +} + +func (x *RestoreItemActionAppliesToResponse) GetResourceSelector() *generated.ResourceSelector { + if x != nil { + return x.ResourceSelector + } + return nil +} + +type RestoreItemActionProgressRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID,proto3" json:"operationID,omitempty"` + Restore []byte `protobuf:"bytes,3,opt,name=restore,proto3" json:"restore,omitempty"` +} + +func (x *RestoreItemActionProgressRequest) Reset() { + *x = RestoreItemActionProgressRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RestoreItemActionProgressRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RestoreItemActionProgressRequest) ProtoMessage() {} + +func (x *RestoreItemActionProgressRequest) ProtoReflect() protoreflect.Message { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RestoreItemActionProgressRequest.ProtoReflect.Descriptor instead. +func (*RestoreItemActionProgressRequest) Descriptor() ([]byte, []int) { + return file_restoreitemaction_v2_RestoreItemAction_proto_rawDescGZIP(), []int{4} +} + +func (x *RestoreItemActionProgressRequest) GetPlugin() string { + if x != nil { + return x.Plugin + } + return "" +} + +func (x *RestoreItemActionProgressRequest) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +func (x *RestoreItemActionProgressRequest) GetRestore() []byte { + if x != nil { + return x.Restore + } + return nil +} + +type RestoreItemActionProgressResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Progress *generated.OperationProgress `protobuf:"bytes,1,opt,name=progress,proto3" json:"progress,omitempty"` +} + +func (x *RestoreItemActionProgressResponse) Reset() { + *x = RestoreItemActionProgressResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RestoreItemActionProgressResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RestoreItemActionProgressResponse) ProtoMessage() {} + +func (x *RestoreItemActionProgressResponse) ProtoReflect() protoreflect.Message { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RestoreItemActionProgressResponse.ProtoReflect.Descriptor instead. +func (*RestoreItemActionProgressResponse) Descriptor() ([]byte, []int) { + return file_restoreitemaction_v2_RestoreItemAction_proto_rawDescGZIP(), []int{5} +} + +func (x *RestoreItemActionProgressResponse) GetProgress() *generated.OperationProgress { + if x != nil { + return x.Progress + } + return nil +} + +type RestoreItemActionCancelRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID,proto3" json:"operationID,omitempty"` + Restore []byte `protobuf:"bytes,3,opt,name=restore,proto3" json:"restore,omitempty"` +} + +func (x *RestoreItemActionCancelRequest) Reset() { + *x = RestoreItemActionCancelRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RestoreItemActionCancelRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RestoreItemActionCancelRequest) ProtoMessage() {} + +func (x *RestoreItemActionCancelRequest) ProtoReflect() protoreflect.Message { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RestoreItemActionCancelRequest.ProtoReflect.Descriptor instead. +func (*RestoreItemActionCancelRequest) Descriptor() ([]byte, []int) { + return file_restoreitemaction_v2_RestoreItemAction_proto_rawDescGZIP(), []int{6} +} + +func (x *RestoreItemActionCancelRequest) GetPlugin() string { + if x != nil { + return x.Plugin + } + return "" +} + +func (x *RestoreItemActionCancelRequest) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +func (x *RestoreItemActionCancelRequest) GetRestore() []byte { + if x != nil { + return x.Restore + } + return nil +} + +type RestoreItemActionItemsReadyRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Restore []byte `protobuf:"bytes,2,opt,name=restore,proto3" json:"restore,omitempty"` + AdditionalItems []*generated.ResourceIdentifier `protobuf:"bytes,3,rep,name=additionalItems,proto3" json:"additionalItems,omitempty"` +} + +func (x *RestoreItemActionItemsReadyRequest) Reset() { + *x = RestoreItemActionItemsReadyRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RestoreItemActionItemsReadyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RestoreItemActionItemsReadyRequest) ProtoMessage() {} + +func (x *RestoreItemActionItemsReadyRequest) ProtoReflect() protoreflect.Message { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RestoreItemActionItemsReadyRequest.ProtoReflect.Descriptor instead. +func (*RestoreItemActionItemsReadyRequest) Descriptor() ([]byte, []int) { + return file_restoreitemaction_v2_RestoreItemAction_proto_rawDescGZIP(), []int{7} +} + +func (x *RestoreItemActionItemsReadyRequest) GetPlugin() string { + if x != nil { + return x.Plugin + } + return "" +} + +func (x *RestoreItemActionItemsReadyRequest) GetRestore() []byte { + if x != nil { + return x.Restore + } + return nil +} + +func (x *RestoreItemActionItemsReadyRequest) GetAdditionalItems() []*generated.ResourceIdentifier { + if x != nil { + return x.AdditionalItems + } + return nil +} + +type RestoreItemActionItemsReadyResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ready bool `protobuf:"varint,1,opt,name=ready,proto3" json:"ready,omitempty"` +} + +func (x *RestoreItemActionItemsReadyResponse) Reset() { + *x = RestoreItemActionItemsReadyResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RestoreItemActionItemsReadyResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RestoreItemActionItemsReadyResponse) ProtoMessage() {} + +func (x *RestoreItemActionItemsReadyResponse) ProtoReflect() protoreflect.Message { + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RestoreItemActionItemsReadyResponse.ProtoReflect.Descriptor instead. +func (*RestoreItemActionItemsReadyResponse) Descriptor() ([]byte, []int) { + return file_restoreitemaction_v2_RestoreItemAction_proto_rawDescGZIP(), []int{8} +} + +func (x *RestoreItemActionItemsReadyResponse) GetReady() bool { + if x != nil { + return x.Ready + } + return false +} + +var File_restoreitemaction_v2_RestoreItemAction_proto protoreflect.FileDescriptor + +var file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc = []byte{ + 0x0a, 0x2c, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x69, 0x74, 0x65, 0x6d, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x32, 0x2f, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, + 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, + 0x76, 0x32, 0x1a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8f, 0x01, + 0x0a, 0x1f, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x74, 0x65, + 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x18, 0x0a, + 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x74, 0x65, 0x6d, 0x46, + 0x72, 0x6f, 0x6d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0e, 0x69, 0x74, 0x65, 0x6d, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, + 0xd8, 0x02, 0x0a, 0x20, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x47, 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x52, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, + 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x6b, 0x69, 0x70, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x6b, 0x69, 0x70, 0x52, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x36, 0x0a, 0x16, 0x77, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, + 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x77, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x41, 0x64, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x5b, 0x0a, + 0x1b, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, + 0x52, 0x65, 0x61, 0x64, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x1b, 0x61, + 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, + 0x61, 0x64, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x3b, 0x0a, 0x21, 0x52, 0x65, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, + 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x22, 0x6d, 0x0a, 0x22, 0x52, 0x65, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, + 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x52, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x76, 0x0a, 0x20, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, + 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x5d, + 0x0a, 0x21, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, + 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, + 0x65, 0x73, 0x73, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x74, 0x0a, + 0x1e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x22, 0x9f, 0x01, 0x0a, 0x22, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, + 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, + 0x61, 0x64, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x47, 0x0a, 0x0f, + 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, + 0x64, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3b, 0x0a, 0x23, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, + 0x65, 0x61, 0x64, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x72, 0x65, 0x61, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x61, + 0x64, 0x79, 0x32, 0xd0, 0x03, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, + 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5a, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x65, 0x73, 0x54, 0x6f, 0x12, 0x25, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x76, + 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x07, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, + 0x23, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x08, 0x50, 0x72, + 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x24, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, + 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x76, + 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x22, 0x2e, + 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x6a, 0x0a, 0x17, 0x41, 0x72, 0x65, + 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, + 0x65, 0x61, 0x64, 0x79, 0x12, 0x26, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, + 0x52, 0x65, 0x61, 0x64, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x76, + 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x61, 0x64, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x4a, 0x5a, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x61, 0x6e, 0x7a, 0x75, + 0x2f, 0x76, 0x65, 0x6c, 0x65, 0x72, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x69, 0x74, 0x65, 0x6d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, + 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_restoreitemaction_v2_RestoreItemAction_proto_rawDescOnce sync.Once + file_restoreitemaction_v2_RestoreItemAction_proto_rawDescData = file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc +) + +func file_restoreitemaction_v2_RestoreItemAction_proto_rawDescGZIP() []byte { + file_restoreitemaction_v2_RestoreItemAction_proto_rawDescOnce.Do(func() { + file_restoreitemaction_v2_RestoreItemAction_proto_rawDescData = protoimpl.X.CompressGZIP(file_restoreitemaction_v2_RestoreItemAction_proto_rawDescData) + }) + return file_restoreitemaction_v2_RestoreItemAction_proto_rawDescData +} + +var file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_restoreitemaction_v2_RestoreItemAction_proto_goTypes = []interface{}{ + (*RestoreItemActionExecuteRequest)(nil), // 0: v2.RestoreItemActionExecuteRequest + (*RestoreItemActionExecuteResponse)(nil), // 1: v2.RestoreItemActionExecuteResponse + (*RestoreItemActionAppliesToRequest)(nil), // 2: v2.RestoreItemActionAppliesToRequest + (*RestoreItemActionAppliesToResponse)(nil), // 3: v2.RestoreItemActionAppliesToResponse + (*RestoreItemActionProgressRequest)(nil), // 4: v2.RestoreItemActionProgressRequest + (*RestoreItemActionProgressResponse)(nil), // 5: v2.RestoreItemActionProgressResponse + (*RestoreItemActionCancelRequest)(nil), // 6: v2.RestoreItemActionCancelRequest + (*RestoreItemActionItemsReadyRequest)(nil), // 7: v2.RestoreItemActionItemsReadyRequest + (*RestoreItemActionItemsReadyResponse)(nil), // 8: v2.RestoreItemActionItemsReadyResponse + (*generated.ResourceIdentifier)(nil), // 9: generated.ResourceIdentifier + (*durationpb.Duration)(nil), // 10: google.protobuf.Duration + (*generated.ResourceSelector)(nil), // 11: generated.ResourceSelector + (*generated.OperationProgress)(nil), // 12: generated.OperationProgress + (*emptypb.Empty)(nil), // 13: google.protobuf.Empty +} +var file_restoreitemaction_v2_RestoreItemAction_proto_depIdxs = []int32{ + 9, // 0: v2.RestoreItemActionExecuteResponse.additionalItems:type_name -> generated.ResourceIdentifier + 10, // 1: v2.RestoreItemActionExecuteResponse.additionalItemsReadyTimeout:type_name -> google.protobuf.Duration + 11, // 2: v2.RestoreItemActionAppliesToResponse.ResourceSelector:type_name -> generated.ResourceSelector + 12, // 3: v2.RestoreItemActionProgressResponse.progress:type_name -> generated.OperationProgress + 9, // 4: v2.RestoreItemActionItemsReadyRequest.additionalItems:type_name -> generated.ResourceIdentifier + 2, // 5: v2.RestoreItemAction.AppliesTo:input_type -> v2.RestoreItemActionAppliesToRequest + 0, // 6: v2.RestoreItemAction.Execute:input_type -> v2.RestoreItemActionExecuteRequest + 4, // 7: v2.RestoreItemAction.Progress:input_type -> v2.RestoreItemActionProgressRequest + 6, // 8: v2.RestoreItemAction.Cancel:input_type -> v2.RestoreItemActionCancelRequest + 7, // 9: v2.RestoreItemAction.AreAdditionalItemsReady:input_type -> v2.RestoreItemActionItemsReadyRequest + 3, // 10: v2.RestoreItemAction.AppliesTo:output_type -> v2.RestoreItemActionAppliesToResponse + 1, // 11: v2.RestoreItemAction.Execute:output_type -> v2.RestoreItemActionExecuteResponse + 5, // 12: v2.RestoreItemAction.Progress:output_type -> v2.RestoreItemActionProgressResponse + 13, // 13: v2.RestoreItemAction.Cancel:output_type -> google.protobuf.Empty + 8, // 14: v2.RestoreItemAction.AreAdditionalItemsReady:output_type -> v2.RestoreItemActionItemsReadyResponse + 10, // [10:15] is the sub-list for method output_type + 5, // [5:10] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_restoreitemaction_v2_RestoreItemAction_proto_init() } +func file_restoreitemaction_v2_RestoreItemAction_proto_init() { + if File_restoreitemaction_v2_RestoreItemAction_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RestoreItemActionExecuteRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RestoreItemActionExecuteResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RestoreItemActionAppliesToRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RestoreItemActionAppliesToResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RestoreItemActionProgressRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RestoreItemActionProgressResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RestoreItemActionCancelRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RestoreItemActionItemsReadyRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RestoreItemActionItemsReadyResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc, + NumEnums: 0, + NumMessages: 9, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_restoreitemaction_v2_RestoreItemAction_proto_goTypes, + DependencyIndexes: file_restoreitemaction_v2_RestoreItemAction_proto_depIdxs, + MessageInfos: file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes, + }.Build() + File_restoreitemaction_v2_RestoreItemAction_proto = out.File + file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc = nil + file_restoreitemaction_v2_RestoreItemAction_proto_goTypes = nil + file_restoreitemaction_v2_RestoreItemAction_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// RestoreItemActionClient is the client API for RestoreItemAction service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type RestoreItemActionClient interface { + AppliesTo(ctx context.Context, in *RestoreItemActionAppliesToRequest, opts ...grpc.CallOption) (*RestoreItemActionAppliesToResponse, error) + Execute(ctx context.Context, in *RestoreItemActionExecuteRequest, opts ...grpc.CallOption) (*RestoreItemActionExecuteResponse, error) + Progress(ctx context.Context, in *RestoreItemActionProgressRequest, opts ...grpc.CallOption) (*RestoreItemActionProgressResponse, error) + Cancel(ctx context.Context, in *RestoreItemActionCancelRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + AreAdditionalItemsReady(ctx context.Context, in *RestoreItemActionItemsReadyRequest, opts ...grpc.CallOption) (*RestoreItemActionItemsReadyResponse, error) +} + +type restoreItemActionClient struct { + cc grpc.ClientConnInterface +} + +func NewRestoreItemActionClient(cc grpc.ClientConnInterface) RestoreItemActionClient { + return &restoreItemActionClient{cc} +} + +func (c *restoreItemActionClient) AppliesTo(ctx context.Context, in *RestoreItemActionAppliesToRequest, opts ...grpc.CallOption) (*RestoreItemActionAppliesToResponse, error) { + out := new(RestoreItemActionAppliesToResponse) + err := c.cc.Invoke(ctx, "/v2.RestoreItemAction/AppliesTo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *restoreItemActionClient) Execute(ctx context.Context, in *RestoreItemActionExecuteRequest, opts ...grpc.CallOption) (*RestoreItemActionExecuteResponse, error) { + out := new(RestoreItemActionExecuteResponse) + err := c.cc.Invoke(ctx, "/v2.RestoreItemAction/Execute", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *restoreItemActionClient) Progress(ctx context.Context, in *RestoreItemActionProgressRequest, opts ...grpc.CallOption) (*RestoreItemActionProgressResponse, error) { + out := new(RestoreItemActionProgressResponse) + err := c.cc.Invoke(ctx, "/v2.RestoreItemAction/Progress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *restoreItemActionClient) Cancel(ctx context.Context, in *RestoreItemActionCancelRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/v2.RestoreItemAction/Cancel", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *restoreItemActionClient) AreAdditionalItemsReady(ctx context.Context, in *RestoreItemActionItemsReadyRequest, opts ...grpc.CallOption) (*RestoreItemActionItemsReadyResponse, error) { + out := new(RestoreItemActionItemsReadyResponse) + err := c.cc.Invoke(ctx, "/v2.RestoreItemAction/AreAdditionalItemsReady", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// RestoreItemActionServer is the server API for RestoreItemAction service. +type RestoreItemActionServer interface { + AppliesTo(context.Context, *RestoreItemActionAppliesToRequest) (*RestoreItemActionAppliesToResponse, error) + Execute(context.Context, *RestoreItemActionExecuteRequest) (*RestoreItemActionExecuteResponse, error) + Progress(context.Context, *RestoreItemActionProgressRequest) (*RestoreItemActionProgressResponse, error) + Cancel(context.Context, *RestoreItemActionCancelRequest) (*emptypb.Empty, error) + AreAdditionalItemsReady(context.Context, *RestoreItemActionItemsReadyRequest) (*RestoreItemActionItemsReadyResponse, error) +} + +// UnimplementedRestoreItemActionServer can be embedded to have forward compatible implementations. +type UnimplementedRestoreItemActionServer struct { +} + +func (*UnimplementedRestoreItemActionServer) AppliesTo(context.Context, *RestoreItemActionAppliesToRequest) (*RestoreItemActionAppliesToResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AppliesTo not implemented") +} +func (*UnimplementedRestoreItemActionServer) Execute(context.Context, *RestoreItemActionExecuteRequest) (*RestoreItemActionExecuteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Execute not implemented") +} +func (*UnimplementedRestoreItemActionServer) Progress(context.Context, *RestoreItemActionProgressRequest) (*RestoreItemActionProgressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Progress not implemented") +} +func (*UnimplementedRestoreItemActionServer) Cancel(context.Context, *RestoreItemActionCancelRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Cancel not implemented") +} +func (*UnimplementedRestoreItemActionServer) AreAdditionalItemsReady(context.Context, *RestoreItemActionItemsReadyRequest) (*RestoreItemActionItemsReadyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AreAdditionalItemsReady not implemented") +} + +func RegisterRestoreItemActionServer(s *grpc.Server, srv RestoreItemActionServer) { + s.RegisterService(&_RestoreItemAction_serviceDesc, srv) +} + +func _RestoreItemAction_AppliesTo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RestoreItemActionAppliesToRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RestoreItemActionServer).AppliesTo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v2.RestoreItemAction/AppliesTo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RestoreItemActionServer).AppliesTo(ctx, req.(*RestoreItemActionAppliesToRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RestoreItemAction_Execute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RestoreItemActionExecuteRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RestoreItemActionServer).Execute(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v2.RestoreItemAction/Execute", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RestoreItemActionServer).Execute(ctx, req.(*RestoreItemActionExecuteRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RestoreItemAction_Progress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RestoreItemActionProgressRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RestoreItemActionServer).Progress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v2.RestoreItemAction/Progress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RestoreItemActionServer).Progress(ctx, req.(*RestoreItemActionProgressRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RestoreItemAction_Cancel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RestoreItemActionCancelRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RestoreItemActionServer).Cancel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v2.RestoreItemAction/Cancel", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RestoreItemActionServer).Cancel(ctx, req.(*RestoreItemActionCancelRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RestoreItemAction_AreAdditionalItemsReady_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RestoreItemActionItemsReadyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RestoreItemActionServer).AreAdditionalItemsReady(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v2.RestoreItemAction/AreAdditionalItemsReady", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RestoreItemActionServer).AreAdditionalItemsReady(ctx, req.(*RestoreItemActionItemsReadyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _RestoreItemAction_serviceDesc = grpc.ServiceDesc{ + ServiceName: "v2.RestoreItemAction", + HandlerType: (*RestoreItemActionServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AppliesTo", + Handler: _RestoreItemAction_AppliesTo_Handler, + }, + { + MethodName: "Execute", + Handler: _RestoreItemAction_Execute_Handler, + }, + { + MethodName: "Progress", + Handler: _RestoreItemAction_Progress_Handler, + }, + { + MethodName: "Cancel", + Handler: _RestoreItemAction_Cancel_Handler, + }, + { + MethodName: "AreAdditionalItemsReady", + Handler: _RestoreItemAction_AreAdditionalItemsReady_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "restoreitemaction/v2/RestoreItemAction.proto", +} diff --git a/pkg/plugin/mocks/manager.go b/pkg/plugin/mocks/manager.go index 5031729a1c..25b6d95ae4 100644 --- a/pkg/plugin/mocks/manager.go +++ b/pkg/plugin/mocks/manager.go @@ -8,6 +8,8 @@ import ( restoreitemactionv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1" + restoreitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2" + v1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v1" v2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v2" @@ -257,6 +259,29 @@ func (_m *Manager) GetRestoreItemAction(name string) (restoreitemactionv1.Restor return r0, r1 } +// GetRestoreItemActionV2 provides a mock function with given fields: name +func (_m *Manager) GetRestoreItemActionV2(name string) (restoreitemactionv2.RestoreItemAction, error) { + ret := _m.Called(name) + + var r0 restoreitemactionv2.RestoreItemAction + if rf, ok := ret.Get(0).(func(string) restoreitemactionv2.RestoreItemAction); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(restoreitemactionv2.RestoreItemAction) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetRestoreItemActions provides a mock function with given fields: func (_m *Manager) GetRestoreItemActions() ([]restoreitemactionv1.RestoreItemAction, error) { ret := _m.Called() @@ -280,6 +305,29 @@ func (_m *Manager) GetRestoreItemActions() ([]restoreitemactionv1.RestoreItemAct return r0, r1 } +// GetRestoreItemActionsV2 provides a mock function with given fields: +func (_m *Manager) GetRestoreItemActionsV2() ([]restoreitemactionv2.RestoreItemAction, error) { + ret := _m.Called() + + var r0 []restoreitemactionv2.RestoreItemAction + if rf, ok := ret.Get(0).(func() []restoreitemactionv2.RestoreItemAction); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]restoreitemactionv2.RestoreItemAction) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetVolumeSnapshotter provides a mock function with given fields: name func (_m *Manager) GetVolumeSnapshotter(name string) (volumesnapshotterv1.VolumeSnapshotter, error) { ret := _m.Called(name) diff --git a/pkg/plugin/proto/restoreitemaction/v2/RestoreItemAction.proto b/pkg/plugin/proto/restoreitemaction/v2/RestoreItemAction.proto new file mode 100644 index 0000000000..a3e9691143 --- /dev/null +++ b/pkg/plugin/proto/restoreitemaction/v2/RestoreItemAction.proto @@ -0,0 +1,61 @@ +syntax = "proto3"; +package v2; +option go_package = "github.com/vmware-tanzu/velero/pkg/plugin/generated/restoreitemaction/v2"; + +import "Shared.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/duration.proto"; + +message RestoreItemActionExecuteRequest { + string plugin = 1; + bytes item = 2; + bytes restore = 3; + bytes itemFromBackup = 4; +} + +message RestoreItemActionExecuteResponse { + bytes item = 1; + repeated generated.ResourceIdentifier additionalItems = 2; + bool skipRestore = 3; + string operationID = 4; + bool waitForAdditionalItems = 5; + google.protobuf.Duration additionalItemsReadyTimeout = 6; +} + +service RestoreItemAction { + rpc AppliesTo(RestoreItemActionAppliesToRequest) returns (RestoreItemActionAppliesToResponse); + rpc Execute(RestoreItemActionExecuteRequest) returns (RestoreItemActionExecuteResponse); + rpc Progress(RestoreItemActionProgressRequest) returns (RestoreItemActionProgressResponse); + rpc Cancel(RestoreItemActionCancelRequest) returns (google.protobuf.Empty); + rpc AreAdditionalItemsReady(RestoreItemActionItemsReadyRequest) returns (RestoreItemActionItemsReadyResponse); +} + +message RestoreItemActionAppliesToRequest { + string plugin = 1; +} + +message RestoreItemActionAppliesToResponse { + generated.ResourceSelector ResourceSelector = 1; +} + +message RestoreItemActionProgressRequest { + string plugin = 1; + string operationID = 2; + bytes restore = 3; +} +message RestoreItemActionProgressResponse { + generated.OperationProgress progress = 1; +} +message RestoreItemActionCancelRequest { + string plugin = 1; + string operationID = 2; + bytes restore = 3; +} +message RestoreItemActionItemsReadyRequest { + string plugin = 1; + bytes restore = 2; + repeated generated.ResourceIdentifier additionalItems = 3; +} +message RestoreItemActionItemsReadyResponse { + bool ready = 1; +} diff --git a/pkg/plugin/velero/mocks/restoreitemaction/v2/RestoreItemAction.go b/pkg/plugin/velero/mocks/restoreitemaction/v2/RestoreItemAction.go new file mode 100644 index 0000000000..0488989626 --- /dev/null +++ b/pkg/plugin/velero/mocks/restoreitemaction/v2/RestoreItemAction.go @@ -0,0 +1,130 @@ +/* +Copyright the Velero contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package v2 + +import ( + mock "github.com/stretchr/testify/mock" + v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + + velero "github.com/vmware-tanzu/velero/pkg/plugin/velero" +) + +// RestoreItemAction is an autogenerated mock type for the RestoreItemAction type +type RestoreItemAction struct { + mock.Mock +} + +// AppliesTo provides a mock function with given fields: +func (_m *RestoreItemAction) AppliesTo() (velero.ResourceSelector, error) { + ret := _m.Called() + + var r0 velero.ResourceSelector + if rf, ok := ret.Get(0).(func() velero.ResourceSelector); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(velero.ResourceSelector) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AreAdditionalItemsReady provides a mock function with given fields: AdditionalItems, restore +func (_m *RestoreItemAction) AreAdditionalItemsReady(AdditionalItems []velero.ResourceIdentifier, restore *v1.Restore) (bool, error) { + ret := _m.Called(AdditionalItems, restore) + + var r0 bool + if rf, ok := ret.Get(0).(func([]velero.ResourceIdentifier, *v1.Restore) bool); ok { + r0 = rf(AdditionalItems, restore) + } else { + r0 = ret.Get(0).(bool) + } + + var r1 error + if rf, ok := ret.Get(1).(func([]velero.ResourceIdentifier, *v1.Restore) error); ok { + r1 = rf(AdditionalItems, restore) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Cancel provides a mock function with given fields: operationID, restore +func (_m *RestoreItemAction) Cancel(operationID string, restore *v1.Restore) error { + ret := _m.Called(operationID, restore) + + var r0 error + if rf, ok := ret.Get(0).(func(string, *v1.Restore) error); ok { + r0 = rf(operationID, restore) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Execute provides a mock function with given fields: input +func (_m *RestoreItemAction) Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) { + ret := _m.Called(input) + + var r0 *velero.RestoreItemActionExecuteOutput + if rf, ok := ret.Get(0).(func(*velero.RestoreItemActionExecuteInput) *velero.RestoreItemActionExecuteOutput); ok { + r0 = rf(input) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*velero.RestoreItemActionExecuteOutput) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(*velero.RestoreItemActionExecuteInput) error); ok { + r1 = rf(input) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Progress provides a mock function with given fields: operationID, restore +func (_m *RestoreItemAction) Progress(operationID string, restore *v1.Restore) (velero.OperationProgress, error) { + ret := _m.Called(operationID, restore) + + var r0 velero.OperationProgress + if rf, ok := ret.Get(0).(func(string, *v1.Restore) velero.OperationProgress); ok { + r0 = rf(operationID, restore) + } else { + r0 = ret.Get(0).(velero.OperationProgress) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, *v1.Restore) error); ok { + r1 = rf(operationID, restore) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/pkg/plugin/velero/restore_item_action_shared.go b/pkg/plugin/velero/restore_item_action_shared.go index 2714d69ab6..a8e285b0c2 100644 --- a/pkg/plugin/velero/restore_item_action_shared.go +++ b/pkg/plugin/velero/restore_item_action_shared.go @@ -17,6 +17,8 @@ limitations under the License. package velero import ( + "time" + "k8s.io/apimachinery/pkg/runtime" api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" @@ -46,6 +48,26 @@ type RestoreItemActionExecuteOutput struct { // on this item, and skip the restore step. When this field's // value is true, AdditionalItems will be ignored. SkipRestore bool + + // v2 and later + // OperationID is an identifier which indicates an ongoing asynchronous action which Velero will + // continue to monitor after restoring this item. If left blank, then there is no ongoing operation. + OperationID string + + // v2 and later + // WaitForAdditionalItems determines whether velero will wait + // until AreAdditionalItemsReady returns true before restoring + // this item. If this field's value is true, then after restoring + // the returned AdditionalItems, velero will not restore this item + // until AreAdditionalItemsReady returns true or the timeout is + // reached. Otherwise, AreAdditionalItemsReady is not called. + WaitForAdditionalItems bool + + // v2 and later + // AdditionalItemsReadyTimeout will override serverConfig.additionalItemsReadyTimeout + // if specified. This value specifies how long velero will wait + // for additional items to be ready before moving on. + AdditionalItemsReadyTimeout time.Duration } // NewRestoreItemActionExecuteOutput creates a new RestoreItemActionExecuteOutput @@ -60,3 +82,15 @@ func (r *RestoreItemActionExecuteOutput) WithoutRestore() *RestoreItemActionExec r.SkipRestore = true return r } + +// WithOperationID returns RestoreItemActionExecuteOutput with OperationID set. +func (r *RestoreItemActionExecuteOutput) WithOperationID(operationID string) *RestoreItemActionExecuteOutput { + r.OperationID = operationID + return r +} + +// WithItemsWait returns RestoreItemActionExecuteOutput with WaitForAdditionalItems set to true. +func (r *RestoreItemActionExecuteOutput) WithItemsWait() *RestoreItemActionExecuteOutput { + r.WaitForAdditionalItems = true + return r +} diff --git a/pkg/plugin/velero/restoreitemaction/v2/restore_item_action.go b/pkg/plugin/velero/restoreitemaction/v2/restore_item_action.go new file mode 100644 index 0000000000..b29df9c754 --- /dev/null +++ b/pkg/plugin/velero/restoreitemaction/v2/restore_item_action.go @@ -0,0 +1,70 @@ +/* +Copyright the Velero contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2 + +import ( + "fmt" + + "github.com/pkg/errors" + + api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "github.com/vmware-tanzu/velero/pkg/plugin/velero" +) + +// RestoreItemAction is an actor that performs an operation on an individual item being restored. +type RestoreItemAction interface { + // AppliesTo returns information about which resources this action should be invoked for. + // A RestoreItemAction's Execute function will only be invoked on items that match the returned + // selector. A zero-valued ResourceSelector matches all resources. + AppliesTo() (velero.ResourceSelector, error) + + // Execute allows the ItemAction to perform arbitrary logic with the item being restored, + // including mutating the item itself prior to restore. The return struct includes: + // The item (unmodified or modified), an optional slice of ResourceIdentifiers + // specifying additional related items that should be restored, an optional OperationID, + // a bool (waitForAdditionalItems) specifying whether Velero should wait until restored additional + // items are ready before restoring this resource, and an optional timeout for the additional items + // wait period. An error is returned if the action fails. + Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) + + // Progress allows the RestoreItemAction to report on progress of an asynchronous action. + // For the passed-in operation, the plugin will return an OperationProgress struct, indicating + // whether the operation has completed, whether there were any errors, a plugin-specific + // indication of how much of the operation is done (items completed out of items-to-complete), + // and started/updated timestamps + Progress(operationID string, restore *api.Restore) (velero.OperationProgress, error) + + // Cancel allows the RestoreItemAction to cancel an asynchronous action (if possible). + // Velero will call this if the wait timeout for asynchronous actions has been reached. + // If operation cancel is not supported, then the plugin just needs to return. No error + // return is expected in this case, since cancellation is optional here. + Cancel(operationID string, restore *api.Restore) error + + // AreAdditionalItemsReady allows the ItemAction to communicate whether the passed-in + // slice of AdditionalItems (previously returned by Execute()) + // are ready. Returns true if all items are ready, and false + // otherwise. The second return value is to report errors + AreAdditionalItemsReady(AdditionalItems []velero.ResourceIdentifier, restore *api.Restore) (bool, error) +} + +func AsyncOperationsNotSupportedError() error { + return errors.New("Plugin does not support asynchronous operations") +} + +func InvalidOperationIDError(operationID string) error { + return errors.New(fmt.Sprintf("Operation ID %v is invalid.", operationID)) +} diff --git a/pkg/restore/restore.go b/pkg/restore/restore.go index bea58fafc4..6df9ef2340 100644 --- a/pkg/restore/restore.go +++ b/pkg/restore/restore.go @@ -59,7 +59,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/label" "github.com/vmware-tanzu/velero/pkg/plugin/framework" "github.com/vmware-tanzu/velero/pkg/plugin/velero" - riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1" + riav2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2" vsv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v1" "github.com/vmware-tanzu/velero/pkg/podexec" "github.com/vmware-tanzu/velero/pkg/podvolume" @@ -88,13 +88,13 @@ type Request struct { type Restorer interface { // Restore restores the backup data from backupReader, returning warnings and errors. Restore(req Request, - actions []riav1.RestoreItemAction, + actions []riav2.RestoreItemAction, snapshotLocationLister listers.VolumeSnapshotLocationLister, volumeSnapshotterGetter VolumeSnapshotterGetter, ) (Result, Result) RestoreWithResolvers( req Request, - restoreItemActionResolver framework.RestoreItemActionResolver, + restoreItemActionResolver framework.RestoreItemActionResolverV2, itemSnapshotterResolver framework.ItemSnapshotterResolver, snapshotLocationLister listers.VolumeSnapshotLocationLister, volumeSnapshotterGetter VolumeSnapshotterGetter, @@ -164,18 +164,18 @@ func NewKubernetesRestorer( // respectively, summarizing info about the restore. func (kr *kubernetesRestorer) Restore( req Request, - actions []riav1.RestoreItemAction, + actions []riav2.RestoreItemAction, snapshotLocationLister listers.VolumeSnapshotLocationLister, volumeSnapshotterGetter VolumeSnapshotterGetter, ) (Result, Result) { - resolver := framework.NewRestoreItemActionResolver(actions) + resolver := framework.NewRestoreItemActionResolverV2(actions) snapshotItemResolver := framework.NewItemSnapshotterResolver(nil) return kr.RestoreWithResolvers(req, resolver, snapshotItemResolver, snapshotLocationLister, volumeSnapshotterGetter) } func (kr *kubernetesRestorer) RestoreWithResolvers( req Request, - restoreItemActionResolver framework.RestoreItemActionResolver, + restoreItemActionResolver framework.RestoreItemActionResolverV2, itemSnapshotterResolver framework.ItemSnapshotterResolver, snapshotLocationLister listers.VolumeSnapshotLocationLister, volumeSnapshotterGetter VolumeSnapshotterGetter, @@ -342,7 +342,7 @@ type restoreContext struct { dynamicFactory client.DynamicFactory fileSystem filesystem.Interface namespaceClient corev1.NamespaceInterface - restoreItemActions []framework.RestoreItemResolvedAction + restoreItemActions []framework.RestoreItemResolvedActionV2 itemSnapshotterActions []framework.ItemSnapshotterResolvedAction volumeSnapshotterGetter VolumeSnapshotterGetter podVolumeRestorer podvolume.Restorer @@ -743,8 +743,8 @@ func getNamespace(logger logrus.FieldLogger, path, remappedName string) *v1.Name } } -func (ctx *restoreContext) getApplicableActions(groupResource schema.GroupResource, namespace string) []framework.RestoreItemResolvedAction { - var actions []framework.RestoreItemResolvedAction +func (ctx *restoreContext) getApplicableActions(groupResource schema.GroupResource, namespace string) []framework.RestoreItemResolvedActionV2 { + var actions []framework.RestoreItemResolvedActionV2 for _, action := range ctx.restoreItemActions { if action.ShouldUse(groupResource, namespace, nil, ctx.log) { actions = append(actions, action) diff --git a/pkg/restore/restore_test.go b/pkg/restore/restore_test.go index c8bd37ad50..88a3a05808 100644 --- a/pkg/restore/restore_test.go +++ b/pkg/restore/restore_test.go @@ -48,7 +48,7 @@ import ( velerov1informers "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions" "github.com/vmware-tanzu/velero/pkg/kuberesource" "github.com/vmware-tanzu/velero/pkg/plugin/velero" - riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1" + riav2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2" vsv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v1" "github.com/vmware-tanzu/velero/pkg/podvolume" uploadermocks "github.com/vmware-tanzu/velero/pkg/podvolume/mocks" @@ -1142,9 +1142,12 @@ func TestRestoreItems(t *testing.T) { // to run for specific resources/namespaces and simply records the items // that it is executed for. type recordResourcesAction struct { - selector velero.ResourceSelector - ids []string - additionalItems []velero.ResourceIdentifier + selector velero.ResourceSelector + ids []string + additionalItems []velero.ResourceIdentifier + operationID string + waitForAdditionalItems bool + additionalItemsReadyTimeout time.Duration } func (a *recordResourcesAction) AppliesTo() (velero.ResourceSelector, error) { @@ -1155,18 +1158,36 @@ func (a *recordResourcesAction) Execute(input *velero.RestoreItemActionExecuteIn metadata, err := meta.Accessor(input.Item) if err != nil { return &velero.RestoreItemActionExecuteOutput{ - UpdatedItem: input.Item, - AdditionalItems: a.additionalItems, + UpdatedItem: input.Item, + AdditionalItems: a.additionalItems, + OperationID: a.operationID, + WaitForAdditionalItems: a.waitForAdditionalItems, + AdditionalItemsReadyTimeout: a.additionalItemsReadyTimeout, }, err } a.ids = append(a.ids, kubeutil.NamespaceAndName(metadata)) return &velero.RestoreItemActionExecuteOutput{ - UpdatedItem: input.Item, - AdditionalItems: a.additionalItems, + UpdatedItem: input.Item, + AdditionalItems: a.additionalItems, + OperationID: a.operationID, + WaitForAdditionalItems: a.waitForAdditionalItems, + AdditionalItemsReadyTimeout: a.additionalItemsReadyTimeout, }, nil } +func (a *recordResourcesAction) Progress(operationID string, restore *velerov1api.Restore) (velero.OperationProgress, error) { + return velero.OperationProgress{}, nil +} + +func (a *recordResourcesAction) Cancel(operationID string, restore *velerov1api.Restore) error { + return nil +} + +func (a *recordResourcesAction) AreAdditionalItemsReady(additionalItems []velero.ResourceIdentifier, restore *velerov1api.Restore) (bool, error) { + return true, nil +} + func (a *recordResourcesAction) ForResource(resource string) *recordResourcesAction { a.selector.IncludedResources = append(a.selector.IncludedResources, resource) return a @@ -1322,7 +1343,7 @@ func TestRestoreActionsRunForCorrectItems(t *testing.T) { h.AddItems(t, r) } - actions := []riav1.RestoreItemAction{} + actions := []riav2.RestoreItemAction{} for action := range tc.actions { actions = append(actions, action) } @@ -1374,11 +1395,23 @@ func (a *pluggableAction) AppliesTo() (velero.ResourceSelector, error) { return a.selector, nil } +func (a *pluggableAction) Progress(operationID string, restore *velerov1api.Restore) (velero.OperationProgress, error) { + return velero.OperationProgress{}, nil +} + +func (a *pluggableAction) Cancel(operationID string, restore *velerov1api.Restore) error { + return nil +} + func (a *pluggableAction) addSelector(selector velero.ResourceSelector) *pluggableAction { a.selector = selector return a } +func (a *pluggableAction) AreAdditionalItemsReady(additionalItems []velero.ResourceIdentifier, restore *velerov1api.Restore) (bool, error) { + return true, nil +} + // TestRestoreActionModifications runs restores with restore item actions that modify resources, and // verifies that that the modified item is correctly created in the API. Verification is done by looking // at the full object in the API. @@ -1409,7 +1442,7 @@ func TestRestoreActionModifications(t *testing.T) { backup *velerov1api.Backup apiResources []*test.APIResource tarball io.Reader - actions []riav1.RestoreItemAction + actions []riav2.RestoreItemAction want []*test.APIResource }{ { @@ -1418,7 +1451,7 @@ func TestRestoreActionModifications(t *testing.T) { backup: defaultBackup().Result(), tarball: test.NewTarWriter(t).AddItems("pods", builder.ForPod("ns-1", "pod-1").Result()).Done(), apiResources: []*test.APIResource{test.Pods()}, - actions: []riav1.RestoreItemAction{ + actions: []riav2.RestoreItemAction{ modifyingActionGetter(func(item *unstructured.Unstructured) { item.SetLabels(map[string]string{"updated": "true"}) }), @@ -1435,7 +1468,7 @@ func TestRestoreActionModifications(t *testing.T) { backup: defaultBackup().Result(), tarball: test.NewTarWriter(t).AddItems("pods", builder.ForPod("ns-1", "pod-1").ObjectMeta(builder.WithLabels("should-be-removed", "true")).Result()).Done(), apiResources: []*test.APIResource{test.Pods()}, - actions: []riav1.RestoreItemAction{ + actions: []riav2.RestoreItemAction{ modifyingActionGetter(func(item *unstructured.Unstructured) { item.SetLabels(nil) }), @@ -1450,7 +1483,7 @@ func TestRestoreActionModifications(t *testing.T) { backup: defaultBackup().Result(), tarball: test.NewTarWriter(t).AddItems("pods", builder.ForPod("ns-1", "pod-1").Result()).Done(), apiResources: []*test.APIResource{test.Pods()}, - actions: []riav1.RestoreItemAction{ + actions: []riav2.RestoreItemAction{ modifyingActionGetter(func(item *unstructured.Unstructured) { item.SetLabels(map[string]string{"updated": "true"}) }).addSelector(velero.ResourceSelector{ @@ -1522,7 +1555,7 @@ func TestRestoreActionAdditionalItems(t *testing.T) { backup *velerov1api.Backup tarball io.Reader apiResources []*test.APIResource - actions []riav1.RestoreItemAction + actions []riav2.RestoreItemAction want map[*test.APIResource][]string }{ { @@ -1531,7 +1564,7 @@ func TestRestoreActionAdditionalItems(t *testing.T) { backup: defaultBackup().Result(), tarball: test.NewTarWriter(t).AddItems("pods", builder.ForPod("ns-1", "pod-1").Result(), builder.ForPod("ns-2", "pod-2").Result()).Done(), apiResources: []*test.APIResource{test.Pods()}, - actions: []riav1.RestoreItemAction{ + actions: []riav2.RestoreItemAction{ &pluggableAction{ selector: velero.ResourceSelector{IncludedNamespaces: []string{"ns-1"}}, executeFunc: func(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) { @@ -1554,7 +1587,7 @@ func TestRestoreActionAdditionalItems(t *testing.T) { backup: defaultBackup().Result(), tarball: test.NewTarWriter(t).AddItems("pods", builder.ForPod("ns-1", "pod-1").Result(), builder.ForPod("ns-2", "pod-2").Result()).Done(), apiResources: []*test.APIResource{test.Pods()}, - actions: []riav1.RestoreItemAction{ + actions: []riav2.RestoreItemAction{ &pluggableAction{ executeFunc: func(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) { return &velero.RestoreItemActionExecuteOutput{ @@ -1579,7 +1612,7 @@ func TestRestoreActionAdditionalItems(t *testing.T) { AddItems("persistentvolumes", builder.ForPersistentVolume("pv-1").Result()). Done(), apiResources: []*test.APIResource{test.Pods(), test.PVs()}, - actions: []riav1.RestoreItemAction{ + actions: []riav2.RestoreItemAction{ &pluggableAction{ executeFunc: func(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) { return &velero.RestoreItemActionExecuteOutput{ @@ -1605,7 +1638,7 @@ func TestRestoreActionAdditionalItems(t *testing.T) { AddItems("persistentvolumes", builder.ForPersistentVolume("pv-1").Result()). Done(), apiResources: []*test.APIResource{test.Pods(), test.PVs()}, - actions: []riav1.RestoreItemAction{ + actions: []riav2.RestoreItemAction{ &pluggableAction{ executeFunc: func(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) { return &velero.RestoreItemActionExecuteOutput{ @@ -1631,7 +1664,7 @@ func TestRestoreActionAdditionalItems(t *testing.T) { AddItems("persistentvolumes", builder.ForPersistentVolume("pv-1").Result()). Done(), apiResources: []*test.APIResource{test.Pods(), test.PVs()}, - actions: []riav1.RestoreItemAction{ + actions: []riav2.RestoreItemAction{ &pluggableAction{ executeFunc: func(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) { return &velero.RestoreItemActionExecuteOutput{