From 985406c969c5a1db85b558c5dd7c7e56792fcdf8 Mon Sep 17 00:00:00 2001 From: juanvallejo Date: Wed, 22 Aug 2018 15:51:02 -0400 Subject: [PATCH 1/3] add cli plugin example repo --- staging/src/BUILD | 2 + .../k8s.io/sample-cli-plugin/CONTRIBUTING.md | 7 + .../sample-cli-plugin/Godeps/Godeps.json | 574 ++++++++++++++++++ .../k8s.io/sample-cli-plugin/Godeps/OWNERS | 3 + .../k8s.io/sample-cli-plugin/Godeps/Readme | 5 + staging/src/k8s.io/sample-cli-plugin/LICENSE | 202 ++++++ staging/src/k8s.io/sample-cli-plugin/OWNERS | 10 + .../src/k8s.io/sample-cli-plugin/README.md | 77 +++ .../sample-cli-plugin/SECURITY_CONTACTS | 17 + .../src/k8s.io/sample-cli-plugin/cmd/BUILD | 34 ++ .../sample-cli-plugin/cmd/kubectl-ns.go | 20 + .../k8s.io/sample-cli-plugin/pkg/cmd/BUILD | 29 + .../k8s.io/sample-cli-plugin/pkg/cmd/ns.go | 191 ++++++ vendor/k8s.io/sample-cli-plugin | 1 + 14 files changed, 1172 insertions(+) create mode 100644 staging/src/k8s.io/sample-cli-plugin/CONTRIBUTING.md create mode 100644 staging/src/k8s.io/sample-cli-plugin/Godeps/Godeps.json create mode 100644 staging/src/k8s.io/sample-cli-plugin/Godeps/OWNERS create mode 100644 staging/src/k8s.io/sample-cli-plugin/Godeps/Readme create mode 100644 staging/src/k8s.io/sample-cli-plugin/LICENSE create mode 100644 staging/src/k8s.io/sample-cli-plugin/OWNERS create mode 100644 staging/src/k8s.io/sample-cli-plugin/README.md create mode 100644 staging/src/k8s.io/sample-cli-plugin/SECURITY_CONTACTS create mode 100644 staging/src/k8s.io/sample-cli-plugin/cmd/BUILD create mode 100644 staging/src/k8s.io/sample-cli-plugin/cmd/kubectl-ns.go create mode 100644 staging/src/k8s.io/sample-cli-plugin/pkg/cmd/BUILD create mode 100644 staging/src/k8s.io/sample-cli-plugin/pkg/cmd/ns.go create mode 120000 vendor/k8s.io/sample-cli-plugin diff --git a/staging/src/BUILD b/staging/src/BUILD index d807c04d5d..a6bb0586b9 100644 --- a/staging/src/BUILD +++ b/staging/src/BUILD @@ -211,6 +211,8 @@ filegroup( "//staging/src/k8s.io/metrics/pkg/client/custom_metrics:all-srcs", "//staging/src/k8s.io/metrics/pkg/client/external_metrics:all-srcs", "//staging/src/k8s.io/sample-apiserver:all-srcs", + "//staging/src/k8s.io/sample-cli-plugin/cmd:all-srcs", + "//staging/src/k8s.io/sample-cli-plugin/pkg/cmd:all-srcs", "//staging/src/k8s.io/sample-controller:all-srcs", ], tags = ["automanaged"], diff --git a/staging/src/k8s.io/sample-cli-plugin/CONTRIBUTING.md b/staging/src/k8s.io/sample-cli-plugin/CONTRIBUTING.md new file mode 100644 index 0000000000..d7556b8163 --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/CONTRIBUTING.md @@ -0,0 +1,7 @@ +# Contributing guidelines + +Do not open pull requests directly against this repository, they will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes. + +This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/sample-cli-plugin](https://git.k8s.io/kubernetes/staging/src/k8s.io/sample-cli-plugin) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot). + +Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/staging.md) for more information diff --git a/staging/src/k8s.io/sample-cli-plugin/Godeps/Godeps.json b/staging/src/k8s.io/sample-cli-plugin/Godeps/Godeps.json new file mode 100644 index 0000000000..4e412244a9 --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/Godeps/Godeps.json @@ -0,0 +1,574 @@ +{ + "ImportPath": "k8s.io/sample-cli-plugin", + "GoVersion": "go1.10", + "GodepVersion": "v80", + "Packages": [ + "./..." + ], + "Deps": [ + { + "ImportPath": "github.com/evanphx/json-patch", + "Rev": "94e38aa1586e8a6c8a75770bddf5ff84c48a106b" + }, + { + "ImportPath": "github.com/ghodss/yaml", + "Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee" + }, + { + "ImportPath": "github.com/gogo/protobuf/proto", + "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" + }, + { + "ImportPath": "github.com/gogo/protobuf/sortkeys", + "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" + }, + { + "ImportPath": "github.com/golang/glog", + "Rev": "44145f04b68cf362d9c4df2182967c2275eaefed" + }, + { + "ImportPath": "github.com/golang/protobuf/proto", + "Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265" + }, + { + "ImportPath": "github.com/golang/protobuf/ptypes", + "Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265" + }, + { + "ImportPath": "github.com/golang/protobuf/ptypes/any", + "Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265" + }, + { + "ImportPath": "github.com/golang/protobuf/ptypes/duration", + "Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265" + }, + { + "ImportPath": "github.com/golang/protobuf/ptypes/timestamp", + "Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265" + }, + { + "ImportPath": "github.com/google/btree", + "Rev": "7d79101e329e5a3adf994758c578dab82b90c017" + }, + { + "ImportPath": "github.com/google/gofuzz", + "Rev": "44d81051d367757e1c7c6a5a86423ece9afcf63c" + }, + { + "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", + "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba" + }, + { + "ImportPath": "github.com/googleapis/gnostic/compiler", + "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba" + }, + { + "ImportPath": "github.com/googleapis/gnostic/extensions", + "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba" + }, + { + "ImportPath": "github.com/gregjones/httpcache", + "Rev": "787624de3eb7bd915c329cba748687a3b22666a6" + }, + { + "ImportPath": "github.com/gregjones/httpcache/diskcache", + "Rev": "787624de3eb7bd915c329cba748687a3b22666a6" + }, + { + "ImportPath": "github.com/imdario/mergo", + "Rev": "9316a62528ac99aaecb4e47eadd6dc8aa6533d58" + }, + { + "ImportPath": "github.com/inconshreveable/mousetrap", + "Rev": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" + }, + { + "ImportPath": "github.com/json-iterator/go", + "Rev": "f2b4162afba35581b6d4a50d3b8f34e33c144682" + }, + { + "ImportPath": "github.com/modern-go/concurrent", + "Rev": "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" + }, + { + "ImportPath": "github.com/modern-go/reflect2", + "Rev": "05fbef0ca5da472bbf96c9322b84a53edc03c9fd" + }, + { + "ImportPath": "github.com/peterbourgon/diskv", + "Rev": "5f041e8faa004a95c88a202771f4cc3e991971e6" + }, + { + "ImportPath": "github.com/spf13/cobra", + "Rev": "c439c4fa093711d42e1b01acb1235b52004753c1" + }, + { + "ImportPath": "github.com/spf13/pflag", + "Rev": "583c0c0531f06d5278b7d917446061adc344b5cd" + }, + { + "ImportPath": "golang.org/x/crypto/ssh/terminal", + "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" + }, + { + "ImportPath": "golang.org/x/net/context", + "Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f" + }, + { + "ImportPath": "golang.org/x/net/http2", + "Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f" + }, + { + "ImportPath": "golang.org/x/net/http2/hpack", + "Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f" + }, + { + "ImportPath": "golang.org/x/net/idna", + "Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f" + }, + { + "ImportPath": "golang.org/x/net/lex/httplex", + "Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f" + }, + { + "ImportPath": "golang.org/x/sys/unix", + "Rev": "95c6576299259db960f6c5b9b69ea52422860fce" + }, + { + "ImportPath": "golang.org/x/sys/windows", + "Rev": "95c6576299259db960f6c5b9b69ea52422860fce" + }, + { + "ImportPath": "golang.org/x/text/encoding", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/text/encoding/internal", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/text/encoding/internal/identifier", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/text/encoding/unicode", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/text/internal/utf8internal", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/text/runes", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/text/secure/bidirule", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/text/transform", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/text/unicode/bidi", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/text/unicode/norm", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/time/rate", + "Rev": "f51c12702a4d776e4c1fa9b0fabab841babae631" + }, + { + "ImportPath": "gopkg.in/inf.v0", + "Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4" + }, + { + "ImportPath": "gopkg.in/yaml.v2", + "Rev": "670d4cfef0544295bc27a114dbac37980d83185a" + }, + { + "ImportPath": "k8s.io/api/admissionregistration/v1alpha1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/admissionregistration/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/apps/v1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/apps/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/apps/v1beta2", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/authentication/v1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/authentication/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/authorization/v1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/authorization/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/autoscaling/v1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/autoscaling/v2beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/batch/v1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/batch/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/batch/v2alpha1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/certificates/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/coordination/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/core/v1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/events/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/extensions/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/networking/v1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/policy/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/rbac/v1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/rbac/v1alpha1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/rbac/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/scheduling/v1alpha1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/scheduling/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/settings/v1alpha1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/storage/v1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/storage/v1alpha1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/api/storage/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/errors", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/meta", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/resource", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/conversion", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/fields", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/labels", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/schema", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/selection", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/types", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/clock", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/errors", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/framer", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/intstr", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/json", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/naming", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/net", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/runtime", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/sets", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/validation", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/validation/field", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/yaml", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/version", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/watch", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/cli-runtime/pkg/genericclioptions", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/cli-runtime/pkg/genericclioptions/printers", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/cli-runtime/pkg/genericclioptions/resource", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/discovery", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/scheme", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/core/v1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/clientauthentication", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/pkg/version", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/plugin/pkg/client/auth/exec", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/rest", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/rest/watch", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/restmapper", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/third_party/forked/golang/template", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/tools/auth", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/tools/clientcmd", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/tools/clientcmd/api", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/tools/clientcmd/api/latest", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/tools/clientcmd/api/v1", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/tools/metrics", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/tools/reference", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/transport", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/util/cert", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/util/connrotation", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/util/flowcontrol", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/util/homedir", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/util/integer", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/client-go/util/jsonpath", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + } + ] +} diff --git a/staging/src/k8s.io/sample-cli-plugin/Godeps/OWNERS b/staging/src/k8s.io/sample-cli-plugin/Godeps/OWNERS new file mode 100644 index 0000000000..9550e5e8e2 --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/Godeps/OWNERS @@ -0,0 +1,3 @@ +approvers: +- juanvallejo +- soltysh diff --git a/staging/src/k8s.io/sample-cli-plugin/Godeps/Readme b/staging/src/k8s.io/sample-cli-plugin/Godeps/Readme new file mode 100644 index 0000000000..4cdaa53d56 --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/Godeps/Readme @@ -0,0 +1,5 @@ +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. diff --git a/staging/src/k8s.io/sample-cli-plugin/LICENSE b/staging/src/k8s.io/sample-cli-plugin/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/staging/src/k8s.io/sample-cli-plugin/OWNERS b/staging/src/k8s.io/sample-cli-plugin/OWNERS new file mode 100644 index 0000000000..24989e5867 --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/OWNERS @@ -0,0 +1,10 @@ +approvers: +- juanvallejo +- soltysh +reviewers: +- seans3 +- deads2k +- soltysh +- juanvallejo +labels: +- sig/cli diff --git a/staging/src/k8s.io/sample-cli-plugin/README.md b/staging/src/k8s.io/sample-cli-plugin/README.md new file mode 100644 index 0000000000..e59a1417ae --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/README.md @@ -0,0 +1,77 @@ +# sample-cli-plugin + +This repository implements a single kubectl plugin for switching the namespace +that the current KUBECONFIG context points to. In order to remain as indestructive +as possible, no existing contexts are modified. + +**Note:** go-get or vendor this package as `k8s.io/sample-cli-plugin`. + +This particular example demonstrates how to perform basic operations such as: + +* How to create a new custom command that follows kubectl patterns +* How to obtain a user's KUBECONFIG settings and modify them +* How to make general use of the provided "cli-runtime" set of helpers for kubectl and third-party plugins + +It makes use of the genericclioptions in [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) +to generate a set of configuration flags which are in turn used to generate a raw representation of +the user's KUBECONFIG, as well as to obtain configuration which can be used with RESTClients when sending +requests to a kubernetes api server. + +## Details + +The sample cli plugin uses the [client-go library](https://github.com/kubernetes/client-go/tree/master/tools/clientcmd) to patch an existing KUBECONFIG file in a user's environment in order to update context information to point the client to a new or existing namespace. + +In order to be as non-destructive as possible, no existing contexts are modified in any way. Rather, the current context is examined, and matched against existing contexts to find a context containing the same "AuthInfo" and "Cluster" information, but with the newly desired namespace requested by the user. + +## Purpose + +This is an example of how to build a kubectl plugin using the same set of tools and helpers available to kubectl. + +## Running + +```sh +# assumes you have a working KUBECONFIG +$ go build cmd/kubectl-ns.go +# place the built binary somewhere in your PATH +$ cp ./kubectl-ns /usr/local/bin + +# you can now begin using this plugin as a regular kubectl command: +# update your configuration to point to "new-namespace" +$ kubectl ns new-namespace +# any kubectl commands you perform from now on will use "new-namespace" +$ kubectl get pod +NAME READY STATUS RESTARTS AGE +new-namespace-pod 1/1 Running 0 1h + +# list all of the namespace in use by contexts in your KUBECONFIG +$ kubectl ns --list + +# show the namespace that the currently set context in your KUBECONFIG points to +$ kubectl ns +``` + +## Use Cases + +This plugin can be used as a developer tool, in order to quickly view or change the current namespace +that kubectl points to. + +It can also be used as a means of showcasing usage of the cli-runtime set of utilities to aid in +third-party plugin development. + +## Cleanup + +You can "uninstall" this plugin from kubectl by simply removing it from your PATH: + + $ rm /usr/local/bin/kubectl-ns + +## Compatibility + +HEAD of this repository will match HEAD of k8s.io/apimachinery and +k8s.io/client-go. + +## Where does it come from? + +`sample-cli-plugin` is synced from +https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/sample-cli-plugin. +Code changes are made in that location, merged into k8s.io/kubernetes and +later synced here. diff --git a/staging/src/k8s.io/sample-cli-plugin/SECURITY_CONTACTS b/staging/src/k8s.io/sample-cli-plugin/SECURITY_CONTACTS new file mode 100644 index 0000000000..0648a8ebff --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/SECURITY_CONTACTS @@ -0,0 +1,17 @@ +# Defined below are the security contacts for this repo. +# +# They are the contact point for the Product Security Team to reach out +# to for triaging and handling of incoming issues. +# +# The below names agree to abide by the +# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy) +# and will be removed and replaced if they violate that agreement. +# +# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE +# INSTRUCTIONS AT https://kubernetes.io/security/ + +cjcullen +jessfraz +liggitt +philips +tallclair diff --git a/staging/src/k8s.io/sample-cli-plugin/cmd/BUILD b/staging/src/k8s.io/sample-cli-plugin/cmd/BUILD new file mode 100644 index 0000000000..ab2ece6445 --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/cmd/BUILD @@ -0,0 +1,34 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") + +go_library( + name = "go_default_library", + srcs = ["kubectl-ns.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/sample-cli-plugin/cmd", + importpath = "k8s.io/sample-cli-plugin/cmd", + visibility = ["//visibility:private"], + deps = [ + "//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library", + "//staging/src/k8s.io/sample-cli-plugin/pkg/cmd:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", + ], +) + +go_binary( + name = "cmd", + embed = [":go_default_library"], + visibility = ["//visibility:public"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/sample-cli-plugin/cmd/kubectl-ns.go b/staging/src/k8s.io/sample-cli-plugin/cmd/kubectl-ns.go new file mode 100644 index 0000000000..5bf5b361c3 --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/cmd/kubectl-ns.go @@ -0,0 +1,20 @@ +package main + +import ( + "os" + + "github.com/spf13/pflag" + + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/sample-cli-plugin/pkg/cmd" +) + +func main() { + flags := pflag.NewFlagSet("kubectl-ns", pflag.ExitOnError) + pflag.CommandLine = flags + + root := cmd.NewCmdNamespace(genericclioptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}) + if err := root.Execute(); err != nil { + os.Exit(1) + } +} diff --git a/staging/src/k8s.io/sample-cli-plugin/pkg/cmd/BUILD b/staging/src/k8s.io/sample-cli-plugin/pkg/cmd/BUILD new file mode 100644 index 0000000000..7664374f9f --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/pkg/cmd/BUILD @@ -0,0 +1,29 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["ns.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/sample-cli-plugin/pkg/cmd", + importpath = "k8s.io/sample-cli-plugin/pkg/cmd", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library", + "//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library", + "//staging/src/k8s.io/client-go/tools/clientcmd/api:go_default_library", + "//vendor/github.com/spf13/cobra:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/sample-cli-plugin/pkg/cmd/ns.go b/staging/src/k8s.io/sample-cli-plugin/pkg/cmd/ns.go new file mode 100644 index 0000000000..3a1ae2f130 --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/pkg/cmd/ns.go @@ -0,0 +1,191 @@ +package cmd + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" + + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/clientcmd/api" + + "k8s.io/cli-runtime/pkg/genericclioptions" +) + +var ( + namespace_example = ` + # view the current namespace in your KUBECONFIG + %[1]s ns + + # view all of the namespaces in use by contexts in your KUBECONFIG + %[1] ns --list + + # switch your current-context to one that contains the desired namespace + %[1]s ns foo +` +) + +type NamespaceOptions struct { + configFlags *genericclioptions.ConfigFlags + + rawConfig api.Config + listNamespaces bool + args []string + + genericclioptions.IOStreams +} + +func NewNamespaceOptions(streams genericclioptions.IOStreams) *NamespaceOptions { + return &NamespaceOptions{ + configFlags: genericclioptions.NewConfigFlags(), + + IOStreams: streams, + } +} + +func NewCmdNamespace(streams genericclioptions.IOStreams) *cobra.Command { + o := NewNamespaceOptions(streams) + + cmd := &cobra.Command{ + Use: "ns [new-namespace] [flags]", + Short: "View or set the current namespace", + Example: namespace_example, + SilenceUsage: true, + RunE: func(c *cobra.Command, args []string) error { + if err := o.Complete(args); err != nil { + return err + } + if err := o.Validate(); err != nil { + return err + } + if err := o.Run(); err != nil { + return err + } + + return nil + }, + } + + cmd.Flags().BoolVar(&o.listNamespaces, "list", o.listNamespaces, "if true, print the list of all namespaces in the current KUBECONFIG") + o.configFlags.AddFlags(cmd.Flags()) + + return cmd +} + +func (o *NamespaceOptions) Complete(args []string) error { + var err error + o.rawConfig, err = o.configFlags.ToRawKubeConfigLoader().RawConfig() + if err != nil { + return err + } + + o.args = args + return nil +} + +func (o *NamespaceOptions) Validate() error { + if len(o.rawConfig.CurrentContext) == 0 { + return fmt.Errorf("no context is currently set in your configuration") + } + if len(o.args) > 1 { + return fmt.Errorf("either one or no arguments are allowed") + } + + return nil +} + +func (o *NamespaceOptions) Run() error { + if len(o.args) > 0 && len(o.args[0]) > 0 { + return o.setNamespace(o.args[0]) + } + + namespaces := map[string]bool{} + + for name, c := range o.rawConfig.Contexts { + if !o.listNamespaces && name == o.rawConfig.CurrentContext { + if len(c.Namespace) == 0 { + return fmt.Errorf("no namespace is set for your current context: %q", name) + } + + fmt.Fprintf(o.Out, "%s\n", c.Namespace) + return nil + } + + // skip if dealing with a namespace we have already seen + // or if the namespace for the current context is empty + if len(c.Namespace) == 0 { + continue + } + if namespaces[c.Namespace] { + continue + } + + namespaces[c.Namespace] = true + } + + if !o.listNamespaces { + return fmt.Errorf("unable to find information for the current namespace in your configuration") + } + + for n := range namespaces { + fmt.Fprintf(o.Out, "%s\n", n) + } + + return nil +} + +func (o *NamespaceOptions) setNamespace(newNamespace string) error { + if len(newNamespace) == 0 { + return fmt.Errorf("a non-empty namespace must be provided") + } + + existingCtx, ok := o.rawConfig.Contexts[o.rawConfig.CurrentContext] + if !ok { + return fmt.Errorf("unable to gather information about the current context") + } + + if existingCtx.Namespace == newNamespace { + fmt.Fprintf(o.Out, "already using namespace %q\n", newNamespace) + return nil + } + + // determine if a context exists for the new namespace + existingCtxName := "" + for name, c := range o.rawConfig.Contexts { + if c.Namespace != newNamespace || c.Cluster != existingCtx.Cluster || c.AuthInfo != existingCtx.AuthInfo { + continue + } + + existingCtxName = name + break + } + + if len(existingCtxName) == 0 { + newCtx := api.NewContext() + newCtx.AuthInfo = existingCtx.AuthInfo + newCtx.Cluster = existingCtx.Cluster + newCtx.Namespace = newNamespace + + newCtxName := newNamespace + if len(existingCtx.Cluster) > 0 { + newCtxName = fmt.Sprintf("%s/%s", newCtxName, existingCtx.Cluster) + } + if len(existingCtx.AuthInfo) > 0 { + cleanAuthInfo := strings.Split(existingCtx.AuthInfo, "/")[0] + newCtxName = fmt.Sprintf("%s/%s", newCtxName, cleanAuthInfo) + } + + o.rawConfig.Contexts[newCtxName] = newCtx + existingCtxName = newCtxName + } + + configAccess := clientcmd.NewDefaultPathOptions() + o.rawConfig.CurrentContext = existingCtxName + + if err := clientcmd.ModifyConfig(configAccess, o.rawConfig, true); err != nil { + return err + } + + fmt.Fprintf(o.Out, "namespace changed to %q\n", newNamespace) + return nil +} diff --git a/vendor/k8s.io/sample-cli-plugin b/vendor/k8s.io/sample-cli-plugin new file mode 120000 index 0000000000..fc41b3df4c --- /dev/null +++ b/vendor/k8s.io/sample-cli-plugin @@ -0,0 +1 @@ +../../staging/src/k8s.io/sample-cli-plugin \ No newline at end of file From a510285d635e77bf88d6889f15b0d8d4c0132131 Mon Sep 17 00:00:00 2001 From: juanvallejo Date: Wed, 22 Aug 2018 19:59:23 -0400 Subject: [PATCH 2/3] add support for --cluster --context --user flags --- .../sample-cli-plugin/cmd/kubectl-ns.go | 16 ++ .../k8s.io/sample-cli-plugin/pkg/cmd/ns.go | 210 +++++++++++++----- 2 files changed, 170 insertions(+), 56 deletions(-) diff --git a/staging/src/k8s.io/sample-cli-plugin/cmd/kubectl-ns.go b/staging/src/k8s.io/sample-cli-plugin/cmd/kubectl-ns.go index 5bf5b361c3..2b5fbb07e5 100644 --- a/staging/src/k8s.io/sample-cli-plugin/cmd/kubectl-ns.go +++ b/staging/src/k8s.io/sample-cli-plugin/cmd/kubectl-ns.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 main import ( diff --git a/staging/src/k8s.io/sample-cli-plugin/pkg/cmd/ns.go b/staging/src/k8s.io/sample-cli-plugin/pkg/cmd/ns.go index 3a1ae2f130..13f26cce45 100644 --- a/staging/src/k8s.io/sample-cli-plugin/pkg/cmd/ns.go +++ b/staging/src/k8s.io/sample-cli-plugin/pkg/cmd/ns.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 cmd import ( @@ -13,21 +29,33 @@ import ( ) var ( - namespace_example = ` + namespaceExample = ` # view the current namespace in your KUBECONFIG %[1]s ns # view all of the namespaces in use by contexts in your KUBECONFIG - %[1] ns --list + %[1]s ns --list # switch your current-context to one that contains the desired namespace %[1]s ns foo ` + + errNoContext = fmt.Errorf("no context is currently set, use %q to select a new one", "kubectl config use-context ") ) +// NamespaceOptions provides information required to update +// the current context on a user's KUBECONFIG type NamespaceOptions struct { configFlags *genericclioptions.ConfigFlags + resultingContext *api.Context + resultingContextName string + + userSpecifiedCluster string + userSpecifiedContext string + userSpecifiedAuthInfo string + userSpecifiedNamespace string + rawConfig api.Config listNamespaces bool args []string @@ -35,6 +63,7 @@ type NamespaceOptions struct { genericclioptions.IOStreams } +// NewNamespaceOptions provides an instance of NamespaceOptions with default values func NewNamespaceOptions(streams genericclioptions.IOStreams) *NamespaceOptions { return &NamespaceOptions{ configFlags: genericclioptions.NewConfigFlags(), @@ -43,16 +72,17 @@ func NewNamespaceOptions(streams genericclioptions.IOStreams) *NamespaceOptions } } +// NewCmdNamespace provides a cobra command wrapping NamespaceOptions func NewCmdNamespace(streams genericclioptions.IOStreams) *cobra.Command { o := NewNamespaceOptions(streams) cmd := &cobra.Command{ Use: "ns [new-namespace] [flags]", Short: "View or set the current namespace", - Example: namespace_example, + Example: fmt.Sprintf(namespaceExample, "kubectl"), SilenceUsage: true, RunE: func(c *cobra.Command, args []string) error { - if err := o.Complete(args); err != nil { + if err := o.Complete(c, args); err != nil { return err } if err := o.Validate(); err != nil { @@ -72,20 +102,103 @@ func NewCmdNamespace(streams genericclioptions.IOStreams) *cobra.Command { return cmd } -func (o *NamespaceOptions) Complete(args []string) error { +// Complete sets all information required for updating the current context +func (o *NamespaceOptions) Complete(cmd *cobra.Command, args []string) error { + o.args = args + var err error o.rawConfig, err = o.configFlags.ToRawKubeConfigLoader().RawConfig() if err != nil { return err } - o.args = args + o.userSpecifiedNamespace, err = cmd.Flags().GetString("namespace") + if err != nil { + return err + } + if len(args) > 0 { + if len(o.userSpecifiedNamespace) > 0 { + return fmt.Errorf("cannot specify both a --namespace value and a new namespace argument") + } + + o.userSpecifiedNamespace = args[0] + } + + // if no namespace argument or flag value was specified, then there + // is no need to generate a resulting context + if len(o.userSpecifiedNamespace) == 0 { + return nil + } + + o.userSpecifiedContext, err = cmd.Flags().GetString("context") + if err != nil { + return err + } + + o.userSpecifiedCluster, err = cmd.Flags().GetString("cluster") + if err != nil { + return err + } + + o.userSpecifiedAuthInfo, err = cmd.Flags().GetString("user") + if err != nil { + return err + } + + currentContext, exists := o.rawConfig.Contexts[o.rawConfig.CurrentContext] + if !exists { + return errNoContext + } + + o.resultingContext = api.NewContext() + o.resultingContext.Cluster = currentContext.Cluster + o.resultingContext.AuthInfo = currentContext.AuthInfo + + // if a target context is explicitly provided by the user, + // use that as our reference for the final, resulting context + if len(o.userSpecifiedContext) > 0 { + o.resultingContextName = o.userSpecifiedContext + if userCtx, exists := o.rawConfig.Contexts[o.userSpecifiedContext]; exists { + o.resultingContext = userCtx.DeepCopy() + } + } + + // override context info with user provided values + o.resultingContext.Namespace = o.userSpecifiedNamespace + + if len(o.userSpecifiedCluster) > 0 { + o.resultingContext.Cluster = o.userSpecifiedCluster + } + if len(o.userSpecifiedAuthInfo) > 0 { + o.resultingContext.AuthInfo = o.userSpecifiedAuthInfo + } + + // generate a unique context name based on its new values if + // user did not explicitly request a context by name + if len(o.userSpecifiedContext) == 0 { + o.resultingContextName = generateContextName(o.resultingContext) + } + return nil } +func generateContextName(fromContext *api.Context) string { + name := fromContext.Namespace + if len(fromContext.Cluster) > 0 { + name = fmt.Sprintf("%s/%s", name, fromContext.Cluster) + } + if len(fromContext.AuthInfo) > 0 { + cleanAuthInfo := strings.Split(fromContext.AuthInfo, "/")[0] + name = fmt.Sprintf("%s/%s", name, cleanAuthInfo) + } + + return name +} + +// Validate ensures that all required arguments and flag values are provided func (o *NamespaceOptions) Validate() error { if len(o.rawConfig.CurrentContext) == 0 { - return fmt.Errorf("no context is currently set in your configuration") + return errNoContext } if len(o.args) > 1 { return fmt.Errorf("either one or no arguments are allowed") @@ -94,9 +207,11 @@ func (o *NamespaceOptions) Validate() error { return nil } +// Run lists all available namespaces on a user's KUBECONFIG or updates the +// current context based on a provided namespace. func (o *NamespaceOptions) Run() error { - if len(o.args) > 0 && len(o.args[0]) > 0 { - return o.setNamespace(o.args[0]) + if len(o.userSpecifiedNamespace) > 0 && o.resultingContext != nil { + return o.setNamespace(o.resultingContext, o.resultingContextName) } namespaces := map[string]bool{} @@ -134,58 +249,41 @@ func (o *NamespaceOptions) Run() error { return nil } -func (o *NamespaceOptions) setNamespace(newNamespace string) error { - if len(newNamespace) == 0 { +func isContextEqual(ctxA, ctxB *api.Context) bool { + if ctxA == nil || ctxB == nil { + return false + } + if ctxA.Cluster != ctxB.Cluster { + return false + } + if ctxA.Namespace != ctxB.Namespace { + return false + } + if ctxA.AuthInfo != ctxB.AuthInfo { + return false + } + + return true +} + +// setNamespace receives a "desired" context state and determines if a similar context +// is already present in a user's KUBECONFIG. If one is not, then a new context is added +// to the user's config under the provided destination name. +// The current context field is updated to point to the new context. +func (o *NamespaceOptions) setNamespace(fromContext *api.Context, withContextName string) error { + if len(fromContext.Namespace) == 0 { return fmt.Errorf("a non-empty namespace must be provided") } - existingCtx, ok := o.rawConfig.Contexts[o.rawConfig.CurrentContext] - if !ok { - return fmt.Errorf("unable to gather information about the current context") - } - - if existingCtx.Namespace == newNamespace { - fmt.Fprintf(o.Out, "already using namespace %q\n", newNamespace) - return nil - } - - // determine if a context exists for the new namespace - existingCtxName := "" - for name, c := range o.rawConfig.Contexts { - if c.Namespace != newNamespace || c.Cluster != existingCtx.Cluster || c.AuthInfo != existingCtx.AuthInfo { - continue - } - - existingCtxName = name - break - } - - if len(existingCtxName) == 0 { - newCtx := api.NewContext() - newCtx.AuthInfo = existingCtx.AuthInfo - newCtx.Cluster = existingCtx.Cluster - newCtx.Namespace = newNamespace - - newCtxName := newNamespace - if len(existingCtx.Cluster) > 0 { - newCtxName = fmt.Sprintf("%s/%s", newCtxName, existingCtx.Cluster) - } - if len(existingCtx.AuthInfo) > 0 { - cleanAuthInfo := strings.Split(existingCtx.AuthInfo, "/")[0] - newCtxName = fmt.Sprintf("%s/%s", newCtxName, cleanAuthInfo) - } - - o.rawConfig.Contexts[newCtxName] = newCtx - existingCtxName = newCtxName - } - configAccess := clientcmd.NewDefaultPathOptions() - o.rawConfig.CurrentContext = existingCtxName - if err := clientcmd.ModifyConfig(configAccess, o.rawConfig, true); err != nil { - return err + // determine if we have already saved this context to the user's KUBECONFIG before + // if so, simply switch the current context to the existing one. + if existingResultingCtx, exists := o.rawConfig.Contexts[withContextName]; !exists || !isContextEqual(fromContext, existingResultingCtx) { + o.rawConfig.Contexts[withContextName] = fromContext } + o.rawConfig.CurrentContext = withContextName - fmt.Fprintf(o.Out, "namespace changed to %q\n", newNamespace) - return nil + fmt.Fprintf(o.Out, "namespace changed to %q\n", fromContext.Namespace) + return clientcmd.ModifyConfig(configAccess, o.rawConfig, true) } From e5599b5ea5bf00f6de679f0fbe99381dbd02c39a Mon Sep 17 00:00:00 2001 From: Maciej Szulik Date: Thu, 23 Aug 2018 09:38:57 +0200 Subject: [PATCH 3/3] Updated staging godeps, import restrictions and missing metadata files --- hack/import-restrictions.yaml | 7 +++++++ .../.github/PULL_REQUEST_TEMPLATE.md | 2 ++ .../src/k8s.io/sample-cli-plugin/Godeps/Godeps.json | 12 ++++-------- .../src/k8s.io/sample-cli-plugin/code-of-conduct.md | 3 +++ 4 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 staging/src/k8s.io/sample-cli-plugin/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 staging/src/k8s.io/sample-cli-plugin/code-of-conduct.md diff --git a/hack/import-restrictions.yaml b/hack/import-restrictions.yaml index 00f2bb0150..55dfe9b1a7 100644 --- a/hack/import-restrictions.yaml +++ b/hack/import-restrictions.yaml @@ -119,3 +119,10 @@ - k8s.io/apimachinery - k8s.io/kube-openapi - k8s.io/gengo + +- baseImportPath: "./vendor/k8s.io/sample-cli-plugin/" + allowedImports: + - k8s.io/api + - k8s.io/cli-runtime + - k8s.io/client-go + - k8s.io/sample-cli-plugin diff --git a/staging/src/k8s.io/sample-cli-plugin/.github/PULL_REQUEST_TEMPLATE.md b/staging/src/k8s.io/sample-cli-plugin/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..e559c074bb --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,2 @@ +Sorry, we do not accept changes directly against this repository. Please see +CONTRIBUTING.md for information on where and how to contribute instead. diff --git a/staging/src/k8s.io/sample-cli-plugin/Godeps/Godeps.json b/staging/src/k8s.io/sample-cli-plugin/Godeps/Godeps.json index 4e412244a9..e17ec100ab 100644 --- a/staging/src/k8s.io/sample-cli-plugin/Godeps/Godeps.json +++ b/staging/src/k8s.io/sample-cli-plugin/Godeps/Godeps.json @@ -234,6 +234,10 @@ "ImportPath": "k8s.io/api/autoscaling/v2beta1", "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }, + { + "ImportPath": "k8s.io/api/autoscaling/v2beta2", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, { "ImportPath": "k8s.io/api/batch/v1", "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" @@ -474,10 +478,6 @@ "ImportPath": "k8s.io/client-go/kubernetes/scheme", "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/core/v1", - "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - }, { "ImportPath": "k8s.io/client-go/pkg/apis/clientauthentication", "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" @@ -538,10 +538,6 @@ "ImportPath": "k8s.io/client-go/tools/metrics", "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }, - { - "ImportPath": "k8s.io/client-go/tools/reference", - "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - }, { "ImportPath": "k8s.io/client-go/transport", "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" diff --git a/staging/src/k8s.io/sample-cli-plugin/code-of-conduct.md b/staging/src/k8s.io/sample-cli-plugin/code-of-conduct.md new file mode 100644 index 0000000000..0d15c00cf3 --- /dev/null +++ b/staging/src/k8s.io/sample-cli-plugin/code-of-conduct.md @@ -0,0 +1,3 @@ +# Kubernetes Community Code of Conduct + +Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)