diff --git a/.generated_docs b/.generated_docs
index e88bda62ae5..b926c676e7b 100644
--- a/.generated_docs
+++ b/.generated_docs
@@ -15,6 +15,9 @@ 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-delete-cluster.1
+docs/man/man1/kubectl-config-delete-context.1
+docs/man/man1/kubectl-config-get-clusters.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
@@ -86,6 +89,9 @@ 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_delete-cluster.md
+docs/user-guide/kubectl/kubectl_config_delete-context.md
+docs/user-guide/kubectl/kubectl_config_get-clusters.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
diff --git a/docs/man/man1/kubectl-config-delete-cluster.1 b/docs/man/man1/kubectl-config-delete-cluster.1
new file mode 100644
index 00000000000..b6fd7a0f989
--- /dev/null
+++ b/docs/man/man1/kubectl-config-delete-cluster.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/man/man1/kubectl-config-delete-context.1 b/docs/man/man1/kubectl-config-delete-context.1
new file mode 100644
index 00000000000..b6fd7a0f989
--- /dev/null
+++ b/docs/man/man1/kubectl-config-delete-context.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/man/man1/kubectl-config-get-clusters.1 b/docs/man/man1/kubectl-config-get-clusters.1
new file mode 100644
index 00000000000..b6fd7a0f989
--- /dev/null
+++ b/docs/man/man1/kubectl-config-get-clusters.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_delete-cluster.md b/docs/user-guide/kubectl/kubectl_config_delete-cluster.md
new file mode 100644
index 00000000000..c917a833ff9
--- /dev/null
+++ b/docs/user-guide/kubectl/kubectl_config_delete-cluster.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/docs/user-guide/kubectl/kubectl_config_delete-context.md b/docs/user-guide/kubectl/kubectl_config_delete-context.md
new file mode 100644
index 00000000000..488025bd1cf
--- /dev/null
+++ b/docs/user-guide/kubectl/kubectl_config_delete-context.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/docs/user-guide/kubectl/kubectl_config_get-clusters.md b/docs/user-guide/kubectl/kubectl_config_get-clusters.md
new file mode 100644
index 00000000000..9cc1dba517b
--- /dev/null
+++ b/docs/user-guide/kubectl/kubectl_config_get-clusters.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 15f0ff2640b..1354c9db306 100644
--- a/pkg/kubectl/cmd/config/config.go
+++ b/pkg/kubectl/cmd/config/config.go
@@ -26,6 +26,7 @@ import (
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
)
+// NewCmdConfig creates a command object for the "config" action, and adds all child commands to it.
func NewCmdConfig(pathOptions *clientcmd.PathOptions, out io.Writer) *cobra.Command {
if len(pathOptions.ExplicitFileFlag) == 0 {
pathOptions.ExplicitFileFlag = clientcmd.RecommendedConfigPathFlag
@@ -58,6 +59,9 @@ The loading order follows these rules:
cmd.AddCommand(NewCmdConfigCurrentContext(out, pathOptions))
cmd.AddCommand(NewCmdConfigUseContext(out, pathOptions))
cmd.AddCommand(NewCmdConfigGetContexts(out, pathOptions))
+ cmd.AddCommand(NewCmdConfigGetClusters(out, pathOptions))
+ cmd.AddCommand(NewCmdConfigDeleteCluster(out, pathOptions))
+ cmd.AddCommand(NewCmdConfigDeleteContext(out, pathOptions))
return cmd
}
diff --git a/pkg/kubectl/cmd/config/delete_cluster.go b/pkg/kubectl/cmd/config/delete_cluster.go
new file mode 100644
index 00000000000..24b30497894
--- /dev/null
+++ b/pkg/kubectl/cmd/config/delete_cluster.go
@@ -0,0 +1,73 @@
+/*
+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"
+
+ "github.com/spf13/cobra"
+ "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
+ cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+)
+
+func NewCmdConfigDeleteCluster(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "delete-cluster NAME",
+ Short: "Delete the specified cluster from the kubeconfig",
+ Run: func(cmd *cobra.Command, args []string) {
+ err := runDeleteCluster(out, configAccess, cmd)
+ cmdutil.CheckErr(err)
+ },
+ }
+
+ return cmd
+}
+
+func runDeleteCluster(out io.Writer, configAccess clientcmd.ConfigAccess, cmd *cobra.Command) error {
+ config, err := configAccess.GetStartingConfig()
+ if err != nil {
+ return err
+ }
+
+ args := cmd.Flags().Args()
+ if len(args) != 1 {
+ cmd.Help()
+ return nil
+ }
+
+ configFile := configAccess.GetDefaultFilename()
+ if configAccess.IsExplicitFile() {
+ configFile = configAccess.GetExplicitFile()
+ }
+
+ name := args[0]
+ _, ok := config.Clusters[name]
+ if !ok {
+ return fmt.Errorf("cannot delete cluster %s, not in %s", name, configFile)
+ }
+
+ delete(config.Clusters, name)
+
+ if err := clientcmd.ModifyConfig(configAccess, *config, true); err != nil {
+ return err
+ }
+
+ fmt.Fprintf(out, "deleted cluster %s from %s", name, configFile)
+
+ return nil
+}
diff --git a/pkg/kubectl/cmd/config/delete_cluster_test.go b/pkg/kubectl/cmd/config/delete_cluster_test.go
new file mode 100644
index 00000000000..55d223cba86
--- /dev/null
+++ b/pkg/kubectl/cmd/config/delete_cluster_test.go
@@ -0,0 +1,94 @@
+/*
+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 (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "reflect"
+ "testing"
+
+ "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
+ clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
+)
+
+type deleteClusterTest struct {
+ config clientcmdapi.Config
+ clusterToDelete string
+ expectedClusters []string
+ expectedOut string
+}
+
+func TestDeleteCluster(t *testing.T) {
+ conf := clientcmdapi.Config{
+ Clusters: map[string]*clientcmdapi.Cluster{
+ "minikube": {Server: "https://192.168.0.99"},
+ "otherkube": {Server: "https://192.168.0.100"},
+ },
+ }
+ test := deleteClusterTest{
+ config: conf,
+ clusterToDelete: "minikube",
+ expectedClusters: []string{"otherkube"},
+ expectedOut: "deleted cluster minikube from %s",
+ }
+
+ test.run(t)
+}
+
+func (test deleteClusterTest) run(t *testing.T) {
+ fakeKubeFile, _ := ioutil.TempFile("", "")
+ defer os.Remove(fakeKubeFile.Name())
+ err := clientcmd.WriteToFile(test.config, fakeKubeFile.Name())
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+
+ pathOptions := clientcmd.NewDefaultPathOptions()
+ pathOptions.GlobalFile = fakeKubeFile.Name()
+ pathOptions.EnvVar = ""
+
+ buf := bytes.NewBuffer([]byte{})
+ cmd := NewCmdConfigDeleteCluster(buf, pathOptions)
+ cmd.SetArgs([]string{test.clusterToDelete})
+ if err := cmd.Execute(); err != nil {
+ t.Fatalf("unexpected error executing command: %v", err)
+ }
+
+ expectedOutWithFile := fmt.Sprintf(test.expectedOut, fakeKubeFile.Name())
+ if expectedOutWithFile != buf.String() {
+ t.Errorf("expected output %s, but got %s", expectedOutWithFile, buf.String())
+ return
+ }
+
+ // Verify cluster was removed from kubeconfig file
+ config, err := clientcmd.LoadFromFile(fakeKubeFile.Name())
+ if err != nil {
+ t.Fatalf("unexpected error loading kubeconfig file: %v", err)
+ }
+
+ clusters := make([]string, 0, len(config.Clusters))
+ for k := range config.Clusters {
+ clusters = append(clusters, k)
+ }
+
+ if !reflect.DeepEqual(test.expectedClusters, clusters) {
+ t.Errorf("expected clusters %v, but found %v in kubeconfig", test.expectedClusters, clusters)
+ }
+}
diff --git a/pkg/kubectl/cmd/config/delete_context.go b/pkg/kubectl/cmd/config/delete_context.go
new file mode 100644
index 00000000000..9a56246deff
--- /dev/null
+++ b/pkg/kubectl/cmd/config/delete_context.go
@@ -0,0 +1,73 @@
+/*
+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"
+
+ "github.com/spf13/cobra"
+ "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
+ cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+)
+
+func NewCmdConfigDeleteContext(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "delete-context NAME",
+ Short: "Delete the specified context from the kubeconfig",
+ Run: func(cmd *cobra.Command, args []string) {
+ err := runDeleteContext(out, configAccess, cmd)
+ cmdutil.CheckErr(err)
+ },
+ }
+
+ return cmd
+}
+
+func runDeleteContext(out io.Writer, configAccess clientcmd.ConfigAccess, cmd *cobra.Command) error {
+ config, err := configAccess.GetStartingConfig()
+ if err != nil {
+ return err
+ }
+
+ args := cmd.Flags().Args()
+ if len(args) != 1 {
+ cmd.Help()
+ return nil
+ }
+
+ configFile := configAccess.GetDefaultFilename()
+ if configAccess.IsExplicitFile() {
+ configFile = configAccess.GetExplicitFile()
+ }
+
+ name := args[0]
+ _, ok := config.Contexts[name]
+ if !ok {
+ return fmt.Errorf("cannot delete context %s, not in %s", name, configFile)
+ }
+
+ delete(config.Contexts, name)
+
+ if err := clientcmd.ModifyConfig(configAccess, *config, true); err != nil {
+ return err
+ }
+
+ fmt.Fprintf(out, "deleted context %s from %s", name, configFile)
+
+ return nil
+}
diff --git a/pkg/kubectl/cmd/config/delete_context_test.go b/pkg/kubectl/cmd/config/delete_context_test.go
new file mode 100644
index 00000000000..c575dd26148
--- /dev/null
+++ b/pkg/kubectl/cmd/config/delete_context_test.go
@@ -0,0 +1,94 @@
+/*
+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 (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "reflect"
+ "testing"
+
+ "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
+ clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
+)
+
+type deleteContextTest struct {
+ config clientcmdapi.Config
+ contextToDelete string
+ expectedContexts []string
+ expectedOut string
+}
+
+func TestDeleteContext(t *testing.T) {
+ conf := clientcmdapi.Config{
+ Contexts: map[string]*clientcmdapi.Context{
+ "minikube": {Cluster: "minikube"},
+ "otherkube": {Cluster: "otherkube"},
+ },
+ }
+ test := deleteContextTest{
+ config: conf,
+ contextToDelete: "minikube",
+ expectedContexts: []string{"otherkube"},
+ expectedOut: "deleted context minikube from %s",
+ }
+
+ test.run(t)
+}
+
+func (test deleteContextTest) run(t *testing.T) {
+ fakeKubeFile, _ := ioutil.TempFile("", "")
+ defer os.Remove(fakeKubeFile.Name())
+ err := clientcmd.WriteToFile(test.config, fakeKubeFile.Name())
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+
+ pathOptions := clientcmd.NewDefaultPathOptions()
+ pathOptions.GlobalFile = fakeKubeFile.Name()
+ pathOptions.EnvVar = ""
+
+ buf := bytes.NewBuffer([]byte{})
+ cmd := NewCmdConfigDeleteContext(buf, pathOptions)
+ cmd.SetArgs([]string{test.contextToDelete})
+ if err := cmd.Execute(); err != nil {
+ t.Fatalf("unexpected error executing command: %v", err)
+ }
+
+ expectedOutWithFile := fmt.Sprintf(test.expectedOut, fakeKubeFile.Name())
+ if expectedOutWithFile != buf.String() {
+ t.Errorf("expected output %s, but got %s", expectedOutWithFile, buf.String())
+ return
+ }
+
+ // Verify context was removed from kubeconfig file
+ config, err := clientcmd.LoadFromFile(fakeKubeFile.Name())
+ if err != nil {
+ t.Fatalf("unexpected error loading kubeconfig file: %v", err)
+ }
+
+ contexts := make([]string, 0, len(config.Contexts))
+ for k := range config.Contexts {
+ contexts = append(contexts, k)
+ }
+
+ if !reflect.DeepEqual(test.expectedContexts, contexts) {
+ t.Errorf("expected contexts %v, but found %v in kubeconfig", test.expectedContexts, contexts)
+ }
+}
diff --git a/pkg/kubectl/cmd/config/get_clusters.go b/pkg/kubectl/cmd/config/get_clusters.go
new file mode 100644
index 00000000000..550be37b50d
--- /dev/null
+++ b/pkg/kubectl/cmd/config/get_clusters.go
@@ -0,0 +1,55 @@
+/*
+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"
+
+ "github.com/spf13/cobra"
+ "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
+ cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+)
+
+// NewCmdConfigGetClusters creates a command object for the "get-clusters" action, which
+// lists all clusters defined in the kubeconfig.
+func NewCmdConfigGetClusters(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "get-clusters",
+ Short: "Display clusters defined in the kubeconfig",
+ Run: func(cmd *cobra.Command, args []string) {
+ err := runGetClusters(out, configAccess)
+ cmdutil.CheckErr(err)
+ },
+ }
+
+ return cmd
+}
+
+func runGetClusters(out io.Writer, configAccess clientcmd.ConfigAccess) error {
+ config, err := configAccess.GetStartingConfig()
+ if err != nil {
+ return err
+ }
+
+ fmt.Fprintf(out, "NAME\n")
+ for name := range config.Clusters {
+ fmt.Fprintf(out, "%s\n", name)
+ }
+
+ return nil
+}
diff --git a/pkg/kubectl/cmd/config/get_clusters_test.go b/pkg/kubectl/cmd/config/get_clusters_test.go
new file mode 100644
index 00000000000..8493de3fcd0
--- /dev/null
+++ b/pkg/kubectl/cmd/config/get_clusters_test.go
@@ -0,0 +1,81 @@
+/*
+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 getClustersTest struct {
+ config clientcmdapi.Config
+ expected string
+}
+
+func TestGetClusters(t *testing.T) {
+ conf := clientcmdapi.Config{
+ Clusters: map[string]*clientcmdapi.Cluster{
+ "minikube": {Server: "https://192.168.0.99"},
+ },
+ }
+ test := getClustersTest{
+ config: conf,
+ expected: `NAME
+minikube
+`,
+ }
+
+ test.run(t)
+}
+
+func TestGetClustersEmpty(t *testing.T) {
+ test := getClustersTest{
+ config: clientcmdapi.Config{},
+ expected: "NAME\n",
+ }
+
+ test.run(t)
+}
+
+func (test getClustersTest) run(t *testing.T) {
+ fakeKubeFile, _ := ioutil.TempFile("", "")
+ defer os.Remove(fakeKubeFile.Name())
+ err := clientcmd.WriteToFile(test.config, fakeKubeFile.Name())
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+
+ pathOptions := clientcmd.NewDefaultPathOptions()
+ pathOptions.GlobalFile = fakeKubeFile.Name()
+ pathOptions.EnvVar = ""
+ buf := bytes.NewBuffer([]byte{})
+ cmd := NewCmdConfigGetClusters(buf, pathOptions)
+ if err := cmd.Execute(); err != nil {
+ t.Fatalf("unexpected error executing command: %v", err)
+ }
+ if len(test.expected) != 0 {
+ if buf.String() != test.expected {
+ t.Errorf("expected %v, but got %v", test.expected, buf.String())
+ }
+ return
+ }
+}