Compare commits

...

7 Commits

Author SHA1 Message Date
Hoang, Phuong
80828f727e Add missing files 2021-11-07 12:22:01 -05:00
Hoang, Phuong
de360a4b31 Simplify implementation. 2021-11-07 12:22:01 -05:00
Hoang, Phuong
3cbd7976bd Simplify implementation 2021-11-07 12:22:01 -05:00
Hoang, Phuong
79d1616ecb Reformat and add version 2 to mock manager. 2021-11-07 12:22:01 -05:00
Hoang, Phuong
f40f0d4e5b Change to new implementation 2021-11-07 12:22:01 -05:00
Hoang, Phuong
5c707d20c1 Refactor code to make it easier to add future version. 2021-11-07 12:22:01 -05:00
Hoang, Phuong
b059030666 Initial implementation of plugin version v2: Adding context object 2021-11-07 12:22:01 -05:00
51 changed files with 1993 additions and 303 deletions

View File

@@ -29,6 +29,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/archive"
"github.com/vmware-tanzu/velero/pkg/discovery"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
deleteactionitemv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/deleteitemaction/v2"
"github.com/vmware-tanzu/velero/pkg/util/collections"
"github.com/vmware-tanzu/velero/pkg/util/filesystem"
)
@@ -37,7 +38,7 @@ import (
type Context struct {
Backup *velerov1api.Backup
BackupReader io.Reader
Actions []velero.DeleteItemAction
Actions []deleteactionitemv2.DeleteItemAction
Filesystem filesystem.Interface
Log logrus.FieldLogger
DiscoveryHelper discovery.Helper
@@ -163,7 +164,7 @@ func (ctx *Context) getApplicableActions(groupResource schema.GroupResource, nam
// resolvedActions are DeleteItemActions decorated with resource/namespace include/exclude collections, as well as label selectors for easy comparison.
type resolvedAction struct {
velero.DeleteItemAction
deleteactionitemv2.DeleteItemAction
resourceIncludesExcludes *collections.IncludesExcludes
namespaceIncludesExcludes *collections.IncludesExcludes
@@ -171,7 +172,7 @@ type resolvedAction struct {
}
// resolveActions resolves the AppliesTo ResourceSelectors of DeleteItemActions plugins against the Kubernetes discovery API for fully-qualified names.
func resolveActions(actions []velero.DeleteItemAction, helper discovery.Helper) ([]resolvedAction, error) {
func resolveActions(actions []deleteactionitemv2.DeleteItemAction, helper discovery.Helper) ([]resolvedAction, error) {
var resolved []resolvedAction
for _, action := range actions {

View File

@@ -44,7 +44,8 @@ import (
"github.com/vmware-tanzu/velero/pkg/discovery"
velerov1client "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1"
"github.com/vmware-tanzu/velero/pkg/kuberesource"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
backupitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v2"
volumesnapshotterv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v2"
"github.com/vmware-tanzu/velero/pkg/podexec"
"github.com/vmware-tanzu/velero/pkg/restic"
"github.com/vmware-tanzu/velero/pkg/util/collections"
@@ -61,7 +62,8 @@ const BackupFormatVersion = "1.1.0"
type Backupper interface {
// Backup takes a backup using the specification in the velerov1api.Backup and writes backup and log data
// to the given writers.
Backup(logger logrus.FieldLogger, backup *Request, backupFile io.Writer, actions []velero.BackupItemAction, volumeSnapshotterGetter VolumeSnapshotterGetter) error
Backup(logger logrus.FieldLogger, backup *Request, backupFile io.Writer,
actions []backupitemactionv2.BackupItemAction, volumeSnapshotterGetter VolumeSnapshotterGetter) error
}
// kubernetesBackupper implements Backupper.
@@ -77,7 +79,7 @@ type kubernetesBackupper struct {
}
type resolvedAction struct {
velero.BackupItemAction
backupitemactionv2.BackupItemAction
resourceIncludesExcludes *collections.IncludesExcludes
namespaceIncludesExcludes *collections.IncludesExcludes
@@ -121,7 +123,7 @@ func NewKubernetesBackupper(
}, nil
}
func resolveActions(actions []velero.BackupItemAction, helper discovery.Helper) ([]resolvedAction, error) {
func resolveActions(actions []backupitemactionv2.BackupItemAction, helper discovery.Helper) ([]resolvedAction, error) {
var resolved []resolvedAction
for _, action := range actions {
@@ -197,7 +199,7 @@ func getResourceHook(hookSpec velerov1api.BackupResourceHookSpec, discoveryHelpe
}
type VolumeSnapshotterGetter interface {
GetVolumeSnapshotter(name string) (velero.VolumeSnapshotter, error)
GetVolumeSnapshotter(name string) (volumesnapshotterv2.VolumeSnapshotter, error)
}
// Backup backs up the items specified in the Backup, placing them in a gzip-compressed tar file
@@ -205,7 +207,8 @@ type VolumeSnapshotterGetter interface {
// a complete backup failure is returned. Errors that constitute partial failures (i.e. failures to
// back up individual resources that don't prevent the backup from continuing to be processed) are logged
// to the backup log.
func (kb *kubernetesBackupper) Backup(log logrus.FieldLogger, backupRequest *Request, backupFile io.Writer, actions []velero.BackupItemAction, volumeSnapshotterGetter VolumeSnapshotterGetter) error {
func (kb *kubernetesBackupper) Backup(log logrus.FieldLogger, backupRequest *Request, backupFile io.Writer,
actions []backupitemactionv2.BackupItemAction, volumeSnapshotterGetter VolumeSnapshotterGetter) error {
gzippedData := gzip.NewWriter(backupFile)
defer gzippedData.Close()

View File

@@ -47,6 +47,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/discovery"
"github.com/vmware-tanzu/velero/pkg/kuberesource"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
backupitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v2"
"github.com/vmware-tanzu/velero/pkg/restic"
"github.com/vmware-tanzu/velero/pkg/test"
testutil "github.com/vmware-tanzu/velero/pkg/test"
@@ -1331,7 +1332,7 @@ func TestBackupActionsRunForCorrectItems(t *testing.T) {
h.addItems(t, resource)
}
actions := []velero.BackupItemAction{}
actions := []backupitemactionv2.BackupItemAction{}
for action := range tc.actions {
actions = append(actions, action)
}
@@ -1357,7 +1358,7 @@ func TestBackupWithInvalidActions(t *testing.T) {
name string
backup *velerov1.Backup
apiResources []*test.APIResource
actions []velero.BackupItemAction
actions []backupitemactionv2.BackupItemAction
}{
{
name: "action with invalid label selector results in an error",
@@ -1373,7 +1374,7 @@ func TestBackupWithInvalidActions(t *testing.T) {
builder.ForPersistentVolume("baz").Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
new(recordResourcesAction).ForLabelSelector("=invalid-selector"),
},
},
@@ -1391,7 +1392,7 @@ func TestBackupWithInvalidActions(t *testing.T) {
builder.ForPersistentVolume("baz").Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
&appliesToErrorAction{},
},
},
@@ -1453,7 +1454,7 @@ func TestBackupActionModifications(t *testing.T) {
name string
backup *velerov1.Backup
apiResources []*test.APIResource
actions []velero.BackupItemAction
actions []backupitemactionv2.BackupItemAction
want map[string]unstructuredObject
}{
{
@@ -1464,7 +1465,7 @@ func TestBackupActionModifications(t *testing.T) {
builder.ForPod("ns-1", "pod-1").Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
modifyingActionGetter(func(item *unstructured.Unstructured) {
item.SetLabels(map[string]string{"updated": "true"})
}),
@@ -1481,7 +1482,7 @@ func TestBackupActionModifications(t *testing.T) {
builder.ForPod("ns-1", "pod-1").ObjectMeta(builder.WithLabels("should-be-removed", "true")).Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
modifyingActionGetter(func(item *unstructured.Unstructured) {
item.SetLabels(nil)
}),
@@ -1498,7 +1499,7 @@ func TestBackupActionModifications(t *testing.T) {
builder.ForPod("ns-1", "pod-1").Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
modifyingActionGetter(func(item *unstructured.Unstructured) {
item.Object["spec"].(map[string]interface{})["nodeName"] = "foo"
}),
@@ -1516,7 +1517,7 @@ func TestBackupActionModifications(t *testing.T) {
builder.ForPod("ns-1", "pod-1").Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
modifyingActionGetter(func(item *unstructured.Unstructured) {
item.SetName(item.GetName() + "-updated")
item.SetNamespace(item.GetNamespace() + "-updated")
@@ -1557,7 +1558,7 @@ func TestBackupActionAdditionalItems(t *testing.T) {
name string
backup *velerov1.Backup
apiResources []*test.APIResource
actions []velero.BackupItemAction
actions []backupitemactionv2.BackupItemAction
want []string
}{
{
@@ -1570,7 +1571,7 @@ func TestBackupActionAdditionalItems(t *testing.T) {
builder.ForPod("ns-3", "pod-3").Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
&pluggableAction{
selector: velero.ResourceSelector{IncludedNamespaces: []string{"ns-1"}},
executeFunc: func(item runtime.Unstructured, backup *velerov1.Backup) (runtime.Unstructured, []velero.ResourceIdentifier, error) {
@@ -1602,7 +1603,7 @@ func TestBackupActionAdditionalItems(t *testing.T) {
builder.ForPod("ns-3", "pod-3").Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
&pluggableAction{
executeFunc: func(item runtime.Unstructured, backup *velerov1.Backup) (runtime.Unstructured, []velero.ResourceIdentifier, error) {
additionalItems := []velero.ResourceIdentifier{
@@ -1632,7 +1633,7 @@ func TestBackupActionAdditionalItems(t *testing.T) {
builder.ForPersistentVolume("pv-2").Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
&pluggableAction{
executeFunc: func(item runtime.Unstructured, backup *velerov1.Backup) (runtime.Unstructured, []velero.ResourceIdentifier, error) {
additionalItems := []velero.ResourceIdentifier{
@@ -1665,7 +1666,7 @@ func TestBackupActionAdditionalItems(t *testing.T) {
builder.ForPersistentVolume("pv-2").Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
&pluggableAction{
executeFunc: func(item runtime.Unstructured, backup *velerov1.Backup) (runtime.Unstructured, []velero.ResourceIdentifier, error) {
additionalItems := []velero.ResourceIdentifier{
@@ -1695,7 +1696,7 @@ func TestBackupActionAdditionalItems(t *testing.T) {
builder.ForPersistentVolume("pv-2").Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
&pluggableAction{
executeFunc: func(item runtime.Unstructured, backup *velerov1.Backup) (runtime.Unstructured, []velero.ResourceIdentifier, error) {
additionalItems := []velero.ResourceIdentifier{
@@ -1726,7 +1727,7 @@ func TestBackupActionAdditionalItems(t *testing.T) {
builder.ForPersistentVolume("pv-2").Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
&pluggableAction{
executeFunc: func(item runtime.Unstructured, backup *velerov1.Backup) (runtime.Unstructured, []velero.ResourceIdentifier, error) {
additionalItems := []velero.ResourceIdentifier{
@@ -1756,7 +1757,7 @@ func TestBackupActionAdditionalItems(t *testing.T) {
builder.ForPod("ns-3", "pod-3").Result(),
),
},
actions: []velero.BackupItemAction{
actions: []backupitemactionv2.BackupItemAction{
&pluggableAction{
selector: velero.ResourceSelector{IncludedNamespaces: []string{"ns-1"}},
executeFunc: func(item runtime.Unstructured, backup *velerov1.Backup) (runtime.Unstructured, []velero.ResourceIdentifier, error) {

View File

@@ -39,7 +39,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/discovery"
"github.com/vmware-tanzu/velero/pkg/kuberesource"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
volumesnapshotterv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v2"
"github.com/vmware-tanzu/velero/pkg/restic"
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
"github.com/vmware-tanzu/velero/pkg/volume"
@@ -56,7 +56,7 @@ type itemBackupper struct {
volumeSnapshotterGetter VolumeSnapshotterGetter
itemHookHandler hook.ItemHookHandler
snapshotLocationVolumeSnapshotters map[string]velero.VolumeSnapshotter
snapshotLocationVolumeSnapshotters map[string]volumesnapshotterv2.VolumeSnapshotter
}
// backupItem backs up an individual item to tarWriter. The item may be excluded based on the
@@ -367,7 +367,8 @@ func (ib *itemBackupper) executeActions(
// volumeSnapshotter instantiates and initializes a VolumeSnapshotter given a VolumeSnapshotLocation,
// or returns an existing one if one's already been initialized for the location.
func (ib *itemBackupper) volumeSnapshotter(snapshotLocation *velerov1api.VolumeSnapshotLocation) (velero.VolumeSnapshotter, error) {
func (ib *itemBackupper) volumeSnapshotter(snapshotLocation *velerov1api.VolumeSnapshotLocation) (
volumesnapshotterv2.VolumeSnapshotter, error) {
if bs, ok := ib.snapshotLocationVolumeSnapshotters[snapshotLocation.Name]; ok {
return bs, nil
}
@@ -382,7 +383,7 @@ func (ib *itemBackupper) volumeSnapshotter(snapshotLocation *velerov1api.VolumeS
}
if ib.snapshotLocationVolumeSnapshotters == nil {
ib.snapshotLocationVolumeSnapshotters = make(map[string]velero.VolumeSnapshotter)
ib.snapshotLocationVolumeSnapshotters = make(map[string]volumesnapshotterv2.VolumeSnapshotter)
}
ib.snapshotLocationVolumeSnapshotters[snapshotLocation.Name] = bs
@@ -438,7 +439,7 @@ func (ib *itemBackupper) takePVSnapshot(obj runtime.Unstructured, log logrus.Fie
var (
volumeID, location string
volumeSnapshotter velero.VolumeSnapshotter
volumeSnapshotter volumesnapshotterv2.VolumeSnapshotter
)
for _, snapshotLocation := range ib.backupRequest.SnapshotLocations {

View File

@@ -48,7 +48,7 @@ import (
persistencemocks "github.com/vmware-tanzu/velero/pkg/persistence/mocks"
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt"
pluginmocks "github.com/vmware-tanzu/velero/pkg/plugin/mocks"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
backupitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v2"
velerotest "github.com/vmware-tanzu/velero/pkg/test"
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
"github.com/vmware-tanzu/velero/pkg/util/logging"
@@ -58,7 +58,7 @@ type fakeBackupper struct {
mock.Mock
}
func (b *fakeBackupper) Backup(logger logrus.FieldLogger, backup *pkgbackup.Request, backupFile io.Writer, actions []velero.BackupItemAction, volumeSnapshotterGetter pkgbackup.VolumeSnapshotterGetter) error {
func (b *fakeBackupper) Backup(logger logrus.FieldLogger, backup *pkgbackup.Request, backupFile io.Writer, actions []backupitemactionv2.BackupItemAction, volumeSnapshotterGetter pkgbackup.VolumeSnapshotterGetter) error {
args := b.Called(logger, backup, backupFile, actions, volumeSnapshotterGetter)
return args.Error(0)
}
@@ -825,7 +825,7 @@ func TestProcessBackupCompletions(t *testing.T) {
pluginManager.On("GetBackupItemActions").Return(nil, nil)
pluginManager.On("CleanupClients").Return(nil)
backupper.On("Backup", mock.Anything, mock.Anything, mock.Anything, []velero.BackupItemAction(nil), pluginManager).Return(nil)
backupper.On("Backup", mock.Anything, mock.Anything, mock.Anything, []backupitemactionv2.BackupItemAction(nil), pluginManager).Return(nil)
backupStore.On("BackupExists", test.backupLocation.Spec.StorageType.ObjectStorage.Bucket, test.backup.Name).Return(test.backupExists, test.existenceCheckError)
// Ensure we have a CompletionTimestamp when uploading and that the backup name matches the backup in the object store.

View File

@@ -46,7 +46,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/metrics"
"github.com/vmware-tanzu/velero/pkg/persistence"
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
volumesnapshotter "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v2"
"github.com/vmware-tanzu/velero/pkg/restic"
"github.com/vmware-tanzu/velero/pkg/util/filesystem"
"github.com/vmware-tanzu/velero/pkg/util/kube"
@@ -333,7 +333,7 @@ func (c *backupDeletionController) processRequest(req *velerov1api.DeleteBackupR
if snapshots, err := backupStore.GetBackupVolumeSnapshots(backup.Name); err != nil {
errs = append(errs, errors.Wrap(err, "error getting backup's volume snapshots").Error())
} else {
volumeSnapshotters := make(map[string]velero.VolumeSnapshotter)
volumeSnapshotters := make(map[string]volumesnapshotter.VolumeSnapshotter)
for _, snapshot := range snapshots {
log.WithField("providerSnapshotID", snapshot.Status.ProviderSnapshotID).Info("Removing snapshot associated with backup")
@@ -433,7 +433,7 @@ func volumeSnapshotterForSnapshotLocation(
namespace, snapshotLocationName string,
snapshotLocationLister velerov1listers.VolumeSnapshotLocationLister,
pluginManager clientmgmt.Manager,
) (velero.VolumeSnapshotter, error) {
) (volumesnapshotter.VolumeSnapshotter, error) {
snapshotLocation, err := snapshotLocationLister.VolumeSnapshotLocations(namespace).Get(snapshotLocationName)
if err != nil {
return nil, errors.Wrapf(err, "error getting volume snapshot location %s", snapshotLocationName)

View File

@@ -45,7 +45,7 @@ import (
persistencemocks "github.com/vmware-tanzu/velero/pkg/persistence/mocks"
"github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt"
pluginmocks "github.com/vmware-tanzu/velero/pkg/plugin/mocks"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
deleteitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/deleteitemaction/v2"
"github.com/vmware-tanzu/velero/pkg/plugin/velero/mocks"
velerotest "github.com/vmware-tanzu/velero/pkg/test"
"github.com/vmware-tanzu/velero/pkg/volume"
@@ -802,7 +802,7 @@ func TestBackupDeletionControllerProcessRequest(t *testing.T) {
pluginManager := &pluginmocks.Manager{}
pluginManager.On("GetVolumeSnapshotter", "provider-1").Return(td.volumeSnapshotter, nil)
pluginManager.On("GetDeleteItemActions").Return([]velero.DeleteItemAction{}, nil)
pluginManager.On("GetDeleteItemActions").Return([]deleteitemactionv2.DeleteItemAction{}, nil)
pluginManager.On("CleanupClients")
td.controller.newPluginManager = func(logrus.FieldLogger) clientmgmt.Manager { return pluginManager }
@@ -932,7 +932,7 @@ func TestBackupDeletionControllerProcessRequest(t *testing.T) {
pluginManager := &pluginmocks.Manager{}
pluginManager.On("GetVolumeSnapshotter", "provider-1").Return(td.volumeSnapshotter, nil)
pluginManager.On("GetDeleteItemActions").Return([]velero.DeleteItemAction{new(mocks.DeleteItemAction)}, nil)
pluginManager.On("GetDeleteItemActions").Return([]deleteitemactionv2.DeleteItemAction{new(mocks.DeleteItemAction)}, nil)
pluginManager.On("CleanupClients")
td.controller.newPluginManager = func(logrus.FieldLogger) clientmgmt.Manager { return pluginManager }

View File

@@ -33,7 +33,7 @@ import (
"github.com/vmware-tanzu/velero/internal/credentials"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
objectstorev2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/objectstore/v2"
"github.com/vmware-tanzu/velero/pkg/volume"
)
@@ -80,16 +80,16 @@ type BackupStore interface {
const DownloadURLTTL = 10 * time.Minute
type objectBackupStore struct {
objectStore velero.ObjectStore
objectStore objectstorev2.ObjectStore
bucket string
layout *ObjectStoreLayout
logger logrus.FieldLogger
}
// ObjectStoreGetter is a type that can get a velero.ObjectStore
// ObjectStoreGetter is a type that can get a objectstorev2.ObjectStore
// from a provider name.
type ObjectStoreGetter interface {
GetObjectStore(provider string) (velero.ObjectStore, error)
GetObjectStore(provider string) (objectstorev2.ObjectStore, error)
}
// ObjectBackupStoreGetter is a type that can get a velero.BackupStore for a
@@ -326,7 +326,7 @@ func (s *objectBackupStore) GetBackupVolumeSnapshots(name string) ([]*volume.Sna
// tryGet returns the object with the given key if it exists, nil if it does not exist,
// or an error if it was unable to check existence or get the object.
func tryGet(objectStore velero.ObjectStore, bucket, key string) (io.ReadCloser, error) {
func tryGet(objectStore objectstorev2.ObjectStore, bucket, key string) (io.ReadCloser, error) {
exists, err := objectStore.ObjectExists(bucket, key)
if err != nil {
return nil, errors.WithStack(err)
@@ -494,7 +494,7 @@ func seekToBeginning(r io.Reader) error {
return err
}
func seekAndPutObject(objectStore velero.ObjectStore, bucket, key string, file io.Reader) error {
func seekAndPutObject(objectStore objectstorev2.ObjectStore, bucket, key string, file io.Reader) error {
if file == nil {
return nil
}

View File

@@ -36,8 +36,8 @@ import (
"github.com/vmware-tanzu/velero/internal/credentials"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/builder"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
providermocks "github.com/vmware-tanzu/velero/pkg/plugin/velero/mocks"
objectstorev2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/objectstore/v2"
velerotest "github.com/vmware-tanzu/velero/pkg/test"
"github.com/vmware-tanzu/velero/pkg/util/encode"
"github.com/vmware-tanzu/velero/pkg/volume"
@@ -595,9 +595,9 @@ func TestGetDownloadURL(t *testing.T) {
}
}
type objectStoreGetter map[string]velero.ObjectStore
type objectStoreGetter map[string]objectstorev2.ObjectStore
func (osg objectStoreGetter) GetObjectStore(provider string) (velero.ObjectStore, error) {
func (osg objectStoreGetter) GetObjectStore(provider string) (objectstorev2.ObjectStore, error) {
res, ok := osg[provider]
if !ok {
return nil, errors.New("object store not found")

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 the Velero contributors.
Copyright 2021 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.
@@ -73,6 +73,12 @@ func (b *clientBuilder) clientConfig() *hcplugin.ClientConfig {
string(framework.PluginKindPluginLister): &framework.PluginListerPlugin{},
string(framework.PluginKindRestoreItemAction): framework.NewRestoreItemActionPlugin(framework.ClientLogger(b.clientLogger)),
string(framework.PluginKindDeleteItemAction): framework.NewDeleteItemActionPlugin(framework.ClientLogger(b.clientLogger)),
// Version 2
string(framework.PluginKindBackupItemActionV2): framework.NewBackupItemActionPlugin(framework.ClientLogger(b.clientLogger)),
string(framework.PluginKindVolumeSnapshotterV2): framework.NewVolumeSnapshotterPlugin(framework.ClientLogger(b.clientLogger)),
string(framework.PluginKindObjectStoreV2): framework.NewObjectStorePlugin(framework.ClientLogger(b.clientLogger)),
string(framework.PluginKindRestoreItemActionV2): framework.NewRestoreItemActionPlugin(framework.ClientLogger(b.clientLogger)),
string(framework.PluginKindDeleteItemActionV2): framework.NewDeleteItemActionPlugin(framework.ClientLogger(b.clientLogger)),
},
Logger: b.pluginLogger,
Cmd: exec.Command(b.commandName, b.commandArgs...),

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 the Velero contributors.
Copyright 2021 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.
@@ -17,40 +17,46 @@ limitations under the License.
package clientmgmt
import (
"errors"
"fmt"
"strings"
"sync"
"github.com/sirupsen/logrus"
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
backupitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v2"
deleteitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/deleteitemaction/v2"
objectstorev2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/objectstore/v2"
restoreitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2"
volumesnapshotterv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v2"
)
// Manager manages the lifecycles of plugins.
type Manager interface {
// GetObjectStore returns the ObjectStore plugin for name.
GetObjectStore(name string) (velero.ObjectStore, error)
GetObjectStore(name string) (objectstorev2.ObjectStore, error)
// GetVolumeSnapshotter returns the VolumeSnapshotter plugin for name.
GetVolumeSnapshotter(name string) (velero.VolumeSnapshotter, error)
GetVolumeSnapshotter(name string) (volumesnapshotterv2.VolumeSnapshotter, error)
// GetBackupItemActions returns all backup item action plugins.
GetBackupItemActions() ([]velero.BackupItemAction, error)
GetBackupItemActions() ([]backupitemactionv2.BackupItemAction, error)
// GetBackupItemAction returns the backup item action plugin for name.
GetBackupItemAction(name string) (velero.BackupItemAction, error)
GetBackupItemAction(name string) (backupitemactionv2.BackupItemAction, error)
// GetRestoreItemActions returns all restore item action plugins.
GetRestoreItemActions() ([]velero.RestoreItemAction, error)
GetRestoreItemActions() ([]restoreitemactionv2.RestoreItemAction, error)
// GetRestoreItemAction returns the restore item action plugin for name.
GetRestoreItemAction(name string) (velero.RestoreItemAction, error)
GetRestoreItemAction(name string) (restoreitemactionv2.RestoreItemAction, error)
// GetDeleteItemActions returns all delete item action plugins.
GetDeleteItemActions() ([]velero.DeleteItemAction, error)
GetDeleteItemActions() ([]deleteitemactionv2.DeleteItemAction, error)
// GetDeleteItemAction returns the delete item action plugin for name.
GetDeleteItemAction(name string) (velero.DeleteItemAction, error)
GetDeleteItemAction(name string) (deleteitemactionv2.DeleteItemAction, error)
// CleanupClients terminates all of the Manager's running plugin processes.
CleanupClients()
@@ -129,39 +135,82 @@ func (m *manager) getRestartableProcess(kind framework.PluginKind, name string)
return restartableProcess, nil
}
// GetObjectStore returns a restartableObjectStore for name.
func (m *manager) GetObjectStore(name string) (velero.ObjectStore, error) {
name = sanitizeName(name)
type RestartableObjectStore struct {
kind framework.PluginKind
// Get returns a restartable ObjectStore for the given name and process, wrapping if necessary
Get func(name string, restartableProcess RestartableProcess) objectstorev2.ObjectStore
}
restartableProcess, err := m.getRestartableProcess(framework.PluginKindObjectStore, name)
if err != nil {
return nil, err
func (m *manager) restartableObjectStores() []RestartableObjectStore {
return []RestartableObjectStore{
{
kind: framework.PluginKindObjectStoreV2,
Get: newRestartableObjectStoreV2,
},
{
kind: framework.PluginKindObjectStore,
Get: newAdaptedV1ObjectStore, // Adapt v1 plugin to v2
},
}
}
r := newRestartableObjectStore(name, restartableProcess)
// GetObjectStore returns a restartableObjectStore for name.
func (m *manager) GetObjectStore(name string) (objectstorev2.ObjectStore, error) {
name = sanitizeName(name)
for _, restartableObjStore := range m.restartableObjectStores() {
restartableProcess, err := m.getRestartableProcess(restartableObjStore.kind, name)
if err != nil {
// Check if plugin was not found
if errors.Is(err, &pluginNotFoundError{}) {
continue
}
return nil, err
}
return restartableObjStore.Get(name, restartableProcess), nil
}
return nil, fmt.Errorf("unable to get valid ObjectStore for %q", name)
}
return r, nil
type RestartableVolumeSnapshotter struct {
kind framework.PluginKind
// Get returns a restartable VolumeSnapshotter for the given name and process, wrapping if necessary
Get func(name string, restartableProcess RestartableProcess) volumesnapshotterv2.VolumeSnapshotter
}
func (m *manager) restartableVolumeSnapshotters() []RestartableVolumeSnapshotter {
return []RestartableVolumeSnapshotter{
{
kind: framework.PluginKindVolumeSnapshotterV2,
Get: newRestartableVolumeSnapshotterV2,
},
{
kind: framework.PluginKindVolumeSnapshotter,
Get: newAdaptedV1VolumeSnapshotter, // Adapt v1 plugin to v2
},
}
}
// GetVolumeSnapshotter returns a restartableVolumeSnapshotter for name.
func (m *manager) GetVolumeSnapshotter(name string) (velero.VolumeSnapshotter, error) {
func (m *manager) GetVolumeSnapshotter(name string) (volumesnapshotterv2.VolumeSnapshotter, error) {
name = sanitizeName(name)
restartableProcess, err := m.getRestartableProcess(framework.PluginKindVolumeSnapshotter, name)
if err != nil {
return nil, err
for _, restartableVolumeSnapshotter := range m.restartableVolumeSnapshotters() {
restartableProcess, err := m.getRestartableProcess(restartableVolumeSnapshotter.kind, name)
if err != nil {
// Check if plugin was not found
if errors.Is(err, &pluginNotFoundError{}) {
continue
}
return nil, err
}
return restartableVolumeSnapshotter.Get(name, restartableProcess), nil
}
r := newRestartableVolumeSnapshotter(name, restartableProcess)
return r, nil
return nil, fmt.Errorf("unable to get valid VolumeSnapshotter for %q", name)
}
// GetBackupItemActions returns all backup item actions as restartableBackupItemActions.
func (m *manager) GetBackupItemActions() ([]velero.BackupItemAction, error) {
list := m.registry.List(framework.PluginKindBackupItemAction)
actions := make([]velero.BackupItemAction, 0, len(list))
func (m *manager) GetBackupItemActions() ([]backupitemactionv2.BackupItemAction, error) {
list := m.registry.ListForKinds(framework.BackupItemActionKinds())
actions := make([]backupitemactionv2.BackupItemAction, 0, len(list))
for i := range list {
id := list[i]
@@ -177,24 +226,47 @@ func (m *manager) GetBackupItemActions() ([]velero.BackupItemAction, error) {
return actions, nil
}
// GetBackupItemAction returns a restartableBackupItemAction for name.
func (m *manager) GetBackupItemAction(name string) (velero.BackupItemAction, error) {
name = sanitizeName(name)
type RestartableBackupItemAction struct {
kind framework.PluginKind
// Get returns a restartable BackupItemAction for the given name and process, wrapping if necessary
Get func(name string, restartableProcess RestartableProcess) backupitemactionv2.BackupItemAction
}
restartableProcess, err := m.getRestartableProcess(framework.PluginKindBackupItemAction, name)
if err != nil {
return nil, err
func (m *manager) restartableBackupItemActions() []RestartableBackupItemAction {
return []RestartableBackupItemAction{
{
kind: framework.PluginKindBackupItemActionV2,
Get: newRestartableBackupItemActionV2,
},
{
kind: framework.PluginKindBackupItemAction,
Get: newAdaptedV1BackupItemAction, // Adapt v1 plugin to v2
},
}
}
r := newRestartableBackupItemAction(name, restartableProcess)
return r, nil
// GetBackupItemAction returns a restartableBackupItemAction for name.
func (m *manager) GetBackupItemAction(name string) (backupitemactionv2.BackupItemAction, error) {
name = sanitizeName(name)
for _, restartableBackupItemAction := range m.restartableBackupItemActions() {
restartableProcess, err := m.getRestartableProcess(restartableBackupItemAction.kind, name)
if err != nil {
// Check if plugin was not found
if errors.Is(err, &pluginNotFoundError{}) {
continue
}
return nil, err
}
return restartableBackupItemAction.Get(name, restartableProcess), nil
}
return nil, fmt.Errorf("unable to get valid BackupItemAction for %q", name)
}
// GetRestoreItemActions returns all restore item actions as restartableRestoreItemActions.
func (m *manager) GetRestoreItemActions() ([]velero.RestoreItemAction, error) {
list := m.registry.List(framework.PluginKindRestoreItemAction)
func (m *manager) GetRestoreItemActions() ([]restoreitemactionv2.RestoreItemAction, error) {
list := m.registry.ListForKinds(framework.RestoreItemActionKinds())
actions := make([]velero.RestoreItemAction, 0, len(list))
actions := make([]restoreitemactionv2.RestoreItemAction, 0, len(list))
for i := range list {
id := list[i]
@@ -210,24 +282,47 @@ func (m *manager) GetRestoreItemActions() ([]velero.RestoreItemAction, error) {
return actions, nil
}
// GetRestoreItemAction returns a restartableRestoreItemAction for name.
func (m *manager) GetRestoreItemAction(name string) (velero.RestoreItemAction, error) {
name = sanitizeName(name)
type RestartableRestoreItemAction struct {
kind framework.PluginKind
// Get returns a restartable RestoreItemAction for the given name and process, wrapping if necessary
Get func(name string, restartableProcess RestartableProcess) restoreitemactionv2.RestoreItemAction
}
restartableProcess, err := m.getRestartableProcess(framework.PluginKindRestoreItemAction, name)
if err != nil {
return nil, err
func (m *manager) restartableRestoreItemActions() []RestartableRestoreItemAction {
return []RestartableRestoreItemAction{
{
kind: framework.PluginKindRestoreItemActionV2,
Get: newRestartableRestoreItemActionV2,
},
{
kind: framework.PluginKindRestoreItemAction,
Get: newAdaptedV1RestoreItemAction, // Adapt v1 plugin to v2
},
}
}
r := newRestartableRestoreItemAction(name, restartableProcess)
return r, nil
// GetRestoreItemAction returns a restartableRestoreItemAction for name.
func (m *manager) GetRestoreItemAction(name string) (restoreitemactionv2.RestoreItemAction, error) {
name = sanitizeName(name)
for _, restartableRestoreItemAction := range m.restartableRestoreItemActions() {
restartableProcess, err := m.getRestartableProcess(restartableRestoreItemAction.kind, name)
if err != nil {
// Check if plugin was not found
if errors.Is(err, &pluginNotFoundError{}) {
continue
}
return nil, err
}
return restartableRestoreItemAction.Get(name, restartableProcess), nil
}
return nil, fmt.Errorf("unable to get valid RestoreItemAction for %q", name)
}
// GetDeleteItemActions returns all delete item actions as restartableDeleteItemActions.
func (m *manager) GetDeleteItemActions() ([]velero.DeleteItemAction, error) {
list := m.registry.List(framework.PluginKindDeleteItemAction)
func (m *manager) GetDeleteItemActions() ([]deleteitemactionv2.DeleteItemAction, error) {
list := m.registry.ListForKinds(framework.DeleteItemActionKinds())
actions := make([]velero.DeleteItemAction, 0, len(list))
actions := make([]deleteitemactionv2.DeleteItemAction, 0, len(list))
for i := range list {
id := list[i]
@@ -243,17 +338,40 @@ func (m *manager) GetDeleteItemActions() ([]velero.DeleteItemAction, error) {
return actions, nil
}
// GetDeleteItemAction returns a restartableDeleteItemAction for name.
func (m *manager) GetDeleteItemAction(name string) (velero.DeleteItemAction, error) {
name = sanitizeName(name)
type RestartableDeleteItemAction struct {
kind framework.PluginKind
// Get returns a restartable DeleteItemAction for the given name and process, wrapping if necessary
Get func(name string, restartableProcess RestartableProcess) deleteitemactionv2.DeleteItemAction
}
restartableProcess, err := m.getRestartableProcess(framework.PluginKindDeleteItemAction, name)
if err != nil {
return nil, err
func (m *manager) restartableDeleteItemActions() []RestartableDeleteItemAction {
return []RestartableDeleteItemAction{
{
kind: framework.PluginKindDeleteItemActionV2,
Get: newRestartableDeleteItemActionV2,
},
{
kind: framework.PluginKindDeleteItemAction,
Get: newAdaptedV1DeleteItemAction, // Adapt v1 plugin to v2
},
}
}
r := newRestartableDeleteItemAction(name, restartableProcess)
return r, nil
// GetDeleteItemAction returns a restartableDeleteItemAction for name.
func (m *manager) GetDeleteItemAction(name string) (deleteitemactionv2.DeleteItemAction, error) {
name = sanitizeName(name)
for _, restartableDeleteItemAction := range m.restartableDeleteItemActions() {
restartableProcess, err := m.getRestartableProcess(restartableDeleteItemAction.kind, name)
if err != nil {
// Check if plugin was not found
if errors.Is(err, &pluginNotFoundError{}) {
continue
}
return nil, err
}
return restartableDeleteItemAction.Get(name, restartableProcess), nil
}
return nil, fmt.Errorf("unable to get valid DeleteItemAction for %q", name)
}
// sanitizeName adds "velero.io" to legacy plugins that weren't namespaced.

View File

@@ -34,6 +34,8 @@ type Registry interface {
DiscoverPlugins() error
// List returns all PluginIdentifiers for kind.
List(kind framework.PluginKind) []framework.PluginIdentifier
// List returns all PluginIdentifiers for a list of kinds.
ListForKinds(kinds []framework.PluginKind) (list []framework.PluginIdentifier)
// Get returns the PluginIdentifier for kind and name.
Get(kind framework.PluginKind, name string) (framework.PluginIdentifier, error)
}
@@ -108,6 +110,13 @@ func (r *registry) discoverPlugins(commands []string) error {
return nil
}
func (r *registry) ListForKinds(kinds []framework.PluginKind) (list []framework.PluginIdentifier) {
for _, kind := range kinds {
list = append(list, r.pluginsByKind[kind]...)
}
return
}
// List returns info about all plugin binaries that implement the given
// PluginKind.
func (r *registry) List(kind framework.PluginKind) []framework.PluginIdentifier {

View File

@@ -0,0 +1,105 @@
/*
Copyright 2021 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 (
"context"
"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/framework"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
backupitemactionv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v1"
backupitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v2"
)
type restartableAdaptedV1BackupItemAction struct {
key kindAndName
sharedPluginProcess RestartableProcess
}
// newAdaptedV1BackupItemAction returns a new restartableAdaptedV1BackupItemAction.
func newAdaptedV1BackupItemAction(
name string, sharedPluginProcess RestartableProcess) backupitemactionv2.BackupItemAction {
r := &restartableAdaptedV1BackupItemAction{
key: kindAndName{kind: framework.PluginKindBackupItemAction, name: name},
sharedPluginProcess: sharedPluginProcess,
}
return r
}
// getBackupItemAction returns the backup item action for this restartableAdaptedV1BackupItemAction.
// It does *not* restart the plugin process.
func (r *restartableAdaptedV1BackupItemAction) getBackupItemAction() (backupitemactionv1.BackupItemAction, error) {
plugin, err := r.sharedPluginProcess.getByKindAndName(r.key)
if err != nil {
return nil, err
}
backupItemAction, ok := plugin.(backupitemactionv1.BackupItemAction)
if !ok {
return nil, errors.Errorf("%T is not a BackupItemAction!", plugin)
}
return backupItemAction, nil
}
// getDelegate restarts the plugin process (if needed) and returns the backup item
// action for this restartableAdaptedV1BackupItemAction.
func (r *restartableAdaptedV1BackupItemAction) getDelegate() (backupitemactionv1.BackupItemAction, error) {
if err := r.sharedPluginProcess.resetIfNeeded(); err != nil {
return nil, err
}
return r.getBackupItemAction()
}
// AppliesTo restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1BackupItemAction) 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 *restartableAdaptedV1BackupItemAction) Execute(
item runtime.Unstructured, backup *api.Backup) (runtime.Unstructured, []velero.ResourceIdentifier, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, nil, err
}
return delegate.Execute(item, backup)
}
// Version 2: simply discard ctx and call version 1 function.
// ExecuteV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1BackupItemAction) ExecuteV2(
ctx context.Context, item runtime.Unstructured, backup *api.Backup) (
runtime.Unstructured, []velero.ResourceIdentifier, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, nil, err
}
return delegate.Execute(item, backup)
}

View File

@@ -0,0 +1,100 @@
/*
Copyright 2021 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 (
"context"
"github.com/pkg/errors"
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
deleteitemactionv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/deleteitemaction/v1"
deleteitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/deleteitemaction/v2"
)
type restartableAdaptedV1DeleteItemAction struct {
key kindAndName
sharedPluginProcess RestartableProcess
config map[string]string
}
// newAdaptedV1DeleteItemAction returns a new restartableAdaptedV1DeleteItemAction.
func newAdaptedV1DeleteItemAction(
name string, sharedPluginProcess RestartableProcess) deleteitemactionv2.DeleteItemAction {
r := &restartableAdaptedV1DeleteItemAction{
key: kindAndName{kind: framework.PluginKindDeleteItemAction, name: name},
sharedPluginProcess: sharedPluginProcess,
}
return r
}
// getDeleteItemAction returns the delete item action for this restartableDeleteItemAction.
// It does *not* restart the plugin process.
func (r *restartableAdaptedV1DeleteItemAction) getDeleteItemAction() (deleteitemactionv1.DeleteItemAction, error) {
plugin, err := r.sharedPluginProcess.getByKindAndName(r.key)
if err != nil {
return nil, err
}
deleteItemAction, ok := plugin.(deleteitemactionv1.DeleteItemAction)
if !ok {
return nil, errors.Errorf("%T is not a DeleteItemAction!", plugin)
}
return deleteItemAction, nil
}
// getDelegate restarts the plugin process (if needed) and returns the delete item action for this restartableDeleteItemAction.
func (r *restartableAdaptedV1DeleteItemAction) getDelegate() (deleteitemactionv1.DeleteItemAction, error) {
if err := r.sharedPluginProcess.resetIfNeeded(); err != nil {
return nil, err
}
return r.getDeleteItemAction()
}
// AppliesTo restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1DeleteItemAction) 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 *restartableAdaptedV1DeleteItemAction) Execute(input *velero.DeleteItemActionExecuteInput) error {
delegate, err := r.getDelegate()
if err != nil {
return err
}
return delegate.Execute(input)
}
// ExecuteV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1DeleteItemAction) ExecuteV2(
ctx context.Context, input *velero.DeleteItemActionExecuteInput) error {
delegate, err := r.getDelegate()
if err != nil {
return err
}
return delegate.Execute(input)
}

View File

@@ -0,0 +1,246 @@
/*
Copyright 2021 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 (
"context"
"io"
"time"
"github.com/pkg/errors"
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
objectstorev1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/objectstore/v1"
objectstorev2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/objectstore/v2"
)
// restartableAdaptedV1ObjectStore is restartableAdaptedV1ObjectStore version 1 adaptive to version 2 plugin
type restartableAdaptedV1ObjectStore struct {
restartableObjectStore
}
// newAdaptedV1ObjectStore returns a new restartableAdaptedV1ObjectStore.
func newAdaptedV1ObjectStore(name string, sharedPluginProcess RestartableProcess) objectstorev2.ObjectStore {
key := kindAndName{kind: framework.PluginKindObjectStore, name: name}
r := &restartableAdaptedV1ObjectStore{
restartableObjectStore: restartableObjectStore{
key: key,
sharedPluginProcess: sharedPluginProcess,
},
}
// Register our reinitializer so we can reinitialize after a restart with r.config.
sharedPluginProcess.addReinitializer(key, r)
return r
}
// reinitialize reinitializes a re-dispensed plugin using the initial data passed to Init().
func (r *restartableAdaptedV1ObjectStore) reinitialize(dispensed interface{}) error {
objectStore, ok := dispensed.(objectstorev1.ObjectStore)
if !ok {
return errors.Errorf("%T is not a ObjectStore!", dispensed)
}
return r.init(objectStore, r.config)
}
// getObjectStore returns the object store for this restartableObjectStore.
// It does *not* restart the plugin process.
func (r *restartableAdaptedV1ObjectStore) getObjectStore() (objectstorev1.ObjectStore, error) {
plugin, err := r.sharedPluginProcess.getByKindAndName(r.key)
if err != nil {
return nil, err
}
objectStore, ok := plugin.(objectstorev1.ObjectStore)
if !ok {
return nil, errors.Errorf("%T is not a ObjectStore!", plugin)
}
return objectStore, nil
}
// getDelegate restarts the plugin process (if needed) and returns the object store for this restartableObjectStore.
func (r *restartableAdaptedV1ObjectStore) getDelegate() (objectstorev1.ObjectStore, error) {
if err := r.sharedPluginProcess.resetIfNeeded(); err != nil {
return nil, err
}
return r.getObjectStore()
}
// Init initializes the object store instance using config. If this is the first invocation, r stores config for future
// reinitialization needs. Init does NOT restart the shared plugin process. Init may only be called once.
func (r *restartableAdaptedV1ObjectStore) Init(config map[string]string) error {
if r.config != nil {
return errors.Errorf("already initialized")
}
// Not using getDelegate() to avoid possible infinite recursion
delegate, err := r.getObjectStore()
if err != nil {
return err
}
r.config = config
return r.init(delegate, config)
}
func (r *restartableAdaptedV1ObjectStore) InitV2(ctx context.Context, config map[string]string) error {
return r.Init(config)
}
// init calls Init on objectStore with config. This is split out from Init() so that both Init() and reinitialize() may
// call it using a specific ObjectStore.
func (r *restartableAdaptedV1ObjectStore) init(objectStore objectstorev1.ObjectStore, config map[string]string) error {
return objectStore.Init(config)
}
// PutObject restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) PutObject(bucket string, key string, body io.Reader) error {
delegate, err := r.getDelegate()
if err != nil {
return err
}
return delegate.PutObject(bucket, key, body)
}
// ObjectExists restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) ObjectExists(bucket, key string) (bool, error) {
delegate, err := r.getDelegate()
if err != nil {
return false, err
}
return delegate.ObjectExists(bucket, key)
}
// GetObject restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) GetObject(bucket string, key string) (io.ReadCloser, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.GetObject(bucket, key)
}
// ListCommonPrefixes restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) ListCommonPrefixes(
bucket string, prefix string, delimiter string) ([]string, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.ListCommonPrefixes(bucket, prefix, delimiter)
}
// ListObjects restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) ListObjects(bucket string, prefix string) ([]string, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.ListObjects(bucket, prefix)
}
// DeleteObject restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) DeleteObject(bucket string, key string) error {
delegate, err := r.getDelegate()
if err != nil {
return err
}
return delegate.DeleteObject(bucket, key)
}
// CreateSignedURL restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) CreateSignedURL(
bucket string, key string, ttl time.Duration) (string, error) {
delegate, err := r.getDelegate()
if err != nil {
return "", err
}
return delegate.CreateSignedURL(bucket, key, ttl)
}
// Version 2. Simply discard ctx.
// PutObjectV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) PutObjectV2(
ctx context.Context, bucket string, key string, body io.Reader) error {
delegate, err := r.getDelegate()
if err != nil {
return err
}
return delegate.PutObject(bucket, key, body)
}
// ObjectExistsV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) ObjectExistsV2(ctx context.Context, bucket, key string) (bool, error) {
delegate, err := r.getDelegate()
if err != nil {
return false, err
}
return delegate.ObjectExists(bucket, key)
}
// GetObjectV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) GetObjectV2(
ctx context.Context, bucket string, key string) (io.ReadCloser, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.GetObject(bucket, key)
}
// ListCommonPrefixesV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) ListCommonPrefixesV2(
ctx context.Context, bucket string, prefix string, delimiter string) ([]string, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.ListCommonPrefixes(bucket, prefix, delimiter)
}
// ListObjectsV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) ListObjectsV2(
ctx context.Context, bucket string, prefix string) ([]string, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.ListObjects(bucket, prefix)
}
// DeleteObjectV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) DeleteObjectV2(ctx context.Context, bucket string, key string) error {
delegate, err := r.getDelegate()
if err != nil {
return err
}
return delegate.DeleteObject(bucket, key)
}
// CreateSignedURLV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1ObjectStore) CreateSignedURLV2(
ctx context.Context, bucket string, key string, ttl time.Duration) (string, error) {
delegate, err := r.getDelegate()
if err != nil {
return "", err
}
return delegate.CreateSignedURL(bucket, key, ttl)
}

View File

@@ -0,0 +1,100 @@
/*
Copyright 2021 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 (
"context"
"github.com/pkg/errors"
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
restoreitemactionv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
restoreitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2"
)
type restartableAdaptedV1RestoreItemAction struct {
key kindAndName
sharedPluginProcess RestartableProcess
config map[string]string
}
// newRestartableRestoreItemAction returns a new restartableRestoreItemAction.
func newAdaptedV1RestoreItemAction(
name string, sharedPluginProcess RestartableProcess) restoreitemactionv2.RestoreItemAction {
r := &restartableAdaptedV1RestoreItemAction{
key: kindAndName{kind: framework.PluginKindRestoreItemAction, name: name},
sharedPluginProcess: sharedPluginProcess,
}
return r
}
// getRestoreItemAction returns the restore item action for this restartableRestoreItemAction.
// It does *not* restart the plugin process.
func (r *restartableAdaptedV1RestoreItemAction) getRestoreItemAction() (restoreitemactionv1.RestoreItemAction, error) {
plugin, err := r.sharedPluginProcess.getByKindAndName(r.key)
if err != nil {
return nil, err
}
restoreItemAction, ok := plugin.(restoreitemactionv1.RestoreItemAction)
if !ok {
return nil, errors.Errorf("%T is not a RestoreItemAction!", plugin)
}
return restoreItemAction, nil
}
// getDelegate restarts the plugin process (if needed) and returns the restore item action for this restartableRestoreItemAction.
func (r *restartableAdaptedV1RestoreItemAction) getDelegate() (restoreitemactionv1.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 *restartableAdaptedV1RestoreItemAction) 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 *restartableAdaptedV1RestoreItemAction) Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.Execute(input)
}
// ExecuteV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1RestoreItemAction) ExecuteV2(
ctx context.Context, input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.Execute(input)
}

View File

@@ -0,0 +1,233 @@
/*
Copyright 2021 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 (
"context"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime"
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
volumesnapshotterv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v1"
volumesnapshotterv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v2"
)
// restartableAdaptedV1VolumeSnapshotter
type restartableAdaptedV1VolumeSnapshotter struct {
key kindAndName
sharedPluginProcess RestartableProcess
config map[string]string
}
// newAdaptedV1VolumeSnapshotter returns a new restartableAdaptedV1VolumeSnapshotter.
func newAdaptedV1VolumeSnapshotter(
name string, sharedPluginProcess RestartableProcess) volumesnapshotterv2.VolumeSnapshotter {
key := kindAndName{kind: framework.PluginKindVolumeSnapshotter, name: name}
r := &restartableAdaptedV1VolumeSnapshotter{
key: key,
sharedPluginProcess: sharedPluginProcess,
}
// Register our reinitializer so we can reinitialize after a restart with r.config.
sharedPluginProcess.addReinitializer(key, r)
return r
}
// reinitialize reinitializes a re-dispensed plugin using the initial data passed to Init().
func (r *restartableAdaptedV1VolumeSnapshotter) reinitialize(dispensed interface{}) error {
volumeSnapshotter, ok := dispensed.(volumesnapshotterv1.VolumeSnapshotter)
if !ok {
return errors.Errorf("%T is not a VolumeSnapshotter!", dispensed)
}
return r.init(volumeSnapshotter, r.config)
}
// getVolumeSnapshotter returns the volume snapshotter for this restartableVolumeSnapshotter.
// It does *not* restart the plugin process.
func (r *restartableAdaptedV1VolumeSnapshotter) getVolumeSnapshotter() (volumesnapshotterv1.VolumeSnapshotter, error) {
plugin, err := r.sharedPluginProcess.getByKindAndName(r.key)
if err != nil {
return nil, err
}
volumeSnapshotter, ok := plugin.(volumesnapshotterv1.VolumeSnapshotter)
if !ok {
return nil, errors.Errorf("%T is not a VolumeSnapshotter!", plugin)
}
return volumeSnapshotter, nil
}
// getDelegate restarts the plugin process (if needed) and returns the volume snapshotter
// for this restartableVolumeSnapshotter.
func (r *restartableAdaptedV1VolumeSnapshotter) getDelegate() (volumesnapshotterv1.VolumeSnapshotter, error) {
if err := r.sharedPluginProcess.resetIfNeeded(); err != nil {
return nil, err
}
return r.getVolumeSnapshotter()
}
// Init initializes the volume snapshotter instance using config. If this is the first invocation,
// r stores config for future reinitialization needs. Init does NOT restart the shared plugin process.
// Init may only be called once.
func (r *restartableAdaptedV1VolumeSnapshotter) Init(config map[string]string) error {
if r.config != nil {
return errors.Errorf("already initialized")
}
// Not using getDelegate() to avoid possible infinite recursion
delegate, err := r.getVolumeSnapshotter()
if err != nil {
return err
}
r.config = config
return r.init(delegate, config)
}
// init calls Init on volumeSnapshotter with config. This is split out from Init() so that both Init()
// and reinitialize() may call it using a specific VolumeSnapshotter.
func (r *restartableAdaptedV1VolumeSnapshotter) init(
volumeSnapshotter volumesnapshotterv1.VolumeSnapshotter, config map[string]string) error {
return volumeSnapshotter.Init(config)
}
// CreateVolumeFromSnapshot restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1VolumeSnapshotter) CreateVolumeFromSnapshot(
snapshotID string, volumeType string, volumeAZ string, iops *int64) (volumeID string, err error) {
delegate, err := r.getDelegate()
if err != nil {
return "", err
}
return delegate.CreateVolumeFromSnapshot(snapshotID, volumeType, volumeAZ, iops)
}
// GetVolumeID restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1VolumeSnapshotter) GetVolumeID(pv runtime.Unstructured) (string, error) {
delegate, err := r.getDelegate()
if err != nil {
return "", err
}
return delegate.GetVolumeID(pv)
}
// SetVolumeID restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1VolumeSnapshotter) SetVolumeID(
pv runtime.Unstructured, volumeID string) (runtime.Unstructured, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.SetVolumeID(pv, volumeID)
}
// GetVolumeInfo restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1VolumeSnapshotter) GetVolumeInfo(
volumeID string, volumeAZ string) (string, *int64, error) {
delegate, err := r.getDelegate()
if err != nil {
return "", nil, err
}
return delegate.GetVolumeInfo(volumeID, volumeAZ)
}
// CreateSnapshot restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1VolumeSnapshotter) CreateSnapshot(
volumeID string, volumeAZ string, tags map[string]string) (snapshotID string, err error) {
delegate, err := r.getDelegate()
if err != nil {
return "", err
}
return delegate.CreateSnapshot(volumeID, volumeAZ, tags)
}
// DeleteSnapshot restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1VolumeSnapshotter) DeleteSnapshot(snapshotID string) error {
delegate, err := r.getDelegate()
if err != nil {
return err
}
return delegate.DeleteSnapshot(snapshotID)
}
// Version 2 simply discard ctx then call Version 1 function
func (r *restartableAdaptedV1VolumeSnapshotter) InitV2(ctx context.Context, config map[string]string) error {
return r.Init(config)
}
// CreateVolumeFromSnapshotV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1VolumeSnapshotter) CreateVolumeFromSnapshotV2(
ctx context.Context, snapshotID string, volumeType string, volumeAZ string, iops *int64) (volumeID string, err error) {
delegate, err := r.getDelegate()
if err != nil {
return "", err
}
return delegate.CreateVolumeFromSnapshot(snapshotID, volumeType, volumeAZ, iops)
}
// GetVolumeIDV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1VolumeSnapshotter) GetVolumeIDV2(
ctx context.Context, pv runtime.Unstructured) (string, error) {
delegate, err := r.getDelegate()
if err != nil {
return "", err
}
return delegate.GetVolumeID(pv)
}
// SetVolumeIDV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1VolumeSnapshotter) SetVolumeIDV2(
ctx context.Context, pv runtime.Unstructured, volumeID string) (runtime.Unstructured, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.SetVolumeID(pv, volumeID)
}
// GetVolumeInfoV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1VolumeSnapshotter) GetVolumeInfoV2(
ctx context.Context, volumeID string, volumeAZ string) (string, *int64, error) {
delegate, err := r.getDelegate()
if err != nil {
return "", nil, err
}
return delegate.GetVolumeInfo(volumeID, volumeAZ)
}
// CreateSnapshotV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1VolumeSnapshotter) CreateSnapshotV2(
ctx context.Context, volumeID string, volumeAZ string, tags map[string]string) (snapshotID string, err error) {
delegate, err := r.getDelegate()
if err != nil {
return "", err
}
return delegate.CreateSnapshot(volumeID, volumeAZ, tags)
}
// DeleteSnapshotV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableAdaptedV1VolumeSnapshotter) DeleteSnapshotV2(ctx context.Context, snapshotID string) error {
delegate, err := r.getDelegate()
if err != nil {
return err
}
return delegate.DeleteSnapshot(snapshotID)
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 the Velero contributors.
Copyright 2018, 2021 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.
@@ -17,12 +17,15 @@ limitations under the License.
package clientmgmt
import (
"context"
"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/framework"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
backupitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v2"
)
// restartableBackupItemAction is a backup item action for a given implementation (such as "pod"). It is associated with
@@ -34,10 +37,11 @@ type restartableBackupItemAction struct {
sharedPluginProcess RestartableProcess
}
// newRestartableBackupItemAction returns a new restartableBackupItemAction.
func newRestartableBackupItemAction(name string, sharedPluginProcess RestartableProcess) *restartableBackupItemAction {
// newRestartableBackupItemActionV2 returns a new restartableBackupItemAction.
func newRestartableBackupItemActionV2(
name string, sharedPluginProcess RestartableProcess) backupitemactionv2.BackupItemAction {
r := &restartableBackupItemAction{
key: kindAndName{kind: framework.PluginKindBackupItemAction, name: name},
key: kindAndName{kind: framework.PluginKindBackupItemActionV2, name: name},
sharedPluginProcess: sharedPluginProcess,
}
return r
@@ -45,13 +49,13 @@ func newRestartableBackupItemAction(name string, sharedPluginProcess Restartable
// getBackupItemAction returns the backup item action for this restartableBackupItemAction. It does *not* restart the
// plugin process.
func (r *restartableBackupItemAction) getBackupItemAction() (velero.BackupItemAction, error) {
func (r *restartableBackupItemAction) getBackupItemAction() (backupitemactionv2.BackupItemAction, error) {
plugin, err := r.sharedPluginProcess.getByKindAndName(r.key)
if err != nil {
return nil, err
}
backupItemAction, ok := plugin.(velero.BackupItemAction)
backupItemAction, ok := plugin.(backupitemactionv2.BackupItemAction)
if !ok {
return nil, errors.Errorf("%T is not a BackupItemAction!", plugin)
}
@@ -60,7 +64,7 @@ func (r *restartableBackupItemAction) getBackupItemAction() (velero.BackupItemAc
}
// getDelegate restarts the plugin process (if needed) and returns the backup item action for this restartableBackupItemAction.
func (r *restartableBackupItemAction) getDelegate() (velero.BackupItemAction, error) {
func (r *restartableBackupItemAction) getDelegate() (backupitemactionv2.BackupItemAction, error) {
if err := r.sharedPluginProcess.resetIfNeeded(); err != nil {
return nil, err
}
@@ -87,3 +91,13 @@ func (r *restartableBackupItemAction) Execute(item runtime.Unstructured, backup
return delegate.Execute(item, backup)
}
// ExecuteV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableBackupItemAction) ExecuteV2(ctx context.Context, item runtime.Unstructured, backup *api.Backup) (runtime.Unstructured, []velero.ResourceIdentifier, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, nil, err
}
return delegate.ExecuteV2(ctx, item, backup)
}

View File

@@ -17,10 +17,13 @@ limitations under the License.
package clientmgmt
import (
"context"
"github.com/pkg/errors"
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
deleteitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/deleteitemaction/v2"
)
// restartableDeleteItemAction is a delete item action for a given implementation (such as "pod"). It is associated with
@@ -34,7 +37,8 @@ type restartableDeleteItemAction struct {
}
// newRestartableDeleteItemAction returns a new restartableDeleteItemAction.
func newRestartableDeleteItemAction(name string, sharedPluginProcess RestartableProcess) *restartableDeleteItemAction {
func newRestartableDeleteItemActionV2(
name string, sharedPluginProcess RestartableProcess) deleteitemactionv2.DeleteItemAction {
r := &restartableDeleteItemAction{
key: kindAndName{kind: framework.PluginKindDeleteItemAction, name: name},
sharedPluginProcess: sharedPluginProcess,
@@ -44,13 +48,13 @@ func newRestartableDeleteItemAction(name string, sharedPluginProcess Restartable
// getDeleteItemAction returns the delete item action for this restartableDeleteItemAction. It does *not* restart the
// plugin process.
func (r *restartableDeleteItemAction) getDeleteItemAction() (velero.DeleteItemAction, error) {
func (r *restartableDeleteItemAction) getDeleteItemAction() (deleteitemactionv2.DeleteItemAction, error) {
plugin, err := r.sharedPluginProcess.getByKindAndName(r.key)
if err != nil {
return nil, err
}
deleteItemAction, ok := plugin.(velero.DeleteItemAction)
deleteItemAction, ok := plugin.(deleteitemactionv2.DeleteItemAction)
if !ok {
return nil, errors.Errorf("%T is not a DeleteItemAction!", plugin)
}
@@ -59,7 +63,7 @@ func (r *restartableDeleteItemAction) getDeleteItemAction() (velero.DeleteItemAc
}
// getDelegate restarts the plugin process (if needed) and returns the delete item action for this restartableDeleteItemAction.
func (r *restartableDeleteItemAction) getDelegate() (velero.DeleteItemAction, error) {
func (r *restartableDeleteItemAction) getDelegate() (deleteitemactionv2.DeleteItemAction, error) {
if err := r.sharedPluginProcess.resetIfNeeded(); err != nil {
return nil, err
}
@@ -86,3 +90,13 @@ func (r *restartableDeleteItemAction) Execute(input *velero.DeleteItemActionExec
return delegate.Execute(input)
}
// ExecuteV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableDeleteItemAction) ExecuteV2(ctx context.Context, input *velero.DeleteItemActionExecuteInput) error {
delegate, err := r.getDelegate()
if err != nil {
return err
}
return delegate.ExecuteV2(ctx, input)
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 the Velero contributors.
Copyright 2021 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.
@@ -17,13 +17,14 @@ limitations under the License.
package clientmgmt
import (
"context"
"io"
"time"
"github.com/pkg/errors"
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
objectstorev2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/objectstore/v2"
)
// restartableObjectStore is an object store for a given implementation (such as "aws"). It is associated with
@@ -38,9 +39,9 @@ type restartableObjectStore struct {
config map[string]string
}
// newRestartableObjectStore returns a new restartableObjectStore.
func newRestartableObjectStore(name string, sharedPluginProcess RestartableProcess) *restartableObjectStore {
key := kindAndName{kind: framework.PluginKindObjectStore, name: name}
// newRestartableObjectStoreV2 returns a new objectstorev2.ObjectStore for PluginKindObjectStoreV2
func newRestartableObjectStoreV2(name string, sharedPluginProcess RestartableProcess) objectstorev2.ObjectStore {
key := kindAndName{kind: framework.PluginKindObjectStoreV2, name: name}
r := &restartableObjectStore{
key: key,
sharedPluginProcess: sharedPluginProcess,
@@ -54,7 +55,7 @@ func newRestartableObjectStore(name string, sharedPluginProcess RestartableProce
// reinitialize reinitializes a re-dispensed plugin using the initial data passed to Init().
func (r *restartableObjectStore) reinitialize(dispensed interface{}) error {
objectStore, ok := dispensed.(velero.ObjectStore)
objectStore, ok := dispensed.(objectstorev2.ObjectStore)
if !ok {
return errors.Errorf("%T is not a ObjectStore!", dispensed)
}
@@ -64,13 +65,13 @@ func (r *restartableObjectStore) reinitialize(dispensed interface{}) error {
// getObjectStore returns the object store for this restartableObjectStore. It does *not* restart the
// plugin process.
func (r *restartableObjectStore) getObjectStore() (velero.ObjectStore, error) {
func (r *restartableObjectStore) getObjectStore() (objectstorev2.ObjectStore, error) {
plugin, err := r.sharedPluginProcess.getByKindAndName(r.key)
if err != nil {
return nil, err
}
objectStore, ok := plugin.(velero.ObjectStore)
objectStore, ok := plugin.(objectstorev2.ObjectStore)
if !ok {
return nil, errors.Errorf("%T is not a ObjectStore!", plugin)
}
@@ -79,7 +80,7 @@ func (r *restartableObjectStore) getObjectStore() (velero.ObjectStore, error) {
}
// getDelegate restarts the plugin process (if needed) and returns the object store for this restartableObjectStore.
func (r *restartableObjectStore) getDelegate() (velero.ObjectStore, error) {
func (r *restartableObjectStore) getDelegate() (objectstorev2.ObjectStore, error) {
if err := r.sharedPluginProcess.resetIfNeeded(); err != nil {
return nil, err
}
@@ -105,9 +106,15 @@ func (r *restartableObjectStore) Init(config map[string]string) error {
return r.init(delegate, config)
}
// InitV2 initializes the object store instance using config. If this is the first invocation, r stores config for future
// reinitialization needs. Init does NOT restart the shared plugin process. Init may only be called once.
func (r *restartableObjectStore) InitV2(ctx context.Context, config map[string]string) error {
return r.Init(config)
}
// init calls Init on objectStore with config. This is split out from Init() so that both Init() and reinitialize() may
// call it using a specific ObjectStore.
func (r *restartableObjectStore) init(objectStore velero.ObjectStore, config map[string]string) error {
func (r *restartableObjectStore) init(objectStore objectstorev2.ObjectStore, config map[string]string) error {
return objectStore.Init(config)
}
@@ -173,3 +180,68 @@ func (r *restartableObjectStore) CreateSignedURL(bucket string, key string, ttl
}
return delegate.CreateSignedURL(bucket, key, ttl)
}
// Version 2
// PutObjectV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableObjectStore) PutObjectV2(ctx context.Context, bucket string, key string, body io.Reader) error {
delegate, err := r.getDelegate()
if err != nil {
return err
}
return delegate.PutObjectV2(ctx, bucket, key, body)
}
// ObjectExistsV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableObjectStore) ObjectExistsV2(ctx context.Context, bucket, key string) (bool, error) {
delegate, err := r.getDelegate()
if err != nil {
return false, err
}
return delegate.ObjectExistsV2(ctx, bucket, key)
}
// GetObjectV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableObjectStore) GetObjectV2(ctx context.Context, bucket string, key string) (io.ReadCloser, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.GetObjectV2(ctx, bucket, key)
}
// ListCommonPrefixesV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableObjectStore) ListCommonPrefixesV2(
ctx context.Context, bucket string, prefix string, delimiter string) ([]string, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.ListCommonPrefixesV2(ctx, bucket, prefix, delimiter)
}
// ListObjectsV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableObjectStore) ListObjectsV2(ctx context.Context, bucket string, prefix string) ([]string, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.ListObjectsV2(ctx, bucket, prefix)
}
// DeleteObjectV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableObjectStore) DeleteObjectV2(ctx context.Context, bucket string, key string) error {
delegate, err := r.getDelegate()
if err != nil {
return err
}
return delegate.DeleteObjectV2(ctx, bucket, key)
}
// CreateSignedURLV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableObjectStore) CreateSignedURLV2(ctx context.Context, bucket string, key string, ttl time.Duration) (string, error) {
delegate, err := r.getDelegate()
if err != nil {
return "", err
}
return delegate.CreateSignedURLV2(ctx, bucket, key, ttl)
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 the Velero contributors.
Copyright 2021 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.
@@ -17,10 +17,13 @@ limitations under the License.
package clientmgmt
import (
"context"
"github.com/pkg/errors"
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
restoreitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2"
)
// restartableRestoreItemAction is a restore item action for a given implementation (such as "pod"). It is associated with
@@ -33,10 +36,11 @@ type restartableRestoreItemAction struct {
config map[string]string
}
// newRestartableRestoreItemAction returns a new restartableRestoreItemAction.
func newRestartableRestoreItemAction(name string, sharedPluginProcess RestartableProcess) *restartableRestoreItemAction {
// newRestartableRestoreItemActionV2 returns a new restartableRestoreItemAction.
func newRestartableRestoreItemActionV2(
name string, sharedPluginProcess RestartableProcess) restoreitemactionv2.RestoreItemAction {
r := &restartableRestoreItemAction{
key: kindAndName{kind: framework.PluginKindRestoreItemAction, name: name},
key: kindAndName{kind: framework.PluginKindRestoreItemActionV2, name: name},
sharedPluginProcess: sharedPluginProcess,
}
return r
@@ -44,13 +48,13 @@ func newRestartableRestoreItemAction(name string, sharedPluginProcess Restartabl
// getRestoreItemAction returns the restore item action for this restartableRestoreItemAction. It does *not* restart the
// plugin process.
func (r *restartableRestoreItemAction) getRestoreItemAction() (velero.RestoreItemAction, error) {
func (r *restartableRestoreItemAction) getRestoreItemAction() (restoreitemactionv2.RestoreItemAction, error) {
plugin, err := r.sharedPluginProcess.getByKindAndName(r.key)
if err != nil {
return nil, err
}
restoreItemAction, ok := plugin.(velero.RestoreItemAction)
restoreItemAction, ok := plugin.(restoreitemactionv2.RestoreItemAction)
if !ok {
return nil, errors.Errorf("%T is not a RestoreItemAction!", plugin)
}
@@ -59,7 +63,7 @@ func (r *restartableRestoreItemAction) getRestoreItemAction() (velero.RestoreIte
}
// getDelegate restarts the plugin process (if needed) and returns the restore item action for this restartableRestoreItemAction.
func (r *restartableRestoreItemAction) getDelegate() (velero.RestoreItemAction, error) {
func (r *restartableRestoreItemAction) getDelegate() (restoreitemactionv2.RestoreItemAction, error) {
if err := r.sharedPluginProcess.resetIfNeeded(); err != nil {
return nil, err
}
@@ -86,3 +90,14 @@ func (r *restartableRestoreItemAction) Execute(input *velero.RestoreItemActionEx
return delegate.Execute(input)
}
// ExecuteV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableRestoreItemAction) ExecuteV2(
ctx context.Context, input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.ExecuteV2(ctx, input)
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018 the Velero contributors.
Copyright 2021 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.
@@ -17,11 +17,13 @@ limitations under the License.
package clientmgmt
import (
"context"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime"
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
volumesnapshotterv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v2"
)
// restartableVolumeSnapshotter is a volume snapshotter for a given implementation (such as "aws"). It is associated with
@@ -34,9 +36,10 @@ type restartableVolumeSnapshotter struct {
config map[string]string
}
// newRestartableVolumeSnapshotter returns a new restartableVolumeSnapshotter.
func newRestartableVolumeSnapshotter(name string, sharedPluginProcess RestartableProcess) *restartableVolumeSnapshotter {
key := kindAndName{kind: framework.PluginKindVolumeSnapshotter, name: name}
// newRestartableVolumeSnapshotterV2 returns a new restartableVolumeSnapshotter.
func newRestartableVolumeSnapshotterV2(
name string, sharedPluginProcess RestartableProcess) volumesnapshotterv2.VolumeSnapshotter {
key := kindAndName{kind: framework.PluginKindVolumeSnapshotterV2, name: name}
r := &restartableVolumeSnapshotter{
key: key,
sharedPluginProcess: sharedPluginProcess,
@@ -50,7 +53,7 @@ func newRestartableVolumeSnapshotter(name string, sharedPluginProcess Restartabl
// reinitialize reinitializes a re-dispensed plugin using the initial data passed to Init().
func (r *restartableVolumeSnapshotter) reinitialize(dispensed interface{}) error {
volumeSnapshotter, ok := dispensed.(velero.VolumeSnapshotter)
volumeSnapshotter, ok := dispensed.(volumesnapshotterv2.VolumeSnapshotter)
if !ok {
return errors.Errorf("%T is not a VolumeSnapshotter!", dispensed)
}
@@ -59,13 +62,13 @@ func (r *restartableVolumeSnapshotter) reinitialize(dispensed interface{}) error
// getVolumeSnapshotter returns the volume snapshotter for this restartableVolumeSnapshotter. It does *not* restart the
// plugin process.
func (r *restartableVolumeSnapshotter) getVolumeSnapshotter() (velero.VolumeSnapshotter, error) {
func (r *restartableVolumeSnapshotter) getVolumeSnapshotter() (volumesnapshotterv2.VolumeSnapshotter, error) {
plugin, err := r.sharedPluginProcess.getByKindAndName(r.key)
if err != nil {
return nil, err
}
volumeSnapshotter, ok := plugin.(velero.VolumeSnapshotter)
volumeSnapshotter, ok := plugin.(volumesnapshotterv2.VolumeSnapshotter)
if !ok {
return nil, errors.Errorf("%T is not a VolumeSnapshotter!", plugin)
}
@@ -74,7 +77,7 @@ func (r *restartableVolumeSnapshotter) getVolumeSnapshotter() (velero.VolumeSnap
}
// getDelegate restarts the plugin process (if needed) and returns the volume snapshotter for this restartableVolumeSnapshotter.
func (r *restartableVolumeSnapshotter) getDelegate() (velero.VolumeSnapshotter, error) {
func (r *restartableVolumeSnapshotter) getDelegate() (volumesnapshotterv2.VolumeSnapshotter, error) {
if err := r.sharedPluginProcess.resetIfNeeded(); err != nil {
return nil, err
}
@@ -102,7 +105,7 @@ func (r *restartableVolumeSnapshotter) Init(config map[string]string) error {
// init calls Init on volumeSnapshotter with config. This is split out from Init() so that both Init() and reinitialize() may
// call it using a specific VolumeSnapshotter.
func (r *restartableVolumeSnapshotter) init(volumeSnapshotter velero.VolumeSnapshotter, config map[string]string) error {
func (r *restartableVolumeSnapshotter) init(volumeSnapshotter volumesnapshotterv2.VolumeSnapshotter, config map[string]string) error {
return volumeSnapshotter.Init(config)
}
@@ -159,3 +162,67 @@ func (r *restartableVolumeSnapshotter) DeleteSnapshot(snapshotID string) error {
}
return delegate.DeleteSnapshot(snapshotID)
}
// Version 2
func (r *restartableVolumeSnapshotter) InitV2(ctx context.Context, config map[string]string) error {
return r.Init(config)
}
// CreateVolumeFromSnapshotV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableVolumeSnapshotter) CreateVolumeFromSnapshotV2(
ctx context.Context, snapshotID string, volumeType string, volumeAZ string, iops *int64) (volumeID string, err error) {
delegate, err := r.getDelegate()
if err != nil {
return "", err
}
return delegate.CreateVolumeFromSnapshotV2(ctx, snapshotID, volumeType, volumeAZ, iops)
}
// GetVolumeIDV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableVolumeSnapshotter) GetVolumeIDV2(
ctx context.Context, pv runtime.Unstructured) (string, error) {
delegate, err := r.getDelegate()
if err != nil {
return "", err
}
return delegate.GetVolumeIDV2(ctx, pv)
}
// SetVolumeIDV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableVolumeSnapshotter) SetVolumeIDV2(
ctx context.Context, pv runtime.Unstructured, volumeID string) (runtime.Unstructured, error) {
delegate, err := r.getDelegate()
if err != nil {
return nil, err
}
return delegate.SetVolumeIDV2(ctx, pv, volumeID)
}
// GetVolumeInfoV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableVolumeSnapshotter) GetVolumeInfoV2(
ctx context.Context, volumeID string, volumeAZ string) (string, *int64, error) {
delegate, err := r.getDelegate()
if err != nil {
return "", nil, err
}
return delegate.GetVolumeInfoV2(ctx, volumeID, volumeAZ)
}
// CreateSnapshotV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableVolumeSnapshotter) CreateSnapshotV2(
ctx context.Context, volumeID string, volumeAZ string, tags map[string]string) (snapshotID string, err error) {
delegate, err := r.getDelegate()
if err != nil {
return "", err
}
return delegate.CreateSnapshotV2(ctx, volumeID, volumeAZ, tags)
}
// DeleteSnapshotV2 restarts the plugin's process if needed, then delegates the call.
func (r *restartableVolumeSnapshotter) DeleteSnapshotV2(ctx context.Context, snapshotID string) error {
delegate, err := r.getDelegate()
if err != nil {
return err
}
return delegate.DeleteSnapshotV2(ctx, snapshotID)
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2019 the Velero contributors.
Copyright 2021 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.

View File

@@ -76,6 +76,13 @@ func (c *BackupItemActionGRPCClient) AppliesTo() (velero.ResourceSelector, error
}
func (c *BackupItemActionGRPCClient) Execute(item runtime.Unstructured, backup *api.Backup) (runtime.Unstructured, []velero.ResourceIdentifier, error) {
return c.ExecuteV2(context.Background(), item, backup)
}
func (c *BackupItemActionGRPCClient) ExecuteV2(
ctx context.Context, item runtime.Unstructured, backup *api.Backup) (
runtime.Unstructured, []velero.ResourceIdentifier, error) {
itemJSON, err := json.Marshal(item.UnstructuredContent())
if err != nil {
return nil, nil, errors.WithStack(err)
@@ -92,7 +99,7 @@ func (c *BackupItemActionGRPCClient) Execute(item runtime.Unstructured, backup *
Backup: backupJSON,
}
res, err := c.grpcClient.Execute(context.Background(), req)
res, err := c.grpcClient.Execute(ctx, req)
if err != nil {
return nil, nil, fromGRPCError(err)
}

View File

@@ -26,6 +26,7 @@ import (
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
proto "github.com/vmware-tanzu/velero/pkg/plugin/generated"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
backupitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v2"
)
// BackupItemActionGRPCServer implements the proto-generated BackupItemAction interface, and accepts
@@ -34,13 +35,13 @@ type BackupItemActionGRPCServer struct {
mux *serverMux
}
func (s *BackupItemActionGRPCServer) getImpl(name string) (velero.BackupItemAction, error) {
func (s *BackupItemActionGRPCServer) getImpl(name string) (backupitemactionv2.BackupItemAction, error) {
impl, err := s.mux.getHandler(name)
if err != nil {
return nil, err
}
itemAction, ok := impl.(velero.BackupItemAction)
itemAction, ok := impl.(backupitemactionv2.BackupItemAction)
if !ok {
return nil, errors.Errorf("%T is not a backup item action", impl)
}
@@ -98,7 +99,7 @@ func (s *BackupItemActionGRPCServer) Execute(ctx context.Context, req *proto.Exe
return nil, newGRPCError(errors.WithStack(err))
}
updatedItem, additionalItems, err := impl.Execute(&item, &backup)
updatedItem, additionalItems, err := impl.ExecuteV2(ctx, &item, &backup)
if err != nil {
return nil, newGRPCError(err)
}

View File

@@ -25,9 +25,10 @@ import (
proto "github.com/vmware-tanzu/velero/pkg/plugin/generated"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
deleteitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/deleteitemaction/v2"
)
var _ velero.DeleteItemAction = &DeleteItemActionGRPCClient{}
var _ deleteitemactionv2.DeleteItemAction = &DeleteItemActionGRPCClient{}
// NewDeleteItemActionPlugin constructs a DeleteItemActionPlugin.
func NewDeleteItemActionPlugin(options ...PluginOption) *DeleteItemActionPlugin {
@@ -70,6 +71,10 @@ func (c *DeleteItemActionGRPCClient) AppliesTo() (velero.ResourceSelector, error
}
func (c *DeleteItemActionGRPCClient) Execute(input *velero.DeleteItemActionExecuteInput) error {
return c.ExecuteV2(context.Background(), input)
}
func (c *DeleteItemActionGRPCClient) ExecuteV2(ctx context.Context, input *velero.DeleteItemActionExecuteInput) error {
itemJSON, err := json.Marshal(input.Item.UnstructuredContent())
if err != nil {
return errors.WithStack(err)
@@ -87,7 +92,7 @@ func (c *DeleteItemActionGRPCClient) Execute(input *velero.DeleteItemActionExecu
}
// First return item is just an empty struct no matter what.
if _, err = c.grpcClient.Execute(context.Background(), req); err != nil {
if _, err = c.grpcClient.Execute(ctx, req); err != nil {
return fromGRPCError(err)
}

View File

@@ -26,6 +26,7 @@ import (
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
proto "github.com/vmware-tanzu/velero/pkg/plugin/generated"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
deleteitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/deleteitemaction/v2"
)
// DeleteItemActionGRPCServer implements the proto-generated DeleteItemActionServer interface, and accepts
@@ -34,13 +35,13 @@ type DeleteItemActionGRPCServer struct {
mux *serverMux
}
func (s *DeleteItemActionGRPCServer) getImpl(name string) (velero.DeleteItemAction, error) {
func (s *DeleteItemActionGRPCServer) getImpl(name string) (deleteitemactionv2.DeleteItemAction, error) {
impl, err := s.mux.getHandler(name)
if err != nil {
return nil, err
}
itemAction, ok := impl.(velero.DeleteItemAction)
itemAction, ok := impl.(deleteitemactionv2.DeleteItemAction)
if !ok {
return nil, errors.Errorf("%T is not a delete item action", impl)
}
@@ -76,7 +77,8 @@ func (s *DeleteItemActionGRPCServer) AppliesTo(ctx context.Context, req *proto.D
}, nil
}
func (s *DeleteItemActionGRPCServer) Execute(ctx context.Context, req *proto.DeleteItemActionExecuteRequest) (_ *proto.Empty, err error) {
func (s *DeleteItemActionGRPCServer) Execute(
ctx context.Context, req *proto.DeleteItemActionExecuteRequest) (_ *proto.Empty, err error) {
defer func() {
if recoveredErr := handlePanic(recover()); recoveredErr != nil {
err = recoveredErr
@@ -101,7 +103,7 @@ func (s *DeleteItemActionGRPCServer) Execute(ctx context.Context, req *proto.Del
return nil, newGRPCError(errors.WithStack(err))
}
if err := impl.Execute(&velero.DeleteItemActionExecuteInput{
if err := impl.ExecuteV2(ctx, &velero.DeleteItemActionExecuteInput{
Item: &item,
Backup: &backup,
}); err != nil {

View File

@@ -69,7 +69,13 @@ func (c *ObjectStoreGRPCClient) Init(config map[string]string) error {
// PutObject creates a new object using the data in body within the specified
// object storage bucket with the given key.
func (c *ObjectStoreGRPCClient) PutObject(bucket, key string, body io.Reader) error {
stream, err := c.grpcClient.PutObject(context.Background())
return c.PutObjectV2(context.Background(), bucket, key, body)
}
// PutObjectV2 creates a new object using the data in body within the specified
// object storage bucket with the given key.
func (c *ObjectStoreGRPCClient) PutObjectV2(ctx context.Context, bucket, key string, body io.Reader) error {
stream, err := c.grpcClient.PutObject(ctx)
if err != nil {
return fromGRPCError(err)
}
@@ -98,13 +104,18 @@ func (c *ObjectStoreGRPCClient) PutObject(bucket, key string, body io.Reader) er
// ObjectExists checks if there is an object with the given key in the object storage bucket.
func (c *ObjectStoreGRPCClient) ObjectExists(bucket, key string) (bool, error) {
return c.ObjectExistsV2(context.Background(), bucket, key)
}
// ObjectExistsV2 checks if there is an object with the given key in the object storage bucket.
func (c *ObjectStoreGRPCClient) ObjectExistsV2(ctx context.Context, bucket, key string) (bool, error) {
req := &proto.ObjectExistsRequest{
Plugin: c.plugin,
Bucket: bucket,
Key: key,
}
res, err := c.grpcClient.ObjectExists(context.Background(), req)
res, err := c.grpcClient.ObjectExists(ctx, req)
if err != nil {
return false, err
}
@@ -115,13 +126,19 @@ func (c *ObjectStoreGRPCClient) ObjectExists(bucket, key string) (bool, error) {
// GetObject retrieves the object with the given key from the specified
// bucket in object storage.
func (c *ObjectStoreGRPCClient) GetObject(bucket, key string) (io.ReadCloser, error) {
return c.GetObjectV2(context.Background(), bucket, key)
}
// GetObjectV2 retrieves the object with the given key from the specified
// bucket in object storage.
func (c *ObjectStoreGRPCClient) GetObjectV2(ctx context.Context, bucket, key string) (io.ReadCloser, error) {
req := &proto.GetObjectRequest{
Plugin: c.plugin,
Bucket: bucket,
Key: key,
}
stream, err := c.grpcClient.GetObject(context.Background(), req)
stream, err := c.grpcClient.GetObject(ctx, req)
if err != nil {
return nil, fromGRPCError(err)
}
@@ -155,6 +172,14 @@ func (c *ObjectStoreGRPCClient) GetObject(bucket, key string) (io.ReadCloser, er
// after the provided prefix and before the provided delimiter (this is
// often used to simulate a directory hierarchy in object storage).
func (c *ObjectStoreGRPCClient) ListCommonPrefixes(bucket, prefix, delimiter string) ([]string, error) {
return c.ListCommonPrefixesV2(context.Background(), bucket, prefix, delimiter)
}
// ListCommonPrefixesV2 gets a list of all object key prefixes that come
// after the provided prefix and before the provided delimiter (this is
// often used to simulate a directory hierarchy in object storage).
func (c *ObjectStoreGRPCClient) ListCommonPrefixesV2(
ctx context.Context, bucket, prefix, delimiter string) ([]string, error) {
req := &proto.ListCommonPrefixesRequest{
Plugin: c.plugin,
Bucket: bucket,
@@ -162,7 +187,7 @@ func (c *ObjectStoreGRPCClient) ListCommonPrefixes(bucket, prefix, delimiter str
Delimiter: delimiter,
}
res, err := c.grpcClient.ListCommonPrefixes(context.Background(), req)
res, err := c.grpcClient.ListCommonPrefixes(ctx, req)
if err != nil {
return nil, fromGRPCError(err)
}
@@ -172,13 +197,19 @@ func (c *ObjectStoreGRPCClient) ListCommonPrefixes(bucket, prefix, delimiter str
// ListObjects gets a list of all objects in bucket that have the same prefix.
func (c *ObjectStoreGRPCClient) ListObjects(bucket, prefix string) ([]string, error) {
return c.ListObjectsV2(context.Background(), bucket, prefix)
}
// ListObjectsV2 gets a list of all objects in bucket that have the same prefix.
func (c *ObjectStoreGRPCClient) ListObjectsV2(
ctx context.Context, bucket, prefix string) ([]string, error) {
req := &proto.ListObjectsRequest{
Plugin: c.plugin,
Bucket: bucket,
Prefix: prefix,
}
res, err := c.grpcClient.ListObjects(context.Background(), req)
res, err := c.grpcClient.ListObjects(ctx, req)
if err != nil {
return nil, fromGRPCError(err)
}
@@ -189,13 +220,19 @@ func (c *ObjectStoreGRPCClient) ListObjects(bucket, prefix string) ([]string, er
// DeleteObject removes object with the specified key from the given
// bucket.
func (c *ObjectStoreGRPCClient) DeleteObject(bucket, key string) error {
return c.DeleteObjectV2(context.Background(), bucket, key)
}
// DeleteObjectV2 removes object with the specified key from the given bucket.
func (c *ObjectStoreGRPCClient) DeleteObjectV2(
ctx context.Context, bucket, key string) error {
req := &proto.DeleteObjectRequest{
Plugin: c.plugin,
Bucket: bucket,
Key: key,
}
if _, err := c.grpcClient.DeleteObject(context.Background(), req); err != nil {
if _, err := c.grpcClient.DeleteObject(ctx, req); err != nil {
return fromGRPCError(err)
}
@@ -204,6 +241,12 @@ func (c *ObjectStoreGRPCClient) DeleteObject(bucket, key string) error {
// CreateSignedURL creates a pre-signed URL for the given bucket and key that expires after ttl.
func (c *ObjectStoreGRPCClient) CreateSignedURL(bucket, key string, ttl time.Duration) (string, error) {
return c.CreateSignedURLV2(context.Background(), bucket, key, ttl)
}
// CreateSignedURLV2 creates a pre-signed URL for the given bucket and key that expires after ttl.
func (c *ObjectStoreGRPCClient) CreateSignedURLV2(
ctx context.Context, bucket, key string, ttl time.Duration) (string, error) {
req := &proto.CreateSignedURLRequest{
Plugin: c.plugin,
Bucket: bucket,
@@ -211,7 +254,7 @@ func (c *ObjectStoreGRPCClient) CreateSignedURL(bucket, key string, ttl time.Dur
Ttl: int64(ttl),
}
res, err := c.grpcClient.CreateSignedURL(context.Background(), req)
res, err := c.grpcClient.CreateSignedURL(ctx, req)
if err != nil {
return "", fromGRPCError(err)
}

View File

@@ -24,7 +24,7 @@ import (
"golang.org/x/net/context"
proto "github.com/vmware-tanzu/velero/pkg/plugin/generated"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
objectstorev2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/objectstore/v2"
)
// ObjectStoreGRPCServer implements the proto-generated ObjectStoreServer interface, and accepts
@@ -33,13 +33,13 @@ type ObjectStoreGRPCServer struct {
mux *serverMux
}
func (s *ObjectStoreGRPCServer) getImpl(name string) (velero.ObjectStore, error) {
func (s *ObjectStoreGRPCServer) getImpl(name string) (objectstorev2.ObjectStore, error) {
impl, err := s.mux.getHandler(name)
if err != nil {
return nil, err
}
itemAction, ok := impl.(velero.ObjectStore)
itemAction, ok := impl.(objectstorev2.ObjectStore)
if !ok {
return nil, errors.Errorf("%T is not an object store", impl)
}
@@ -62,7 +62,7 @@ func (s *ObjectStoreGRPCServer) Init(ctx context.Context, req *proto.ObjectStore
return nil, newGRPCError(err)
}
if err := impl.Init(req.Config); err != nil {
if err := impl.InitV2(ctx, req.Config); err != nil {
return nil, newGRPCError(err)
}
@@ -141,7 +141,7 @@ func (s *ObjectStoreGRPCServer) ObjectExists(ctx context.Context, req *proto.Obj
return nil, newGRPCError(err)
}
exists, err := impl.ObjectExists(req.Bucket, req.Key)
exists, err := impl.ObjectExistsV2(ctx, req.Bucket, req.Key)
if err != nil {
return nil, newGRPCError(err)
}
@@ -200,7 +200,7 @@ func (s *ObjectStoreGRPCServer) ListCommonPrefixes(ctx context.Context, req *pro
return nil, newGRPCError(err)
}
prefixes, err := impl.ListCommonPrefixes(req.Bucket, req.Prefix, req.Delimiter)
prefixes, err := impl.ListCommonPrefixesV2(ctx, req.Bucket, req.Prefix, req.Delimiter)
if err != nil {
return nil, newGRPCError(err)
}
@@ -221,7 +221,7 @@ func (s *ObjectStoreGRPCServer) ListObjects(ctx context.Context, req *proto.List
return nil, newGRPCError(err)
}
keys, err := impl.ListObjects(req.Bucket, req.Prefix)
keys, err := impl.ListObjectsV2(ctx, req.Bucket, req.Prefix)
if err != nil {
return nil, newGRPCError(err)
}
@@ -243,7 +243,7 @@ func (s *ObjectStoreGRPCServer) DeleteObject(ctx context.Context, req *proto.Del
return nil, newGRPCError(err)
}
if err := impl.DeleteObject(req.Bucket, req.Key); err != nil {
if err := impl.DeleteObjectV2(ctx, req.Bucket, req.Key); err != nil {
return nil, newGRPCError(err)
}
@@ -263,7 +263,7 @@ func (s *ObjectStoreGRPCServer) CreateSignedURL(ctx context.Context, req *proto.
return nil, newGRPCError(err)
}
url, err := impl.CreateSignedURL(req.Bucket, req.Key, time.Duration(req.Ttl))
url, err := impl.CreateSignedURLV2(ctx, req.Bucket, req.Key, time.Duration(req.Ttl))
if err != nil {
return nil, newGRPCError(err)
}

View File

@@ -45,6 +45,58 @@ const (
PluginKindPluginLister PluginKind = "PluginLister"
)
const (
// PluginKindObjectStoreV2 represents an object store plugin version 2.
PluginKindObjectStoreV2 PluginKind = "ObjectStoreV2"
// PluginKindVolumeSnapshotterV2 represents a volume snapshotter plugin version 2.
PluginKindVolumeSnapshotterV2 PluginKind = "VolumeSnapshotterV2"
// PluginKindBackupItemActionV2 represents a backup item action plugin version 2.
PluginKindBackupItemActionV2 PluginKind = "BackupItemActionV2"
// PluginKindRestoreItemActionV2 represents a restore item action plugin version 2.
PluginKindRestoreItemActionV2 PluginKind = "RestoreItemActionV2"
// PluginKindDeleteItemActionV2 represents a delete item action plugin version 2.
PluginKindDeleteItemActionV2 PluginKind = "DeleteItemActionV2"
)
func ObjectStoreKinds() []PluginKind {
return []PluginKind{
PluginKindObjectStoreV2,
PluginKindObjectStore,
}
}
func VolumeSnapshotterKinds() []PluginKind {
return []PluginKind{
PluginKindVolumeSnapshotterV2,
PluginKindVolumeSnapshotter,
}
}
func BackupItemActionKinds() []PluginKind {
return []PluginKind{
PluginKindBackupItemActionV2,
PluginKindBackupItemAction,
}
}
func RestoreItemActionKinds() []PluginKind {
return []PluginKind{
PluginKindRestoreItemActionV2,
PluginKindRestoreItemAction,
}
}
func DeleteItemActionKinds() []PluginKind {
return []PluginKind{
PluginKindDeleteItemActionV2,
PluginKindDeleteItemAction,
}
}
// AllPluginKinds contains all the valid plugin kinds that Velero supports, excluding PluginLister because that is not a
// kind that a developer would ever need to implement (it's handled by Velero and the Velero plugin library code).
func AllPluginKinds() map[string]PluginKind {
@@ -54,5 +106,11 @@ func AllPluginKinds() map[string]PluginKind {
allPluginKinds[PluginKindBackupItemAction.String()] = PluginKindBackupItemAction
allPluginKinds[PluginKindRestoreItemAction.String()] = PluginKindRestoreItemAction
allPluginKinds[PluginKindDeleteItemAction.String()] = PluginKindDeleteItemAction
// Version 2
allPluginKinds[PluginKindObjectStoreV2.String()] = PluginKindObjectStoreV2
allPluginKinds[PluginKindVolumeSnapshotterV2.String()] = PluginKindVolumeSnapshotterV2
allPluginKinds[PluginKindBackupItemActionV2.String()] = PluginKindBackupItemActionV2
allPluginKinds[PluginKindRestoreItemActionV2.String()] = PluginKindRestoreItemActionV2
allPluginKinds[PluginKindDeleteItemActionV2.String()] = PluginKindDeleteItemActionV2
return allPluginKinds
}

View File

@@ -27,9 +27,10 @@ import (
proto "github.com/vmware-tanzu/velero/pkg/plugin/generated"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
restoreitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2"
)
var _ velero.RestoreItemAction = &RestoreItemActionGRPCClient{}
var _ restoreitemactionv2.RestoreItemAction = &RestoreItemActionGRPCClient{}
// NewRestoreItemActionPlugin constructs a RestoreItemActionPlugin.
func NewRestoreItemActionPlugin(options ...PluginOption) *RestoreItemActionPlugin {
@@ -71,7 +72,14 @@ func (c *RestoreItemActionGRPCClient) AppliesTo() (velero.ResourceSelector, erro
}, nil
}
func (c *RestoreItemActionGRPCClient) Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) {
func (c *RestoreItemActionGRPCClient) Execute(
input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) {
return c.ExecuteV2(context.Background(), input)
}
func (c *RestoreItemActionGRPCClient) ExecuteV2(
ctx context.Context, input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) {
itemJSON, err := json.Marshal(input.Item.UnstructuredContent())
if err != nil {
return nil, errors.WithStack(err)
@@ -94,7 +102,7 @@ func (c *RestoreItemActionGRPCClient) Execute(input *velero.RestoreItemActionExe
Restore: restoreJSON,
}
res, err := c.grpcClient.Execute(context.Background(), req)
res, err := c.grpcClient.Execute(ctx, req)
if err != nil {
return nil, fromGRPCError(err)
}

View File

@@ -26,6 +26,7 @@ import (
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
proto "github.com/vmware-tanzu/velero/pkg/plugin/generated"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
restoreitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2"
)
// RestoreItemActionGRPCServer implements the proto-generated RestoreItemActionServer interface, and accepts
@@ -34,13 +35,13 @@ type RestoreItemActionGRPCServer struct {
mux *serverMux
}
func (s *RestoreItemActionGRPCServer) getImpl(name string) (velero.RestoreItemAction, error) {
func (s *RestoreItemActionGRPCServer) getImpl(name string) (restoreitemactionv2.RestoreItemAction, error) {
impl, err := s.mux.getHandler(name)
if err != nil {
return nil, err
}
itemAction, ok := impl.(velero.RestoreItemAction)
itemAction, ok := impl.(restoreitemactionv2.RestoreItemAction)
if !ok {
return nil, errors.Errorf("%T is not a restore item action", impl)
}
@@ -76,7 +77,9 @@ func (s *RestoreItemActionGRPCServer) AppliesTo(ctx context.Context, req *proto.
}, nil
}
func (s *RestoreItemActionGRPCServer) Execute(ctx context.Context, req *proto.RestoreItemActionExecuteRequest) (response *proto.RestoreItemActionExecuteResponse, err error) {
func (s *RestoreItemActionGRPCServer) Execute(
ctx context.Context, req *proto.RestoreItemActionExecuteRequest) (response *proto.RestoreItemActionExecuteResponse, err error) {
defer func() {
if recoveredErr := handlePanic(recover()); recoveredErr != nil {
err = recoveredErr
@@ -106,11 +109,12 @@ func (s *RestoreItemActionGRPCServer) Execute(ctx context.Context, req *proto.Re
return nil, newGRPCError(errors.WithStack(err))
}
executeOutput, err := impl.Execute(&velero.RestoreItemActionExecuteInput{
Item: &item,
ItemFromBackup: &itemFromBackup,
Restore: &restoreObj,
})
executeOutput, err := impl.ExecuteV2(ctx,
&velero.RestoreItemActionExecuteInput{
Item: &item,
ItemFromBackup: &itemFromBackup,
Restore: &restoreObj,
})
if err != nil {
return nil, newGRPCError(err)
}

View File

@@ -74,21 +74,65 @@ type Server interface {
// RegisterDeleteItemActions registers multiple Delete item actions.
RegisterDeleteItemActions(map[string]HandlerInitializer) Server
// Version 2
// RegisterVolumeSnapshottersV2 registers multiple volume snapshotters.
RegisterVolumeSnapshottersV2(map[string]HandlerInitializer) Server
// RegisterObjectStoreV2 registers an object store. Accepted format
// for the plugin name is <DNS subdomain>/<non-empty name>.
RegisterObjectStoreV2(pluginName string, initializer HandlerInitializer) Server
// RegisterBackupItemActionV2 registers a backup item action. Accepted format
// for the plugin name is <DNS subdomain>/<non-empty name>.
RegisterBackupItemActionV2(pluginName string, initializer HandlerInitializer) Server
// RegisterBackupItemActionsV2 registers multiple backup item actions.
RegisterBackupItemActionsV2(map[string]HandlerInitializer) Server
// RegisterVolumeSnapshotterV2 registers a volume snapshotter. Accepted format
// for the plugin name is <DNS subdomain>/<non-empty name>.
RegisterVolumeSnapshotterV2(pluginName string, initializer HandlerInitializer) Server
// RegisterObjectStoresV2 registers multiple object stores.
RegisterObjectStoresV2(map[string]HandlerInitializer) Server
// RegisterRestoreItemActionV2 registers a restore item action. Accepted format
// for the plugin name is <DNS subdomain>/<non-empty name>.
RegisterRestoreItemActionV2(pluginName string, initializer HandlerInitializer) Server
// RegisterRestoreItemActionsV2 registers multiple restore item actions.
RegisterRestoreItemActionsV2(map[string]HandlerInitializer) Server
// RegisterDeleteItemActionV2 registers a delete item action. Accepted format
// for the plugin name is <DNS subdomain>/<non-empty name>.
RegisterDeleteItemActionV2(pluginName string, initializer HandlerInitializer) Server
// RegisterDeleteItemActionsV2 registers multiple Delete item actions.
RegisterDeleteItemActionsV2(map[string]HandlerInitializer) Server
// Server runs the plugin server.
Serve()
}
// server implements Server.
type server struct {
log *logrus.Logger
logLevelFlag *logging.LevelFlag
flagSet *pflag.FlagSet
featureSet *veleroflag.StringArray
log *logrus.Logger
logLevelFlag *logging.LevelFlag
flagSet *pflag.FlagSet
featureSet *veleroflag.StringArray
// Version 1
backupItemAction *BackupItemActionPlugin
volumeSnapshotter *VolumeSnapshotterPlugin
objectStore *ObjectStorePlugin
restoreItemAction *RestoreItemActionPlugin
deleteItemAction *DeleteItemActionPlugin
// Version 2
backupItemActionV2 *BackupItemActionPlugin
volumeSnapshotterV2 *VolumeSnapshotterPlugin
objectStoreV2 *ObjectStorePlugin
restoreItemActionV2 *RestoreItemActionPlugin
deleteItemActionV2 *DeleteItemActionPlugin
}
// NewServer returns a new Server
@@ -97,14 +141,19 @@ func NewServer() Server {
features := veleroflag.NewStringArray()
return &server{
log: log,
logLevelFlag: logging.LogLevelFlag(log.Level),
featureSet: &features,
backupItemAction: NewBackupItemActionPlugin(serverLogger(log)),
volumeSnapshotter: NewVolumeSnapshotterPlugin(serverLogger(log)),
objectStore: NewObjectStorePlugin(serverLogger(log)),
restoreItemAction: NewRestoreItemActionPlugin(serverLogger(log)),
deleteItemAction: NewDeleteItemActionPlugin(serverLogger(log)),
log: log,
logLevelFlag: logging.LogLevelFlag(log.Level),
featureSet: &features,
backupItemAction: NewBackupItemActionPlugin(serverLogger(log)),
volumeSnapshotter: NewVolumeSnapshotterPlugin(serverLogger(log)),
objectStore: NewObjectStorePlugin(serverLogger(log)),
restoreItemAction: NewRestoreItemActionPlugin(serverLogger(log)),
deleteItemAction: NewDeleteItemActionPlugin(serverLogger(log)),
backupItemActionV2: NewBackupItemActionPlugin(serverLogger(log)),
volumeSnapshotterV2: NewVolumeSnapshotterPlugin(serverLogger(log)),
objectStoreV2: NewObjectStorePlugin(serverLogger(log)),
restoreItemActionV2: NewRestoreItemActionPlugin(serverLogger(log)),
deleteItemActionV2: NewDeleteItemActionPlugin(serverLogger(log)),
}
}
@@ -177,6 +226,67 @@ func (s *server) RegisterDeleteItemActions(m map[string]HandlerInitializer) Serv
return s
}
// Version 2
func (s *server) RegisterBackupItemActionV2(name string, initializer HandlerInitializer) Server {
s.backupItemActionV2.register(name, initializer)
return s
}
func (s *server) RegisterBackupItemActionsV2(m map[string]HandlerInitializer) Server {
for name := range m {
s.RegisterBackupItemActionV2(name, m[name])
}
return s
}
func (s *server) RegisterVolumeSnapshotterV2(name string, initializer HandlerInitializer) Server {
s.volumeSnapshotterV2.register(name, initializer)
return s
}
func (s *server) RegisterVolumeSnapshottersV2(m map[string]HandlerInitializer) Server {
for name := range m {
s.RegisterVolumeSnapshotterV2(name, m[name])
}
return s
}
func (s *server) RegisterObjectStoreV2(name string, initializer HandlerInitializer) Server {
s.objectStoreV2.register(name, initializer)
return s
}
func (s *server) RegisterObjectStoresV2(m map[string]HandlerInitializer) Server {
for name := range m {
s.RegisterObjectStoreV2(name, m[name])
}
return s
}
func (s *server) RegisterRestoreItemActionV2(name string, initializer HandlerInitializer) Server {
s.restoreItemActionV2.register(name, initializer)
return s
}
func (s *server) RegisterRestoreItemActionsV2(m map[string]HandlerInitializer) Server {
for name := range m {
s.RegisterRestoreItemActionV2(name, m[name])
}
return s
}
func (s *server) RegisterDeleteItemActionV2(name string, initializer HandlerInitializer) Server {
s.deleteItemActionV2.register(name, initializer)
return s
}
func (s *server) RegisterDeleteItemActionsV2(m map[string]HandlerInitializer) Server {
for name := range m {
s.RegisterDeleteItemActionV2(name, m[name])
}
return s
}
// getNames returns a list of PluginIdentifiers registered with plugin.
func getNames(command string, kind PluginKind, plugin Interface) []PluginIdentifier {
var pluginIdentifiers []PluginIdentifier
@@ -206,6 +316,12 @@ func (s *server) Serve() {
pluginIdentifiers = append(pluginIdentifiers, getNames(command, PluginKindObjectStore, s.objectStore)...)
pluginIdentifiers = append(pluginIdentifiers, getNames(command, PluginKindRestoreItemAction, s.restoreItemAction)...)
pluginIdentifiers = append(pluginIdentifiers, getNames(command, PluginKindDeleteItemAction, s.deleteItemAction)...)
// Version 2
pluginIdentifiers = append(pluginIdentifiers, getNames(command, PluginKindBackupItemActionV2, s.backupItemActionV2)...)
pluginIdentifiers = append(pluginIdentifiers, getNames(command, PluginKindVolumeSnapshotterV2, s.volumeSnapshotterV2)...)
pluginIdentifiers = append(pluginIdentifiers, getNames(command, PluginKindObjectStoreV2, s.objectStoreV2)...)
pluginIdentifiers = append(pluginIdentifiers, getNames(command, PluginKindRestoreItemActionV2, s.restoreItemActionV2)...)
pluginIdentifiers = append(pluginIdentifiers, getNames(command, PluginKindDeleteItemActionV2, s.deleteItemActionV2)...)
pluginLister := NewPluginLister(pluginIdentifiers...)
@@ -218,6 +334,12 @@ func (s *server) Serve() {
string(PluginKindPluginLister): NewPluginListerPlugin(pluginLister),
string(PluginKindRestoreItemAction): s.restoreItemAction,
string(PluginKindDeleteItemAction): s.deleteItemAction,
// Version 2
string(PluginKindBackupItemActionV2): s.backupItemActionV2,
string(PluginKindVolumeSnapshotterV2): s.volumeSnapshotterV2,
string(PluginKindObjectStoreV2): s.objectStoreV2,
string(PluginKindRestoreItemActionV2): s.restoreItemActionV2,
string(PluginKindDeleteItemActionV2): s.deleteItemActionV2,
},
GRPCServer: plugin.DefaultGRPCServer,
})

View File

@@ -53,12 +53,19 @@ func newVolumeSnapshotterGRPCClient(base *clientBase, clientConn *grpc.ClientCon
// configuration key-value pairs. It returns an error if the VolumeSnapshotter
// cannot be initialized from the provided config.
func (c *VolumeSnapshotterGRPCClient) Init(config map[string]string) error {
return c.InitV2(context.Background(), config)
}
// InitV2 prepares the VolumeSnapshotter for usage using the provided map of
// configuration key-value pairs. It returns an error if the VolumeSnapshotter
// cannot be initialized from the provided config.
func (c *VolumeSnapshotterGRPCClient) InitV2(ctx context.Context, config map[string]string) error {
req := &proto.VolumeSnapshotterInitRequest{
Plugin: c.plugin,
Config: config,
}
if _, err := c.grpcClient.Init(context.Background(), req); err != nil {
if _, err := c.grpcClient.Init(ctx, req); err != nil {
return fromGRPCError(err)
}
@@ -67,7 +74,14 @@ func (c *VolumeSnapshotterGRPCClient) Init(config map[string]string) error {
// CreateVolumeFromSnapshot creates a new block volume, initialized from the provided snapshot,
// and with the specified type and IOPS (if using provisioned IOPS).
func (c *VolumeSnapshotterGRPCClient) CreateVolumeFromSnapshot(snapshotID, volumeType, volumeAZ string, iops *int64) (string, error) {
func (c *VolumeSnapshotterGRPCClient) CreateVolumeFromSnapshot(
snapshotID, volumeType, volumeAZ string, iops *int64) (string, error) {
return c.CreateVolumeFromSnapshotV2(context.Background(), snapshotID, volumeType, volumeAZ, iops)
}
func (c *VolumeSnapshotterGRPCClient) CreateVolumeFromSnapshotV2(
ctx context.Context, snapshotID, volumeType, volumeAZ string, iops *int64) (string, error) {
req := &proto.CreateVolumeRequest{
Plugin: c.plugin,
SnapshotID: snapshotID,
@@ -81,7 +95,7 @@ func (c *VolumeSnapshotterGRPCClient) CreateVolumeFromSnapshot(snapshotID, volum
req.Iops = *iops
}
res, err := c.grpcClient.CreateVolumeFromSnapshot(context.Background(), req)
res, err := c.grpcClient.CreateVolumeFromSnapshot(ctx, req)
if err != nil {
return "", fromGRPCError(err)
}
@@ -92,13 +106,19 @@ func (c *VolumeSnapshotterGRPCClient) CreateVolumeFromSnapshot(snapshotID, volum
// GetVolumeInfo returns the type and IOPS (if using provisioned IOPS) for a specified block
// volume.
func (c *VolumeSnapshotterGRPCClient) GetVolumeInfo(volumeID, volumeAZ string) (string, *int64, error) {
return c.GetVolumeInfoV2(context.Background(), volumeID, volumeAZ)
}
func (c *VolumeSnapshotterGRPCClient) GetVolumeInfoV2(
ctx context.Context, volumeID, volumeAZ string) (string, *int64, error) {
req := &proto.GetVolumeInfoRequest{
Plugin: c.plugin,
VolumeID: volumeID,
VolumeAZ: volumeAZ,
}
res, err := c.grpcClient.GetVolumeInfo(context.Background(), req)
res, err := c.grpcClient.GetVolumeInfo(ctx, req)
if err != nil {
return "", nil, fromGRPCError(err)
}
@@ -114,6 +134,11 @@ func (c *VolumeSnapshotterGRPCClient) GetVolumeInfo(volumeID, volumeAZ string) (
// CreateSnapshot creates a snapshot of the specified block volume, and applies the provided
// set of tags to the snapshot.
func (c *VolumeSnapshotterGRPCClient) CreateSnapshot(volumeID, volumeAZ string, tags map[string]string) (string, error) {
return c.CreateSnapshotV2(context.Background(), volumeID, volumeID, tags)
}
func (c *VolumeSnapshotterGRPCClient) CreateSnapshotV2(
ctx context.Context, volumeID, volumeAZ string, tags map[string]string) (string, error) {
req := &proto.CreateSnapshotRequest{
Plugin: c.plugin,
VolumeID: volumeID,
@@ -121,7 +146,7 @@ func (c *VolumeSnapshotterGRPCClient) CreateSnapshot(volumeID, volumeAZ string,
Tags: tags,
}
res, err := c.grpcClient.CreateSnapshot(context.Background(), req)
res, err := c.grpcClient.CreateSnapshot(ctx, req)
if err != nil {
return "", fromGRPCError(err)
}
@@ -131,12 +156,17 @@ func (c *VolumeSnapshotterGRPCClient) CreateSnapshot(volumeID, volumeAZ string,
// DeleteSnapshot deletes the specified volume snapshot.
func (c *VolumeSnapshotterGRPCClient) DeleteSnapshot(snapshotID string) error {
return c.DeleteSnapshotV2(context.Background(), snapshotID)
}
func (c *VolumeSnapshotterGRPCClient) DeleteSnapshotV2(
ctx context.Context, snapshotID string) error {
req := &proto.DeleteSnapshotRequest{
Plugin: c.plugin,
SnapshotID: snapshotID,
}
if _, err := c.grpcClient.DeleteSnapshot(context.Background(), req); err != nil {
if _, err := c.grpcClient.DeleteSnapshot(ctx, req); err != nil {
return fromGRPCError(err)
}
@@ -144,6 +174,11 @@ func (c *VolumeSnapshotterGRPCClient) DeleteSnapshot(snapshotID string) error {
}
func (c *VolumeSnapshotterGRPCClient) GetVolumeID(pv runtime.Unstructured) (string, error) {
return c.GetVolumeIDV2(context.Background(), pv)
}
func (c *VolumeSnapshotterGRPCClient) GetVolumeIDV2(
ctx context.Context, pv runtime.Unstructured) (string, error) {
encodedPV, err := json.Marshal(pv.UnstructuredContent())
if err != nil {
return "", errors.WithStack(err)
@@ -154,7 +189,7 @@ func (c *VolumeSnapshotterGRPCClient) GetVolumeID(pv runtime.Unstructured) (stri
PersistentVolume: encodedPV,
}
resp, err := c.grpcClient.GetVolumeID(context.Background(), req)
resp, err := c.grpcClient.GetVolumeID(ctx, req)
if err != nil {
return "", fromGRPCError(err)
}
@@ -163,6 +198,11 @@ func (c *VolumeSnapshotterGRPCClient) GetVolumeID(pv runtime.Unstructured) (stri
}
func (c *VolumeSnapshotterGRPCClient) SetVolumeID(pv runtime.Unstructured, volumeID string) (runtime.Unstructured, error) {
return c.SetVolumeIDV2(context.Background(), pv, volumeID)
}
func (c *VolumeSnapshotterGRPCClient) SetVolumeIDV2(
ctx context.Context, pv runtime.Unstructured, volumeID string) (runtime.Unstructured, error) {
encodedPV, err := json.Marshal(pv.UnstructuredContent())
if err != nil {
return nil, errors.WithStack(err)
@@ -174,7 +214,7 @@ func (c *VolumeSnapshotterGRPCClient) SetVolumeID(pv runtime.Unstructured, volum
VolumeID: volumeID,
}
resp, err := c.grpcClient.SetVolumeID(context.Background(), req)
resp, err := c.grpcClient.SetVolumeID(ctx, req)
if err != nil {
return nil, fromGRPCError(err)
}

View File

@@ -24,7 +24,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
proto "github.com/vmware-tanzu/velero/pkg/plugin/generated"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
volumesnapshotterv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v2"
)
// VolumeSnapshotterGRPCServer implements the proto-generated VolumeSnapshotterServer interface, and accepts
@@ -33,13 +33,13 @@ type VolumeSnapshotterGRPCServer struct {
mux *serverMux
}
func (s *VolumeSnapshotterGRPCServer) getImpl(name string) (velero.VolumeSnapshotter, error) {
func (s *VolumeSnapshotterGRPCServer) getImpl(name string) (volumesnapshotterv2.VolumeSnapshotter, error) {
impl, err := s.mux.getHandler(name)
if err != nil {
return nil, err
}
volumeSnapshotter, ok := impl.(velero.VolumeSnapshotter)
volumeSnapshotter, ok := impl.(volumesnapshotterv2.VolumeSnapshotter)
if !ok {
return nil, errors.Errorf("%T is not a volume snapshotter", impl)
}
@@ -62,7 +62,7 @@ func (s *VolumeSnapshotterGRPCServer) Init(ctx context.Context, req *proto.Volum
return nil, newGRPCError(err)
}
if err := impl.Init(req.Config); err != nil {
if err := impl.InitV2(ctx, req.Config); err != nil {
return nil, newGRPCError(err)
}
@@ -92,7 +92,7 @@ func (s *VolumeSnapshotterGRPCServer) CreateVolumeFromSnapshot(ctx context.Conte
iops = &req.Iops
}
volumeID, err := impl.CreateVolumeFromSnapshot(snapshotID, volumeType, volumeAZ, iops)
volumeID, err := impl.CreateVolumeFromSnapshotV2(ctx, snapshotID, volumeType, volumeAZ, iops)
if err != nil {
return nil, newGRPCError(err)
}
@@ -114,7 +114,7 @@ func (s *VolumeSnapshotterGRPCServer) GetVolumeInfo(ctx context.Context, req *pr
return nil, newGRPCError(err)
}
volumeType, iops, err := impl.GetVolumeInfo(req.VolumeID, req.VolumeAZ)
volumeType, iops, err := impl.GetVolumeInfoV2(ctx, req.VolumeID, req.VolumeAZ)
if err != nil {
return nil, newGRPCError(err)
}
@@ -144,7 +144,7 @@ func (s *VolumeSnapshotterGRPCServer) CreateSnapshot(ctx context.Context, req *p
return nil, newGRPCError(err)
}
snapshotID, err := impl.CreateSnapshot(req.VolumeID, req.VolumeAZ, req.Tags)
snapshotID, err := impl.CreateSnapshotV2(ctx, req.VolumeID, req.VolumeAZ, req.Tags)
if err != nil {
return nil, newGRPCError(err)
}
@@ -165,7 +165,7 @@ func (s *VolumeSnapshotterGRPCServer) DeleteSnapshot(ctx context.Context, req *p
return nil, newGRPCError(err)
}
if err := impl.DeleteSnapshot(req.SnapshotID); err != nil {
if err := impl.DeleteSnapshotV2(ctx, req.SnapshotID); err != nil {
return nil, newGRPCError(err)
}
@@ -190,7 +190,7 @@ func (s *VolumeSnapshotterGRPCServer) GetVolumeID(ctx context.Context, req *prot
return nil, newGRPCError(errors.WithStack(err))
}
volumeID, err := impl.GetVolumeID(&pv)
volumeID, err := impl.GetVolumeIDV2(ctx, &pv)
if err != nil {
return nil, newGRPCError(err)
}
@@ -215,7 +215,7 @@ func (s *VolumeSnapshotterGRPCServer) SetVolumeID(ctx context.Context, req *prot
return nil, newGRPCError(errors.WithStack(err))
}
updatedPV, err := impl.SetVolumeID(&pv, req.VolumeID)
updatedPV, err := impl.SetVolumeIDV2(ctx, &pv, req.VolumeID)
if err != nil {
return nil, newGRPCError(err)
}

View File

@@ -4,7 +4,12 @@ package mocks
import (
mock "github.com/stretchr/testify/mock"
velero "github.com/vmware-tanzu/velero/pkg/plugin/velero"
backupitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v2"
deleteitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/deleteitemaction/v2"
objectstorev2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/objectstore/v2"
restoreitemactionv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2"
volumesnapshotterv2 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v2"
)
// Manager is an autogenerated mock type for the Manager type
@@ -18,15 +23,15 @@ func (_m *Manager) CleanupClients() {
}
// GetBackupItemAction provides a mock function with given fields: name
func (_m *Manager) GetBackupItemAction(name string) (velero.BackupItemAction, error) {
func (_m *Manager) GetBackupItemAction(name string) (backupitemactionv2.BackupItemAction, error) {
ret := _m.Called(name)
var r0 velero.BackupItemAction
if rf, ok := ret.Get(0).(func(string) velero.BackupItemAction); ok {
var r0 backupitemactionv2.BackupItemAction
if rf, ok := ret.Get(0).(func(string) backupitemactionv2.BackupItemAction); ok {
r0 = rf(name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(velero.BackupItemAction)
r0 = ret.Get(0).(backupitemactionv2.BackupItemAction)
}
}
@@ -41,15 +46,15 @@ func (_m *Manager) GetBackupItemAction(name string) (velero.BackupItemAction, er
}
// GetBackupItemActions provides a mock function with given fields:
func (_m *Manager) GetBackupItemActions() ([]velero.BackupItemAction, error) {
func (_m *Manager) GetBackupItemActions() ([]backupitemactionv2.BackupItemAction, error) {
ret := _m.Called()
var r0 []velero.BackupItemAction
if rf, ok := ret.Get(0).(func() []velero.BackupItemAction); ok {
var r0 []backupitemactionv2.BackupItemAction
if rf, ok := ret.Get(0).(func() []backupitemactionv2.BackupItemAction); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]velero.BackupItemAction)
r0 = ret.Get(0).([]backupitemactionv2.BackupItemAction)
}
}
@@ -64,15 +69,15 @@ func (_m *Manager) GetBackupItemActions() ([]velero.BackupItemAction, error) {
}
// GetDeleteItemAction provides a mock function with given fields: name
func (_m *Manager) GetDeleteItemAction(name string) (velero.DeleteItemAction, error) {
func (_m *Manager) GetDeleteItemAction(name string) (deleteitemactionv2.DeleteItemAction, error) {
ret := _m.Called(name)
var r0 velero.DeleteItemAction
if rf, ok := ret.Get(0).(func(string) velero.DeleteItemAction); ok {
var r0 deleteitemactionv2.DeleteItemAction
if rf, ok := ret.Get(0).(func(string) deleteitemactionv2.DeleteItemAction); ok {
r0 = rf(name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(velero.DeleteItemAction)
r0 = ret.Get(0).(deleteitemactionv2.DeleteItemAction)
}
}
@@ -87,15 +92,15 @@ func (_m *Manager) GetDeleteItemAction(name string) (velero.DeleteItemAction, er
}
// GetDeleteItemActions provides a mock function with given fields:
func (_m *Manager) GetDeleteItemActions() ([]velero.DeleteItemAction, error) {
func (_m *Manager) GetDeleteItemActions() ([]deleteitemactionv2.DeleteItemAction, error) {
ret := _m.Called()
var r0 []velero.DeleteItemAction
if rf, ok := ret.Get(0).(func() []velero.DeleteItemAction); ok {
var r0 []deleteitemactionv2.DeleteItemAction
if rf, ok := ret.Get(0).(func() []deleteitemactionv2.DeleteItemAction); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]velero.DeleteItemAction)
r0 = ret.Get(0).([]deleteitemactionv2.DeleteItemAction)
}
}
@@ -110,15 +115,15 @@ func (_m *Manager) GetDeleteItemActions() ([]velero.DeleteItemAction, error) {
}
// GetObjectStore provides a mock function with given fields: name
func (_m *Manager) GetObjectStore(name string) (velero.ObjectStore, error) {
func (_m *Manager) GetObjectStore(name string) (objectstorev2.ObjectStore, error) {
ret := _m.Called(name)
var r0 velero.ObjectStore
if rf, ok := ret.Get(0).(func(string) velero.ObjectStore); ok {
var r0 objectstorev2.ObjectStore
if rf, ok := ret.Get(0).(func(string) objectstorev2.ObjectStore); ok {
r0 = rf(name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(velero.ObjectStore)
r0 = ret.Get(0).(objectstorev2.ObjectStore)
}
}
@@ -133,15 +138,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) (restoreitemactionv2.RestoreItemAction, error) {
ret := _m.Called(name)
var r0 velero.RestoreItemAction
if rf, ok := ret.Get(0).(func(string) velero.RestoreItemAction); ok {
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).(velero.RestoreItemAction)
r0 = ret.Get(0).(restoreitemactionv2.RestoreItemAction)
}
}
@@ -156,15 +161,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() ([]restoreitemactionv2.RestoreItemAction, error) {
ret := _m.Called()
var r0 []velero.RestoreItemAction
if rf, ok := ret.Get(0).(func() []velero.RestoreItemAction); ok {
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).([]velero.RestoreItemAction)
r0 = ret.Get(0).([]restoreitemactionv2.RestoreItemAction)
}
}
@@ -179,15 +184,15 @@ func (_m *Manager) GetRestoreItemActions() ([]velero.RestoreItemAction, error) {
}
// GetVolumeSnapshotter provides a mock function with given fields: name
func (_m *Manager) GetVolumeSnapshotter(name string) (velero.VolumeSnapshotter, error) {
func (_m *Manager) GetVolumeSnapshotter(name string) (volumesnapshotterv2.VolumeSnapshotter, error) {
ret := _m.Called(name)
var r0 velero.VolumeSnapshotter
if rf, ok := ret.Get(0).(func(string) velero.VolumeSnapshotter); ok {
var r0 volumesnapshotterv2.VolumeSnapshotter
if rf, ok := ret.Get(0).(func(string) volumesnapshotterv2.VolumeSnapshotter); ok {
r0 = rf(name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(velero.VolumeSnapshotter)
r0 = ret.Get(0).(volumesnapshotterv2.VolumeSnapshotter)
}
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2017 the Velero contributors.
Copyright 2021 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,13 +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"
"k8s.io/apimachinery/pkg/runtime/schema"
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
)
// BackupItemAction is an actor that performs an operation on an individual item being backed up.
@@ -28,18 +28,12 @@ type BackupItemAction interface {
// AppliesTo returns information about which resources this action should be invoked for.
// A BackupItemAction'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 backed up,
// including mutating the item itself prior to backup. The item (unmodified or modified)
// should be returned, along with an optional slice of ResourceIdentifiers specifying
// additional related items that should be backed up.
Execute(item runtime.Unstructured, backup *api.Backup) (runtime.Unstructured, []ResourceIdentifier, error)
}
// ResourceIdentifier describes a single item by its group, resource, namespace, and name.
type ResourceIdentifier struct {
schema.GroupResource
Namespace string
Name string
Execute(item runtime.Unstructured, backup *api.Backup) (
runtime.Unstructured, []velero.ResourceIdentifier, error)
}

View File

@@ -0,0 +1,38 @@
/*
Copyright 2021 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 (
"k8s.io/apimachinery/pkg/runtime"
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
v1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/backupitemaction/v1"
"context"
)
type BackupItemAction interface {
v1.BackupItemAction
// ExecuteV2 allows the ItemAction to perform arbitrary logic with the item being backed up,
// including mutating the item itself prior to backup. The item (unmodified or modified)
// should be returned, along with an optional slice of ResourceIdentifiers specifying
// additional related items that should be backed up.
ExecuteV2(ctx context.Context, item runtime.Unstructured,
backup *api.Backup) (runtime.Unstructured, []velero.ResourceIdentifier, error)
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2020 the Velero contributors.
Copyright 2020, 2021 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.
@@ -22,20 +22,6 @@ import (
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
)
// DeleteItemAction is an actor that performs an operation on an individual item being restored.
type DeleteItemAction interface {
// AppliesTo returns information about which resources this action should be invoked for.
// A DeleteItemAction's Execute function will only be invoked on items that match the returned
// selector. A zero-valued ResourceSelector matches all resources.
AppliesTo() (ResourceSelector, error)
// Execute allows the ItemAction to perform arbitrary logic with the item being deleted.
// An error should be returned if there were problems with the deletion process, but the
// overall deletion process cannot be stopped.
// Returned errors are logged.
Execute(input *DeleteItemActionExecuteInput) error
}
// DeleteItemActionExecuteInput contains the input parameters for the ItemAction's Execute function.
type DeleteItemActionExecuteInput struct {
// Item is the item taken from the pristine backed up version of resource.

View File

@@ -0,0 +1,35 @@
/*
Copyright 2021 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/vmware-tanzu/velero/pkg/plugin/velero"
)
// DeleteItemAction is an actor that performs an operation on an individual item being restored.
type DeleteItemAction interface {
// AppliesTo returns information about which resources this action should be invoked for.
// A DeleteItemAction'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 deleted.
// An error should be returned if there were problems with the deletion process, but the
// overall deletion process cannot be stopped.
// Returned errors are logged.
Execute(input *velero.DeleteItemActionExecuteInput) error
}

View File

@@ -0,0 +1,34 @@
/*
Copyright 2021 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/vmware-tanzu/velero/pkg/plugin/velero"
v1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/deleteitemaction/v1"
"context"
)
type DeleteItemAction interface {
v1.DeleteItemAction
// ExecuteV2 allows the ItemAction to perform arbitrary logic with the item being deleted.
// An error should be returned if there were problems with the deletion process, but the
// overall deletion process cannot be stopped.
// Returned errors are logged.
ExecuteV2(ctx context.Context, input *velero.DeleteItemActionExecuteInput) error
}

View File

@@ -4,7 +4,7 @@ package mocks
import (
mock "github.com/stretchr/testify/mock"
velero "github.com/vmware-tanzu/velero/pkg/plugin/velero"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
)
// DeleteItemAction is an autogenerated mock type for the DeleteItemAction type
@@ -46,3 +46,8 @@ func (_m *DeleteItemAction) Execute(input *velero.DeleteItemActionExecuteInput)
return r0
}
// ExecuteV2 provides a mock function with given fields: ctx, input
func (_m *DeleteItemAction) ExecuteV2(ctx context.Context, input *velero.DeleteItemActionExecuteInput) error {
return _m.Execute(input)
}

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package velero
package v1
import (
"io"

View File

@@ -0,0 +1,68 @@
/*
Copyright 2021 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 (
v1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/objectstore/v1"
"context"
"io"
"time"
)
type ObjectStore interface {
v1.ObjectStore
// InitV2 prepares the ObjectStore for usage using the provided map of
// configuration key-value pairs. It returns an error if the ObjectStore
// cannot be initialized from the provided config.
InitV2(ctx context.Context, config map[string]string) error
// PutObjectV2 creates a new object using the data in body within the specified
// object storage bucket with the given key.
PutObjectV2(ctx context.Context, bucket, key string, body io.Reader) error
// ObjectExistsV2 checks if there is an object with the given key in the object storage bucket.
ObjectExistsV2(ctx context.Context, bucket, key string) (bool, error)
// GetObjectV2 retrieves the object with the given key from the specified
// bucket in object storage.
GetObjectV2(ctx context.Context, bucket, key string) (io.ReadCloser, error)
// ListCommonPrefixesV2 gets a list of all object key prefixes that start with
// the specified prefix and stop at the next instance of the provided delimiter.
//
// For example, if the bucket contains the following keys:
// a-prefix/foo-1/bar
// a-prefix/foo-1/baz
// a-prefix/foo-2/baz
// some-other-prefix/foo-3/bar
// and the provided prefix arg is "a-prefix/", and the delimiter is "/",
// this will return the slice {"a-prefix/foo-1/", "a-prefix/foo-2/"}.
ListCommonPrefixesV2(ctx context.Context, bucket, prefix, delimiter string) ([]string, error)
// ListObjectsV2 gets a list of all keys in the specified bucket
// that have the given prefix.
ListObjectsV2(ctx context.Context, bucket, prefix string) ([]string, error)
// DeleteObjectV2 removes the object with the specified key from the given
// bucket.
DeleteObjectV2(ctx context.Context, bucket, key string) error
// CreateSignedURLV2 creates a pre-signed URL for the given bucket and key that expires after ttl.
CreateSignedURLV2(ctx context.Context, bucket, key string, ttl time.Duration) (string, error)
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2017, 2019 the Velero contributors.
Copyright 2017, 2019, 2021 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.
@@ -22,22 +22,6 @@ import (
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
)
// 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() (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)
// should be returned, along with an optional slice of ResourceIdentifiers specifying additional
// related items that should be restored, a warning (which will be logged but will not prevent
// the item from being restored) or error (which will be logged and will prevent the item
// from being restored) if applicable.
Execute(input *RestoreItemActionExecuteInput) (*RestoreItemActionExecuteOutput, error)
}
// RestoreItemActionExecuteInput contains the input parameters for the ItemAction's Execute function.
type RestoreItemActionExecuteInput struct {
// Item is the item being restored. It is likely different from the pristine backed up version

View File

@@ -0,0 +1,37 @@
/*
Copyright 2021 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/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 item (unmodified or modified)
// should be returned, along with an optional slice of ResourceIdentifiers specifying additional
// related items that should be restored, a warning (which will be logged but will not prevent
// the item from being restored) or error (which will be logged and will prevent the item
// from being restored) if applicable.
Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error)
}

View File

@@ -0,0 +1,37 @@
/*
Copyright 2021 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/vmware-tanzu/velero/pkg/plugin/velero"
v1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v1"
"context"
)
type RestoreItemAction interface {
v1.RestoreItemAction
// ExecuteV2 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)
// should be returned, along with an optional slice of ResourceIdentifiers specifying additional
// related items that should be restored, a warning (which will be logged but will not prevent
// the item from being restored) or error (which will be logged and will prevent the item
// from being restored) if applicable.
ExecuteV2(ctx context.Context,
input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error)
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2019 the Velero contributors.
Copyright 2019, 2021 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.
@@ -20,6 +20,10 @@ limitations under the License.
// plugins of any type can be implemented.
package velero
import (
"k8s.io/apimachinery/pkg/runtime/schema"
)
// ResourceSelector is a collection of included/excluded namespaces,
// included/excluded resources, and a label-selector that can be used
// to match a set of items from a cluster.
@@ -48,3 +52,10 @@ type ResourceSelector struct {
// for details on syntax.
LabelSelector string
}
// ResourceIdentifier describes a single item by its group, resource, namespace, and name.
type ResourceIdentifier struct {
schema.GroupResource
Namespace string
Name string
}

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package velero
package v1
import (
"k8s.io/apimachinery/pkg/runtime"

View File

@@ -0,0 +1,59 @@
/*
Copyright 2021 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 (
"k8s.io/apimachinery/pkg/runtime"
v1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v1"
"context"
)
type VolumeSnapshotter interface {
v1.VolumeSnapshotter
// InitV2 prepares the VolumeSnapshotter for usage using the provided map of
// configuration key-value pairs. It returns an error if the VolumeSnapshotter
// cannot be initialized from the provided config.
InitV2(ctx context.Context, config map[string]string) error
// CreateVolumeFromSnapshotV2 creates a new volume in the specified
// availability zone, initialized from the provided snapshot,
// and with the specified type and IOPS (if using provisioned IOPS).
CreateVolumeFromSnapshotV2(ctx context.Context,
snapshotID, volumeType, volumeAZ string, iops *int64) (volumeID string, err error)
// GetVolumeIDV2 returns the cloud provider specific identifier for the PersistentVolume.
GetVolumeIDV2(ctx context.Context, pv runtime.Unstructured) (string, error)
// SetVolumeIDV2 sets the cloud provider specific identifier for the PersistentVolume.
SetVolumeIDV2(ctx context.Context,
pv runtime.Unstructured, volumeID string) (runtime.Unstructured, error)
// GetVolumeInfoV2 returns the type and IOPS (if using provisioned IOPS) for
// the specified volume in the given availability zone.
GetVolumeInfoV2(ctx context.Context, volumeID, volumeAZ string) (string, *int64, error)
// CreateSnapshotV2 creates a snapshot of the specified volume, and applies the provided
// set of tags to the snapshot.
CreateSnapshotV2(ctx context.Context,
volumeID, volumeAZ string, tags map[string]string) (snapshotID string, err error)
// DeleteSnapshotV2 deletes the specified volume snapshot.
DeleteSnapshotV2(ctx context.Context, snapshotID string) error
}

View File

@@ -57,6 +57,8 @@ import (
"github.com/vmware-tanzu/velero/pkg/kuberesource"
"github.com/vmware-tanzu/velero/pkg/label"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
restoreitemaction "github.com/vmware-tanzu/velero/pkg/plugin/velero/restoreitemaction/v2"
volumesnapshotter "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v2"
"github.com/vmware-tanzu/velero/pkg/podexec"
"github.com/vmware-tanzu/velero/pkg/restic"
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
@@ -75,7 +77,7 @@ const KubeAnnBoundByController = "pv.kubernetes.io/bound-by-controller"
const KubeAnnDynamicallyProvisioned = "pv.kubernetes.io/provisioned-by"
type VolumeSnapshotterGetter interface {
GetVolumeSnapshotter(name string) (velero.VolumeSnapshotter, error)
GetVolumeSnapshotter(name string) (volumesnapshotter.VolumeSnapshotter, error)
}
type Request struct {
@@ -92,7 +94,7 @@ type Request struct {
type Restorer interface {
// Restore restores the backup data from backupReader, returning warnings and errors.
Restore(req Request,
actions []velero.RestoreItemAction,
actions []restoreitemaction.RestoreItemAction,
snapshotLocationLister listers.VolumeSnapshotLocationLister,
volumeSnapshotterGetter VolumeSnapshotterGetter,
) (Result, Result)
@@ -158,7 +160,7 @@ func NewKubernetesRestorer(
// respectively, summarizing info about the restore.
func (kr *kubernetesRestorer) Restore(
req Request,
actions []velero.RestoreItemAction,
actions []restoreitemaction.RestoreItemAction,
snapshotLocationLister listers.VolumeSnapshotLocationLister,
volumeSnapshotterGetter VolumeSnapshotterGetter,
) (Result, Result) {
@@ -278,14 +280,14 @@ func (kr *kubernetesRestorer) Restore(
}
type resolvedAction struct {
velero.RestoreItemAction
restoreitemaction.RestoreItemAction
resourceIncludesExcludes *collections.IncludesExcludes
namespaceIncludesExcludes *collections.IncludesExcludes
selector labels.Selector
}
func resolveActions(actions []velero.RestoreItemAction, helper discovery.Helper) ([]resolvedAction, error) {
func resolveActions(actions []restoreitemaction.RestoreItemAction, helper discovery.Helper) ([]resolvedAction, error) {
var resolved []resolvedAction
for _, action := range actions {