mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-01-03 11:45:20 +00:00
Implement DeleteItemAction plugin support (#2808)
* Add DeleteItemAction struct & protobuf definition Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
This commit is contained in:
44
pkg/plugin/framework/delete_item_action.go
Normal file
44
pkg/plugin/framework/delete_item_action.go
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright 2020 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 framework
|
||||
|
||||
import (
|
||||
plugin "github.com/hashicorp/go-plugin"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
proto "github.com/vmware-tanzu/velero/pkg/plugin/generated"
|
||||
)
|
||||
|
||||
// RestoreItemActionPlugin is an implementation of go-plugin's Plugin
|
||||
// interface with support for gRPC for the restore/ItemAction
|
||||
// interface.
|
||||
type DeleteItemActionPlugin struct {
|
||||
plugin.NetRPCUnsupportedPlugin
|
||||
*pluginBase
|
||||
}
|
||||
|
||||
// GRPCClient returns a RestoreItemAction gRPC client.
|
||||
func (p *DeleteItemActionPlugin) GRPCClient(_ context.Context, _ *plugin.GRPCBroker, clientConn *grpc.ClientConn) (interface{}, error) {
|
||||
return newClientDispenser(p.clientLogger, clientConn, newDeleteItemActionGRPCClient), nil
|
||||
}
|
||||
|
||||
// GRPCServer registers a DeleteItemAction gRPC server.
|
||||
func (p *DeleteItemActionPlugin) GRPCServer(_ *plugin.GRPCBroker, server *grpc.Server) error {
|
||||
proto.RegisterDeleteItemActionServer(server, &DeleteItemActionGRPCServer{mux: p.serverMux})
|
||||
return nil
|
||||
}
|
||||
95
pkg/plugin/framework/delete_item_action_client.go
Normal file
95
pkg/plugin/framework/delete_item_action_client.go
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright 2020 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 framework
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
proto "github.com/vmware-tanzu/velero/pkg/plugin/generated"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
|
||||
)
|
||||
|
||||
var _ velero.DeleteItemAction = &DeleteItemActionGRPCClient{}
|
||||
|
||||
// NewDeleteItemActionPlugin constructs a DeleteItemActionPlugin.
|
||||
func NewDeleteItemActionPlugin(options ...PluginOption) *DeleteItemActionPlugin {
|
||||
return &DeleteItemActionPlugin{
|
||||
pluginBase: newPluginBase(options...),
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteItemActionGRPCClient implements the backup/ItemAction interface and uses a
|
||||
// gRPC client to make calls to the plugin server.
|
||||
type DeleteItemActionGRPCClient struct {
|
||||
*clientBase
|
||||
grpcClient proto.DeleteItemActionClient
|
||||
}
|
||||
|
||||
func newDeleteItemActionGRPCClient(base *clientBase, clientConn *grpc.ClientConn) interface{} {
|
||||
return &DeleteItemActionGRPCClient{
|
||||
clientBase: base,
|
||||
grpcClient: proto.NewDeleteItemActionClient(clientConn),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DeleteItemActionGRPCClient) AppliesTo() (velero.ResourceSelector, error) {
|
||||
res, err := c.grpcClient.AppliesTo(context.Background(), &proto.DeleteItemActionAppliesToRequest{Plugin: c.plugin})
|
||||
if err != nil {
|
||||
return velero.ResourceSelector{}, fromGRPCError(err)
|
||||
}
|
||||
|
||||
if res.ResourceSelector == nil {
|
||||
return velero.ResourceSelector{}, nil
|
||||
}
|
||||
|
||||
return velero.ResourceSelector{
|
||||
IncludedNamespaces: res.ResourceSelector.IncludedNamespaces,
|
||||
ExcludedNamespaces: res.ResourceSelector.ExcludedNamespaces,
|
||||
IncludedResources: res.ResourceSelector.IncludedResources,
|
||||
ExcludedResources: res.ResourceSelector.ExcludedResources,
|
||||
LabelSelector: res.ResourceSelector.Selector,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *DeleteItemActionGRPCClient) Execute(input *velero.DeleteItemActionExecuteInput) error {
|
||||
itemJSON, err := json.Marshal(input.Item.UnstructuredContent())
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
backupJSON, err := json.Marshal(input.Backup)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
req := &proto.DeleteItemActionExecuteRequest{
|
||||
Plugin: c.plugin,
|
||||
Item: itemJSON,
|
||||
Backup: backupJSON,
|
||||
}
|
||||
|
||||
// First return item is just an empty struct no matter what.
|
||||
if _, err = c.grpcClient.Execute(context.Background(), req); err != nil {
|
||||
return fromGRPCError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
112
pkg/plugin/framework/delete_item_action_server.go
Normal file
112
pkg/plugin/framework/delete_item_action_server.go
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
Copyright 2020 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 framework
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// DeleteItemActionGRPCServer implements the proto-generated DeleteItemActionServer interface, and accepts
|
||||
// gRPC calls and forwards them to an implementation of the pluggable interface.
|
||||
type DeleteItemActionGRPCServer struct {
|
||||
mux *serverMux
|
||||
}
|
||||
|
||||
func (s *DeleteItemActionGRPCServer) getImpl(name string) (velero.DeleteItemAction, error) {
|
||||
impl, err := s.mux.getHandler(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
itemAction, ok := impl.(velero.DeleteItemAction)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("%T is not a delete item action", impl)
|
||||
}
|
||||
|
||||
return itemAction, nil
|
||||
}
|
||||
|
||||
func (s *DeleteItemActionGRPCServer) AppliesTo(ctx context.Context, req *proto.DeleteItemActionAppliesToRequest) (response *proto.DeleteItemActionAppliesToResponse, err error) {
|
||||
defer func() {
|
||||
if recoveredErr := handlePanic(recover()); recoveredErr != nil {
|
||||
err = recoveredErr
|
||||
}
|
||||
}()
|
||||
|
||||
impl, err := s.getImpl(req.Plugin)
|
||||
if err != nil {
|
||||
return nil, newGRPCError(err)
|
||||
}
|
||||
|
||||
resourceSelector, err := impl.AppliesTo()
|
||||
if err != nil {
|
||||
return nil, newGRPCError(err)
|
||||
}
|
||||
|
||||
return &proto.DeleteItemActionAppliesToResponse{
|
||||
&proto.ResourceSelector{
|
||||
IncludedNamespaces: resourceSelector.IncludedNamespaces,
|
||||
ExcludedNamespaces: resourceSelector.ExcludedNamespaces,
|
||||
IncludedResources: resourceSelector.IncludedResources,
|
||||
ExcludedResources: resourceSelector.ExcludedResources,
|
||||
Selector: resourceSelector.LabelSelector,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *DeleteItemActionGRPCServer) Execute(ctx context.Context, req *proto.DeleteItemActionExecuteRequest) (_ *proto.Empty, err error) {
|
||||
defer func() {
|
||||
if recoveredErr := handlePanic(recover()); recoveredErr != nil {
|
||||
err = recoveredErr
|
||||
}
|
||||
}()
|
||||
|
||||
impl, err := s.getImpl(req.Plugin)
|
||||
if err != nil {
|
||||
return nil, newGRPCError(err)
|
||||
}
|
||||
|
||||
var (
|
||||
item unstructured.Unstructured
|
||||
backup api.Backup
|
||||
)
|
||||
|
||||
if err := json.Unmarshal(req.Item, &item); err != nil {
|
||||
return nil, newGRPCError(errors.WithStack(err))
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(req.Backup, &backup); err != nil {
|
||||
return nil, newGRPCError(errors.WithStack(err))
|
||||
}
|
||||
|
||||
if err := impl.Execute(&velero.DeleteItemActionExecuteInput{
|
||||
Item: &item,
|
||||
Backup: &backup,
|
||||
}); err != nil {
|
||||
return nil, newGRPCError(err)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2019 the Velero contributors.
|
||||
Copyright 2020 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.
|
||||
@@ -19,12 +19,15 @@ package framework
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
|
||||
)
|
||||
|
||||
func ExampleNewServer_volumeSnapshotter() {
|
||||
NewServer(). // call the server
|
||||
RegisterVolumeSnapshotter("example.io/volumesnapshotter", newVolumeSnapshotter). // register the plugin with a valid name
|
||||
Serve() // serve the plugin
|
||||
RegisterDeleteItemAction("example.io/delete-item-action", newDeleteItemAction).
|
||||
Serve() // serve the plugin
|
||||
}
|
||||
|
||||
func newVolumeSnapshotter(logger logrus.FieldLogger) (interface{}, error) {
|
||||
@@ -91,3 +94,29 @@ func (b *VolumeSnapshotter) DeleteSnapshot(snapshotID string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Implement all methods for the DeleteItemAction interface
|
||||
|
||||
func newDeleteItemAction(logger logrus.FieldLogger) (interface{}, error) {
|
||||
return DeleteItemAction{FieldLogger: logger}, nil
|
||||
}
|
||||
|
||||
type DeleteItemAction struct {
|
||||
FieldLogger logrus.FieldLogger
|
||||
}
|
||||
|
||||
func (d *DeleteItemAction) AppliesTo() (velero.ResourceSelector, error) {
|
||||
d.FieldLogger.Infof("AppliesTo called")
|
||||
|
||||
// ...
|
||||
|
||||
return velero.ResourceSelector{}, nil
|
||||
}
|
||||
|
||||
func (d *DeleteItemAction) Execute(input *velero.DeleteItemActionExecuteInput) error {
|
||||
d.FieldLogger.Infof("Execute called")
|
||||
|
||||
// ...
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -38,6 +38,9 @@ const (
|
||||
// PluginKindRestoreItemAction represents a restore item action plugin.
|
||||
PluginKindRestoreItemAction PluginKind = "RestoreItemAction"
|
||||
|
||||
// PluginKindDeleteItemAction represents a delete item action plugin.
|
||||
PluginKindDeleteItemAction PluginKind = "DeleteItemAction"
|
||||
|
||||
// PluginKindPluginLister represents a plugin lister plugin.
|
||||
PluginKindPluginLister PluginKind = "PluginLister"
|
||||
)
|
||||
@@ -50,5 +53,6 @@ func AllPluginKinds() map[string]PluginKind {
|
||||
allPluginKinds[PluginKindVolumeSnapshotter.String()] = PluginKindVolumeSnapshotter
|
||||
allPluginKinds[PluginKindBackupItemAction.String()] = PluginKindBackupItemAction
|
||||
allPluginKinds[PluginKindRestoreItemAction.String()] = PluginKindRestoreItemAction
|
||||
allPluginKinds[PluginKindDeleteItemAction.String()] = PluginKindDeleteItemAction
|
||||
return allPluginKinds
|
||||
}
|
||||
|
||||
@@ -67,6 +67,13 @@ type Server interface {
|
||||
// RegisterRestoreItemActions registers multiple restore item actions.
|
||||
RegisterRestoreItemActions(map[string]HandlerInitializer) Server
|
||||
|
||||
// RegisterDeleteItemAction registers a delete item action. Accepted format
|
||||
// for the plugin name is <DNS subdomain>/<non-empty name>.
|
||||
RegisterDeleteItemAction(pluginName string, initializer HandlerInitializer) Server
|
||||
|
||||
// RegisterDeleteItemActions registers multiple Delete item actions.
|
||||
RegisterDeleteItemActions(map[string]HandlerInitializer) Server
|
||||
|
||||
// Server runs the plugin server.
|
||||
Serve()
|
||||
}
|
||||
@@ -81,6 +88,7 @@ type server struct {
|
||||
volumeSnapshotter *VolumeSnapshotterPlugin
|
||||
objectStore *ObjectStorePlugin
|
||||
restoreItemAction *RestoreItemActionPlugin
|
||||
deleteItemAction *DeleteItemActionPlugin
|
||||
}
|
||||
|
||||
// NewServer returns a new Server
|
||||
@@ -96,6 +104,7 @@ func NewServer() Server {
|
||||
volumeSnapshotter: NewVolumeSnapshotterPlugin(serverLogger(log)),
|
||||
objectStore: NewObjectStorePlugin(serverLogger(log)),
|
||||
restoreItemAction: NewRestoreItemActionPlugin(serverLogger(log)),
|
||||
deleteItemAction: NewDeleteItemActionPlugin(serverLogger(log)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +165,18 @@ func (s *server) RegisterRestoreItemActions(m map[string]HandlerInitializer) Ser
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *server) RegisterDeleteItemAction(name string, initializer HandlerInitializer) Server {
|
||||
s.deleteItemAction.register(name, initializer)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *server) RegisterDeleteItemActions(m map[string]HandlerInitializer) Server {
|
||||
for name := range m {
|
||||
s.RegisterDeleteItemAction(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
|
||||
|
||||
Reference in New Issue
Block a user