diff --git a/.generated_docs b/.generated_docs
index f606691a406..f36b59e130d 100644
--- a/.generated_docs
+++ b/.generated_docs
@@ -15,6 +15,7 @@ docs/man/man1/kubectl-cluster-info-dump.1
docs/man/man1/kubectl-cluster-info.1
docs/man/man1/kubectl-completion.1
docs/man/man1/kubectl-config-current-context.1
+docs/man/man1/kubectl-config-get-contexts.1
docs/man/man1/kubectl-config-set-cluster.1
docs/man/man1/kubectl-config-set-context.1
docs/man/man1/kubectl-config-set-credentials.1
@@ -75,6 +76,7 @@ docs/user-guide/kubectl/kubectl_cluster-info_dump.md
docs/user-guide/kubectl/kubectl_completion.md
docs/user-guide/kubectl/kubectl_config.md
docs/user-guide/kubectl/kubectl_config_current-context.md
+docs/user-guide/kubectl/kubectl_config_get-contexts.md
docs/user-guide/kubectl/kubectl_config_set-cluster.md
docs/user-guide/kubectl/kubectl_config_set-context.md
docs/user-guide/kubectl/kubectl_config_set-credentials.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 02a08dfa79d..f6bbc1710ae 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,11 +2,9 @@
- [v1.3.0](#v130)
- [Downloads](#downloads)
- - [Major Themes](#major-themes)
- - [Other notable improvements](#other-notable-improvements)
- - [Known Issues](#known-issues)
+ - [Highlights](#highlights)
+ - [Known Issues and Important Steps before Upgrading](#known-issues-and-important-steps-before-upgrading)
- [Provider-specific Notes](#provider-specific-notes)
- - [Changelog since v1.3.0-beta.3](#changelog-since-v130-beta3)
- [Previous Releases Included in v1.3.0](#previous-releases-included-in-v130)
- [v1.3.0-beta.3](#v130-beta3)
- [Downloads](#downloads)
@@ -102,7 +100,7 @@ binary | sha1 hash | md5 hash
* Authorization:
* **Alpha** RBAC authorization API group
-* Federation
+* Federation
* federation api group is now **beta**
* Services from all federated clusters are now registered in Cloud DNS (AWS and GCP).
* Stateful Apps:
@@ -139,7 +137,7 @@ binary | sha1 hash | md5 hash
* ARP caching fix
* Use /dev/xvdXX names
* ELB:
- * ELB proxy protocol support
+ * ELB proxy protocol support
* mixed plaintext/encrypted ports support in ELBs
* SSL support for ELB listeners
* Allow VPC CIDR to be specified (experimental)
diff --git a/docs/man/man1/kubectl-config-get-contexts.1 b/docs/man/man1/kubectl-config-get-contexts.1
new file mode 100644
index 00000000000..b6fd7a0f989
--- /dev/null
+++ b/docs/man/man1/kubectl-config-get-contexts.1
@@ -0,0 +1,3 @@
+This file is autogenerated, but we've stopped checking such files into the
+repository to reduce the need for rebases. Please run hack/generate-docs.sh to
+populate this file.
diff --git a/docs/user-guide/kubectl/kubectl_config_get-contexts.md b/docs/user-guide/kubectl/kubectl_config_get-contexts.md
new file mode 100644
index 00000000000..0df905e80a5
--- /dev/null
+++ b/docs/user-guide/kubectl/kubectl_config_get-contexts.md
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
PLEASE NOTE: This document applies to the HEAD of the source tree
+
+If you are using a released version of Kubernetes, you should
+refer to the docs that go with that version.
+
+Documentation for other releases can be found at
+[releases.k8s.io](http://releases.k8s.io).
+
+--
+
+
+
+
+
+This file is autogenerated, but we've stopped checking such files into the
+repository to reduce the need for rebases. Please run hack/generate-docs.sh to
+populate this file.
+
+
+[]()
+
diff --git a/pkg/kubectl/cmd/config/config.go b/pkg/kubectl/cmd/config/config.go
index 2a3523a614a..1504fa92a5e 100644
--- a/pkg/kubectl/cmd/config/config.go
+++ b/pkg/kubectl/cmd/config/config.go
@@ -57,6 +57,7 @@ The loading order follows these rules:
cmd.AddCommand(NewCmdConfigUnset(out, pathOptions))
cmd.AddCommand(NewCmdConfigCurrentContext(out, pathOptions))
cmd.AddCommand(NewCmdConfigUseContext(out, pathOptions))
+ cmd.AddCommand(NewCmdConfigGetContexts(out, pathOptions))
return cmd
}
diff --git a/pkg/kubectl/cmd/config/get_contexts.go b/pkg/kubectl/cmd/config/get_contexts.go
new file mode 100644
index 00000000000..cef853e76fe
--- /dev/null
+++ b/pkg/kubectl/cmd/config/get_contexts.go
@@ -0,0 +1,168 @@
+/*
+Copyright 2016 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 config
+
+import (
+ "fmt"
+ "io"
+ "strings"
+ "text/tabwriter"
+
+ "github.com/spf13/cobra"
+ "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
+ clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
+ "k8s.io/kubernetes/pkg/kubectl"
+
+ cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+ utilerrors "k8s.io/kubernetes/pkg/util/errors"
+ "k8s.io/kubernetes/pkg/util/sets"
+)
+
+// GetContextsOptions contains the assignable options from the args.
+type GetContextsOptions struct {
+ configAccess clientcmd.ConfigAccess
+ nameOnly bool
+ showHeaders bool
+ contextNames []string
+ out io.Writer
+}
+
+const (
+ getContextsLong = `Displays one or many contexts from the kubeconfig file.`
+
+ getContextsExample = `# List all the contexts in your kubeconfig file
+kubectl config get-contexts
+
+# Describe one context in your kubeconfig file.
+kubectl config get-contexts my-context`
+)
+
+// NewCmdConfigGetContexts creates a command object for the "get-contexts" action, which
+// retrieves one or more contexts from a kubeconfig.
+func NewCmdConfigGetContexts(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
+ options := &GetContextsOptions{configAccess: configAccess}
+
+ cmd := &cobra.Command{
+ Use: "get-contexts [(-o|--output=)name)]",
+ Short: "Describe one or many contexts",
+ Long: getContextsLong,
+ Example: getContextsExample,
+ Run: func(cmd *cobra.Command, args []string) {
+ validOutputTypes := sets.NewString("", "json", "yaml", "wide", "name", "go-template", "go-template-file", "jsonpath", "jsonpath-file")
+ supportedOutputTypes := sets.NewString("", "name")
+ outputFormat := cmdutil.GetFlagString(cmd, "output")
+ if !validOutputTypes.Has(outputFormat) {
+ cmdutil.CheckErr(fmt.Errorf("output must be one of '' or 'name': %v", outputFormat))
+ }
+ if !supportedOutputTypes.Has(outputFormat) {
+ fmt.Fprintf(out, "--output %v is not available in kubectl config get-contexts; reseting to default output format", outputFormat)
+ cmd.Flags().Set("output", "")
+ }
+ cmdutil.CheckErr(options.Complete(cmd, args, out))
+ cmdutil.CheckErr(options.RunGetContexts())
+ },
+ }
+ cmdutil.AddOutputFlags(cmd)
+ cmdutil.AddNoHeadersFlags(cmd)
+ return cmd
+}
+
+// Complete assigns GetContextsOptions from the args.
+func (o *GetContextsOptions) Complete(cmd *cobra.Command, args []string, out io.Writer) error {
+ o.contextNames = args
+ o.out = out
+ o.nameOnly = false
+ if cmdutil.GetFlagString(cmd, "output") == "name" {
+ o.nameOnly = true
+ }
+ o.showHeaders = true
+ if cmdutil.GetFlagBool(cmd, "no-headers") || o.nameOnly {
+ o.showHeaders = false
+ }
+
+ return nil
+}
+
+// RunGetContexts implements all the necessary functionality for context retrieval.
+func (o GetContextsOptions) RunGetContexts() error {
+ config, err := o.configAccess.GetStartingConfig()
+ if err != nil {
+ return err
+ }
+
+ out, found := o.out.(*tabwriter.Writer)
+ if !found {
+ out = kubectl.GetNewTabWriter(o.out)
+ defer out.Flush()
+ }
+
+ // Build a list of context names to print, and warn if any requested contexts are not found.
+ // Do this before printing the headers so it doesn't look ugly.
+ allErrs := []error{}
+ toPrint := []string{}
+ if len(o.contextNames) == 0 {
+ for name := range config.Contexts {
+ toPrint = append(toPrint, name)
+ }
+ } else {
+ for _, name := range o.contextNames {
+ _, ok := config.Contexts[name]
+ if ok {
+ toPrint = append(toPrint, name)
+ } else {
+ allErrs = append(allErrs, fmt.Errorf("context %v not found", name))
+ }
+ }
+ }
+ if o.showHeaders {
+ err = printContextHeaders(out, o.nameOnly)
+ if err != nil {
+ allErrs = append(allErrs, err)
+ }
+ }
+
+ for _, name := range toPrint {
+ err = printContext(name, config.Contexts[name], out, o.nameOnly, config.CurrentContext == name)
+ if err != nil {
+ allErrs = append(allErrs, err)
+ }
+ }
+
+ return utilerrors.NewAggregate(allErrs)
+}
+
+func printContextHeaders(out io.Writer, nameOnly bool) error {
+ columnNames := []string{"CURRENT", "NAME", "CLUSTER", "AUTHINFO", "NAMESPACE"}
+ if nameOnly {
+ columnNames = columnNames[:1]
+ }
+ _, err := fmt.Fprintf(out, "%s\n", strings.Join(columnNames, "\t"))
+ return err
+}
+
+func printContext(name string, context *clientcmdapi.Context, w io.Writer, nameOnly, current bool) error {
+ if nameOnly {
+ _, err := fmt.Fprintf(w, "%s\n", name)
+ return err
+ }
+ prefix := " "
+ if current {
+ prefix = "*"
+ }
+ _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", prefix, name, context.Cluster, context.AuthInfo, context.Namespace)
+ return err
+}
diff --git a/pkg/kubectl/cmd/config/get_contexts_test.go b/pkg/kubectl/cmd/config/get_contexts_test.go
new file mode 100644
index 00000000000..6bb38896d85
--- /dev/null
+++ b/pkg/kubectl/cmd/config/get_contexts_test.go
@@ -0,0 +1,158 @@
+/*
+Copyright 2014 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 config
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "testing"
+
+ "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
+ clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
+)
+
+type getContextsTest struct {
+ startingConfig clientcmdapi.Config
+ names []string
+ noHeader bool
+ nameOnly bool
+ expectedOut string
+}
+
+func TestGetContextsAll(t *testing.T) {
+ tconf := clientcmdapi.Config{
+ CurrentContext: "shaker-context",
+ Contexts: map[string]*clientcmdapi.Context{
+ "shaker-context": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}}}
+ test := getContextsTest{
+ startingConfig: tconf,
+ names: []string{},
+ noHeader: false,
+ nameOnly: false,
+ expectedOut: `CURRENT NAME CLUSTER AUTHINFO NAMESPACE
+* shaker-context big-cluster blue-user saw-ns
+`,
+ }
+ test.run(t)
+}
+
+func TestGetContextsAllNoHeader(t *testing.T) {
+ tconf := clientcmdapi.Config{
+ CurrentContext: "shaker-context",
+ Contexts: map[string]*clientcmdapi.Context{
+ "shaker-context": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}}}
+ test := getContextsTest{
+ startingConfig: tconf,
+ names: []string{},
+ noHeader: true,
+ nameOnly: false,
+ expectedOut: "* shaker-context big-cluster blue-user saw-ns\n",
+ }
+ test.run(t)
+}
+
+func TestGetContextsAllName(t *testing.T) {
+ tconf := clientcmdapi.Config{
+ Contexts: map[string]*clientcmdapi.Context{
+ "shaker-context": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}}}
+ test := getContextsTest{
+ startingConfig: tconf,
+ names: []string{},
+ noHeader: false,
+ nameOnly: true,
+ expectedOut: "shaker-context\n",
+ }
+ test.run(t)
+}
+
+func TestGetContextsAllNameNoHeader(t *testing.T) {
+ tconf := clientcmdapi.Config{
+ CurrentContext: "shaker-context",
+ Contexts: map[string]*clientcmdapi.Context{
+ "shaker-context": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}}}
+ test := getContextsTest{
+ startingConfig: tconf,
+ names: []string{},
+ noHeader: true,
+ nameOnly: true,
+ expectedOut: "shaker-context\n",
+ }
+ test.run(t)
+}
+
+func TestGetContextsAllNone(t *testing.T) {
+ test := getContextsTest{
+ startingConfig: *clientcmdapi.NewConfig(),
+ names: []string{},
+ noHeader: true,
+ nameOnly: false,
+ expectedOut: "",
+ }
+ test.run(t)
+}
+
+func TestGetContextsSelectOneOfTwo(t *testing.T) {
+ tconf := clientcmdapi.Config{
+ CurrentContext: "shaker-context",
+ Contexts: map[string]*clientcmdapi.Context{
+ "shaker-context": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"},
+ "not-this": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}}}
+ test := getContextsTest{
+ startingConfig: tconf,
+ names: []string{"shaker-context"},
+ noHeader: true,
+ nameOnly: true,
+ expectedOut: "shaker-context\n",
+ }
+ test.run(t)
+}
+
+func (test getContextsTest) run(t *testing.T) {
+ fakeKubeFile, _ := ioutil.TempFile("", "")
+ defer os.Remove(fakeKubeFile.Name())
+ err := clientcmd.WriteToFile(test.startingConfig, fakeKubeFile.Name())
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+
+ pathOptions := clientcmd.NewDefaultPathOptions()
+ pathOptions.GlobalFile = fakeKubeFile.Name()
+ pathOptions.EnvVar = ""
+ buf := bytes.NewBuffer([]byte{})
+ options := GetContextsOptions{
+ configAccess: pathOptions,
+ }
+ cmd := NewCmdConfigGetContexts(buf, options.configAccess)
+ if test.nameOnly {
+ cmd.Flags().Set("output", "name")
+ }
+ if test.noHeader {
+ cmd.Flags().Set("no-headers", "true")
+ }
+ cmd.Run(cmd, test.names)
+ if len(test.expectedOut) != 0 {
+ if buf.String() != test.expectedOut {
+ t.Errorf("Expected %v, but got %v", test.expectedOut, buf.String())
+ }
+ return
+ }
+
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+}
diff --git a/pkg/kubectl/cmd/util/printing.go b/pkg/kubectl/cmd/util/printing.go
index 205d50b23d1..7d4592d148c 100644
--- a/pkg/kubectl/cmd/util/printing.go
+++ b/pkg/kubectl/cmd/util/printing.go
@@ -30,9 +30,9 @@ import (
// AddPrinterFlags adds printing related flags to a command (e.g. output format, no headers, template path)
func AddPrinterFlags(cmd *cobra.Command) {
- cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://kubernetes.io/docs/user-guide/jsonpath].")
+ AddOutputFlags(cmd)
cmd.Flags().String("output-version", "", "Output the formatted object with the given group version (for ex: 'extensions/v1beta1').")
- cmd.Flags().Bool("no-headers", false, "When using the default output, don't print headers.")
+ AddNoHeadersFlags(cmd)
cmd.Flags().Bool("show-labels", false, "When printing, show all labels as the last column (default hide labels column)")
cmd.Flags().String("template", "", "Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].")
cmd.MarkFlagFilename("template")
@@ -45,6 +45,16 @@ func AddOutputFlagsForMutation(cmd *cobra.Command) {
cmd.Flags().StringP("output", "o", "", "Output mode. Use \"-o name\" for shorter output (resource/name).")
}
+// AddOutputFlags adds output related flags to a command.
+func AddOutputFlags(cmd *cobra.Command) {
+ cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://kubernetes.io/docs/user-guide/jsonpath].")
+}
+
+// AddNoHeadersFlags adds no-headers flags to a command.
+func AddNoHeadersFlags(cmd *cobra.Command) {
+ cmd.Flags().Bool("no-headers", false, "When using the default output, don't print headers.")
+}
+
// PrintSuccess prints message after finishing mutating operations
func PrintSuccess(mapper meta.RESTMapper, shortOutput bool, out io.Writer, resource string, name string, operation string) {
resource, _ = mapper.ResourceSingularizer(resource)