Files
kubernetes/pkg/kubectl/cmd/BUILD
Kubernetes Submit Queue 1737a43324 Merge pull request #66876 from juanvallejo/jvallejo/prototype-plugins
Automatic merge from submit-queue (batch tested with PRs 67062, 67169, 67539, 67504, 66876). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Update the kubectl plugin mechanism

**Release note**:
```release-note
The plugin mechanism functionality to closely follow the git plugin design
```

Replace the existing plugin mechanism with the design proposed in https://github.com/kubernetes/community/pull/2437.

~~_The full implementation of the plugin mechanism itself is entirely contained within the first commit._~~

## Walkthrough

Under the new design, there is no plugin installation or loading required to use plugins.
A plugin is simply any executable file on a user's PATH whose name begins with `kubectl-`.
- Plugins receive the inherited environment from the `kubectl` binary. All environment variables
accessible by `kubectl` become accessible by the plugin.
- Plugins decide which command path they wish to implement based on their name. For example, a plugin wanting to provide a new command `foo`, would simply be named `kubectl-foo`.

### Creating a plugin

Below is an example plugin, that we will use for this walkthrough. Plugins may be written in any language, and handle arguments and flags in any way, optionally (as a convention) providing a way to retrieve their version via a `version` subcommand.

```bash
#!/bin/bash

# optional argument handling
if [[ "$1" == "version" ]]
then
    echo "1.0.0"
    exit 0
fi

# optional argument handling
if [[ "$1" == "config" ]]
then
    echo $KUBECONFIG
    exit 0
fi

echo "I am a plugin named kubectl-foo"
```

### Using a plugin

To use a plugin, simply make it executable:

```bash
sudo chmod +x ./kubectl-foo
```

and place it anywhere in your PATH:

```bash
sudo mv ./kubectl-foo /usr/local/bin
```

You may now invoke your plugin as a `kubectl` command:

```bash
$ kubectl foo
I am a plugin named kubectl-foo
```

All args and flags are passed as-is to the executable:

```bash
$ kubectl foo version
1.0.0
```

All environment variables are also passed as-is to the executable:

```bash
$ export KUBECONFIG=~/.kube/config
$ kubectl foo config
/home/<user>/.kube/config

$ KUBECONFIG=/etc/kube/config kubectl foo config
/etc/kube/config
```

Additionally, the first argument that is passed to a plugin will always be the full path to the location where it was invoked (`$0` would equal `/usr/local/bin/kubectl-foo` in our example above).

### Plugin discoverability

Seeing as how the `kubectl plugin` command is left as a no-op with this PR (perhaps it could serve as an entrypoint towards additional plugin functionality in the future), a small subcommand has been included that _lists all available plugin executables on a user's PATH_, along with any warnings it finds.

Example usage of this new subcommand is included below:

```bash
$ kubectl plugin list
The following kubectl-compatible plugins are available:

test/fixtures/pkg/kubectl/plugins/kubectl-foo
plugins/kubectl-foo
  - warning: plugins/kubectl-foo is overshadowed by a similarly named plugin: test/fixtures/pkg/kubectl/plugins/kubectl-foo
plugins/kubectl-invalid
  - warning: plugins/kubectl-invalid identified as a kubectl plugin, but it is not executable
plugins/kubectl-bar

error: 2 plugin warnings were found
```

cc @kubernetes/kubectl-maintainers @kubernetes/sig-cli-pr-reviews @soltysh @seans3 @mengqiy
2018-08-17 11:58:22 -07:00

269 lines
12 KiB
Python

load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"alpha.go",
"annotate.go",
"apiresources.go",
"apiversions.go",
"apply.go",
"apply_edit_last_applied.go",
"apply_set_last_applied.go",
"apply_view_last_applied.go",
"attach.go",
"autoscale.go",
"certificates.go",
"clusterinfo.go",
"clusterinfo_dump.go",
"cmd.go",
"completion.go",
"convert.go",
"cp.go",
"delete.go",
"delete_flags.go",
"describe.go",
"diff.go",
"drain.go",
"edit.go",
"exec.go",
"explain.go",
"expose.go",
"help.go",
"label.go",
"logs.go",
"options.go",
"patch.go",
"plugin.go",
"portforward.go",
"proxy.go",
"replace.go",
"rollingupdate.go",
"run.go",
"scale.go",
"taint.go",
"top.go",
"top_node.go",
"top_pod.go",
"version.go",
],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd",
visibility = [
"//build/visible_to:pkg_kubectl_cmd_CONSUMERS",
],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/apply/parse:go_default_library",
"//pkg/kubectl/apply/strategy:go_default_library",
"//pkg/kubectl/cmd/auth:go_default_library",
"//pkg/kubectl/cmd/config:go_default_library",
"//pkg/kubectl/cmd/create:go_default_library",
"//pkg/kubectl/cmd/get:go_default_library",
"//pkg/kubectl/cmd/rollout:go_default_library",
"//pkg/kubectl/cmd/scalejob:go_default_library",
"//pkg/kubectl/cmd/set:go_default_library",
"//pkg/kubectl/cmd/templates:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/cmd/util/editor:go_default_library",
"//pkg/kubectl/cmd/util/openapi:go_default_library",
"//pkg/kubectl/cmd/wait:go_default_library",
"//pkg/kubectl/explain:go_default_library",
"//pkg/kubectl/genericclioptions:go_default_library",
"//pkg/kubectl/genericclioptions/printers:go_default_library",
"//pkg/kubectl/genericclioptions/resource:go_default_library",
"//pkg/kubectl/metricsutil:go_default_library",
"//pkg/kubectl/polymorphichelpers:go_default_library",
"//pkg/kubectl/proxy:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/term:go_default_library",
"//pkg/kubectl/validation:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/util/interrupt:go_default_library",
"//pkg/util/taints:go_default_library",
"//pkg/version:go_default_library",
"//staging/src/k8s.io/api/autoscaling/v1:go_default_library",
"//staging/src/k8s.io/api/certificates/v1beta1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/policy/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/json:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/jsonmergepatch:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/mergepatch:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//staging/src/k8s.io/client-go/discovery:go_default_library",
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/apps/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/autoscaling/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/batch/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/scale:go_default_library",
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
"//staging/src/k8s.io/client-go/tools/portforward:go_default_library",
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//staging/src/k8s.io/client-go/tools/watch:go_default_library",
"//staging/src/k8s.io/client-go/transport/spdy:go_default_library",
"//staging/src/k8s.io/metrics/pkg/apis/metrics:go_default_library",
"//staging/src/k8s.io/metrics/pkg/apis/metrics/v1beta1:go_default_library",
"//staging/src/k8s.io/metrics/pkg/client/clientset/versioned:go_default_library",
"//vendor/github.com/daviddengcn/go-colortext:go_default_library",
"//vendor/github.com/docker/distribution/reference:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/github.com/evanphx/json-patch:go_default_library",
"//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/jonboulle/clockwork:go_default_library",
"//vendor/github.com/renstrom/dedent:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"annotate_test.go",
"apply_test.go",
"attach_test.go",
"clusterinfo_dump_test.go",
"cmd_printing_test.go",
"cmd_test.go",
"convert_test.go",
"cp_test.go",
"delete_test.go",
"describe_test.go",
"diff_test.go",
"drain_test.go",
"edit_test.go",
"exec_test.go",
"expose_test.go",
"label_test.go",
"logs_test.go",
"patch_test.go",
"portforward_test.go",
"replace_test.go",
"rollingupdate_test.go",
"run_test.go",
"taint_test.go",
"top_node_test.go",
"top_pod_test.go",
"top_test.go",
],
data = [
"testdata",
"//api/openapi-spec:swagger-spec",
"//test/e2e/testing-manifests:all-srcs",
"//test/fixtures",
],
embed = [":go_default_library"],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/api/testing:go_default_library",
"//pkg/apis/batch:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/kubectl/cmd/create:go_default_library",
"//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/cmd/util/openapi:go_default_library",
"//pkg/kubectl/genericclioptions:go_default_library",
"//pkg/kubectl/genericclioptions/printers:go_default_library",
"//pkg/kubectl/genericclioptions/resource:go_default_library",
"//pkg/kubectl/polymorphichelpers:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library",
"//pkg/kubectl/util/term:go_default_library",
"//pkg/printers:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/policy/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/testing:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
"//staging/src/k8s.io/client-go/dynamic/fake:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/rest/fake:go_default_library",
"//staging/src/k8s.io/client-go/testing:go_default_library",
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//staging/src/k8s.io/metrics/pkg/apis/metrics/v1alpha1:go_default_library",
"//staging/src/k8s.io/metrics/pkg/apis/metrics/v1beta1:go_default_library",
"//staging/src/k8s.io/metrics/pkg/client/clientset/versioned/fake:go_default_library",
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/gopkg.in/yaml.v2:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/kubectl/cmd/auth:all-srcs",
"//pkg/kubectl/cmd/config:all-srcs",
"//pkg/kubectl/cmd/create:all-srcs",
"//pkg/kubectl/cmd/get:all-srcs",
"//pkg/kubectl/cmd/rollout:all-srcs",
"//pkg/kubectl/cmd/scalejob:all-srcs",
"//pkg/kubectl/cmd/set:all-srcs",
"//pkg/kubectl/cmd/templates:all-srcs",
"//pkg/kubectl/cmd/testdata/edit:all-srcs",
"//pkg/kubectl/cmd/testing:all-srcs",
"//pkg/kubectl/cmd/util:all-srcs",
"//pkg/kubectl/cmd/wait:all-srcs",
],
tags = ["automanaged"],
visibility = [
"//build/visible_to:pkg_kubectl_cmd_CONSUMERS",
],
)