Merge pull request #6761 from deads2k/deads-kubeconfig-squash

add flattening and minifying options to config view
This commit is contained in:
Derek Carr 2015-04-14 11:45:39 -04:00
commit 9b6ba23622
34 changed files with 464 additions and 73 deletions

View File

@ -530,9 +530,11 @@ _kubectl_config_view()
flags_with_completion=()
flags_completion=()
flags+=("--flatten")
flags+=("--help")
flags+=("-h")
flags+=("--merge")
flags+=("--minify")
flags+=("--no-headers")
flags+=("--output=")
two_word_flags+=("-o")

View File

@ -66,4 +66,4 @@ kubectl
* [kubectl update](kubectl_update.md) - Update a resource by filename or stdin.
* [kubectl version](kubectl_version.md) - Print the client and server version information.
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.865844658 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.453079685 +0000 UTC

View File

@ -50,4 +50,4 @@ kubectl api-versions
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.865438603 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.452805417 +0000 UTC

View File

@ -50,4 +50,4 @@ kubectl cluster-info
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.865291243 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.452687658 +0000 UTC

View File

@ -58,6 +58,6 @@ kubectl config SUBCOMMAND
* [kubectl config set-credentials](kubectl_config_set-credentials.md) - Sets a user entry in kubeconfig
* [kubectl config unset](kubectl_config_unset.md) - Unsets an individual value in a kubeconfig file
* [kubectl config use-context](kubectl_config_use-context.md) - Sets the current-context in a kubeconfig file
* [kubectl config view](kubectl_config_view.md) - displays merged kubeconfig settings or a specified kubeconfig file.
* [kubectl config view](kubectl_config_view.md) - displays Merged kubeconfig settings or a specified kubeconfig file.
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.86513156 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.452570294 +0000 UTC

View File

@ -68,4 +68,4 @@ $ kubectl config set-cluster e2e --insecure-skip-tls-verify=true
### SEE ALSO
* [kubectl config](kubectl_config.md) - config modifies kubeconfig files
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.864096021 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.451768559 +0000 UTC

View File

@ -61,4 +61,4 @@ $ kubectl config set-context gce --user=cluster-admin
### SEE ALSO
* [kubectl config](kubectl_config.md) - config modifies kubeconfig files
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.86442717 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.452031181 +0000 UTC

View File

@ -81,4 +81,4 @@ $ kubectl set-credentials cluster-admin --client-certificate=~/.kube/admin.crt -
### SEE ALSO
* [kubectl config](kubectl_config.md) - config modifies kubeconfig files
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.864263862 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.451906112 +0000 UTC

View File

@ -55,4 +55,4 @@ kubectl config set PROPERTY_NAME PROPERTY_VALUE
### SEE ALSO
* [kubectl config](kubectl_config.md) - config modifies kubeconfig files
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.864594301 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.45217009 +0000 UTC

View File

@ -54,4 +54,4 @@ kubectl config unset PROPERTY_NAME
### SEE ALSO
* [kubectl config](kubectl_config.md) - config modifies kubeconfig files
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.864788809 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.452318625 +0000 UTC

View File

@ -53,4 +53,4 @@ kubectl config use-context CONTEXT_NAME
### SEE ALSO
* [kubectl config](kubectl_config.md) - config modifies kubeconfig files
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.864953658 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.452447654 +0000 UTC

View File

@ -1,11 +1,11 @@
## kubectl config view
displays merged kubeconfig settings or a specified kubeconfig file.
displays Merged kubeconfig settings or a specified kubeconfig file.
### Synopsis
displays merged kubeconfig settings or a specified kubeconfig file.
displays Merged kubeconfig settings or a specified kubeconfig file.
You can use --output=template --template=TEMPLATE to extract specific values.
@ -16,7 +16,7 @@ kubectl config view
### Examples
```
// Show merged kubeconfig settings.
// Show Merged kubeconfig settings.
$ kubectl config view
// Show only local kubeconfig settings
@ -29,8 +29,10 @@ $ kubectl config view -o template --template='{{range .users}}{{ if eq .name "e2
### Options
```
--flatten=false: flatten the resulting kubeconfig file into self contained output (useful for creating portable kubeconfig files)
-h, --help=false: help for view
--merge=true: merge together the full hierarchy of kubeconfig files
--minify=false: remove all information not used by current-context from the output
--no-headers=false: When using the default output, don't print headers.
-o, --output="": Output format. One of: json|yaml|template|templatefile.
--output-version="": Output the formatted object with the given version (default api-version).
@ -73,4 +75,4 @@ $ kubectl config view -o template --template='{{range .users}}{{ if eq .name "e2
### SEE ALSO
* [kubectl config](kubectl_config.md) - config modifies kubeconfig files
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.863759642 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.451646336 +0000 UTC

View File

@ -63,4 +63,4 @@ $ cat pod.json | kubectl create -f -
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.858089037 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.44924428 +0000 UTC

View File

@ -81,4 +81,4 @@ $ kubectl delete pods --all
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.858739718 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.449502668 +0000 UTC

View File

@ -53,4 +53,4 @@ kubectl describe RESOURCE ID
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.857744518 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.449099339 +0000 UTC

View File

@ -64,4 +64,4 @@ $ kubectl exec -p 123456-7890 -c ruby-container -i -t -- bash -il
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.860311374 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.450677119 +0000 UTC

View File

@ -82,4 +82,4 @@ $ kubectl expose streamer --port=4100 --protocol=udp --service-name=video-stream
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.863051668 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.451362859 +0000 UTC

View File

@ -85,4 +85,4 @@ $ kubectl get rc/web service/frontend pods/web-pod-13je7
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.836684094 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.448937009 +0000 UTC

View File

@ -81,4 +81,4 @@ $ kubectl label pods foo bar-
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.863412074 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.45150424 +0000 UTC

View File

@ -62,4 +62,4 @@ $ kubectl log -f 123456-7890 ruby-container
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.859351191 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.450201574 +0000 UTC

View File

@ -53,4 +53,4 @@ kubectl namespace [namespace]
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.859053402 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.449618977 +0000 UTC

View File

@ -68,4 +68,4 @@ $ kubectl port-forward -p mypod 0:5000
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.860596821 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.45080362 +0000 UTC

View File

@ -65,4 +65,4 @@ $ kubectl proxy --api-prefix=k8s-api
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.860912037 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.45092701 +0000 UTC

View File

@ -68,4 +68,4 @@ $ kubectl resize --current-replicas=2 --replicas=3 replicationcontrollers foo
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.859972905 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.450528897 +0000 UTC

View File

@ -68,4 +68,4 @@ $ cat frontend-v2.json | kubectl rolling-update frontend-v1 -f -
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.859654934 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.450394023 +0000 UTC

View File

@ -78,4 +78,4 @@ $ kubectl run-container nginx --image=dockerfile/nginx --overrides='{ "apiVersio
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.861280128 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.4510703 +0000 UTC

View File

@ -72,4 +72,4 @@ $ kubectl stop -f path/to/resources
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.862654585 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.451196696 +0000 UTC

View File

@ -67,4 +67,4 @@ $ kubectl update pods my-pod --patch='{ "apiVersion": "v1beta1", "desiredState":
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.858390462 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.449377932 +0000 UTC

View File

@ -51,4 +51,4 @@ kubectl version
### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-04-12 19:00:26.865600008 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-14 14:22:51.452926558 +0000 UTC

View File

@ -3,7 +3,7 @@
.SH NAME
.PP
kubectl config view \- displays merged kubeconfig settings or a specified kubeconfig file.
kubectl config view \- displays Merged kubeconfig settings or a specified kubeconfig file.
.SH SYNOPSIS
@ -13,13 +13,17 @@ kubectl config view \- displays merged kubeconfig settings or a specified kubeco
.SH DESCRIPTION
.PP
displays merged kubeconfig settings or a specified kubeconfig file.
displays Merged kubeconfig settings or a specified kubeconfig file.
.PP
You can use \-\-output=template \-\-template=TEMPLATE to extract specific values.
.SH OPTIONS
.PP
\fB\-\-flatten\fP=false
flatten the resulting kubeconfig file into self contained output (useful for creating portable kubeconfig files)
.PP
\fB\-h\fP, \fB\-\-help\fP=false
help for view
@ -28,6 +32,10 @@ You can use \-\-output=template \-\-template=TEMPLATE to extract specific values
\fB\-\-merge\fP=true
merge together the full hierarchy of kubeconfig files
.PP
\fB\-\-minify\fP=false
remove all information not used by current\-context from the output
.PP
\fB\-\-no\-headers\fP=false
When using the default output, don't print headers.
@ -165,7 +173,7 @@ You can use \-\-output=template \-\-template=TEMPLATE to extract specific values
.RS
.nf
// Show merged kubeconfig settings.
// Show Merged kubeconfig settings.
$ kubectl config view
// Show only local kubeconfig settings

View File

@ -0,0 +1,149 @@
/*
Copyright 2015 Google Inc. All rights reserved.
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 api
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
)
// MinifyConfig read the current context and uses that to keep only the relevant pieces of config
// This is useful for making secrets based on kubeconfig files
func MinifyConfig(config *Config) error {
if len(config.CurrentContext) == 0 {
return errors.New("current-context must exist in order to minify")
}
currContext, exists := config.Contexts[config.CurrentContext]
if !exists {
return fmt.Errorf("cannot locate context %v", config.CurrentContext)
}
newContexts := map[string]Context{}
newContexts[config.CurrentContext] = currContext
newClusters := map[string]Cluster{}
if len(currContext.Cluster) > 0 {
if _, exists := config.Clusters[currContext.Cluster]; !exists {
return fmt.Errorf("cannot locate cluster %v", currContext.Cluster)
}
newClusters[currContext.Cluster] = config.Clusters[currContext.Cluster]
}
newAuthInfos := map[string]AuthInfo{}
if len(currContext.AuthInfo) > 0 {
if _, exists := config.AuthInfos[currContext.AuthInfo]; !exists {
return fmt.Errorf("cannot locate user %v", currContext.AuthInfo)
}
newAuthInfos[currContext.AuthInfo] = config.AuthInfos[currContext.AuthInfo]
}
config.AuthInfos = newAuthInfos
config.Clusters = newClusters
config.Contexts = newContexts
return nil
}
// Flatten changes the config object into a self contained config (useful for making secrets)
// AuthPath is not handled.
func FlattenConfig(config *Config) error {
for key, authInfo := range config.AuthInfos {
baseDir, err := MakeAbs(path.Dir(authInfo.LocationOfOrigin), "")
if err != nil {
return err
}
if len(authInfo.AuthPath) != 0 {
return fmt.Errorf("auth path of %v is not empty: %v", key, authInfo.AuthPath)
}
if err := FlattenContent(&authInfo.ClientCertificate, &authInfo.ClientCertificateData, baseDir); err != nil {
return err
}
if err := FlattenContent(&authInfo.ClientKey, &authInfo.ClientKeyData, baseDir); err != nil {
return err
}
config.AuthInfos[key] = authInfo
}
for key, cluster := range config.Clusters {
baseDir, err := MakeAbs(path.Dir(cluster.LocationOfOrigin), "")
if err != nil {
return err
}
if err := FlattenContent(&cluster.CertificateAuthority, &cluster.CertificateAuthorityData, baseDir); err != nil {
return err
}
config.Clusters[key] = cluster
}
return nil
}
func FlattenContent(path *string, contents *[]byte, baseDir string) error {
if len(*path) != 0 {
if len(*contents) > 0 {
return errors.New("cannot have values for both path and contents")
}
var err error
absPath := ResolvePath(*path, baseDir)
*contents, err = ioutil.ReadFile(absPath)
if err != nil {
return err
}
*path = ""
}
return nil
}
// ResolvePath returns the path as an absolute paths, relative to the given base directory
func ResolvePath(path string, base string) string {
// Don't resolve empty paths
if len(path) > 0 {
// Don't resolve absolute paths
if !filepath.IsAbs(path) {
return filepath.Join(base, path)
}
}
return path
}
func MakeAbs(path, base string) (string, error) {
if filepath.IsAbs(path) {
return path, nil
}
if len(base) == 0 {
cwd, err := os.Getwd()
if err != nil {
return "", err
}
base = cwd
}
return filepath.Join(base, path), nil
}

View File

@ -0,0 +1,204 @@
/*
Copyright 2015 Google Inc. All rights reserved.
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 api
import (
"io/ioutil"
"os"
"reflect"
"testing"
)
func newMergedConfig(certFile, certContent, keyFile, keyContent, caFile, caContent string, t *testing.T) Config {
if err := ioutil.WriteFile(certFile, []byte(certContent), 0644); err != nil {
t.Errorf("unexpected error: %v", err)
}
if err := ioutil.WriteFile(keyFile, []byte(keyContent), 0600); err != nil {
t.Errorf("unexpected error: %v", err)
}
if err := ioutil.WriteFile(caFile, []byte(caContent), 0644); err != nil {
t.Errorf("unexpected error: %v", err)
}
return Config{
AuthInfos: map[string]AuthInfo{
"red-user": {Token: "red-token"},
"blue-user": {Token: "blue-token", ClientCertificate: certFile, ClientKey: keyFile}},
Clusters: map[string]Cluster{
"cow-cluster": {Server: "http://cow.org:8080"},
"chicken-cluster": {Server: "http://chicken.org:8080", CertificateAuthority: caFile}},
Contexts: map[string]Context{
"federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster"},
"shaker-context": {AuthInfo: "blue-user", Cluster: "chicken-cluster"}},
CurrentContext: "federal-context",
}
}
func TestMinifySuccess(t *testing.T) {
certFile, _ := ioutil.TempFile("", "")
defer os.Remove(certFile.Name())
keyFile, _ := ioutil.TempFile("", "")
defer os.Remove(keyFile.Name())
caFile, _ := ioutil.TempFile("", "")
defer os.Remove(caFile.Name())
mutatingConfig := newMergedConfig(certFile.Name(), "cert", keyFile.Name(), "key", caFile.Name(), "ca", t)
if err := MinifyConfig(&mutatingConfig); err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(mutatingConfig.Contexts) > 1 {
t.Errorf("unexpected contexts: %v", mutatingConfig.Contexts)
}
if _, exists := mutatingConfig.Contexts["federal-context"]; !exists {
t.Errorf("missing context")
}
if len(mutatingConfig.Clusters) > 1 {
t.Errorf("unexpected clusters: %v", mutatingConfig.Clusters)
}
if _, exists := mutatingConfig.Clusters["cow-cluster"]; !exists {
t.Errorf("missing cluster")
}
if len(mutatingConfig.AuthInfos) > 1 {
t.Errorf("unexpected users: %v", mutatingConfig.AuthInfos)
}
if _, exists := mutatingConfig.AuthInfos["red-user"]; !exists {
t.Errorf("missing user")
}
}
func TestMinifyMissingContext(t *testing.T) {
certFile, _ := ioutil.TempFile("", "")
defer os.Remove(certFile.Name())
keyFile, _ := ioutil.TempFile("", "")
defer os.Remove(keyFile.Name())
caFile, _ := ioutil.TempFile("", "")
defer os.Remove(caFile.Name())
mutatingConfig := newMergedConfig(certFile.Name(), "cert", keyFile.Name(), "key", caFile.Name(), "ca", t)
mutatingConfig.CurrentContext = "missing"
errMsg := "cannot locate context missing"
if err := MinifyConfig(&mutatingConfig); err == nil || err.Error() != errMsg {
t.Errorf("expected %v, got %v", errMsg, err)
}
}
func TestMinifyMissingCluster(t *testing.T) {
certFile, _ := ioutil.TempFile("", "")
defer os.Remove(certFile.Name())
keyFile, _ := ioutil.TempFile("", "")
defer os.Remove(keyFile.Name())
caFile, _ := ioutil.TempFile("", "")
defer os.Remove(caFile.Name())
mutatingConfig := newMergedConfig(certFile.Name(), "cert", keyFile.Name(), "key", caFile.Name(), "ca", t)
delete(mutatingConfig.Clusters, mutatingConfig.Contexts[mutatingConfig.CurrentContext].Cluster)
errMsg := "cannot locate cluster cow-cluster"
if err := MinifyConfig(&mutatingConfig); err == nil || err.Error() != errMsg {
t.Errorf("expected %v, got %v", errMsg, err)
}
}
func TestMinifyMissingAuthInfo(t *testing.T) {
certFile, _ := ioutil.TempFile("", "")
defer os.Remove(certFile.Name())
keyFile, _ := ioutil.TempFile("", "")
defer os.Remove(keyFile.Name())
caFile, _ := ioutil.TempFile("", "")
defer os.Remove(caFile.Name())
mutatingConfig := newMergedConfig(certFile.Name(), "cert", keyFile.Name(), "key", caFile.Name(), "ca", t)
delete(mutatingConfig.AuthInfos, mutatingConfig.Contexts[mutatingConfig.CurrentContext].AuthInfo)
errMsg := "cannot locate user red-user"
if err := MinifyConfig(&mutatingConfig); err == nil || err.Error() != errMsg {
t.Errorf("expected %v, got %v", errMsg, err)
}
}
func TestFlattenSuccess(t *testing.T) {
certFile, _ := ioutil.TempFile("", "")
defer os.Remove(certFile.Name())
keyFile, _ := ioutil.TempFile("", "")
defer os.Remove(keyFile.Name())
caFile, _ := ioutil.TempFile("", "")
defer os.Remove(caFile.Name())
certData := "cert"
keyData := "key"
caData := "ca"
unchangingCluster := "cow-cluster"
unchangingAuthInfo := "red-user"
changingCluster := "chicken-cluster"
changingAuthInfo := "blue-user"
startingConfig := newMergedConfig(certFile.Name(), certData, keyFile.Name(), keyData, caFile.Name(), caData, t)
mutatingConfig := startingConfig
if err := FlattenConfig(&mutatingConfig); err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(mutatingConfig.Contexts) != 2 {
t.Errorf("unexpected contexts: %v", mutatingConfig.Contexts)
}
if !reflect.DeepEqual(startingConfig.Contexts, mutatingConfig.Contexts) {
t.Errorf("expected %v, got %v", startingConfig.Contexts, mutatingConfig.Contexts)
}
if len(mutatingConfig.Clusters) != 2 {
t.Errorf("unexpected clusters: %v", mutatingConfig.Clusters)
}
if !reflect.DeepEqual(startingConfig.Clusters[unchangingCluster], mutatingConfig.Clusters[unchangingCluster]) {
t.Errorf("expected %v, got %v", startingConfig.Clusters[unchangingCluster], mutatingConfig.Clusters[unchangingCluster])
}
if len(mutatingConfig.Clusters[changingCluster].CertificateAuthority) != 0 {
t.Errorf("unexpected caFile")
}
if string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData) != caData {
t.Errorf("expected %v, got %v", caData, string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData))
}
if len(mutatingConfig.AuthInfos) != 2 {
t.Errorf("unexpected users: %v", mutatingConfig.AuthInfos)
}
if !reflect.DeepEqual(startingConfig.AuthInfos[unchangingAuthInfo], mutatingConfig.AuthInfos[unchangingAuthInfo]) {
t.Errorf("expected %v, got %v", startingConfig.AuthInfos[unchangingAuthInfo], mutatingConfig.AuthInfos[unchangingAuthInfo])
}
if len(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificate) != 0 {
t.Errorf("unexpected caFile")
}
if string(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificateData) != certData {
t.Errorf("expected %v, got %v", certData, string(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificateData))
}
if len(mutatingConfig.AuthInfos[changingAuthInfo].ClientKey) != 0 {
t.Errorf("unexpected caFile")
}
if string(mutatingConfig.AuthInfos[changingAuthInfo].ClientKeyData) != keyData {
t.Errorf("expected %v, got %v", keyData, string(mutatingConfig.AuthInfos[changingAuthInfo].ClientKeyData))
}
}

View File

@ -39,6 +39,7 @@ func newRedFederalCowHammerConfig() clientcmdapi.Config {
"cow-cluster": {Server: "http://cow.org:8080"}},
Contexts: map[string]clientcmdapi.Context{
"federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster"}},
CurrentContext: "federal-context",
}
}
@ -70,7 +71,7 @@ func ExampleView() {
// cluster: cow-cluster
// user: red-user
// name: federal-context
// current-context: ""
// current-context: federal-context
// kind: Config
// preferences: {}
// users:

View File

@ -31,16 +31,18 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
type viewOptions struct {
pathOptions *PathOptions
merge util.BoolFlag
type ViewOptions struct {
PathOptions *PathOptions
Merge util.BoolFlag
Flatten bool
Minify bool
}
const (
view_long = `displays merged kubeconfig settings or a specified kubeconfig file.
view_long = `displays Merged kubeconfig settings or a specified kubeconfig file.
You can use --output=template --template=TEMPLATE to extract specific values.`
view_example = `// Show merged kubeconfig settings.
view_example = `// Show Merged kubeconfig settings.
$ kubectl config view
// Show only local kubeconfig settings
@ -50,16 +52,16 @@ $ kubectl config view --local
$ kubectl config view -o template --template='{{range .users}}{{ if eq .name "e2e" }}{{ index .user.password }}{{end}}{{end}}'`
)
func NewCmdConfigView(out io.Writer, pathOptions *PathOptions) *cobra.Command {
options := &viewOptions{pathOptions: pathOptions}
func NewCmdConfigView(out io.Writer, PathOptions *PathOptions) *cobra.Command {
options := &ViewOptions{PathOptions: PathOptions}
cmd := &cobra.Command{
Use: "view",
Short: "displays merged kubeconfig settings or a specified kubeconfig file.",
Short: "displays Merged kubeconfig settings or a specified kubeconfig file.",
Long: view_long,
Example: view_example,
Run: func(cmd *cobra.Command, args []string) {
options.complete()
options.Complete()
printer, _, err := cmdutil.PrinterForCommand(cmd)
if err != nil {
@ -68,15 +70,10 @@ func NewCmdConfigView(out io.Writer, pathOptions *PathOptions) *cobra.Command {
version := cmdutil.OutputVersion(cmd, latest.Version)
printer = kubectl.NewVersionedPrinter(printer, clientcmdapi.Scheme, version)
config, err := options.loadConfig()
if err != nil {
if err := options.Run(out, printer); err != nil {
glog.FatalDepth(1, err)
}
err = printer.PrintObj(config, out)
if err != nil {
glog.FatalDepth(1, err)
}
},
}
@ -84,24 +81,52 @@ func NewCmdConfigView(out io.Writer, pathOptions *PathOptions) *cobra.Command {
// Default to yaml
cmd.Flags().Set("output", "yaml")
options.merge.Default(true)
cmd.Flags().Var(&options.merge, "merge", "merge together the full hierarchy of kubeconfig files")
options.Merge.Default(true)
cmd.Flags().Var(&options.Merge, "merge", "merge together the full hierarchy of kubeconfig files")
cmd.Flags().BoolVar(&options.Flatten, "flatten", false, "flatten the resulting kubeconfig file into self contained output (useful for creating portable kubeconfig files)")
cmd.Flags().BoolVar(&options.Minify, "minify", false, "remove all information not used by current-context from the output")
return cmd
}
func (o *viewOptions) complete() bool {
func (o ViewOptions) Run(out io.Writer, printer kubectl.ResourcePrinter) error {
config, err := o.loadConfig()
if err != nil {
return err
}
if o.Minify {
if err := clientcmdapi.MinifyConfig(config); err != nil {
return err
}
}
if o.Flatten {
if err := clientcmdapi.FlattenConfig(config); err != nil {
return err
}
}
err = printer.PrintObj(config, out)
if err != nil {
return err
}
return nil
}
func (o *ViewOptions) Complete() bool {
// if --kubeconfig, --global, or --local is specified, then merging doesn't make sense since you're declaring precise intent
if o.pathOptions.Global || o.pathOptions.Local || o.pathOptions.UseEnvVar {
if !o.merge.Provided() {
o.merge.Set("false")
if o.PathOptions.Global || o.PathOptions.Local || o.PathOptions.UseEnvVar {
if !o.Merge.Provided() {
o.Merge.Set("false")
}
}
return true
}
func (o viewOptions) loadConfig() (*clientcmdapi.Config, error) {
err := o.validate()
func (o ViewOptions) loadConfig() (*clientcmdapi.Config, error) {
err := o.Validate()
if err != nil {
return nil, err
}
@ -110,33 +135,33 @@ func (o viewOptions) loadConfig() (*clientcmdapi.Config, error) {
return config, err
}
func (o viewOptions) validate() error {
return o.pathOptions.Validate()
func (o ViewOptions) Validate() error {
return o.PathOptions.Validate()
}
// getStartingConfig returns the Config object built from the sources specified by the options, the filename read (only if it was a single file), and an error if something goes wrong
func (o *viewOptions) getStartingConfig() (*clientcmdapi.Config, error) {
func (o *ViewOptions) getStartingConfig() (*clientcmdapi.Config, error) {
switch {
case !o.merge.Value():
case !o.Merge.Value():
switch {
case len(o.pathOptions.LoadingRules.ExplicitPath) > 0:
return clientcmd.LoadFromFile(o.pathOptions.LoadingRules.ExplicitPath)
case len(o.PathOptions.LoadingRules.ExplicitPath) > 0:
return clientcmd.LoadFromFile(o.PathOptions.LoadingRules.ExplicitPath)
case o.pathOptions.Global:
return clientcmd.LoadFromFile(o.pathOptions.GlobalFile)
case o.PathOptions.Global:
return clientcmd.LoadFromFile(o.PathOptions.GlobalFile)
case o.pathOptions.UseEnvVar:
return clientcmd.LoadFromFile(o.pathOptions.EnvVarFile)
case o.PathOptions.UseEnvVar:
return clientcmd.LoadFromFile(o.PathOptions.EnvVarFile)
case o.pathOptions.Local:
return clientcmd.LoadFromFile(o.pathOptions.LocalFile)
case o.PathOptions.Local:
return clientcmd.LoadFromFile(o.PathOptions.LocalFile)
default:
return nil, errors.New("if merge==false a precise file must to specified")
return nil, errors.New("if Merge==false a precise file must to specified")
}
default:
return o.pathOptions.getStartingConfig()
return o.PathOptions.getStartingConfig()
}
}