diff --git a/pkg/plugin/clientmgmt/manager.go b/pkg/plugin/clientmgmt/manager.go index ca5de4003..0266bc736 100644 --- a/pkg/plugin/clientmgmt/manager.go +++ b/pkg/plugin/clientmgmt/manager.go @@ -18,6 +18,7 @@ package clientmgmt import ( "errors" + "fmt" "strings" "sync" @@ -96,7 +97,23 @@ func (m *manager) CleanupClients() { m.lock.Unlock() } -// getRestartableProcessV2 returns a restartableProcess for a plugin identified by kind and name, creating a +func (m *manager) getRestartableProcessOfKinds( + kinds []framework.PluginKind, name string) (RestartableProcess, framework.PluginKind, error) { + var err error + var process RestartableProcess + var kind framework.PluginKind + for _, kind = range kinds { + process, err = m.getRestartableProcess(kind, name) + if err == nil { + return process, kind, nil + } else if !errors.Is(err, &pluginNotFoundError{}) { + return nil, kind, err + } + } + return nil, kind, err +} + +// getRestartableProcess returns a restartableProcess for a plugin identified by kind and name, creating a // restartableProcess if it is the first time it has been requested. func (m *manager) getRestartableProcess(kind framework.PluginKind, name string) (RestartableProcess, error) { m.lock.Lock() @@ -133,61 +150,57 @@ func (m *manager) getRestartableProcess(kind framework.PluginKind, name string) return restartableProcess, nil } +type NewObjectStoreFunction func(string, RestartableProcess) objectstorev2.ObjectStore + +var ObjectStoreFunctions = map[framework.PluginKind]NewObjectStoreFunction{ + framework.PluginKindObjectStoreV2: newRestartableObjectStoreV2, + framework.PluginKindObjectStore: newAdaptedV1ObjectStore, +} + // GetObjectStore returns a restartableObjectStore for name. func (m *manager) GetObjectStore(name string) (objectstorev2.ObjectStore, error) { name = sanitizeName(name) - restartableProcess, err := m.getRestartableProcess(framework.PluginKindObjectStoreV2, name) + restartableProcess, kind, err := m.getRestartableProcessOfKinds(framework.ObjectStoreKinds(), name) if err != nil { - // Check if plugin was not found - if errors.Is(err, &pluginNotFoundError{}) { - // Try again but with previous version - restartableProcess, err := m.getRestartableProcess(framework.PluginKindObjectStore, name) - if err != nil { - // No v1 version found, return - return nil, err - } - // Adapt v1 plugin to v2 - return newAdaptedV1ObjectStore(name, restartableProcess), nil - } else { - return nil, err - } + return nil, err } - return newRestartableObjectStoreV2(name, restartableProcess), nil + + f, ok := ObjectStoreFunctions[kind] + if !ok || f == nil { + err = fmt.Errorf("Unable to create ObjectStore for kind '%s'.", kind) + return nil, err + } + return f(name, restartableProcess), nil +} + +type NewVolumeSnapshotterFunction func(string, RestartableProcess) volumesnapshotterv2.VolumeSnapshotter + +var VolumeSnapshotterFunctions = map[framework.PluginKind]NewVolumeSnapshotterFunction{ + framework.PluginKindVolumeSnapshotterV2: newRestartableVolumeSnapshotterV2, + framework.PluginKindVolumeSnapshotter: newAdaptedV1VolumeSnapshotter, } // GetVolumeSnapshotter returns a restartableVolumeSnapshotter for name. func (m *manager) GetVolumeSnapshotter(name string) (volumesnapshotterv2.VolumeSnapshotter, error) { name = sanitizeName(name) - restartableProcess, err := m.getRestartableProcess(framework.PluginKindVolumeSnapshotterV2, name) + restartableProcess, kind, err := m.getRestartableProcessOfKinds(framework.VolumeSnapshotterKinds(), name) if err != nil { - // Check if plugin was not found - if errors.Is(err, &pluginNotFoundError{}) { - // Try again but with previous version - restartableProcess, err := m.getRestartableProcess(framework.PluginKindVolumeSnapshotter, name) - if err != nil { - // No v1 version found, return - return nil, err - } - // Adapt v1 plugin to v2 - return newAdaptedV1VolumeSnapshotter(name, restartableProcess), nil - } else { - return nil, err - } + return nil, err } - r := newRestartableVolumeSnapshotterV2(name, restartableProcess) - - return r, nil + f, ok := VolumeSnapshotterFunctions[kind] + if !ok || f == nil { + err = fmt.Errorf("Unable to create VolumeSnapshotter for kind '%s'.", kind) + return nil, err + } + return f(name, restartableProcess), nil } // GetBackupItemActions returns all backup item actions as restartableBackupItemActions. func (m *manager) GetBackupItemActions() ([]backupitemactionv2.BackupItemAction, error) { - listv1 := m.registry.List(framework.PluginKindBackupItemAction) - listv2 := m.registry.List(framework.PluginKindBackupItemActionV2) - list := append(listv1, listv2...) - + list := m.registry.ListForKinds(framework.BackupItemActionKinds()) actions := make([]backupitemactionv2.BackupItemAction, 0, len(list)) for i := range list { @@ -204,36 +217,33 @@ func (m *manager) GetBackupItemActions() ([]backupitemactionv2.BackupItemAction, return actions, nil } +type NewBackupItemActionFunction func(string, RestartableProcess) backupitemactionv2.BackupItemAction + +var BackupItemActionFunctions = map[framework.PluginKind]NewBackupItemActionFunction { + framework.PluginKindBackupItemActionV2: newRestartableBackupItemActionV2, + framework.PluginKindBackupItemAction: newAdaptedV1BackupItemAction, +} + // GetBackupItemAction returns a restartableBackupItemAction for name. func (m *manager) GetBackupItemAction(name string) (backupitemactionv2.BackupItemAction, error) { name = sanitizeName(name) - restartableProcess, err := m.getRestartableProcess(framework.PluginKindBackupItemActionV2, name) + restartableProcess, kind, err := m.getRestartableProcessOfKinds(framework.BackupItemActionKinds(), name) if err != nil { - // Check if plugin was not found - if errors.Is(err, &pluginNotFoundError{}) { - // Try again but with previous version - restartableProcess, err := m.getRestartableProcess(framework.PluginKindBackupItemAction, name) - if err != nil { - // No v1 version found, return - return nil, err - } - // Adapt v1 plugin to v2 - return newAdaptedV1BackupItemAction(name, restartableProcess), nil - } else { - return nil, err - } + return nil, err } - r := newRestartableBackupItemActionV2(name, restartableProcess) - return r, nil + f, ok := BackupItemActionFunctions[kind] + if !ok || f == nil { + err = fmt.Errorf("Unable to create BackupItemAction for kind '%s'.", kind) + return nil, err + } + return f(name, restartableProcess), nil } // GetRestoreItemActions returns all restore item actions as restartableRestoreItemActions. func (m *manager) GetRestoreItemActions() ([]restoreitemactionv2.RestoreItemAction, error) { - listv1 := m.registry.List(framework.PluginKindRestoreItemAction) - listv2 := m.registry.List(framework.PluginKindRestoreItemActionV2) - list := append(listv1, listv2...) + list := m.registry.ListForKinds(framework.RestoreItemActionKinds()) actions := make([]restoreitemactionv2.RestoreItemAction, 0, len(list)) @@ -251,36 +261,33 @@ func (m *manager) GetRestoreItemActions() ([]restoreitemactionv2.RestoreItemActi return actions, nil } +type NewRestoreItemActionFunction func(string, RestartableProcess) restoreitemactionv2.RestoreItemAction + +var RestoreItemActionFunctions = map[framework.PluginKind]NewRestoreItemActionFunction { + framework.PluginKindRestoreItemActionV2: newRestartableRestoreItemActionV2, + framework.PluginKindRestoreItemAction: newAdaptedV1RestoreItemAction, +} + // GetRestoreItemAction returns a restartableRestoreItemAction for name. func (m *manager) GetRestoreItemAction(name string) (restoreitemactionv2.RestoreItemAction, error) { name = sanitizeName(name) - restartableProcess, err := m.getRestartableProcess(framework.PluginKindRestoreItemActionV2, name) + restartableProcess, kind, err := m.getRestartableProcessOfKinds(framework.RestoreItemActionKinds(), name) if err != nil { - // Check if plugin was not found - if errors.Is(err, &pluginNotFoundError{}) { - // Try again but with previous version - restartableProcess, err := m.getRestartableProcess(framework.PluginKindRestoreItemAction, name) - if err != nil { - // No v1 version found, return - return nil, err - } - // Adapt v1 plugin to v2 - return newAdaptedV1RestoreItemAction(name, restartableProcess), nil - } else { - return nil, err - } + return nil, err } - r := newRestartableRestoreItemActionV2(name, restartableProcess) - return r, nil + f, ok := RestoreItemActionFunctions[kind] + if !ok || f == nil { + err = fmt.Errorf("Unable to create RestoreItemAction for kind '%s'.", kind) + return nil, err + } + return f(name, restartableProcess), nil } // GetDeleteItemActions returns all delete item actions as restartableDeleteItemActions. func (m *manager) GetDeleteItemActions() ([]deleteitemactionv2.DeleteItemAction, error) { - listv1 := m.registry.List(framework.PluginKindDeleteItemAction) - listv2 := m.registry.List(framework.PluginKindDeleteItemActionV2) - list := append(listv1, listv2...) + list := m.registry.ListForKinds(framework.DeleteItemActionKinds()) actions := make([]deleteitemactionv2.DeleteItemAction, 0, len(list)) @@ -298,29 +305,27 @@ func (m *manager) GetDeleteItemActions() ([]deleteitemactionv2.DeleteItemAction, return actions, nil } +type NewDeleteItemActionFunction func(string, RestartableProcess) deleteitemactionv2.DeleteItemAction +var DeleteItemActionFunctions = map[framework.PluginKind]NewDeleteItemActionFunction { + framework.PluginKindDeleteItemActionV2: newRestartableDeleteItemActionV2, + framework.PluginKindDeleteItemAction: newAdaptedV1DeleteItemAction, +} + // GetDeleteItemAction returns a restartableDeleteItemAction for name. func (m *manager) GetDeleteItemAction(name string) (deleteitemactionv2.DeleteItemAction, error) { name = sanitizeName(name) - restartableProcess, err := m.getRestartableProcess(framework.PluginKindDeleteItemActionV2, name) + restartableProcess, kind, err := m.getRestartableProcessOfKinds(framework.DeleteItemActionKinds(), name) if err != nil { - // Check if plugin was not found - if errors.Is(err, &pluginNotFoundError{}) { - // Try again but with previous version - restartableProcess, err := m.getRestartableProcess(framework.PluginKindDeleteItemAction, name) - if err != nil { - // No v1 version found, return - return nil, err - } - // Adapt v1 plugin to v2 - return newAdaptedV1DeleteItemAction(name, restartableProcess), nil - } else { - return nil, err - } + return nil, err } - r := newRestartableDeleteItemActionV2(name, restartableProcess) - return r, nil + f, ok := DeleteItemActionFunctions[kind] + if !ok || f == nil { + err = fmt.Errorf("Unable to create DeleteItemAction for kind '%s'.", kind) + return nil, err + } + return f(name, restartableProcess), nil } // sanitizeName adds "velero.io" to legacy plugins that weren't namespaced. diff --git a/pkg/plugin/clientmgmt/registry.go b/pkg/plugin/clientmgmt/registry.go index fe8a7f4b4..d32c329b2 100644 --- a/pkg/plugin/clientmgmt/registry.go +++ b/pkg/plugin/clientmgmt/registry.go @@ -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 { diff --git a/pkg/plugin/clientmgmt/restartable_adapted_v1_backup_item_action.go b/pkg/plugin/clientmgmt/restartable_adapted_v1_backup_item_action.go index bacf7f5e6..164a2d026 100644 --- a/pkg/plugin/clientmgmt/restartable_adapted_v1_backup_item_action.go +++ b/pkg/plugin/clientmgmt/restartable_adapted_v1_backup_item_action.go @@ -20,11 +20,12 @@ 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" + "k8s.io/apimachinery/pkg/runtime" ) type restartableAdaptedV1BackupItemAction struct { @@ -33,7 +34,8 @@ type restartableAdaptedV1BackupItemAction struct { } // newAdaptedV1BackupItemAction returns a new restartableAdaptedV1BackupItemAction. -func newAdaptedV1BackupItemAction(name string, sharedPluginProcess RestartableProcess) *restartableAdaptedV1BackupItemAction { +func newAdaptedV1BackupItemAction( + name string, sharedPluginProcess RestartableProcess) backupitemactionv2.BackupItemAction { r := &restartableAdaptedV1BackupItemAction{ key: kindAndName{kind: framework.PluginKindBackupItemAction, name: name}, sharedPluginProcess: sharedPluginProcess, diff --git a/pkg/plugin/clientmgmt/restartable_adapted_v1_object_store.go b/pkg/plugin/clientmgmt/restartable_adapted_v1_object_store.go index a29766b7d..1b891888e 100644 --- a/pkg/plugin/clientmgmt/restartable_adapted_v1_object_store.go +++ b/pkg/plugin/clientmgmt/restartable_adapted_v1_object_store.go @@ -18,12 +18,13 @@ package clientmgmt import ( "context" - "github.com/vmware-tanzu/velero/pkg/plugin/framework" "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 @@ -32,7 +33,7 @@ type restartableAdaptedV1ObjectStore struct { } // newAdaptedV1ObjectStore returns a new restartableAdaptedV1ObjectStore. -func newAdaptedV1ObjectStore(name string, sharedPluginProcess RestartableProcess) *restartableAdaptedV1ObjectStore { +func newAdaptedV1ObjectStore(name string, sharedPluginProcess RestartableProcess) objectstorev2.ObjectStore { key := kindAndName{kind: framework.PluginKindObjectStore, name: name} r := &restartableAdaptedV1ObjectStore{ restartableObjectStore: restartableObjectStore{ diff --git a/pkg/plugin/clientmgmt/restartable_adapted_v1_restore_item_action.go b/pkg/plugin/clientmgmt/restartable_adapted_v1_restore_item_action.go index c333aadb0..564c149d0 100644 --- a/pkg/plugin/clientmgmt/restartable_adapted_v1_restore_item_action.go +++ b/pkg/plugin/clientmgmt/restartable_adapted_v1_restore_item_action.go @@ -23,6 +23,7 @@ import ( "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 { @@ -32,7 +33,8 @@ type restartableAdaptedV1RestoreItemAction struct { } // newRestartableRestoreItemAction returns a new restartableRestoreItemAction. -func newAdaptedV1RestoreItemAction(name string, sharedPluginProcess RestartableProcess) *restartableAdaptedV1RestoreItemAction { +func newAdaptedV1RestoreItemAction( + name string, sharedPluginProcess RestartableProcess) restoreitemactionv2.RestoreItemAction { r := &restartableAdaptedV1RestoreItemAction{ key: kindAndName{kind: framework.PluginKindRestoreItemAction, name: name}, sharedPluginProcess: sharedPluginProcess, diff --git a/pkg/plugin/clientmgmt/restartable_backup_item_action.go b/pkg/plugin/clientmgmt/restartable_backup_item_action.go index 58c11245a..95abe90f0 100644 --- a/pkg/plugin/clientmgmt/restartable_backup_item_action.go +++ b/pkg/plugin/clientmgmt/restartable_backup_item_action.go @@ -38,7 +38,8 @@ type restartableBackupItemAction struct { } // newRestartableBackupItemActionV2 returns a new restartableBackupItemAction. -func newRestartableBackupItemActionV2(name string, sharedPluginProcess RestartableProcess) *restartableBackupItemAction { +func newRestartableBackupItemActionV2( + name string, sharedPluginProcess RestartableProcess) backupitemactionv2.BackupItemAction { r := &restartableBackupItemAction{ key: kindAndName{kind: framework.PluginKindBackupItemActionV2, name: name}, sharedPluginProcess: sharedPluginProcess, diff --git a/pkg/plugin/clientmgmt/restartable_delete_item_action.go b/pkg/plugin/clientmgmt/restartable_delete_item_action.go index 68acff69d..351d4c6ca 100644 --- a/pkg/plugin/clientmgmt/restartable_delete_item_action.go +++ b/pkg/plugin/clientmgmt/restartable_delete_item_action.go @@ -38,7 +38,8 @@ type restartableDeleteItemAction struct { } // newRestartableDeleteItemAction returns a new restartableDeleteItemAction. -func newRestartableDeleteItemActionV2(name string, sharedPluginProcess RestartableProcess) *restartableDeleteItemAction { +func newRestartableDeleteItemActionV2( + name string, sharedPluginProcess RestartableProcess) deleteitemactionv2.DeleteItemAction { r := &restartableDeleteItemAction{ key: kindAndName{kind: framework.PluginKindDeleteItemAction, name: name}, sharedPluginProcess: sharedPluginProcess, diff --git a/pkg/plugin/clientmgmt/restartable_object_store.go b/pkg/plugin/clientmgmt/restartable_object_store.go index 9550c8911..2b4675e4b 100644 --- a/pkg/plugin/clientmgmt/restartable_object_store.go +++ b/pkg/plugin/clientmgmt/restartable_object_store.go @@ -39,8 +39,8 @@ type restartableObjectStore struct { config map[string]string } -// newRestartableObjectStoreV2 returns a new restartableObjectStore for version 2. -func newRestartableObjectStoreV2(name string, sharedPluginProcess RestartableProcess) *restartableObjectStore { +// 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, diff --git a/pkg/plugin/clientmgmt/restartable_restore_item_action.go b/pkg/plugin/clientmgmt/restartable_restore_item_action.go index 25943eb4d..39546aeaa 100644 --- a/pkg/plugin/clientmgmt/restartable_restore_item_action.go +++ b/pkg/plugin/clientmgmt/restartable_restore_item_action.go @@ -36,7 +36,8 @@ type restartableRestoreItemAction struct { } // newRestartableRestoreItemActionV2 returns a new restartableRestoreItemAction. -func newRestartableRestoreItemActionV2(name string, sharedPluginProcess RestartableProcess) *restartableRestoreItemAction { +func newRestartableRestoreItemActionV2( + name string, sharedPluginProcess RestartableProcess) restoreitemactionv2.RestoreItemAction { r := &restartableRestoreItemAction{ key: kindAndName{kind: framework.PluginKindRestoreItemActionV2, name: name}, sharedPluginProcess: sharedPluginProcess, diff --git a/pkg/plugin/clientmgmt/restartable_volume_snapshotter.go b/pkg/plugin/clientmgmt/restartable_volume_snapshotter.go index fd8c383c9..4f9731250 100644 --- a/pkg/plugin/clientmgmt/restartable_volume_snapshotter.go +++ b/pkg/plugin/clientmgmt/restartable_volume_snapshotter.go @@ -37,7 +37,8 @@ type restartableVolumeSnapshotter struct { } // newRestartableVolumeSnapshotterV2 returns a new restartableVolumeSnapshotter. -func newRestartableVolumeSnapshotterV2(name string, sharedPluginProcess RestartableProcess) *restartableVolumeSnapshotter { +func newRestartableVolumeSnapshotterV2( + name string, sharedPluginProcess RestartableProcess) volumesnapshotterv2.VolumeSnapshotter { key := kindAndName{kind: framework.PluginKindVolumeSnapshotterV2, name: name} r := &restartableVolumeSnapshotter{ key: key, diff --git a/pkg/plugin/framework/plugin_kinds.go b/pkg/plugin/framework/plugin_kinds.go index 335dc2e71..fd2aa4067 100644 --- a/pkg/plugin/framework/plugin_kinds.go +++ b/pkg/plugin/framework/plugin_kinds.go @@ -60,12 +60,43 @@ const ( // PluginKindDeleteItemActionV2 represents a delete item action plugin version 2. PluginKindDeleteItemActionV2 PluginKind = "DeleteItemActionV2" - - // TODO: we may not need this - // PluginKindPluginListerV2 represents a plugin lister plugin version 2. - PluginKindPluginListerV2 PluginKind = "PluginListerV2" ) +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 {