mirror of https://github.com/k3s-io/k3s
allow re-usability of plugin handler, allow support for multiple valid plugin filename prefixes
parent
556c0b8593
commit
0257a2bcee
|
@ -293,7 +293,7 @@ var (
|
|||
|
||||
// NewDefaultKubectlCommand creates the `kubectl` command with default arguments
|
||||
func NewDefaultKubectlCommand() *cobra.Command {
|
||||
return NewDefaultKubectlCommandWithArgs(&defaultPluginHandler{}, os.Args, os.Stdin, os.Stdout, os.Stderr)
|
||||
return NewDefaultKubectlCommandWithArgs(NewDefaultPluginHandler(plugin.ValidPluginFilenamePrefixes), os.Args, os.Stdin, os.Stdout, os.Stderr)
|
||||
}
|
||||
|
||||
// NewDefaultKubectlCommandWithArgs creates the `kubectl` command with arguments
|
||||
|
@ -310,7 +310,7 @@ func NewDefaultKubectlCommandWithArgs(pluginHandler PluginHandler, args []string
|
|||
// only look for suitable extension executables if
|
||||
// the specified command does not already exist
|
||||
if _, _, err := cmd.Find(cmdPathPieces); err != nil {
|
||||
if err := handleEndpointExtensions(pluginHandler, cmdPathPieces); err != nil {
|
||||
if err := HandlePluginCommand(pluginHandler, cmdPathPieces); err != nil {
|
||||
fmt.Fprintf(errout, "%v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
@ -324,29 +324,51 @@ func NewDefaultKubectlCommandWithArgs(pluginHandler PluginHandler, args []string
|
|||
// and performing executable filename lookups to search
|
||||
// for valid plugin files, and execute found plugins.
|
||||
type PluginHandler interface {
|
||||
// Lookup receives a potential filename and returns
|
||||
// a full or relative path to an executable, if one
|
||||
// exists at the given filename, or an error.
|
||||
Lookup(filename string) (string, error)
|
||||
// exists at the given filename, or a boolean false.
|
||||
// Lookup will iterate over a list of given prefixes
|
||||
// in order to recognize valid plugin filenames.
|
||||
// The first filepath to match a prefix is returned.
|
||||
Lookup(filename string) (string, bool)
|
||||
// Execute receives an executable's filepath, a slice
|
||||
// of arguments, and a slice of environment variables
|
||||
// to relay to the executable.
|
||||
Execute(executablePath string, cmdArgs, environment []string) error
|
||||
}
|
||||
|
||||
type defaultPluginHandler struct{}
|
||||
// DefaultPluginHandler implements PluginHandler
|
||||
type DefaultPluginHandler struct {
|
||||
ValidPrefixes []string
|
||||
}
|
||||
|
||||
// NewDefaultPluginHandler instantiates the DefaultPluginHandler with a list of
|
||||
// given filename prefixes used to identify valid plugin filenames.
|
||||
func NewDefaultPluginHandler(validPrefixes []string) *DefaultPluginHandler {
|
||||
return &DefaultPluginHandler{
|
||||
ValidPrefixes: validPrefixes,
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup implements PluginHandler
|
||||
func (h *defaultPluginHandler) Lookup(filename string) (string, error) {
|
||||
return exec.LookPath(filename)
|
||||
func (h *DefaultPluginHandler) Lookup(filename string) (string, bool) {
|
||||
for _, prefix := range h.ValidPrefixes {
|
||||
path, err := exec.LookPath(fmt.Sprintf("%s-%s", prefix, filename))
|
||||
if err != nil || len(path) == 0 {
|
||||
continue
|
||||
}
|
||||
return path, true
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Execute implements PluginHandler
|
||||
func (h *defaultPluginHandler) Execute(executablePath string, cmdArgs, environment []string) error {
|
||||
func (h *DefaultPluginHandler) Execute(executablePath string, cmdArgs, environment []string) error {
|
||||
return syscall.Exec(executablePath, cmdArgs, environment)
|
||||
}
|
||||
|
||||
func handleEndpointExtensions(pluginHandler PluginHandler, cmdArgs []string) error {
|
||||
// HandlePluginCommand receives a pluginHandler and command-line arguments and attempts to find
|
||||
// a plugin executable on the PATH that satisfies the given arguments.
|
||||
func HandlePluginCommand(pluginHandler PluginHandler, cmdArgs []string) error {
|
||||
remainingArgs := []string{} // all "non-flag" arguments
|
||||
|
||||
for idx := range cmdArgs {
|
||||
|
@ -360,8 +382,8 @@ func handleEndpointExtensions(pluginHandler PluginHandler, cmdArgs []string) err
|
|||
|
||||
// attempt to find binary, starting at longest possible name with given cmdArgs
|
||||
for len(remainingArgs) > 0 {
|
||||
path, err := pluginHandler.Lookup(fmt.Sprintf("kubectl-%s", strings.Join(remainingArgs, "-")))
|
||||
if err != nil || len(path) == 0 {
|
||||
path, found := pluginHandler.Lookup(strings.Join(remainingArgs, "-"))
|
||||
if !found {
|
||||
remainingArgs = remainingArgs[:len(remainingArgs)-1]
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -175,32 +175,35 @@ type testPluginHandler struct {
|
|||
err error
|
||||
}
|
||||
|
||||
func (h *testPluginHandler) Lookup(filename string) (string, error) {
|
||||
func (h *testPluginHandler) Lookup(filename string) (string, bool) {
|
||||
// append supported plugin prefix to the filename
|
||||
filename = fmt.Sprintf("%s-%s", "kubectl", filename)
|
||||
|
||||
dir, err := os.Stat(h.pluginsDirectory)
|
||||
if err != nil {
|
||||
h.err = err
|
||||
return "", err
|
||||
return "", false
|
||||
}
|
||||
|
||||
if !dir.IsDir() {
|
||||
h.err = fmt.Errorf("expected %q to be a directory", h.pluginsDirectory)
|
||||
return "", h.err
|
||||
return "", false
|
||||
}
|
||||
|
||||
plugins, err := ioutil.ReadDir(h.pluginsDirectory)
|
||||
if err != nil {
|
||||
h.err = err
|
||||
return "", err
|
||||
return "", false
|
||||
}
|
||||
|
||||
for _, p := range plugins {
|
||||
if p.Name() == filename {
|
||||
return fmt.Sprintf("%s/%s", h.pluginsDirectory, p.Name()), nil
|
||||
return fmt.Sprintf("%s/%s", h.pluginsDirectory, p.Name()), true
|
||||
}
|
||||
}
|
||||
|
||||
h.err = fmt.Errorf("unable to find a plugin executable %q", filename)
|
||||
return "", h.err
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (h *testPluginHandler) Execute(executablePath string, cmdArgs, env []string) error {
|
||||
|
|
|
@ -49,6 +49,8 @@ var (
|
|||
- anywhere on the user's PATH
|
||||
- begin with "kubectl-"
|
||||
`)
|
||||
|
||||
ValidPluginFilenamePrefixes = []string{"kubectl"}
|
||||
)
|
||||
|
||||
func NewCmdPlugin(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
|
@ -127,12 +129,12 @@ func (o *PluginListOptions) Run() error {
|
|||
if f.IsDir() {
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(f.Name(), "kubectl-") {
|
||||
if !hasValidPrefix(f.Name(), ValidPluginFilenamePrefixes) {
|
||||
continue
|
||||
}
|
||||
|
||||
if isFirstFile {
|
||||
fmt.Fprintf(o.ErrOut, "The following kubectl-compatible plugins are available:\n\n")
|
||||
fmt.Fprintf(o.ErrOut, "The following compatible plugins are available:\n\n")
|
||||
pluginsFound = true
|
||||
isFirstFile = false
|
||||
}
|
||||
|
@ -262,3 +264,13 @@ func uniquePathsList(paths []string) []string {
|
|||
}
|
||||
return newPaths
|
||||
}
|
||||
|
||||
func hasValidPrefix(filepath string, validPrefixes []string) bool {
|
||||
for _, prefix := range validPrefixes {
|
||||
if !strings.HasPrefix(filepath, prefix+"-") {
|
||||
continue
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue