mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
Add command "kubectl config get-contexts"
Note: Context is not a runtime object (doesn't have Kind and Version) so we can't use the resource_printer
This commit is contained in:
parent
b37a5ded3c
commit
e0ce987f4e
@ -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
|
||||
|
10
CHANGELOG.md
10
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)
|
||||
|
3
docs/man/man1/kubectl-config-get-contexts.1
Normal file
3
docs/man/man1/kubectl-config-get-contexts.1
Normal file
@ -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.
|
36
docs/user-guide/kubectl/kubectl_config_get-contexts.md
Normal file
36
docs/user-guide/kubectl/kubectl_config_get-contexts.md
Normal file
@ -0,0 +1,36 @@
|
||||
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
|
||||
|
||||
<!-- BEGIN STRIP_FOR_RELEASE -->
|
||||
|
||||
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
|
||||
<h2>PLEASE NOTE: This document applies to the HEAD of the source tree</h2>
|
||||
|
||||
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).
|
||||
</strong>
|
||||
--
|
||||
|
||||
<!-- END STRIP_FOR_RELEASE -->
|
||||
|
||||
<!-- END MUNGE: UNVERSIONED_WARNING -->
|
||||
|
||||
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.
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
@ -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
|
||||
}
|
||||
|
168
pkg/kubectl/cmd/config/get_contexts.go
Normal file
168
pkg/kubectl/cmd/config/get_contexts.go
Normal file
@ -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
|
||||
}
|
158
pkg/kubectl/cmd/config/get_contexts_test.go
Normal file
158
pkg/kubectl/cmd/config/get_contexts_test.go
Normal file
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user