Files
velero/pkg/plugin/clientmgmt/process/process.go
Wenkai Yin(尹文开) dc6eeafe98 Pass Velero server command args to the plugins
Pass Velero server command args to the plugins

Fixes #7806

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
2024-09-04 13:43:27 +08:00

127 lines
3.3 KiB
Go

/*
Copyright 2018 the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package process
import (
plugin "github.com/hashicorp/go-plugin"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
)
type Factory interface {
newProcess(command string, logger logrus.FieldLogger, logLevel logrus.Level) (Process, error)
}
type processFactory struct {
}
func newProcessFactory() Factory {
return &processFactory{}
}
func (pf *processFactory) newProcess(command string, logger logrus.FieldLogger, logLevel logrus.Level) (Process, error) {
return newProcess(command, logger, logLevel)
}
type Process interface {
dispense(key KindAndName) (interface{}, error)
exited() bool
kill()
}
type process struct {
client *plugin.Client
protocolClient plugin.ClientProtocol
}
func newProcess(command string, logger logrus.FieldLogger, logLevel logrus.Level) (Process, error) {
builder := newClientBuilder(command, logger.WithField("cmd", command), logLevel)
// This creates a new go-plugin Client that has its own unique exec.Cmd for launching the plugin process.
client := builder.client()
// This launches the plugin process.
protocolClient, err := client.Client()
if err != nil {
return nil, err
}
p := &process{
client: client,
protocolClient: protocolClient,
}
return p, nil
}
// removeFeaturesFlag looks for and removes the '--features' arg
// as well as the arg immediately following it (the flag value).
func removeFeaturesFlag(args []string) []string {
var commandArgs []string
var featureFlag bool
for _, arg := range args {
// if this arg is the flag name, skip it
if arg == "--features" {
featureFlag = true
continue
}
// if the last arg we saw was the flag name, then
// this arg is the value for the flag, so skip it
if featureFlag {
featureFlag = false
continue
}
// otherwise, keep the arg
commandArgs = append(commandArgs, arg)
}
return commandArgs
}
func (r *process) dispense(key KindAndName) (interface{}, error) {
// This calls GRPCClient(clientConn) on the plugin instance registered for key.name.
dispensed, err := r.protocolClient.Dispense(key.Kind.String())
if err != nil {
return nil, errors.WithStack(err)
}
// Currently all plugins except for PluginLister dispense clientDispenser instances.
if clientDispenser, ok := dispensed.(common.ClientDispenser); ok {
if key.Name == "" {
return nil, errors.Errorf("%s plugin requested but name is missing", key.Kind.String())
}
// Get the instance that implements our plugin interface (e.g. ObjectStore) that is a gRPC-based
// client
dispensed = clientDispenser.ClientFor(key.Name)
}
return dispensed, nil
}
func (r *process) exited() bool {
return r.client.Exited()
}
func (r *process) kill() {
r.client.Kill()
}