-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
189d493
commit 99276cc
Showing
2 changed files
with
203 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
24 | ||
25 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
--- | ||
kep-number: 24 | ||
title: Kubectl Plugins | ||
authors: | ||
- "@juanvallejo" | ||
owning-sig: sig-cli | ||
participating-sigs: | ||
- sig-cli | ||
reviewers: | ||
- "@pwittrock" | ||
- "@deads2k" | ||
- "@liggitt" | ||
- "@soltysh" | ||
approvers: | ||
- "@pwittrock" | ||
- "@soltysh" | ||
editor: juanvallejo | ||
creation-date: 2018-07-24 | ||
last-updated: yyyy-mm-dd | ||
status: provisional | ||
see-also: | ||
- n/a | ||
replaces: | ||
- "https://github.com/kubernetes/community/blob/master/contributors/design-proposals/cli/kubectl-extension.md" | ||
- "https://github.com/kubernetes/community/pull/481" | ||
superseded-by: | ||
- n/a | ||
--- | ||
|
||
# Kubectl Plugins | ||
|
||
## Table of Contents | ||
|
||
* [Table of Contents](#table-of-contents) | ||
* [Summary](#summary) | ||
* [Motivation](#motivation) | ||
* [Goals](#goals) | ||
* [Non-Goals](#non-goals) | ||
* [Proposal](#proposal) | ||
* [Scenarios](#scenarios) | ||
* [Implementation Details/Design/Constraints](#implementation-detailsdesign) | ||
* [Naming Conventions](#naming-conventions) | ||
* [Implementation Notes/Constraints](#implementation-notesconstraints) | ||
* [Risks and Mitigations](#risks-and-mitigations) | ||
* [Graduation Criteria](#graduation-criteria) | ||
* [Implementation History](#implementation-history) | ||
* [Drawbacks](#drawbacks) | ||
* [Future Improvements/Considerations](#future-improvementsconsiderations) | ||
|
||
## Summary | ||
|
||
This proposal introduces the main design for a plugin mechanism in `kubectl`. | ||
The mechanism is a git-style system, that looks for executables on a user's `$PATH` whose name begins with `kubectl-`. | ||
This allows plugin binaries to override existing command paths and add custom commands and subcommands to `kubectl`. | ||
|
||
## Motivation | ||
|
||
The existing alpha plugin system in `kubectl` presents a few limitations with its current design. | ||
It forces plugin scripts and executables to exist in a pre-determined location, requires a per-plugin metadata file for | ||
interpretation, and does not provide a clear way to override existing command paths or provide additional subcommands | ||
without having to override a top-level command. | ||
|
||
A re-design plugins system allows us to implement extensibility requests from users that the current system cannot address | ||
(See https://github.com/kubernetes/kubernetes/issues/53640 and https://github.com/kubernetes/kubernetes/issues/55708). | ||
|
||
### Goals | ||
|
||
* Avoid any kind of installation process (no additional config, users drop an executable in their `PATH`, for example, | ||
and they are then able to use that plugin with `kubectl`). | ||
No additional configuration is needed, only the plugin executable. | ||
A plugin's filename determines the plugin's intention, such as which path in the command tree it applies to: | ||
`/usr/bin/kubectl-educate-dolphins` would, for example be invoked under the command `kubectl educate dolphins --flag1 --flag2`. | ||
It is up to a plugin to parse any arguments and flags given to it. A plugin decides when an argument is a | ||
subcommand, as well as any limitations or constraints that its flags should have. | ||
* Relay all information given to `kubectl` (via command line args) to plugins as-is. | ||
Plugins receive all arguments and flags provided by users and are responsible for adjusting their behavior | ||
accordingly. | ||
* Provide a way to limit which command paths can and cannot be overriddden by plugins in the command tree. | ||
|
||
### Non-Goals | ||
|
||
* The new plugin mechanism will not be a "plugin installer" or wizard. It will not have specific or baked-in knowledge | ||
regarding a plugin's location or composition, nor will it it provide a way to download or unpack plugins in a correct | ||
location. | ||
* Plugin discovery is not a main focus of this mechanism. As such, it will not attempt to collect data about every | ||
plugin that exists in an environment. | ||
* Plugin management is out of the scope of this design. A mechanism for updating and managing lifecycle of existing | ||
plugins should be covered as a separate design (See https://github.com/kubernetes/community/pull/2340). | ||
* Provide a standard package of common cli utilities that is consumed by `kubectl` and plugins alike. | ||
This should be done as an independent effort of this plugin mechanism. | ||
|
||
## Proposal | ||
|
||
### Scenarios | ||
|
||
* Developer wants to create and expose a plugin to `kubectl`. | ||
They use a programming language of their choice and create an executable file. | ||
The executable's filename consists of the command path to implement, and is prefixed with `kubectl-`. | ||
The executable file is placed on the user's `PATH`. | ||
|
||
### Implementation Details/Design | ||
|
||
The proposed design passes through all environment variables, flags, input, and output streams exactly as they are given | ||
to the parent `kubectl` process. This has the effect of letting plugins run without the need for any special parsing | ||
or case-handling in `kubectl`. | ||
|
||
In essence, a plugin binary must be able to run as a standalone process, completely independent of `kubectl`. | ||
|
||
* When `kubectl` is executed with a subcommand _foo_ that does not exist exist in the command tree, it will attempt to look | ||
for a filename `kubectl-foo` (`kubectl-foo.exe` on Windows) in the user's `PATH` and execute it, relaying all arguments given | ||
as well as all environment variables to the plugin child-process. | ||
|
||
A brief example (not an actual prototype) is provided below to clarify the core logic of the proposed design: | ||
|
||
```go | ||
// treat all args given by the user as pieces of a plugin binary's filename | ||
// and short-circuit once we find an arg that appears to be a flag. | ||
remainingArgs := []string{} // all "non-flag" arguments | ||
|
||
for idx := range cmdArgs { | ||
if strings.HasPrefix(cmdArgs[idx], "-") { | ||
break | ||
} | ||
remainingArgs = append(remainingArgs, strings.Replace(cmdArgs[idx], "-", "_", -1)) | ||
} | ||
|
||
foundBinaryPath := "" | ||
|
||
// find binary in the user's PATH, starting with the longest possible filename | ||
// based on the given non-flag arguments by the user | ||
for len(remainingArgs) > 0 { | ||
path, err := exec.LookPath(fmt.Sprintf("kubectl-%s", strings.Join(remainingArgs, "-"))) | ||
if err != nil || len(path) == 0 { | ||
remainingArgs = remainingArgs[:len(remainingArgs)-1] | ||
continue | ||
} | ||
|
||
foundBinaryPath = path | ||
break | ||
} | ||
|
||
// if we are able to find a suitable plugin executable, perform a syscall.Exec call | ||
// and relay all remaining arguments (in order given), as well as environment vars. | ||
syscall.Exec(foundBinaryPath, append([]string{foundBinaryPath}, cmdArgs[len(remainingArgs):]...), os.Environ()) | ||
``` | ||
|
||
#### Naming Conventions | ||
|
||
Under this proposal, `kubectl` would identify plugins by looking for filenames beginning with the `kubectl-` prefix. | ||
A search for these names would occur on a user's `PATH`. Only files that are executable and begin with this prefix | ||
would be identified. | ||
|
||
### Implementation Notes/Constraints | ||
|
||
The current implementation details for the proposed design rely on using a plugin executable's name to determine what | ||
command the plugin is adding. | ||
For a given command `kubectl foo --bar baz`, an executable `kubectl-foo` will be matched on a user's `PATH`, | ||
and the arguments `--bar baz` will be passed to it in that order. | ||
|
||
A potential limitation of this could present itself in the order of arguments provided by a user. | ||
A user could intend to run a plugin `kubectl-foo-bar` with the flag `--baz` with the following command | ||
`kubectl foo --baz bar`, but instead end up matching `kubectl-foo` with the flag `--baz` and the argument `bar` based | ||
on the placement of the flag `--baz`. | ||
|
||
A notable constraint of this design is that it excludes any form of plugin lifecycle management, or version compatibility. | ||
A plugin may depend on other plugins based on the decision of a plugin author, however the proposed design does nothing | ||
to facilitate such dependencies. It is up to the plugin's author (or a separate / independent plugin management system) to | ||
provide documentation or instructions on how to meet any dependencies required by a plugin. | ||
|
||
Further, with the proposed design, plugins that rely on multiple "helper" files to properly function, should provide an | ||
"entrypoint" executable (which is placed on a user's `PATH`), with any additional files located elsewhere (e.g. ~/.kubeplugins/myplugin/helper1.py). | ||
|
||
### Risks and Mitigations | ||
|
||
Unlike the existing alpha plugin mechanism, the proposed design does not constrain commands added by plugins to exist as subcommands of the | ||
`kubectl plugin` design. Commands provided by plugins under the new mechanism can be invoked as first-class commands (`/usr/bin/kubectl-foo` provides the `kubectl foo` parent command). | ||
|
||
A potential risk associated with this could present in the form of a "land-rush" by plugin providers. | ||
Multiple plugin authors would be incentivized to provide their own version of plugin `foo`. | ||
Users would be at the mercy of whichever variation of `kubectl-foo` is discovered in their `PATH` first when executing that command. | ||
|
||
A way to mitigate the above scenario would be to have users take advantage of the proposed plugin mechanism's design by renaming multiple variations of `kubectl-foo` | ||
to include the provider's name, for example: `kubectl-acme-foo`, or `kubectl-companyB-foo`. | ||
|
||
Conflicts such as this one could further be mitigated by a plugin manager, which could perform conflict resolution among similarly named plugins on behalf of a user. | ||
|
||
## Graduation Criteria | ||
|
||
* Make this mechanism a part of `kubectl`'s command-lookup logic. | ||
|
||
## Implementation History | ||
|
||
This plugin design closely follows major aspects of the plugin system design for `git`. | ||
|
||
## Drawbacks | ||
|
||
Implementing this design could potentially conflict with any ongoing work that depends on the current alpha plugin system. | ||
|
||
## Future Improvements/Considerations | ||
|
||
The proposed design is flexible enough to accommodate future updates that could allow certain command paths to be overwritten | ||
or extended (with the addition of subcommands) via plugins. |