RestoreItemAction v1 refactoring for plugin api versioning

Signed-off-by: Scott Seago <sseago@redhat.com>
This commit is contained in:
Scott Seago
2022-09-20 17:43:56 -04:00
parent 07da9b9cf8
commit 32ef20d317
51 changed files with 493 additions and 580 deletions
@@ -25,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"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"
@@ -57,7 +58,7 @@ func TestRestartableGetBackupItemAction(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
defer p.AssertExpectations(t)
name := "pod"
@@ -78,7 +79,7 @@ func TestRestartableGetBackupItemAction(t *testing.T) {
}
func TestRestartableBackupItemActionGetDelegate(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
defer p.AssertExpectations(t)
// Reset error
@@ -121,7 +122,7 @@ func TestRestartableBackupItemActionDelegatedFunctions(t *testing.T) {
},
}
runRestartableDelegateTests(
restartabletest.RunRestartableDelegateTests(
t,
common.PluginKindBackupItemAction,
func(key process.KindAndName, p process.RestartableProcess) interface{} {
@@ -130,20 +131,20 @@ func TestRestartableBackupItemActionDelegatedFunctions(t *testing.T) {
SharedPluginProcess: p,
}
},
func() mockable {
func() restartabletest.Mockable {
return new(mocks.BackupItemAction)
},
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: "AppliesTo",
Inputs: []interface{}{},
ExpectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "Execute",
inputs: []interface{}{pv, b},
expectedErrorOutputs: []interface{}{nil, ([]velero.ResourceIdentifier)(nil), errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{pvToReturn, additionalItems, errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "Execute",
Inputs: []interface{}{pv, b},
ExpectedErrorOutputs: []interface{}{nil, ([]velero.ResourceIdentifier)(nil), errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{pvToReturn, additionalItems, errors.Errorf("delegate error")},
},
)
}
@@ -1,156 +0,0 @@
/*
Copyright 2018 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 v1
import (
"reflect"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
)
type mockRestartableProcess struct {
mock.Mock
}
func (rp *mockRestartableProcess) AddReinitializer(key process.KindAndName, r process.Reinitializer) {
rp.Called(key, r)
}
func (rp *mockRestartableProcess) Reset() error {
args := rp.Called()
return args.Error(0)
}
func (rp *mockRestartableProcess) ResetIfNeeded() error {
args := rp.Called()
return args.Error(0)
}
func (rp *mockRestartableProcess) GetByKindAndName(key process.KindAndName) (interface{}, error) {
args := rp.Called(key)
return args.Get(0), args.Error(1)
}
func (rp *mockRestartableProcess) Stop() {
rp.Called()
}
type restartableDelegateTest struct {
function string
inputs []interface{}
expectedErrorOutputs []interface{}
expectedDelegateOutputs []interface{}
}
type mockable interface {
Test(t mock.TestingT)
On(method string, args ...interface{}) *mock.Call
AssertExpectations(t mock.TestingT) bool
}
func runRestartableDelegateTests(
t *testing.T,
kind common.PluginKind,
newRestartable func(key process.KindAndName, p process.RestartableProcess) interface{},
newMock func() mockable,
tests ...restartableDelegateTest,
) {
for _, tc := range tests {
t.Run(tc.function, func(t *testing.T) {
p := new(mockRestartableProcess)
p.Test(t)
defer p.AssertExpectations(t)
// getDelegate error
p.On("ResetIfNeeded").Return(errors.Errorf("reset error")).Once()
name := "delegateName"
key := process.KindAndName{Kind: kind, Name: name}
r := newRestartable(key, p)
// Get the method we're going to call using reflection
method := reflect.ValueOf(r).MethodByName(tc.function)
require.NotEmpty(t, method)
// Convert the test case inputs ([]interface{}) to []reflect.Value
var inputValues []reflect.Value
for i := range tc.inputs {
inputValues = append(inputValues, reflect.ValueOf(tc.inputs[i]))
}
// Invoke the method being tested
actual := method.Call(inputValues)
// This function asserts that the actual outputs match the expected outputs
checkOutputs := func(expected []interface{}, actual []reflect.Value) {
require.Equal(t, len(expected), len(actual))
for i := range actual {
// Get the underlying value from the reflect.Value
a := actual[i].Interface()
// Check if it's an error
actualErr, actualErrOk := a.(error)
// Check if the expected output element is an error
expectedErr, expectedErrOk := expected[i].(error)
// If both are errors, use EqualError
if actualErrOk && expectedErrOk {
assert.EqualError(t, actualErr, expectedErr.Error())
continue
}
// If function returns nil as struct return type, we cannot just
// compare the interface to nil as its type will not be nil,
// only the value will be
if expected[i] == nil && reflect.ValueOf(a).Kind() == reflect.Ptr {
assert.True(t, reflect.ValueOf(a).IsNil())
continue
}
// Otherwise, use plain Equal
assert.Equal(t, expected[i], a)
}
}
// Make sure we get what we expected when getDelegate returned an error
checkOutputs(tc.expectedErrorOutputs, actual)
// Invoke delegate, make sure all returned values are passed through
p.On("ResetIfNeeded").Return(nil)
delegate := newMock()
delegate.Test(t)
defer delegate.AssertExpectations(t)
p.On("GetByKindAndName", key).Return(delegate, nil)
// Set up the mocked method in the delegate
delegate.On(tc.function, tc.inputs...).Return(tc.expectedDelegateOutputs...)
// Invoke the method being tested
actual = method.Call(inputValues)
// Make sure we get what we expected when invoking the delegate
checkOutputs(tc.expectedDelegateOutputs, actual)
})
}
}
+18 -11
View File
@@ -26,10 +26,12 @@ import (
biav1cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/backupitemaction/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"
biav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v1"
isv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/item_snapshotter/v1"
riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
)
// Manager manages the lifecycles of plugins.
@@ -47,10 +49,10 @@ type Manager interface {
GetBackupItemAction(name string) (biav1.BackupItemAction, error)
// GetRestoreItemActions returns all restore item action plugins.
GetRestoreItemActions() ([]velero.RestoreItemAction, error)
GetRestoreItemActions() ([]riav1.RestoreItemAction, error)
// GetRestoreItemAction returns the restore item action plugin for name.
GetRestoreItemAction(name string) (velero.RestoreItemAction, error)
GetRestoreItemAction(name string) (riav1.RestoreItemAction, error)
// GetDeleteItemActions returns all delete item action plugins.
GetDeleteItemActions() ([]velero.DeleteItemAction, error)
@@ -211,10 +213,10 @@ func (m *manager) GetBackupItemAction(name string) (biav1.BackupItemAction, erro
}
// GetRestoreItemActions returns all restore item actions as restartableRestoreItemActions.
func (m *manager) GetRestoreItemActions() ([]velero.RestoreItemAction, error) {
func (m *manager) GetRestoreItemActions() ([]riav1.RestoreItemAction, error) {
list := m.registry.List(common.PluginKindRestoreItemAction)
actions := make([]velero.RestoreItemAction, 0, len(list))
actions := make([]riav1.RestoreItemAction, 0, len(list))
for i := range list {
id := list[i]
@@ -231,16 +233,21 @@ func (m *manager) GetRestoreItemActions() ([]velero.RestoreItemAction, error) {
}
// GetRestoreItemAction returns a restartableRestoreItemAction for name.
func (m *manager) GetRestoreItemAction(name string) (velero.RestoreItemAction, error) {
func (m *manager) GetRestoreItemAction(name string) (riav1.RestoreItemAction, error) {
name = sanitizeName(name)
restartableProcess, err := m.getRestartableProcess(common.PluginKindRestoreItemAction, name)
if err != nil {
return nil, err
for _, adaptedRestoreItemAction := range riav1cli.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
}
r := NewRestartableRestoreItemAction(name, restartableProcess)
return r, nil
return nil, fmt.Errorf("unable to get valid RestoreItemAction for %q", name)
}
// GetDeleteItemActions returns all delete item actions as restartableDeleteItemActions.
+17 -42
View File
@@ -26,8 +26,10 @@ import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/vmware-tanzu/velero/internal/restartabletest"
biav1cli "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/backupitemaction/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"
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
"github.com/vmware-tanzu/velero/pkg/test"
@@ -84,33 +86,6 @@ func (f *mockRestartableProcessFactory) NewRestartableProcess(command string, lo
return rp, args.Error(1)
}
type mockRestartableProcess struct {
mock.Mock
}
func (rp *mockRestartableProcess) AddReinitializer(key process.KindAndName, r process.Reinitializer) {
rp.Called(key, r)
}
func (rp *mockRestartableProcess) Reset() error {
args := rp.Called()
return args.Error(0)
}
func (rp *mockRestartableProcess) ResetIfNeeded() error {
args := rp.Called()
return args.Error(0)
}
func (rp *mockRestartableProcess) GetByKindAndName(key process.KindAndName) (interface{}, error) {
args := rp.Called(key)
return args.Get(0), args.Error(1)
}
func (rp *mockRestartableProcess) Stop() {
rp.Called()
}
func TestGetRestartableProcess(t *testing.T) {
logger := test.NewLogger()
logLevel := logrus.InfoLevel
@@ -144,7 +119,7 @@ func TestGetRestartableProcess(t *testing.T) {
assert.EqualError(t, err, "factory")
// Test 3: registry ok, factory ok
restartableProcess := &mockRestartableProcess{}
restartableProcess := &restartabletest.MockRestartableProcess{}
defer restartableProcess.AssertExpectations(t)
factory.On("NewRestartableProcess", podID.Command, logger, logLevel).Return(restartableProcess, nil).Once()
rp, err = m.getRestartableProcess(pluginKind, pluginName)
@@ -167,7 +142,7 @@ func TestCleanupClients(t *testing.T) {
m := NewManager(logger, logLevel, registry).(*manager)
for i := 0; i < 5; i++ {
rp := &mockRestartableProcess{}
rp := &restartabletest.MockRestartableProcess{}
defer rp.AssertExpectations(t)
rp.On("Stop")
m.restartableProcesses[fmt.Sprintf("rp%d", i)] = rp
@@ -235,9 +210,9 @@ func TestGetRestoreItemAction(t *testing.T) {
return m.GetRestoreItemAction(name)
},
func(name string, sharedPluginProcess process.RestartableProcess) interface{} {
return &restartableRestoreItemAction{
key: process.KindAndName{Kind: common.PluginKindRestoreItemAction, Name: name},
sharedPluginProcess: sharedPluginProcess,
return &riav1cli.RestartableRestoreItemAction{
Key: process.KindAndName{Kind: common.PluginKindRestoreItemAction, Name: name},
SharedPluginProcess: sharedPluginProcess,
}
},
false,
@@ -272,7 +247,7 @@ func getPluginTest(
}
registry.On("Get", pluginKind, pluginName).Return(pluginID, nil)
restartableProcess := &mockRestartableProcess{}
restartableProcess := &restartabletest.MockRestartableProcess{}
defer restartableProcess.AssertExpectations(t)
// Test 1: error getting restartable process
@@ -349,7 +324,7 @@ func TestGetBackupItemActions(t *testing.T) {
registry.On("Get", pluginKind, pluginName).Return(pluginID, nil)
restartableProcess := &mockRestartableProcess{}
restartableProcess := &restartabletest.MockRestartableProcess{}
defer restartableProcess.AssertExpectations(t)
expected := &biav1cli.RestartableBackupItemAction{
@@ -441,12 +416,12 @@ func TestGetRestoreItemActions(t *testing.T) {
registry.On("Get", pluginKind, pluginName).Return(pluginID, nil)
restartableProcess := &mockRestartableProcess{}
restartableProcess := &restartabletest.MockRestartableProcess{}
defer restartableProcess.AssertExpectations(t)
expected := &restartableRestoreItemAction{
key: process.KindAndName{Kind: pluginKind, Name: pluginName},
sharedPluginProcess: restartableProcess,
expected := &riav1cli.RestartableRestoreItemAction{
Key: process.KindAndName{Kind: pluginKind, Name: pluginName},
SharedPluginProcess: restartableProcess,
}
if tc.newRestartableProcessError != nil {
@@ -540,12 +515,12 @@ func TestGetDeleteItemActions(t *testing.T) {
registry.On("Get", pluginKind, pluginName).Return(pluginID, nil)
restartableProcess := &mockRestartableProcess{}
restartableProcess := &restartabletest.MockRestartableProcess{}
defer restartableProcess.AssertExpectations(t)
expected := &restartableRestoreItemAction{
key: process.KindAndName{Kind: pluginKind, Name: pluginName},
sharedPluginProcess: restartableProcess,
expected := &riav1cli.RestartableRestoreItemAction{
Key: process.KindAndName{Kind: pluginKind, Name: pluginName},
SharedPluginProcess: restartableProcess,
}
if tc.newRestartableProcessError != nil {
@@ -1,129 +0,0 @@
/*
Copyright 2018 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 clientmgmt
import (
"reflect"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
)
type restartableDelegateTest struct {
function string
inputs []interface{}
expectedErrorOutputs []interface{}
expectedDelegateOutputs []interface{}
}
type mockable interface {
Test(t mock.TestingT)
On(method string, args ...interface{}) *mock.Call
AssertExpectations(t mock.TestingT) bool
}
func runRestartableDelegateTests(
t *testing.T,
kind common.PluginKind,
newRestartable func(key process.KindAndName, p process.RestartableProcess) interface{},
newMock func() mockable,
tests ...restartableDelegateTest,
) {
for _, tc := range tests {
t.Run(tc.function, func(t *testing.T) {
p := new(mockRestartableProcess)
p.Test(t)
defer p.AssertExpectations(t)
// getDelegate error
p.On("ResetIfNeeded").Return(errors.Errorf("reset error")).Once()
name := "delegateName"
key := process.KindAndName{Kind: kind, Name: name}
r := newRestartable(key, p)
// Get the method we're going to call using reflection
method := reflect.ValueOf(r).MethodByName(tc.function)
require.NotEmpty(t, method)
// Convert the test case inputs ([]interface{}) to []reflect.Value
var inputValues []reflect.Value
for i := range tc.inputs {
inputValues = append(inputValues, reflect.ValueOf(tc.inputs[i]))
}
// Invoke the method being tested
actual := method.Call(inputValues)
// This function asserts that the actual outputs match the expected outputs
checkOutputs := func(expected []interface{}, actual []reflect.Value) {
require.Equal(t, len(expected), len(actual))
for i := range actual {
// Get the underlying value from the reflect.Value
a := actual[i].Interface()
// Check if it's an error
actualErr, actualErrOk := a.(error)
// Check if the expected output element is an error
expectedErr, expectedErrOk := expected[i].(error)
// If both are errors, use EqualError
if actualErrOk && expectedErrOk {
assert.EqualError(t, actualErr, expectedErr.Error())
continue
}
// If function returns nil as struct return type, we cannot just
// compare the interface to nil as its type will not be nil,
// only the value will be
if expected[i] == nil && reflect.ValueOf(a).Kind() == reflect.Ptr {
assert.True(t, reflect.ValueOf(a).IsNil())
continue
}
// Otherwise, use plain Equal
assert.Equal(t, expected[i], a)
}
}
// Make sure we get what we expected when getDelegate returned an error
checkOutputs(tc.expectedErrorOutputs, actual)
// Invoke delegate, make sure all returned values are passed through
p.On("ResetIfNeeded").Return(nil)
delegate := newMock()
delegate.Test(t)
defer delegate.AssertExpectations(t)
p.On("GetByKindAndName", key).Return(delegate, nil)
// Set up the mocked method in the delegate
delegate.On(tc.function, tc.inputs...).Return(tc.expectedDelegateOutputs...)
// Invoke the method being tested
actual = method.Call(inputValues)
// Make sure we get what we expected when invoking the delegate
checkOutputs(tc.expectedDelegateOutputs, actual)
})
}
}
@@ -24,6 +24,7 @@ import (
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/vmware-tanzu/velero/internal/restartabletest"
api "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"
@@ -56,7 +57,7 @@ func TestRestartableGetDeleteItemAction(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
defer p.AssertExpectations(t)
name := "pod"
@@ -77,7 +78,7 @@ func TestRestartableGetDeleteItemAction(t *testing.T) {
}
func TestRestartableDeleteItemActionGetDelegate(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
defer p.AssertExpectations(t)
// Reset error
@@ -114,7 +115,7 @@ func TestRestartableDeleteItemActionDelegatedFunctions(t *testing.T) {
Backup: backup,
}
runRestartableDelegateTests(
restartabletest.RunRestartableDelegateTests(
t,
common.PluginKindDeleteItemAction,
func(key process.KindAndName, p process.RestartableProcess) interface{} {
@@ -123,21 +124,21 @@ func TestRestartableDeleteItemActionDelegatedFunctions(t *testing.T) {
sharedPluginProcess: p,
}
},
func() mockable {
func() restartabletest.Mockable {
// Currently broken because this mocks the restore item action interface
return new(mocks.DeleteItemAction)
},
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: "AppliesTo",
Inputs: []interface{}{},
ExpectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "Execute",
inputs: []interface{}{input},
expectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "Execute",
Inputs: []interface{}{input},
ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
},
)
}
@@ -27,6 +27,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/vmware-tanzu/velero/internal/restartabletest"
v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/plugin/velero/item_snapshotter/v1/mocks"
@@ -61,7 +62,7 @@ func TestRestartableGetItemSnapshotter(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
defer p.AssertExpectations(t)
name := "pvc"
@@ -82,7 +83,7 @@ func TestRestartableGetItemSnapshotter(t *testing.T) {
}
func TestRestartableItemSnapshotterGetDelegate(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
defer p.AssertExpectations(t)
// Reset error
@@ -175,7 +176,7 @@ func TestRestartableItemSnasphotterDelegatedFunctions(t *testing.T) {
SnapshotMetadata: nil,
Params: nil,
}
runRestartableDelegateTests(
restartabletest.RunRestartableDelegateTests(
t,
common.PluginKindItemSnapshotter,
func(key process.KindAndName, p process.RestartableProcess) interface{} {
@@ -184,50 +185,50 @@ func TestRestartableItemSnasphotterDelegatedFunctions(t *testing.T) {
sharedPluginProcess: p,
}
},
func() mockable {
func() restartabletest.Mockable {
return new(mocks.ItemSnapshotter)
},
restartableDelegateTest{
function: "Init",
inputs: []interface{}{map[string]string{}},
expectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "Init",
Inputs: []interface{}{map[string]string{}},
ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
},
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: "AppliesTo",
Inputs: []interface{}{},
ExpectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "AlsoHandles",
inputs: []interface{}{&isv1.AlsoHandlesInput{}},
expectedErrorOutputs: []interface{}{[]velero.ResourceIdentifier([]velero.ResourceIdentifier(nil)), errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{[]velero.ResourceIdentifier([]velero.ResourceIdentifier(nil)), errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "AlsoHandles",
Inputs: []interface{}{&isv1.AlsoHandlesInput{}},
ExpectedErrorOutputs: []interface{}{[]velero.ResourceIdentifier([]velero.ResourceIdentifier(nil)), errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{[]velero.ResourceIdentifier([]velero.ResourceIdentifier(nil)), errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "SnapshotItem",
inputs: []interface{}{ctx, sii},
expectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{sio, errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "SnapshotItem",
Inputs: []interface{}{ctx, sii},
ExpectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{sio, errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "CreateItemFromSnapshot",
inputs: []interface{}{ctx, cii},
expectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{cio, errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "CreateItemFromSnapshot",
Inputs: []interface{}{ctx, cii},
ExpectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{cio, errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "Progress",
inputs: []interface{}{pi},
expectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{po, errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "Progress",
Inputs: []interface{}{pi},
ExpectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{po, errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "DeleteSnapshot",
inputs: []interface{}{ctx, dsi},
expectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "DeleteSnapshot",
Inputs: []interface{}{ctx, dsi},
ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
},
)
}
@@ -26,6 +26,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vmware-tanzu/velero/internal/restartabletest"
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
providermocks "github.com/vmware-tanzu/velero/pkg/plugin/velero/mocks"
@@ -56,7 +57,7 @@ func TestRestartableGetObjectStore(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
p.Test(t)
defer p.AssertExpectations(t)
@@ -81,7 +82,7 @@ func TestRestartableGetObjectStore(t *testing.T) {
}
func TestRestartableObjectStoreReinitialize(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
p.Test(t)
defer p.AssertExpectations(t)
@@ -112,7 +113,7 @@ func TestRestartableObjectStoreReinitialize(t *testing.T) {
}
func TestRestartableObjectStoreGetDelegate(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
p.Test(t)
defer p.AssertExpectations(t)
@@ -141,7 +142,7 @@ func TestRestartableObjectStoreGetDelegate(t *testing.T) {
}
func TestRestartableObjectStoreInit(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
p.Test(t)
defer p.AssertExpectations(t)
@@ -185,7 +186,7 @@ func TestRestartableObjectStoreInit(t *testing.T) {
}
func TestRestartableObjectStoreDelegatedFunctions(t *testing.T) {
runRestartableDelegateTests(
restartabletest.RunRestartableDelegateTests(
t,
common.PluginKindObjectStore,
func(key process.KindAndName, p process.RestartableProcess) interface{} {
@@ -194,44 +195,44 @@ func TestRestartableObjectStoreDelegatedFunctions(t *testing.T) {
sharedPluginProcess: p,
}
},
func() mockable {
func() restartabletest.Mockable {
return new(providermocks.ObjectStore)
},
restartableDelegateTest{
function: "PutObject",
inputs: []interface{}{"bucket", "key", strings.NewReader("body")},
expectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "PutObject",
Inputs: []interface{}{"bucket", "key", strings.NewReader("body")},
ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "GetObject",
inputs: []interface{}{"bucket", "key"},
expectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{ioutil.NopCloser(strings.NewReader("object")), errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "GetObject",
Inputs: []interface{}{"bucket", "key"},
ExpectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{ioutil.NopCloser(strings.NewReader("object")), errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "ListCommonPrefixes",
inputs: []interface{}{"bucket", "prefix", "delimiter"},
expectedErrorOutputs: []interface{}{([]string)(nil), errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{[]string{"a", "b"}, errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "ListCommonPrefixes",
Inputs: []interface{}{"bucket", "prefix", "delimiter"},
ExpectedErrorOutputs: []interface{}{([]string)(nil), errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{[]string{"a", "b"}, errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "ListObjects",
inputs: []interface{}{"bucket", "prefix"},
expectedErrorOutputs: []interface{}{([]string)(nil), errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{[]string{"a", "b"}, errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "ListObjects",
Inputs: []interface{}{"bucket", "prefix"},
ExpectedErrorOutputs: []interface{}{([]string)(nil), errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{[]string{"a", "b"}, errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "DeleteObject",
inputs: []interface{}{"bucket", "key"},
expectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "DeleteObject",
Inputs: []interface{}{"bucket", "key"},
ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "CreateSignedURL",
inputs: []interface{}{"bucket", "key", 30 * time.Minute},
expectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{"signedURL", errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "CreateSignedURL",
Inputs: []interface{}{"bucket", "key", 30 * time.Minute},
ExpectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{"signedURL", errors.Errorf("delegate error")},
},
)
}
@@ -25,6 +25,7 @@ import (
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/vmware-tanzu/velero/internal/restartabletest"
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt/process"
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
providermocks "github.com/vmware-tanzu/velero/pkg/plugin/velero/mocks"
@@ -55,7 +56,7 @@ func TestRestartableGetVolumeSnapshotter(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
p.Test(t)
defer p.AssertExpectations(t)
@@ -80,7 +81,7 @@ func TestRestartableGetVolumeSnapshotter(t *testing.T) {
}
func TestRestartableVolumeSnapshotterReinitialize(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
p.Test(t)
defer p.AssertExpectations(t)
@@ -111,7 +112,7 @@ func TestRestartableVolumeSnapshotterReinitialize(t *testing.T) {
}
func TestRestartableVolumeSnapshotterGetDelegate(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
p.Test(t)
defer p.AssertExpectations(t)
@@ -140,7 +141,7 @@ func TestRestartableVolumeSnapshotterGetDelegate(t *testing.T) {
}
func TestRestartableVolumeSnapshotterInit(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
p.Test(t)
defer p.AssertExpectations(t)
@@ -196,7 +197,7 @@ func TestRestartableVolumeSnapshotterDelegatedFunctions(t *testing.T) {
},
}
runRestartableDelegateTests(
restartabletest.RunRestartableDelegateTests(
t,
common.PluginKindVolumeSnapshotter,
func(key process.KindAndName, p process.RestartableProcess) interface{} {
@@ -205,44 +206,44 @@ func TestRestartableVolumeSnapshotterDelegatedFunctions(t *testing.T) {
sharedPluginProcess: p,
}
},
func() mockable {
func() restartabletest.Mockable {
return new(providermocks.VolumeSnapshotter)
},
restartableDelegateTest{
function: "CreateVolumeFromSnapshot",
inputs: []interface{}{"snapshotID", "volumeID", "volumeAZ", to.Int64Ptr(10000)},
expectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{"volumeID", errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "CreateVolumeFromSnapshot",
Inputs: []interface{}{"snapshotID", "volumeID", "volumeAZ", to.Int64Ptr(10000)},
ExpectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{"volumeID", errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "GetVolumeID",
inputs: []interface{}{pv},
expectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{"volumeID", errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "GetVolumeID",
Inputs: []interface{}{pv},
ExpectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{"volumeID", errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "SetVolumeID",
inputs: []interface{}{pv, "volumeID"},
expectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{pvToReturn, errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "SetVolumeID",
Inputs: []interface{}{pv, "volumeID"},
ExpectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{pvToReturn, errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "GetVolumeInfo",
inputs: []interface{}{"volumeID", "volumeAZ"},
expectedErrorOutputs: []interface{}{"", (*int64)(nil), errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{"volumeType", to.Int64Ptr(10000), errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "GetVolumeInfo",
Inputs: []interface{}{"volumeID", "volumeAZ"},
ExpectedErrorOutputs: []interface{}{"", (*int64)(nil), errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{"volumeType", to.Int64Ptr(10000), errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "CreateSnapshot",
inputs: []interface{}{"volumeID", "volumeAZ", map[string]string{"a": "b"}},
expectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{"snapshotID", errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "CreateSnapshot",
Inputs: []interface{}{"volumeID", "volumeAZ", map[string]string{"a": "b"}},
ExpectedErrorOutputs: []interface{}{"", errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{"snapshotID", errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "DeleteSnapshot",
inputs: []interface{}{"snapshotID"},
expectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
restartabletest.RestartableDelegateTest{
Function: "DeleteSnapshot",
Inputs: []interface{}{"snapshotID"},
ExpectedErrorOutputs: []interface{}{errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{errors.Errorf("delegate error")},
},
)
}
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package clientmgmt
package v1
import (
"github.com/pkg/errors"
@@ -22,36 +22,56 @@ import (
"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"
riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
)
// AdaptedRestoreItemAction is a restore item action adapted to the v1 RestoreItemAction 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) riav1.RestoreItemAction
}
func AdaptedRestoreItemActions() []AdaptedRestoreItemAction {
return []AdaptedRestoreItemAction{
{
Kind: common.PluginKindRestoreItemAction,
GetRestartable: func(name string, restartableProcess process.RestartableProcess) riav1.RestoreItemAction {
return 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
// 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
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.PluginKindRestoreItemAction, Name: name},
sharedPluginProcess: sharedPluginProcess,
func NewRestartableRestoreItemAction(name string, sharedPluginProcess process.RestartableProcess) *RestartableRestoreItemAction {
r := &RestartableRestoreItemAction{
Key: process.KindAndName{Kind: common.PluginKindRestoreItemAction, Name: name},
SharedPluginProcess: sharedPluginProcess,
}
return r
}
// getRestoreItemAction returns the restore item action for this restartableRestoreItemAction. It does *not* restart the
// getRestoreItemAction returns the restore item action for this RestartableRestoreItemAction. It does *not* restart the
// plugin process.
func (r *restartableRestoreItemAction) getRestoreItemAction() (velero.RestoreItemAction, error) {
plugin, err := r.sharedPluginProcess.GetByKindAndName(r.key)
func (r *RestartableRestoreItemAction) getRestoreItemAction() (riav1.RestoreItemAction, error) {
plugin, err := r.SharedPluginProcess.GetByKindAndName(r.Key)
if err != nil {
return nil, err
}
restoreItemAction, ok := plugin.(velero.RestoreItemAction)
restoreItemAction, ok := plugin.(riav1.RestoreItemAction)
if !ok {
return nil, errors.Errorf("%T is not a RestoreItemAction!", plugin)
}
@@ -59,9 +79,9 @@ func (r *restartableRestoreItemAction) getRestoreItemAction() (velero.RestoreIte
return restoreItemAction, nil
}
// getDelegate restarts the plugin process (if needed) and returns the restore item action for this restartableRestoreItemAction.
func (r *restartableRestoreItemAction) getDelegate() (velero.RestoreItemAction, error) {
if err := r.sharedPluginProcess.ResetIfNeeded(); err != nil {
// getDelegate restarts the plugin process (if needed) and returns the restore item action for this RestartableRestoreItemAction.
func (r *RestartableRestoreItemAction) getDelegate() (riav1.RestoreItemAction, error) {
if err := r.SharedPluginProcess.ResetIfNeeded(); err != nil {
return nil, err
}
@@ -69,7 +89,7 @@ func (r *restartableRestoreItemAction) getDelegate() (velero.RestoreItemAction,
}
// AppliesTo restarts the plugin's process if needed, then delegates the call.
func (r *restartableRestoreItemAction) AppliesTo() (velero.ResourceSelector, error) {
func (r RestartableRestoreItemAction) AppliesTo() (velero.ResourceSelector, error) {
delegate, err := r.getDelegate()
if err != nil {
return velero.ResourceSelector{}, err
@@ -79,7 +99,7 @@ func (r *restartableRestoreItemAction) AppliesTo() (velero.ResourceSelector, err
}
// Execute restarts the plugin's process if needed, then delegates the call.
func (r *restartableRestoreItemAction) Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) {
func (r *RestartableRestoreItemAction) Execute(input *riav1.RestoreItemActionExecuteInput) (*riav1.RestoreItemActionExecuteOutput, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package clientmgmt
package v1
import (
"testing"
@@ -24,11 +24,13 @@ import (
"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"
"github.com/vmware-tanzu/velero/pkg/restore/mocks"
mocks "github.com/vmware-tanzu/velero/pkg/plugin/velero/mocks/restoreitemaction/v1"
riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
)
func TestRestartableGetRestoreItemAction(t *testing.T) {
@@ -50,13 +52,13 @@ func TestRestartableGetRestoreItemAction(t *testing.T) {
},
{
name: "happy path",
plugin: new(mocks.ItemAction),
plugin: new(mocks.RestoreItemAction),
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
defer p.AssertExpectations(t)
name := "pod"
@@ -77,7 +79,7 @@ func TestRestartableGetRestoreItemAction(t *testing.T) {
}
func TestRestartableRestoreItemActionGetDelegate(t *testing.T) {
p := new(mockRestartableProcess)
p := new(restartabletest.MockRestartableProcess)
defer p.AssertExpectations(t)
// Reset error
@@ -90,7 +92,7 @@ func TestRestartableRestoreItemActionGetDelegate(t *testing.T) {
// Happy path
p.On("ResetIfNeeded").Return(nil)
expected := new(mocks.ItemAction)
expected := new(mocks.RestoreItemAction)
key := process.KindAndName{Kind: common.PluginKindRestoreItemAction, Name: name}
p.On("GetByKindAndName", key).Return(expected, nil)
@@ -106,13 +108,13 @@ func TestRestartableRestoreItemActionDelegatedFunctions(t *testing.T) {
},
}
input := &velero.RestoreItemActionExecuteInput{
input := &riav1.RestoreItemActionExecuteInput{
Item: pv,
ItemFromBackup: pv,
Restore: new(v1.Restore),
}
output := &velero.RestoreItemActionExecuteOutput{
output := &riav1.RestoreItemActionExecuteOutput{
UpdatedItem: &unstructured.Unstructured{
Object: map[string]interface{}{
"color": "green",
@@ -120,29 +122,29 @@ func TestRestartableRestoreItemActionDelegatedFunctions(t *testing.T) {
},
}
runRestartableDelegateTests(
restartabletest.RunRestartableDelegateTests(
t,
common.PluginKindRestoreItemAction,
func(key process.KindAndName, p process.RestartableProcess) interface{} {
return &restartableRestoreItemAction{
key: key,
sharedPluginProcess: p,
return &RestartableRestoreItemAction{
Key: key,
SharedPluginProcess: p,
}
},
func() mockable {
return new(mocks.ItemAction)
func() restartabletest.Mockable {
return new(mocks.RestoreItemAction)
},
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: "AppliesTo",
Inputs: []interface{}{},
ExpectedErrorOutputs: []interface{}{velero.ResourceSelector{}, errors.Errorf("reset error")},
ExpectedDelegateOutputs: []interface{}{velero.ResourceSelector{IncludedNamespaces: []string{"a"}}, errors.Errorf("delegate error")},
},
restartableDelegateTest{
function: "Execute",
inputs: []interface{}{input},
expectedErrorOutputs: []interface{}{nil, errors.Errorf("reset error")},
expectedDelegateOutputs: []interface{}{output, 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")},
},
)
}
+4 -3
View File
@@ -26,6 +26,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
biav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v1"
isv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/item_snapshotter/v1"
riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
"github.com/vmware-tanzu/velero/pkg/util/collections"
)
@@ -108,7 +109,7 @@ func NewBackupItemActionResolver(actions []biav1.BackupItemAction) BackupItemAct
}
}
func NewRestoreItemActionResolver(actions []velero.RestoreItemAction) RestoreItemActionResolver {
func NewRestoreItemActionResolver(actions []riav1.RestoreItemAction) RestoreItemActionResolver {
return RestoreItemActionResolver{
actions: actions,
}
@@ -155,12 +156,12 @@ func (recv BackupItemActionResolver) ResolveActions(helper discovery.Helper, log
}
type RestoreItemResolvedAction struct {
velero.RestoreItemAction
riav1.RestoreItemAction
resolvedAction
}
type RestoreItemActionResolver struct {
actions []velero.RestoreItemAction
actions []riav1.RestoreItemAction
}
func (recv RestoreItemActionResolver) ResolveActions(helper discovery.Helper, log logrus.FieldLogger) ([]RestoreItemResolvedAction, error) {
@@ -28,9 +28,10 @@ import (
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
proto "github.com/vmware-tanzu/velero/pkg/plugin/generated"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
)
var _ velero.RestoreItemAction = &RestoreItemActionGRPCClient{}
var _ riav1.RestoreItemAction = &RestoreItemActionGRPCClient{}
// NewRestoreItemActionPlugin constructs a RestoreItemActionPlugin.
func NewRestoreItemActionPlugin(options ...common.PluginOption) *RestoreItemActionPlugin {
@@ -72,7 +73,7 @@ func (c *RestoreItemActionGRPCClient) AppliesTo() (velero.ResourceSelector, erro
}, nil
}
func (c *RestoreItemActionGRPCClient) Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) {
func (c *RestoreItemActionGRPCClient) Execute(input *riav1.RestoreItemActionExecuteInput) (*riav1.RestoreItemActionExecuteOutput, error) {
itemJSON, err := json.Marshal(input.Item.UnstructuredContent())
if err != nil {
return nil, errors.WithStack(err)
@@ -119,7 +120,7 @@ func (c *RestoreItemActionGRPCClient) Execute(input *velero.RestoreItemActionExe
additionalItems = append(additionalItems, newItem)
}
return &velero.RestoreItemActionExecuteOutput{
return &riav1.RestoreItemActionExecuteOutput{
UpdatedItem: &updatedItem,
AdditionalItems: additionalItems,
SkipRestore: res.SkipRestore,
@@ -27,6 +27,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
proto "github.com/vmware-tanzu/velero/pkg/plugin/generated"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
)
// RestoreItemActionGRPCServer implements the proto-generated RestoreItemActionServer interface, and accepts
@@ -35,13 +36,13 @@ type RestoreItemActionGRPCServer struct {
mux *common.ServerMux
}
func (s *RestoreItemActionGRPCServer) getImpl(name string) (velero.RestoreItemAction, error) {
func (s *RestoreItemActionGRPCServer) getImpl(name string) (riav1.RestoreItemAction, error) {
impl, err := s.mux.GetHandler(name)
if err != nil {
return nil, err
}
itemAction, ok := impl.(velero.RestoreItemAction)
itemAction, ok := impl.(riav1.RestoreItemAction)
if !ok {
return nil, errors.Errorf("%T is not a restore item action", impl)
}
@@ -107,7 +108,7 @@ func (s *RestoreItemActionGRPCServer) Execute(ctx context.Context, req *proto.Re
return nil, common.NewGRPCError(errors.WithStack(err))
}
executeOutput, err := impl.Execute(&velero.RestoreItemActionExecuteInput{
executeOutput, err := impl.Execute(&riav1.RestoreItemActionExecuteInput{
Item: &item,
ItemFromBackup: &itemFromBackup,
Restore: &restoreObj,
+68 -64
View File
@@ -1,13 +1,16 @@
// Code generated by mockery v2.1.0. DO NOT EDIT.
// Code generated by mockery v1.0.0. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
item_snapshotterv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/item_snapshotter/v1"
restoreitemactionv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
v1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v1"
velero "github.com/vmware-tanzu/velero/pkg/plugin/velero"
biav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v1"
isv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/item_snapshotter/v1"
)
// Manager is an autogenerated mock type for the Manager type
@@ -21,15 +24,15 @@ func (_m *Manager) CleanupClients() {
}
// GetBackupItemAction provides a mock function with given fields: name
func (_m *Manager) GetBackupItemAction(name string) (biav1.BackupItemAction, error) {
func (_m *Manager) GetBackupItemAction(name string) (v1.BackupItemAction, error) {
ret := _m.Called(name)
var r0 biav1.BackupItemAction
if rf, ok := ret.Get(0).(func(string) biav1.BackupItemAction); ok {
var r0 v1.BackupItemAction
if rf, ok := ret.Get(0).(func(string) v1.BackupItemAction); ok {
r0 = rf(name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(biav1.BackupItemAction)
r0 = ret.Get(0).(v1.BackupItemAction)
}
}
@@ -44,15 +47,15 @@ func (_m *Manager) GetBackupItemAction(name string) (biav1.BackupItemAction, err
}
// GetBackupItemActions provides a mock function with given fields:
func (_m *Manager) GetBackupItemActions() ([]biav1.BackupItemAction, error) {
func (_m *Manager) GetBackupItemActions() ([]v1.BackupItemAction, error) {
ret := _m.Called()
var r0 []biav1.BackupItemAction
if rf, ok := ret.Get(0).(func() []biav1.BackupItemAction); ok {
var r0 []v1.BackupItemAction
if rf, ok := ret.Get(0).(func() []v1.BackupItemAction); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]biav1.BackupItemAction)
r0 = ret.Get(0).([]v1.BackupItemAction)
}
}
@@ -112,6 +115,52 @@ func (_m *Manager) GetDeleteItemActions() ([]velero.DeleteItemAction, error) {
return r0, r1
}
// GetItemSnapshotter provides a mock function with given fields: name
func (_m *Manager) GetItemSnapshotter(name string) (item_snapshotterv1.ItemSnapshotter, error) {
ret := _m.Called(name)
var r0 item_snapshotterv1.ItemSnapshotter
if rf, ok := ret.Get(0).(func(string) item_snapshotterv1.ItemSnapshotter); ok {
r0 = rf(name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(item_snapshotterv1.ItemSnapshotter)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(name)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetItemSnapshotters provides a mock function with given fields:
func (_m *Manager) GetItemSnapshotters() ([]item_snapshotterv1.ItemSnapshotter, error) {
ret := _m.Called()
var r0 []item_snapshotterv1.ItemSnapshotter
if rf, ok := ret.Get(0).(func() []item_snapshotterv1.ItemSnapshotter); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]item_snapshotterv1.ItemSnapshotter)
}
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetObjectStore provides a mock function with given fields: name
func (_m *Manager) GetObjectStore(name string) (velero.ObjectStore, error) {
ret := _m.Called(name)
@@ -136,15 +185,15 @@ func (_m *Manager) GetObjectStore(name string) (velero.ObjectStore, error) {
}
// GetRestoreItemAction provides a mock function with given fields: name
func (_m *Manager) GetRestoreItemAction(name string) (velero.RestoreItemAction, error) {
func (_m *Manager) GetRestoreItemAction(name string) (restoreitemactionv1.RestoreItemAction, error) {
ret := _m.Called(name)
var r0 velero.RestoreItemAction
if rf, ok := ret.Get(0).(func(string) velero.RestoreItemAction); ok {
var r0 restoreitemactionv1.RestoreItemAction
if rf, ok := ret.Get(0).(func(string) restoreitemactionv1.RestoreItemAction); ok {
r0 = rf(name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(velero.RestoreItemAction)
r0 = ret.Get(0).(restoreitemactionv1.RestoreItemAction)
}
}
@@ -159,15 +208,15 @@ func (_m *Manager) GetRestoreItemAction(name string) (velero.RestoreItemAction,
}
// GetRestoreItemActions provides a mock function with given fields:
func (_m *Manager) GetRestoreItemActions() ([]velero.RestoreItemAction, error) {
func (_m *Manager) GetRestoreItemActions() ([]restoreitemactionv1.RestoreItemAction, error) {
ret := _m.Called()
var r0 []velero.RestoreItemAction
if rf, ok := ret.Get(0).(func() []velero.RestoreItemAction); ok {
var r0 []restoreitemactionv1.RestoreItemAction
if rf, ok := ret.Get(0).(func() []restoreitemactionv1.RestoreItemAction); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]velero.RestoreItemAction)
r0 = ret.Get(0).([]restoreitemactionv1.RestoreItemAction)
}
}
@@ -203,48 +252,3 @@ func (_m *Manager) GetVolumeSnapshotter(name string) (velero.VolumeSnapshotter,
return r0, r1
}
// GetItemSnapshotter provides a mock function with given fields: name
func (_m *Manager) GetItemSnapshotter(name string) (isv1.ItemSnapshotter, error) {
ret := _m.Called(name)
var r0 isv1.ItemSnapshotter
if rf, ok := ret.Get(0).(func(string) isv1.ItemSnapshotter); ok {
r0 = rf(name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(isv1.ItemSnapshotter)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(name)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetItemSnapshotters provides a mock function with given fields:
func (_m *Manager) GetItemSnapshotters() ([]isv1.ItemSnapshotter, error) {
ret := _m.Called()
var r0 []isv1.ItemSnapshotter
if rf, ok := ret.Get(0).(func() []isv1.ItemSnapshotter); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]isv1.ItemSnapshotter)
}
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
@@ -0,0 +1,73 @@
/*
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 v1
import (
mock "github.com/stretchr/testify/mock"
velero "github.com/vmware-tanzu/velero/pkg/plugin/velero"
riav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
)
// 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
}
// Execute provides a mock function with given fields: input
func (_m *RestoreItemAction) Execute(input *riav1.RestoreItemActionExecuteInput) (*riav1.RestoreItemActionExecuteOutput, error) {
ret := _m.Called(input)
var r0 *riav1.RestoreItemActionExecuteOutput
if rf, ok := ret.Get(0).(func(*riav1.RestoreItemActionExecuteInput) *riav1.RestoreItemActionExecuteOutput); ok {
r0 = rf(input)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*riav1.RestoreItemActionExecuteOutput)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(*riav1.RestoreItemActionExecuteInput) error); ok {
r1 = rf(input)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
@@ -1,5 +1,5 @@
/*
Copyright 2017, 2019 the Velero contributors.
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.
@@ -14,12 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package velero
package v1
import (
"k8s.io/apimachinery/pkg/runtime"
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.
@@ -27,7 +28,7 @@ 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() (ResourceSelector, error)
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 item (unmodified or modified)
@@ -56,7 +57,7 @@ type RestoreItemActionExecuteOutput struct {
// AdditionalItems is a list of additional related items that should
// be restored.
AdditionalItems []ResourceIdentifier
AdditionalItems []velero.ResourceIdentifier
// SkipRestore tells velero to stop executing further actions
// on this item, and skip the restore step. When this field's