-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create new ItemBlockAction (IBA) plugin type
Signed-off-by: Scott Seago <[email protected]>
- Loading branch information
Showing
21 changed files
with
1,851 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Created new ItemBlockAction (IBA) plugin type |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
pkg/plugin/clientmgmt/itemblockaction/v1/restartable_item_block_action.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/* | ||
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 v1 | ||
|
||
import ( | ||
"github.com/pkg/errors" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
|
||
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" | ||
"github.com/vmware-tanzu/velero/pkg/plugin/velero" | ||
ibav1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/itemblockaction/v1" | ||
) | ||
|
||
// AdaptedItemBlockAction is an ItemBlock action adapted to the v1 ItemBlockAction API | ||
type AdaptedItemBlockAction struct { | ||
Kind common.PluginKind | ||
|
||
// Get returns a restartable ItemBlockAction for the given name and process, wrapping if necessary | ||
GetRestartable func(name string, restartableProcess process.RestartableProcess) ibav1.ItemBlockAction | ||
} | ||
|
||
func AdaptedItemBlockActions() []AdaptedItemBlockAction { | ||
return []AdaptedItemBlockAction{ | ||
{ | ||
Kind: common.PluginKindItemBlockAction, | ||
GetRestartable: func(name string, restartableProcess process.RestartableProcess) ibav1.ItemBlockAction { | ||
return NewRestartableItemBlockAction(name, restartableProcess) | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
// RestartableItemBlockAction is an ItemBlock 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 restartableItemBlockAction 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 RestartableItemBlockAction struct { | ||
Key process.KindAndName | ||
SharedPluginProcess process.RestartableProcess | ||
} | ||
|
||
// NewRestartableItemBlockAction returns a new RestartableItemBlockAction. | ||
func NewRestartableItemBlockAction(name string, sharedPluginProcess process.RestartableProcess) *RestartableItemBlockAction { | ||
r := &RestartableItemBlockAction{ | ||
Key: process.KindAndName{Kind: common.PluginKindItemBlockAction, Name: name}, | ||
SharedPluginProcess: sharedPluginProcess, | ||
} | ||
return r | ||
} | ||
|
||
// getItemBlockAction returns the ItemBlock action for this restartableItemBlockAction. It does *not* restart the | ||
// plugin process. | ||
func (r *RestartableItemBlockAction) getItemBlockAction() (ibav1.ItemBlockAction, error) { | ||
plugin, err := r.SharedPluginProcess.GetByKindAndName(r.Key) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
itemBlockAction, ok := plugin.(ibav1.ItemBlockAction) | ||
if !ok { | ||
return nil, errors.Errorf("plugin %T is not an ItemBlockAction", plugin) | ||
} | ||
|
||
return itemBlockAction, nil | ||
} | ||
|
||
// getDelegate restarts the plugin process (if needed) and returns the ItemBlock action for this restartableItemBlockAction. | ||
func (r *RestartableItemBlockAction) getDelegate() (ibav1.ItemBlockAction, error) { | ||
if err := r.SharedPluginProcess.ResetIfNeeded(); err != nil { | ||
return nil, err | ||
} | ||
|
||
return r.getItemBlockAction() | ||
} | ||
|
||
// Name returns the plugin's name. | ||
func (r *RestartableItemBlockAction) Name() string { | ||
return r.Key.Name | ||
} | ||
|
||
// AppliesTo restarts the plugin's process if needed, then delegates the call. | ||
func (r *RestartableItemBlockAction) AppliesTo() (velero.ResourceSelector, error) { | ||
delegate, err := r.getDelegate() | ||
if err != nil { | ||
return velero.ResourceSelector{}, err | ||
} | ||
|
||
return delegate.AppliesTo() | ||
} | ||
|
||
// GetRelatedItems restarts the plugin's process if needed, then delegates the call. | ||
func (r *RestartableItemBlockAction) GetRelatedItems(item runtime.Unstructured, backup *api.Backup) ([]velero.ResourceIdentifier, error) { | ||
delegate, err := r.getDelegate() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return delegate.GetRelatedItems(item, backup) | ||
} |
144 changes: 144 additions & 0 deletions
144
pkg/plugin/clientmgmt/itemblockaction/v1/restartable_item_block_action_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
/* | ||
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 v1 | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/pkg/errors" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"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" | ||
"github.com/vmware-tanzu/velero/pkg/plugin/velero" | ||
mocks "github.com/vmware-tanzu/velero/pkg/plugin/velero/mocks/itemblockaction/v1" | ||
) | ||
|
||
func TestRestartableGetItemBlockAction(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: "plugin int is not an ItemBlockAction", | ||
}, | ||
{ | ||
name: "happy path", | ||
plugin: new(mocks.ItemBlockAction), | ||
}, | ||
} | ||
|
||
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.PluginKindItemBlockAction, Name: name} | ||
p.On("GetByKindAndName", key).Return(tc.plugin, tc.getError) | ||
|
||
r := NewRestartableItemBlockAction(name, p) | ||
a, err := r.getItemBlockAction() | ||
if tc.expectedError != "" { | ||
assert.EqualError(t, err, tc.expectedError) | ||
return | ||
} | ||
require.NoError(t, err) | ||
|
||
assert.Equal(t, tc.plugin, a) | ||
}) | ||
} | ||
} | ||
|
||
func TestRestartableItemBlockActionGetDelegate(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 := NewRestartableItemBlockAction(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.ItemBlockAction) | ||
key := process.KindAndName{Kind: common.PluginKindItemBlockAction, Name: name} | ||
p.On("GetByKindAndName", key).Return(expected, nil) | ||
|
||
a, err = r.getDelegate() | ||
assert.NoError(t, err) | ||
assert.Equal(t, expected, a) | ||
} | ||
|
||
func TestRestartableItemBlockActionDelegatedFunctions(t *testing.T) { | ||
b := new(v1.Backup) | ||
|
||
pv := &unstructured.Unstructured{ | ||
Object: map[string]interface{}{ | ||
"color": "blue", | ||
}, | ||
} | ||
|
||
relatedItems := []velero.ResourceIdentifier{ | ||
{ | ||
GroupResource: schema.GroupResource{Group: "velero.io", Resource: "backups"}, | ||
}, | ||
} | ||
|
||
restartabletest.RunRestartableDelegateTests( | ||
t, | ||
common.PluginKindItemBlockAction, | ||
func(key process.KindAndName, p process.RestartableProcess) interface{} { | ||
return &RestartableItemBlockAction{ | ||
Key: key, | ||
SharedPluginProcess: p, | ||
} | ||
}, | ||
func() restartabletest.Mockable { | ||
return new(mocks.ItemBlockAction) | ||
}, | ||
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: "GetRelatedItems", | ||
Inputs: []interface{}{pv, b}, | ||
ExpectedErrorOutputs: []interface{}{([]velero.ResourceIdentifier)(nil), errors.Errorf("reset error")}, | ||
ExpectedDelegateOutputs: []interface{}{relatedItems, errors.Errorf("delegate error")}, | ||
}, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.