Skip to content

Commit 42c7d7c

Browse files
authored
Merge pull request kubernetes#2437 from juanvallejo/jvallejo/add-plugins-kep
Add kubectl plugin mechanism KEP
2 parents c504d59 + adf7d4f commit 42c7d7c

File tree

2 files changed

+235
-1
lines changed

2 files changed

+235
-1
lines changed

NEXT_KEP_NUMBER

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
24
1+
25

sig-cli/0024-kubectl-plugins.md

+234
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
---
2+
kep-number: 24
3+
title: Kubectl Plugins
4+
authors:
5+
- "@juanvallejo"
6+
owning-sig: sig-cli
7+
participating-sigs:
8+
- sig-cli
9+
reviewers:
10+
- "@pwittrock"
11+
- "@deads2k"
12+
- "@liggitt"
13+
- "@soltysh"
14+
approvers:
15+
- "@pwittrock"
16+
- "@soltysh"
17+
editor: juanvallejo
18+
creation-date: 2018-07-24
19+
last-updated: 2018-08-09
20+
status: provisional
21+
see-also:
22+
- n/a
23+
replaces:
24+
- "https://github.com/kubernetes/community/blob/master/contributors/design-proposals/cli/kubectl-extension.md"
25+
- "https://github.com/kubernetes/community/pull/481"
26+
superseded-by:
27+
- n/a
28+
---
29+
30+
# Kubectl Plugins
31+
32+
## Table of Contents
33+
34+
* [Table of Contents](#table-of-contents)
35+
* [Summary](#summary)
36+
* [Motivation](#motivation)
37+
* [Limitations of the Existing Design](#limitations-of-the-existing-design)
38+
* [Goals](#goals)
39+
* [Non-Goals](#non-goals)
40+
* [Proposal](#proposal)
41+
* [Scenarios](#scenarios)
42+
* [Implementation Details/Design/Constraints](#implementation-detailsdesign)
43+
* [Naming Conventions](#naming-conventions)
44+
* [Implementation Notes/Constraints](#implementation-notesconstraints)
45+
* [Risks and Mitigations](#risks-and-mitigations)
46+
* [Graduation Criteria](#graduation-criteria)
47+
* [Implementation History](#implementation-history)
48+
* [Drawbacks](#drawbacks)
49+
* [Future Improvements/Considerations](#future-improvementsconsiderations)
50+
51+
## Summary
52+
53+
This proposal introduces the main design for a plugin mechanism in `kubectl`.
54+
The mechanism is a git-style system, that looks for executables on a user's `$PATH` whose name begins with `kubectl-`.
55+
This allows plugin binaries to override existing command paths and add custom commands and subcommands to `kubectl`.
56+
57+
## Motivation
58+
59+
The main motivation behind a plugin system for `kubectl` stems from being able to provide users with a way to extend
60+
the functionality of `kubectl`, beyond what is offered by its core commands.
61+
62+
By picturing the core commands provided by `kubectl` as essential building blocks for interacting with a Kubernetes
63+
cluster, we can begin to think of plugins as a means of using these building blocks to provide more complex functionality.
64+
A new command, `kubectl set-ns`, for example, could take advantage of the rudimentary functionality already provided by
65+
the `kubectl config` command, and build on top of it to provide users with a powerful, yet easy-to-use way of switching
66+
to a new namespace.
67+
68+
For example, the user experience for switching namespaces could go from:
69+
70+
```bash
71+
kubectl config set-context $(kubectl config current-context) --namespace=mynewnamespace
72+
```
73+
74+
to:
75+
76+
```
77+
kubectl set-ns mynewnamespace
78+
```
79+
80+
where `set-ns` would be a user-provided plugin which would call the initial `kubectl config set-context ...` command
81+
and set the namespace flag according to the value provided as the plugin's first parameter.
82+
83+
The `set-ns` command above could have multiple variations, or be expanded to support subcommands with relative ease.
84+
Since plugins would be distributed by their authors, independent from the core Kubernetes repository, plugins could
85+
release updates and changes at their own pace.
86+
87+
### Limitations of the Existing Design
88+
89+
The existing alpha plugin system in `kubectl` presents a few limitations with its current design.
90+
It forces plugin scripts and executables to exist in a pre-determined location, requires a per-plugin metadata file for
91+
interpretation, and does not provide a clear way to override existing command paths or provide additional subcommands
92+
without having to override a top-level command.
93+
94+
The proposed git-style re-design of the plugin system allows us to implement extensibility requests from users that the
95+
current system is unable to address.
96+
See https://github.com/kubernetes/kubernetes/issues/53640 and https://github.com/kubernetes/kubernetes/issues/55708.
97+
98+
### Goals
99+
100+
* Avoid any kind of installation process (no additional config, users drop an executable in their `PATH`, for example,
101+
and they are then able to use that plugin with `kubectl`).
102+
No additional configuration is needed, only the plugin executable.
103+
A plugin's filename determines the plugin's intention, such as which path in the command tree it applies to:
104+
`/usr/bin/kubectl-educate-dolphins` would, for example be invoked under the command `kubectl educate dolphins --flag1 --flag2`.
105+
It is up to a plugin to parse any arguments and flags given to it. A plugin decides when an argument is a
106+
subcommand, as well as any limitations or constraints that its flags should have.
107+
* Relay all information given to `kubectl` (via command line args) to plugins as-is.
108+
Plugins receive all arguments and flags provided by users and are responsible for adjusting their behavior
109+
accordingly.
110+
* Provide a way to limit which command paths can and cannot be overriddden by plugins in the command tree.
111+
112+
### Non-Goals
113+
114+
* The new plugin mechanism will not be a "plugin installer" or wizard. It will not have specific or baked-in knowledge
115+
regarding a plugin's location or composition, nor will it it provide a way to download or unpack plugins in a correct
116+
location.
117+
* Plugin discovery is not a main focus of this mechanism. As such, it will not attempt to collect data about every
118+
plugin that exists in an environment.
119+
* Plugin management is out of the scope of this design. A mechanism for updating and managing lifecycle of existing
120+
plugins should be covered as a separate design (See https://github.com/kubernetes/community/pull/2340).
121+
* Provide a standard package of common cli utilities that is consumed by `kubectl` and plugins alike.
122+
This should be done as an independent effort of this plugin mechanism.
123+
124+
## Proposal
125+
126+
### Scenarios
127+
128+
* Developer wants to create and expose a plugin to `kubectl`.
129+
They use a programming language of their choice and create an executable file.
130+
The executable's filename consists of the command path to implement, and is prefixed with `kubectl-`.
131+
The executable file is placed on the user's `PATH`.
132+
133+
### Implementation Details/Design
134+
135+
The proposed design passes through all environment variables, flags, input, and output streams exactly as they are given
136+
to the parent `kubectl` process. This has the effect of letting plugins run without the need for any special parsing
137+
or case-handling in `kubectl`.
138+
139+
In essence, a plugin binary must be able to run as a standalone process, completely independent of `kubectl`.
140+
141+
* When `kubectl` is executed with a subcommand _foo_ that does not exist exist in the command tree, it will attempt to look
142+
for a filename `kubectl-foo` (`kubectl-foo.exe` on Windows) in the user's `PATH` and execute it, relaying all arguments given
143+
as well as all environment variables to the plugin child-process.
144+
145+
A brief example (not an actual prototype) is provided below to clarify the core logic of the proposed design:
146+
147+
```go
148+
// treat all args given by the user as pieces of a plugin binary's filename
149+
// and short-circuit once we find an arg that appears to be a flag.
150+
remainingArgs := []string{} // all "non-flag" arguments
151+
152+
for idx := range cmdArgs {
153+
if strings.HasPrefix(cmdArgs[idx], "-") {
154+
break
155+
}
156+
remainingArgs = append(remainingArgs, strings.Replace(cmdArgs[idx], "-", "_", -1))
157+
}
158+
159+
foundBinaryPath := ""
160+
161+
// find binary in the user's PATH, starting with the longest possible filename
162+
// based on the given non-flag arguments by the user
163+
for len(remainingArgs) > 0 {
164+
path, err := exec.LookPath(fmt.Sprintf("kubectl-%s", strings.Join(remainingArgs, "-")))
165+
if err != nil || len(path) == 0 {
166+
remainingArgs = remainingArgs[:len(remainingArgs)-1]
167+
continue
168+
}
169+
170+
foundBinaryPath = path
171+
break
172+
}
173+
174+
// if we are able to find a suitable plugin executable, perform a syscall.Exec call
175+
// and relay all remaining arguments (in order given), as well as environment vars.
176+
syscall.Exec(foundBinaryPath, append([]string{foundBinaryPath}, cmdArgs[len(remainingArgs):]...), os.Environ())
177+
```
178+
179+
#### Naming Conventions
180+
181+
Under this proposal, `kubectl` would identify plugins by looking for filenames beginning with the `kubectl-` prefix.
182+
A search for these names would occur on a user's `PATH`. Only files that are executable and begin with this prefix
183+
would be identified.
184+
185+
### Implementation Notes/Constraints
186+
187+
The current implementation details for the proposed design rely on using a plugin executable's name to determine what
188+
command the plugin is adding.
189+
For a given command `kubectl foo --bar baz`, an executable `kubectl-foo` will be matched on a user's `PATH`,
190+
and the arguments `--bar baz` will be passed to it in that order.
191+
192+
A potential limitation of this could present itself in the order of arguments provided by a user.
193+
A user could intend to run a plugin `kubectl-foo-bar` with the flag `--baz` with the following command
194+
`kubectl foo --baz bar`, but instead end up matching `kubectl-foo` with the flag `--baz` and the argument `bar` based
195+
on the placement of the flag `--baz`.
196+
197+
A notable constraint of this design is that it excludes any form of plugin lifecycle management, or version compatibility.
198+
A plugin may depend on other plugins based on the decision of a plugin author, however the proposed design does nothing
199+
to facilitate such dependencies. It is up to the plugin's author (or a separate / independent plugin management system) to
200+
provide documentation or instructions on how to meet any dependencies required by a plugin.
201+
202+
Further, with the proposed design, plugins that rely on multiple "helper" files to properly function, should provide an
203+
"entrypoint" executable (which is placed on a user's `PATH`), with any additional files located elsewhere (e.g. ~/.kubeplugins/myplugin/helper1.py).
204+
205+
### Risks and Mitigations
206+
207+
Unlike the existing alpha plugin mechanism, the proposed design does not constrain commands added by plugins to exist as subcommands of the
208+
`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).
209+
210+
A potential risk associated with this could present in the form of a "land-rush" by plugin providers.
211+
Multiple plugin authors would be incentivized to provide their own version of plugin `foo`.
212+
Users would be at the mercy of whichever variation of `kubectl-foo` is discovered in their `PATH` first when executing that command.
213+
214+
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`
215+
to include the provider's name, for example: `kubectl-acme-foo`, or `kubectl-companyB-foo`.
216+
217+
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.
218+
219+
## Graduation Criteria
220+
221+
* Make this mechanism a part of `kubectl`'s command-lookup logic.
222+
223+
## Implementation History
224+
225+
This plugin design closely follows major aspects of the plugin system design for `git`.
226+
227+
## Drawbacks
228+
229+
Implementing this design could potentially conflict with any ongoing work that depends on the current alpha plugin system.
230+
231+
## Future Improvements/Considerations
232+
233+
The proposed design is flexible enough to accommodate future updates that could allow certain command paths to be overwritten
234+
or extended (with the addition of subcommands) via plugins.

0 commit comments

Comments
 (0)