Commit de4be542 authored by deads2k's avatar deads2k

change kubeconfig loading order

parent b59266ad
......@@ -747,12 +747,9 @@ _kubectl_config()
flags_with_completion=()
flags_completion=()
flags+=("--envvar")
flags+=("--global")
flags+=("--help")
flags+=("-h")
flags+=("--kubeconfig=")
flags+=("--local")
must_have_one_flag=()
must_have_one_noun=()
......
......@@ -84,15 +84,20 @@ If the contents of the kubernetes_auth file conflict with entries in .kubeconfig
## Loading and merging rules
The rules for loading and merging the .kubeconfig files are straightforward, but there are a lot of them. The final config is built in this order:
1. Merge together the kubeconfig itself. This is done with the following hierarchy and merge rules:
1. Get the kubeconfig from disk. This is done with the following hierarchy and merge rules:
If the CommandLineLocation (the value of the `kubeconfig` command line option) is set, use this file only. No merging. Only one instance of this flag is allowed.
Else, if EnvVarLocation (the value of $KUBECONFIG) is available, use it as a list of files that should be merged.
Merge files together based on the following rules.
Empty filenames are ignored. Files with non-deserializable content produced errors.
The first file to set a particular value or map key wins and the value or map key is never changed.
This means that the first file to set CurrentContext will have its context preserved. It also means that if two files specify a "red-user", only values from the first file's red-user are used. Even non-conflicting entries from the second file's "red-user" are discarded.
1. CommandLineLocation - the value of the `kubeconfig` command line option
1. EnvVarLocation - the value of $KUBECONFIG
1. CurrentDirectoryLocation - ``pwd``/.kubeconfig
1. HomeDirectoryLocation = ~/.kube/.kubeconfig
Otherwise, use HomeDirectoryLocation (~/.kube/config) with no merging.
1. Determine the context to use based on the first hit in this chain
1. command line argument - the value of the `context` command line option
1. current-context from the merged kubeconfig 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-14 19:53:16.641789142 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.392549632 +0000 UTC
......@@ -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-14 19:53:16.641051929 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.39227534 +0000 UTC
......@@ -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-14 19:53:16.640723377 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.392162759 +0000 UTC
......@@ -7,6 +7,12 @@ config modifies kubeconfig files
config modifies kubeconfig files using subcommands like "kubectl config set current-context my-context"
The loading order follows these rules:
1. If the --kubeconfig flag is set, then only that file is loaded. The flag may only be set once and no merging takes place.
2. If $KUBECONFIG environment variable is set, then it is used a list of paths (normal path delimitting rules for your system). These paths are merged together. When a value is modified, it is modified in the file that defines the stanza. When a value is created, it is created in the first file that exists. If no files in the chain exist, then it creates the last file in the list.
3. Otherwise, ${HOME}/.kube/config is used and no merging takes place.
```
kubectl config SUBCOMMAND
```
......@@ -14,11 +20,8 @@ kubectl config SUBCOMMAND
### Options
```
--envvar=false: use the kubeconfig from $KUBECONFIG
--global=false: use the kubeconfig from /home/username/.kube/.kubeconfig
-h, --help=false: help for config
--kubeconfig="": use a particular kubeconfig file
--local=false: use the kubeconfig in the current directory
```
### Options inherrited from parent commands
......@@ -60,4 +63,4 @@ kubectl config SUBCOMMAND
* [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.
###### Auto generated by spf13/cobra at 2015-04-14 19:53:16.640323684 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.392043616 +0000 UTC
......@@ -45,10 +45,7 @@ $ kubectl config set-cluster e2e --insecure-skip-tls-verify=true
--client-key="": Path to a client key file for TLS.
--cluster="": The name of the kubeconfig cluster to use
--context="": The name of the kubeconfig context to use
--envvar=false: use the kubeconfig from $KUBECONFIG
--global=false: use the kubeconfig from /home/username/.kube/.kubeconfig
--kubeconfig="": use a particular kubeconfig file
--local=false: use the kubeconfig in the current directory
--log_backtrace_at=:0: when logging hits line file:N, emit a stack trace
--log_dir=: If non-empty, write log files in this directory
--log_flush_frequency=5s: Maximum number of seconds between log flushes
......@@ -68,4 +65,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-14 19:53:16.637680508 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.39119629 +0000 UTC
......@@ -38,11 +38,8 @@ $ kubectl config set-context gce --user=cluster-admin
--client-certificate="": Path to a client key file for TLS.
--client-key="": Path to a client key file for TLS.
--context="": The name of the kubeconfig context to use
--envvar=false: use the kubeconfig from $KUBECONFIG
--global=false: use the kubeconfig from /home/username/.kube/.kubeconfig
--insecure-skip-tls-verify=false: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
--kubeconfig="": use a particular kubeconfig file
--local=false: use the kubeconfig in the current directory
--log_backtrace_at=:0: when logging hits line file:N, emit a stack trace
--log_dir=: If non-empty, write log files in this directory
--log_flush_frequency=5s: Maximum number of seconds between log flushes
......@@ -61,4 +58,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-14 19:53:16.638371771 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.391488399 +0000 UTC
......@@ -59,11 +59,8 @@ $ kubectl set-credentials cluster-admin --client-certificate=~/.kube/admin.crt -
--certificate-authority="": Path to a cert. file for the certificate authority.
--cluster="": The name of the kubeconfig cluster to use
--context="": The name of the kubeconfig context to use
--envvar=false: use the kubeconfig from $KUBECONFIG
--global=false: use the kubeconfig from /home/username/.kube/.kubeconfig
--insecure-skip-tls-verify=false: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
--kubeconfig="": use a particular kubeconfig file
--local=false: use the kubeconfig in the current directory
--log_backtrace_at=:0: when logging hits line file:N, emit a stack trace
--log_dir=: If non-empty, write log files in this directory
--log_flush_frequency=5s: Maximum number of seconds between log flushes
......@@ -81,4 +78,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-14 19:53:16.638019407 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.391323192 +0000 UTC
......@@ -30,11 +30,8 @@ kubectl config set PROPERTY_NAME PROPERTY_VALUE
--client-key="": Path to a client key file for TLS.
--cluster="": The name of the kubeconfig cluster to use
--context="": The name of the kubeconfig context to use
--envvar=false: use the kubeconfig from $KUBECONFIG
--global=false: use the kubeconfig from /home/username/.kube/.kubeconfig
--insecure-skip-tls-verify=false: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
--kubeconfig="": use a particular kubeconfig file
--local=false: use the kubeconfig in the current directory
--log_backtrace_at=:0: when logging hits line file:N, emit a stack trace
--log_dir=: If non-empty, write log files in this directory
--log_flush_frequency=5s: Maximum number of seconds between log flushes
......@@ -55,4 +52,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-14 19:53:16.638724317 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.391618859 +0000 UTC
......@@ -29,11 +29,8 @@ kubectl config unset PROPERTY_NAME
--client-key="": Path to a client key file for TLS.
--cluster="": The name of the kubeconfig cluster to use
--context="": The name of the kubeconfig context to use
--envvar=false: use the kubeconfig from $KUBECONFIG
--global=false: use the kubeconfig from /home/username/.kube/.kubeconfig
--insecure-skip-tls-verify=false: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
--kubeconfig="": use a particular kubeconfig file
--local=false: use the kubeconfig in the current directory
--log_backtrace_at=:0: when logging hits line file:N, emit a stack trace
--log_dir=: If non-empty, write log files in this directory
--log_flush_frequency=5s: Maximum number of seconds between log flushes
......@@ -54,4 +51,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-14 19:53:16.639325332 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.391735806 +0000 UTC
......@@ -28,11 +28,8 @@ kubectl config use-context CONTEXT_NAME
--client-key="": Path to a client key file for TLS.
--cluster="": The name of the kubeconfig cluster to use
--context="": The name of the kubeconfig context to use
--envvar=false: use the kubeconfig from $KUBECONFIG
--global=false: use the kubeconfig from /home/username/.kube/.kubeconfig
--insecure-skip-tls-verify=false: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
--kubeconfig="": use a particular kubeconfig file
--local=false: use the kubeconfig in the current directory
--log_backtrace_at=:0: when logging hits line file:N, emit a stack trace
--log_dir=: If non-empty, write log files in this directory
--log_flush_frequency=5s: Maximum number of seconds between log flushes
......@@ -53,4 +50,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-14 19:53:16.639859272 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.391848246 +0000 UTC
......@@ -50,11 +50,8 @@ $ kubectl config view -o template --template='{{range .users}}{{ if eq .name "e2
--client-key="": Path to a client key file for TLS.
--cluster="": The name of the kubeconfig cluster to use
--context="": The name of the kubeconfig context to use
--envvar=false: use the kubeconfig from $KUBECONFIG
--global=false: use the kubeconfig from /home/username/.kube/.kubeconfig
--insecure-skip-tls-verify=false: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
--kubeconfig="": use a particular kubeconfig file
--local=false: use the kubeconfig in the current directory
--log_backtrace_at=:0: when logging hits line file:N, emit a stack trace
--log_dir=: If non-empty, write log files in this directory
--log_flush_frequency=5s: Maximum number of seconds between log flushes
......@@ -75,4 +72,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-14 19:53:16.637312729 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.391073075 +0000 UTC
......@@ -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-14 19:53:16.629142674 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.388588064 +0000 UTC
......@@ -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-14 19:53:16.630884641 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.389412973 +0000 UTC
......@@ -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-14 19:53:16.628735136 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.388410556 +0000 UTC
......@@ -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-14 19:53:16.632991694 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.390127525 +0000 UTC
......@@ -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-14 19:53:16.636399596 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.390792874 +0000 UTC
......@@ -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-14 19:53:16.620151758 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.387483074 +0000 UTC
......@@ -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-14 19:53:16.636842283 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.390937166 +0000 UTC
......@@ -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-14 19:53:16.631637812 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.389728881 +0000 UTC
......@@ -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-14 19:53:16.63128386 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.389609191 +0000 UTC
......@@ -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-14 19:53:16.633423694 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.390241417 +0000 UTC
......@@ -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-14 19:53:16.633829265 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.390360738 +0000 UTC
......@@ -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-14 19:53:16.632560634 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.389989377 +0000 UTC
......@@ -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-14 19:53:16.632023561 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.38985117 +0000 UTC
......@@ -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-14 19:53:16.634391744 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.390501802 +0000 UTC
......@@ -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-14 19:53:16.635920945 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.390631789 +0000 UTC
......@@ -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-14 19:53:16.630218109 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.388743178 +0000 UTC
......@@ -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-14 19:53:16.641381587 +0000 UTC
###### Auto generated by spf13/cobra at 2015-04-16 17:04:37.392395408 +0000 UTC
......@@ -69,22 +69,10 @@ Specifying a name that already exists will merge new fields on top of existing v
The name of the kubeconfig context to use
.PP
\fB\-\-envvar\fP=false
use the kubeconfig from $KUBECONFIG
.PP
\fB\-\-global\fP=false
use the kubeconfig from /home/username/.kube/.kubeconfig
.PP
\fB\-\-kubeconfig\fP=""
use a particular kubeconfig file
.PP
\fB\-\-local\fP=false
use the kubeconfig in the current directory
.PP
\fB\-\-log\_backtrace\_at\fP=:0
when logging hits line file:N, emit a stack trace
......
......@@ -65,14 +65,6 @@ Specifying a name that already exists will merge new fields on top of existing v
The name of the kubeconfig context to use
.PP
\fB\-\-envvar\fP=false
use the kubeconfig from $KUBECONFIG
.PP
\fB\-\-global\fP=false
use the kubeconfig from /home/username/.kube/.kubeconfig
.PP
\fB\-\-insecure\-skip\-tls\-verify\fP=false
If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
......@@ -81,10 +73,6 @@ Specifying a name that already exists will merge new fields on top of existing v
use a particular kubeconfig file
.PP
\fB\-\-local\fP=false
use the kubeconfig in the current directory
.PP
\fB\-\-log\_backtrace\_at\fP=:0
when logging hits line file:N, emit a stack trace
......
......@@ -88,14 +88,6 @@ Bearer token and basic auth are mutually exclusive.
The name of the kubeconfig context to use
.PP
\fB\-\-envvar\fP=false
use the kubeconfig from $KUBECONFIG
.PP
\fB\-\-global\fP=false
use the kubeconfig from /home/username/.kube/.kubeconfig
.PP
\fB\-\-insecure\-skip\-tls\-verify\fP=false
If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
......@@ -104,10 +96,6 @@ Bearer token and basic auth are mutually exclusive.
use a particular kubeconfig file
.PP
\fB\-\-local\fP=false
use the kubeconfig in the current directory
.PP
\fB\-\-log\_backtrace\_at\fP=:0
when logging hits line file:N, emit a stack trace
......
......@@ -58,14 +58,6 @@ PROPERTY\_VALUE is the new value you wish to set.
The name of the kubeconfig context to use
.PP
\fB\-\-envvar\fP=false
use the kubeconfig from $KUBECONFIG
.PP
\fB\-\-global\fP=false
use the kubeconfig from /home/username/.kube/.kubeconfig
.PP
\fB\-\-insecure\-skip\-tls\-verify\fP=false
If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
......@@ -74,10 +66,6 @@ PROPERTY\_VALUE is the new value you wish to set.
use a particular kubeconfig file
.PP
\fB\-\-local\fP=false
use the kubeconfig in the current directory
.PP
\fB\-\-log\_backtrace\_at\fP=:0
when logging hits line file:N, emit a stack trace
......
......@@ -57,14 +57,6 @@ PROPERTY\_NAME is a dot delimited name where each token represents either a attr
The name of the kubeconfig context to use
.PP
\fB\-\-envvar\fP=false
use the kubeconfig from $KUBECONFIG
.PP
\fB\-\-global\fP=false
use the kubeconfig from /home/username/.kube/.kubeconfig
.PP
\fB\-\-insecure\-skip\-tls\-verify\fP=false
If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
......@@ -73,10 +65,6 @@ PROPERTY\_NAME is a dot delimited name where each token represents either a attr
use a particular kubeconfig file
.PP
\fB\-\-local\fP=false
use the kubeconfig in the current directory
.PP
\fB\-\-log\_backtrace\_at\fP=:0
when logging hits line file:N, emit a stack trace
......
......@@ -56,14 +56,6 @@ Sets the current\-context in a kubeconfig file
The name of the kubeconfig context to use
.PP
\fB\-\-envvar\fP=false
use the kubeconfig from $KUBECONFIG
.PP
\fB\-\-global\fP=false
use the kubeconfig from /home/username/.kube/.kubeconfig
.PP
\fB\-\-insecure\-skip\-tls\-verify\fP=false
If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
......@@ -72,10 +64,6 @@ Sets the current\-context in a kubeconfig file
use a particular kubeconfig file
.PP
\fB\-\-local\fP=false
use the kubeconfig in the current directory
.PP
\fB\-\-log\_backtrace\_at\fP=:0
when logging hits line file:N, emit a stack trace
......
......@@ -88,14 +88,6 @@ You can use \-\-output=template \-\-template=TEMPLATE to extract specific values
The name of the kubeconfig context to use
.PP
\fB\-\-envvar\fP=false
use the kubeconfig from $KUBECONFIG
.PP
\fB\-\-global\fP=false
use the kubeconfig from /home/username/.kube/.kubeconfig
.PP
\fB\-\-insecure\-skip\-tls\-verify\fP=false
If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
......@@ -104,10 +96,6 @@ You can use \-\-output=template \-\-template=TEMPLATE to extract specific values
use a particular kubeconfig file
.PP
\fB\-\-local\fP=false
use the kubeconfig in the current directory
.PP
\fB\-\-log\_backtrace\_at\fP=:0
when logging hits line file:N, emit a stack trace
......
......@@ -15,16 +15,14 @@ kubectl config \- config modifies kubeconfig files
.PP
config modifies kubeconfig files using subcommands like "kubectl config set current\-context my\-context"
.SH OPTIONS
.PP
\fB\-\-envvar\fP=false
use the kubeconfig from $KUBECONFIG
The loading order follows these rules:
1. If the \-\-kubeconfig flag is set, then only that file is loaded. The flag may only be set once and no merging takes place.
2. If $KUBECONFIG environment variable is set, then it is used a list of paths (normal path delimitting rules for your system). These paths are merged together. When a value is modified, it is modified in the file that defines the stanza. When a value is created, it is created in the first file that exists. If no files in the chain exist, then it creates the last file in the list.
3. Otherwise, $\{HOME\}/.kube/config is used and no merging takes place.
.PP
\fB\-\-global\fP=false
use the kubeconfig from /home/username/.kube/.kubeconfig
.SH OPTIONS
.PP
\fB\-h\fP, \fB\-\-help\fP=false
help for config
......@@ -33,10 +31,6 @@ config modifies kubeconfig files using subcommands like "kubectl config set curr
\fB\-\-kubeconfig\fP=""
use a particular kubeconfig file
.PP
\fB\-\-local\fP=false
use the kubeconfig in the current directory
.SH OPTIONS INHERITED FROM PARENT COMMANDS
.PP
......
......@@ -18,8 +18,10 @@ package clientcmd
import (
"fmt"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"github.com/ghodss/yaml"
......@@ -33,22 +35,24 @@ import (
const (
RecommendedConfigPathFlag = "kubeconfig"
RecommendedConfigPathEnvVar = "KUBECONFIG"
DefaultEnvVarIndex = 0
DefaultCurrentDirIndex = 1
DefaultHomeDirIndex = 2
RecommendedHomeFileName = "/.kube/config"
)
var OldRecommendedHomeFile = path.Join(os.Getenv("HOME"), "/.kube/.kubeconfig")
var RecommendedHomeFile = path.Join(os.Getenv("HOME"), RecommendedHomeFileName)
// ClientConfigLoadingRules is an ExplicitPath and string slice of specific locations that are used for merging together a Config
// Callers can put the chain together however they want, but we'd recommend:
// [0] = EnvVarPath
// [1] = CurrentDirectoryPath
// [2] = HomeDirectoryPath
// EnvVarPathFiles if set (a list of files if set) OR the HomeDirectoryPath
// ExplicitPath is special, because if a user specifically requests a certain file be used and error is reported if thie file is not present
type ClientConfigLoadingRules struct {
ExplicitPath string
Precedence []string
// MigrationRules is a map of destination files to source files. If a destination file is not present, then the source file is checked.
// If the source file is present, then it is copied to the destination file BEFORE any further loading happens.
MigrationRules map[string]string
// DoNotResolvePaths indicates whether or not to resolve paths with respect to the originating files. This is phrased as a negative so
// that a default object that doesn't set this will usually get the behavior it wants.
DoNotResolvePaths bool
......@@ -57,14 +61,29 @@ type ClientConfigLoadingRules struct {
// NewDefaultClientConfigLoadingRules returns a ClientConfigLoadingRules object with default fields filled in. You are not required to
// use this constructor
func NewDefaultClientConfigLoadingRules() *ClientConfigLoadingRules {
chain := []string{}
migrationRules := map[string]string{}
envVarFiles := os.Getenv(RecommendedConfigPathEnvVar)
if len(envVarFiles) != 0 {
chain = append(chain, filepath.SplitList(envVarFiles)...)
} else {
chain = append(chain, RecommendedHomeFile)
migrationRules[RecommendedHomeFile] = OldRecommendedHomeFile
}
return &ClientConfigLoadingRules{
Precedence: []string{os.Getenv(RecommendedConfigPathEnvVar), ".kubeconfig", os.Getenv("HOME") + "/.kube/.kubeconfig"},
Precedence: chain,
MigrationRules: migrationRules,
}
}
// Load takes the loading rules and merges together a Config object based on following order.
// 1. ExplicitPath
// 2. Precedence slice
// Load starts by running the MigrationRules and then
// takes the loading rules and returns a Config object based on following rules.
// if the ExplicitPath, return the unmerged explicit file
// Otherwise, return a merged config based on the Precedence slice
// A missing ExplicitPath file produces an error. Empty filenames or other missing files are ignored.
// Read errors or files with non-deserializable content produce errors.
// The first file to set a particular map key wins and map key's value is never changed.
......@@ -75,17 +94,25 @@ func NewDefaultClientConfigLoadingRules() *ClientConfigLoadingRules {
// Relative paths inside of the .kubeconfig files are resolved against the .kubeconfig file's parent folder
// and only absolute file paths are returned.
func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {
if err := rules.Migrate(); err != nil {
return nil, err
}
errlist := []error{}
kubeConfigFiles := []string{}
// Make sure a file we were explicitly told to use exists
if len(rules.ExplicitPath) > 0 {
if _, err := os.Stat(rules.ExplicitPath); os.IsNotExist(err) {
errlist = append(errlist, fmt.Errorf("The config file %v does not exist", rules.ExplicitPath))
return nil, err
}
}
kubeConfigFiles = append(kubeConfigFiles, rules.ExplicitPath)
kubeConfigFiles := []string{rules.ExplicitPath}
kubeConfigFiles = append(kubeConfigFiles, rules.Precedence...)
} else {
kubeConfigFiles = append(kubeConfigFiles, rules.Precedence...)
}
// first merge all of our maps
mapConfig := clientcmdapi.NewConfig()
......@@ -120,6 +147,53 @@ func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {
return config, errors.NewAggregate(errlist)
}
// Migrate uses the MigrationRules map. If a destination file is not present, then the source file is checked.
// If the source file is present, then it is copied to the destination file BEFORE any further loading happens.
func (rules *ClientConfigLoadingRules) Migrate() error {
if rules.MigrationRules == nil {
return nil
}
for destination, source := range rules.MigrationRules {
if _, err := os.Stat(destination); err == nil {
// if the destination already exists, do nothing
continue
} else if !os.IsNotExist(err) {
// if we had an error other than non-existence, fail
return err
}
if sourceInfo, err := os.Stat(source); err != nil {
if os.IsNotExist(err) {
// if the source file doesn't exist, there's no work to do.
continue
}
// if we had an error other than non-existence, fail
return err
} else if sourceInfo.IsDir() {
return fmt.Errorf("cannot migrate %v to %v because it is a directory", source, destination)
}
in, err := os.Open(source)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(destination)
if err != nil {
return err
}
defer out.Close()
if _, err = io.Copy(out, in); err != nil {
return err
}
}
return nil
}
func mergeConfigWithFile(startingConfig *clientcmdapi.Config, filename string) error {
if len(filename) == 0 {
// no work to do
......
......@@ -22,6 +22,7 @@ import (
"os"
"path"
"path/filepath"
"reflect"
"strings"
"testing"
......@@ -209,8 +210,7 @@ func TestResolveRelativePaths(t *testing.T) {
WriteToFile(pathResolutionConfig2, configFile2)
loadingRules := ClientConfigLoadingRules{
ExplicitPath: configFile1,
Precedence: []string{configFile2},
Precedence: []string{configFile1, configFile2},
}
mergedConfig, err := loadingRules.Load()
......@@ -274,7 +274,86 @@ func TestResolveRelativePaths(t *testing.T) {
}
func ExampleMergingSomeWithConflict() {
func TestMigratingFile(t *testing.T) {
sourceFile, _ := ioutil.TempFile("", "")
defer os.Remove(sourceFile.Name())
destinationFile, _ := ioutil.TempFile("", "")
// delete the file so that we'll write to it
os.Remove(destinationFile.Name())
WriteToFile(testConfigAlfa, sourceFile.Name())
loadingRules := ClientConfigLoadingRules{
MigrationRules: map[string]string{destinationFile.Name(): sourceFile.Name()},
}
if _, err := loadingRules.Load(); err != nil {
t.Errorf("unexpected error %v", err)
}
// the load should have recreated this file
defer os.Remove(destinationFile.Name())
sourceContent, err := ioutil.ReadFile(sourceFile.Name())
if err != nil {
t.Errorf("unexpected error %v", err)
}
destinationContent, err := ioutil.ReadFile(destinationFile.Name())
if err != nil {
t.Errorf("unexpected error %v", err)
}
if !reflect.DeepEqual(sourceContent, destinationContent) {
t.Errorf("source and destination do not match")
}
}
func TestMigratingFileLeaveExistingFileAlone(t *testing.T) {
sourceFile, _ := ioutil.TempFile("", "")
defer os.Remove(sourceFile.Name())
destinationFile, _ := ioutil.TempFile("", "")
defer os.Remove(destinationFile.Name())
WriteToFile(testConfigAlfa, sourceFile.Name())
loadingRules := ClientConfigLoadingRules{
MigrationRules: map[string]string{destinationFile.Name(): sourceFile.Name()},
}
if _, err := loadingRules.Load(); err != nil {
t.Errorf("unexpected error %v", err)
}
destinationContent, err := ioutil.ReadFile(destinationFile.Name())
if err != nil {
t.Errorf("unexpected error %v", err)
}
if len(destinationContent) > 0 {
t.Errorf("destination should not have been touched")
}
}
func TestMigratingFileSourceMissingSkip(t *testing.T) {
sourceFilename := "some-missing-file"
destinationFile, _ := ioutil.TempFile("", "")
// delete the file so that we'll write to it
os.Remove(destinationFile.Name())
loadingRules := ClientConfigLoadingRules{
MigrationRules: map[string]string{destinationFile.Name(): sourceFilename},
}
if _, err := loadingRules.Load(); err != nil {
t.Errorf("unexpected error %v", err)
}
if _, err := os.Stat(destinationFile.Name()); !os.IsNotExist(err) {
t.Errorf("destination should not exist")
}
}
func ExampleNoMergingOnExplicitPaths() {
commandLineFile, _ := ioutil.TempFile("", "")
defer os.Remove(commandLineFile.Name())
envVarFile, _ := ioutil.TempFile("", "")
......@@ -306,6 +385,52 @@ func ExampleMergingSomeWithConflict() {
// - cluster:
// server: http://cow.org:8080
// name: cow-cluster
// contexts:
// - context:
// cluster: cow-cluster
// namespace: hammer-ns
// user: red-user
// name: federal-context
// current-context: ""
// kind: Config
// preferences: {}
// users:
// - name: red-user
// user:
// token: red-token
}
func ExampleMergingSomeWithConflict() {
commandLineFile, _ := ioutil.TempFile("", "")
defer os.Remove(commandLineFile.Name())
envVarFile, _ := ioutil.TempFile("", "")
defer os.Remove(envVarFile.Name())
WriteToFile(testConfigAlfa, commandLineFile.Name())
WriteToFile(testConfigConflictAlfa, envVarFile.Name())
loadingRules := ClientConfigLoadingRules{
Precedence: []string{commandLineFile.Name(), envVarFile.Name()},
}
mergedConfig, err := loadingRules.Load()
json, err := clientcmdlatest.Codec.Encode(mergedConfig)
if err != nil {
fmt.Printf("Unexpected error: %v", err)
}
output, err := yaml.JSONToYAML(json)
if err != nil {
fmt.Printf("Unexpected error: %v", err)
}
fmt.Printf("%v", string(output))
// Output:
// apiVersion: v1
// clusters:
// - cluster:
// server: http://cow.org:8080
// name: cow-cluster
// - cluster:
// insecure-skip-tls-verify: true
// server: http://donkey.org:8080
......@@ -344,8 +469,7 @@ func ExampleMergingEverythingNoConflicts() {
WriteToFile(testConfigDelta, homeDirFile.Name())
loadingRules := ClientConfigLoadingRules{
ExplicitPath: commandLineFile.Name(),
Precedence: []string{envVarFile.Name(), currentDirFile.Name(), homeDirFile.Name()},
Precedence: []string{commandLineFile.Name(), envVarFile.Name(), currentDirFile.Name(), homeDirFile.Name()},
}
mergedConfig, err := loadingRules.Load()
......
......@@ -78,10 +78,7 @@ func testWriteAuthInfoFile(auth clientauth.Info, filename string) error {
}
func testBindClientConfig(cmd *cobra.Command) ClientConfig {
loadingRules := NewDefaultClientConfigLoadingRules()
loadingRules.Precedence[DefaultEnvVarIndex] = ""
loadingRules.Precedence[DefaultCurrentDirIndex] = ""
loadingRules.Precedence[DefaultHomeDirIndex] = ""
loadingRules := &ClientConfigLoadingRules{}
cmd.PersistentFlags().StringVar(&loadingRules.ExplicitPath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
overrides := &ConfigOverrides{}
......
......@@ -31,7 +31,7 @@ import (
)
type createAuthInfoOptions struct {
pathOptions *PathOptions
configAccess ConfigAccess
name string
authPath util.StringFlag
clientCertificate util.StringFlag
......@@ -67,8 +67,8 @@ $ kubectl set-credentials cluster-admin --username=admin --password=uXFGweU9l35q
// Embed client certificate data in the "cluster-admin" entry
$ kubectl set-credentials cluster-admin --client-certificate=~/.kube/admin.crt --embed-certs=true`
func NewCmdConfigSetAuthInfo(out io.Writer, pathOptions *PathOptions) *cobra.Command {
options := &createAuthInfoOptions{pathOptions: pathOptions}
func NewCmdConfigSetAuthInfo(out io.Writer, configAccess ConfigAccess) *cobra.Command {
options := &createAuthInfoOptions{configAccess: configAccess}
cmd := &cobra.Command{
Use: fmt.Sprintf("set-credentials NAME [--%v=/path/to/authfile] [--%v=path/to/certfile] [--%v=path/to/keyfile] [--%v=bearer_token] [--%v=basic_user] [--%v=basic_password]", clientcmd.FlagAuthPath, clientcmd.FlagCertFile, clientcmd.FlagKeyFile, clientcmd.FlagBearerToken, clientcmd.FlagUsername, clientcmd.FlagPassword),
......@@ -104,7 +104,7 @@ func (o createAuthInfoOptions) run() error {
return err
}
config, err := o.pathOptions.getStartingConfig()
config, err := o.configAccess.GetStartingConfig()
if err != nil {
return err
}
......@@ -112,7 +112,7 @@ func (o createAuthInfoOptions) run() error {
authInfo := o.modifyAuthInfo(config.AuthInfos[o.name])
config.AuthInfos[o.name] = authInfo
if err := o.pathOptions.ModifyConfig(*config); err != nil {
if err := ModifyConfig(o.configAccess, *config); err != nil {
return err
}
......@@ -225,5 +225,5 @@ func (o createAuthInfoOptions) validate() error {
}
}
return o.pathOptions.Validate()
return nil
}
......@@ -30,7 +30,7 @@ import (
)
type createClusterOptions struct {
pathOptions *PathOptions
configAccess ConfigAccess
name string
server util.StringFlag
apiVersion util.StringFlag
......@@ -52,8 +52,8 @@ $ kubectl config set-cluster e2e --certificate-authority=~/.kube/e2e/kubernetes.
$ kubectl config set-cluster e2e --insecure-skip-tls-verify=true`
)
func NewCmdConfigSetCluster(out io.Writer, pathOptions *PathOptions) *cobra.Command {
options := &createClusterOptions{pathOptions: pathOptions}
func NewCmdConfigSetCluster(out io.Writer, configAccess ConfigAccess) *cobra.Command {
options := &createClusterOptions{configAccess: configAccess}
cmd := &cobra.Command{
Use: fmt.Sprintf("set-cluster NAME [--%v=server] [--%v=path/to/certficate/authority] [--%v=apiversion] [--%v=true]", clientcmd.FlagAPIServer, clientcmd.FlagCAFile, clientcmd.FlagAPIVersion, clientcmd.FlagInsecure),
......@@ -89,7 +89,7 @@ func (o createClusterOptions) run() error {
return err
}
config, err := o.pathOptions.getStartingConfig()
config, err := o.configAccess.GetStartingConfig()
if err != nil {
return err
}
......@@ -97,7 +97,7 @@ func (o createClusterOptions) run() error {
cluster := o.modifyCluster(config.Clusters[o.name])
config.Clusters[o.name] = cluster
if err := o.pathOptions.ModifyConfig(*config); err != nil {
if err := ModifyConfig(o.configAccess, *config); err != nil {
return err
}
......@@ -169,5 +169,5 @@ func (o createClusterOptions) validate() error {
}
}
return o.pathOptions.Validate()
return nil
}
......@@ -29,11 +29,11 @@ import (
)
type createContextOptions struct {
pathOptions *PathOptions
name string
cluster util.StringFlag
authInfo util.StringFlag
namespace util.StringFlag
configAccess ConfigAccess
name string
cluster util.StringFlag
authInfo util.StringFlag
namespace util.StringFlag
}
const (
......@@ -43,8 +43,8 @@ Specifying a name that already exists will merge new fields on top of existing v
$ kubectl config set-context gce --user=cluster-admin`
)
func NewCmdConfigSetContext(out io.Writer, pathOptions *PathOptions) *cobra.Command {
options := &createContextOptions{pathOptions: pathOptions}
func NewCmdConfigSetContext(out io.Writer, configAccess ConfigAccess) *cobra.Command {
options := &createContextOptions{configAccess: configAccess}
cmd := &cobra.Command{
Use: fmt.Sprintf("set-context NAME [--%v=cluster_nickname] [--%v=user_nickname] [--%v=namespace]", clientcmd.FlagClusterName, clientcmd.FlagAuthInfoName, clientcmd.FlagNamespace),
......@@ -76,7 +76,7 @@ func (o createContextOptions) run() error {
return err
}
config, err := o.pathOptions.getStartingConfig()
config, err := o.configAccess.GetStartingConfig()
if err != nil {
return err
}
......@@ -84,7 +84,7 @@ func (o createContextOptions) run() error {
context := o.modifyContext(config.Contexts[o.name])
config.Contexts[o.name] = context
if err := o.pathOptions.ModifyConfig(*config); err != nil {
if err := ModifyConfig(o.configAccess, *config); err != nil {
return err
}
......@@ -123,5 +123,5 @@ func (o createContextOptions) validate() error {
return errors.New("You must specify a non-empty context name")
}
return o.pathOptions.Validate()
return nil
}
......@@ -32,7 +32,7 @@ const (
)
type setOptions struct {
pathOptions *PathOptions
configAccess ConfigAccess
propertyName string
propertyValue string
}
......@@ -41,8 +41,8 @@ const set_long = `Sets an individual value in a kubeconfig file
PROPERTY_NAME is a dot delimited name where each token represents either a attribute name or a map key. Map keys may not contain dots.
PROPERTY_VALUE is the new value you wish to set.`
func NewCmdConfigSet(out io.Writer, pathOptions *PathOptions) *cobra.Command {
options := &setOptions{pathOptions: pathOptions}
func NewCmdConfigSet(out io.Writer, configAccess ConfigAccess) *cobra.Command {
options := &setOptions{configAccess: configAccess}
cmd := &cobra.Command{
Use: "set PROPERTY_NAME PROPERTY_VALUE",
......@@ -69,7 +69,7 @@ func (o setOptions) run() error {
return err
}
config, err := o.pathOptions.getStartingConfig()
config, err := o.configAccess.GetStartingConfig()
if err != nil {
return err
}
......@@ -82,7 +82,7 @@ func (o setOptions) run() error {
return err
}
if err := o.pathOptions.ModifyConfig(*config); err != nil {
if err := ModifyConfig(o.configAccess, *config); err != nil {
return err
}
......@@ -110,7 +110,7 @@ func (o setOptions) validate() error {
return errors.New("You must specify a property")
}
return o.pathOptions.Validate()
return nil
}
func modifyConfig(curr reflect.Value, steps *navigationSteps, propertyValue string, unset bool) error {
......
......@@ -26,15 +26,15 @@ import (
)
type unsetOptions struct {
pathOptions *PathOptions
configAccess ConfigAccess
propertyName string
}
const unset_long = `Unsets an individual value in a kubeconfig file
PROPERTY_NAME is a dot delimited name where each token represents either a attribute name or a map key. Map keys may not contain dots.`
func NewCmdConfigUnset(out io.Writer, pathOptions *PathOptions) *cobra.Command {
options := &unsetOptions{pathOptions: pathOptions}
func NewCmdConfigUnset(out io.Writer, configAccess ConfigAccess) *cobra.Command {
options := &unsetOptions{configAccess: configAccess}
cmd := &cobra.Command{
Use: "unset PROPERTY_NAME",
......@@ -61,7 +61,7 @@ func (o unsetOptions) run() error {
return err
}
config, err := o.pathOptions.getStartingConfig()
config, err := o.configAccess.GetStartingConfig()
if err != nil {
return err
}
......@@ -75,7 +75,7 @@ func (o unsetOptions) run() error {
return err
}
if err := o.pathOptions.ModifyConfig(*config); err != nil {
if err := ModifyConfig(o.configAccess, *config); err != nil {
return err
}
......@@ -98,5 +98,5 @@ func (o unsetOptions) validate() error {
return errors.New("You must specify a property")
}
return o.pathOptions.Validate()
return nil
}
......@@ -25,12 +25,12 @@ import (
)
type useContextOptions struct {
pathOptions *PathOptions
contextName string
configAccess ConfigAccess
contextName string
}
func NewCmdConfigUseContext(out io.Writer, pathOptions *PathOptions) *cobra.Command {
options := &useContextOptions{pathOptions: pathOptions}
func NewCmdConfigUseContext(out io.Writer, configAccess ConfigAccess) *cobra.Command {
options := &useContextOptions{configAccess: configAccess}
cmd := &cobra.Command{
Use: "use-context CONTEXT_NAME",
......@@ -57,14 +57,14 @@ func (o useContextOptions) run() error {
return err
}
config, err := o.pathOptions.getStartingConfig()
config, err := o.configAccess.GetStartingConfig()
if err != nil {
return err
}
config.CurrentContext = o.contextName
if err := o.pathOptions.ModifyConfig(*config); err != nil {
if err := ModifyConfig(o.configAccess, *config); err != nil {
return err
}
......@@ -87,5 +87,5 @@ func (o useContextOptions) validate() error {
return errors.New("You must specify a current-context")
}
return o.pathOptions.Validate()
return nil
}
......@@ -32,10 +32,10 @@ import (
)
type ViewOptions struct {
PathOptions *PathOptions
Merge util.BoolFlag
Flatten bool
Minify bool
ConfigAccess ConfigAccess
Merge util.BoolFlag
Flatten bool
Minify bool
}
const (
......@@ -52,8 +52,8 @@ $ 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, ConfigAccess ConfigAccess) *cobra.Command {
options := &ViewOptions{ConfigAccess: ConfigAccess}
cmd := &cobra.Command{
Use: "view",
......@@ -116,7 +116,7 @@ func (o ViewOptions) Run(out io.Writer, printer kubectl.ResourcePrinter) error {
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.ConfigAccess.IsExplicitFile() {
if !o.Merge.Provided() {
o.Merge.Set("false")
}
......@@ -136,32 +136,20 @@ func (o ViewOptions) loadConfig() (*clientcmdapi.Config, error) {
}
func (o ViewOptions) Validate() error {
return o.PathOptions.Validate()
if !o.Merge.Value() && !o.ConfigAccess.IsExplicitFile() {
return errors.New("if merge==false a precise file must to specified")
}
return nil
}
// 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) {
switch {
case !o.Merge.Value():
switch {
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.UseEnvVar:
return clientcmd.LoadFromFile(o.PathOptions.EnvVarFile)
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 clientcmd.LoadFromFile(o.ConfigAccess.GetExplicitFile())
default:
return o.PathOptions.getStartingConfig()
return o.ConfigAccess.GetStartingConfig()
}
}
......@@ -286,11 +286,11 @@ func (c *clientSwaggerSchema) ValidateBytes(data []byte) error {
// DefaultClientConfig creates a clientcmd.ClientConfig with the following hierarchy:
// 1. Use the kubeconfig builder. The number of merges and overrides here gets a little crazy. Stay with me.
// 1. Merge together the kubeconfig itself. This is done with the following hierarchy and merge rules:
// 1. CommandLineLocation - this parsed from the command line, so it must be late bound
// 2. EnvVarLocation
// 3. CurrentDirectoryLocation
// 4. HomeDirectoryLocation
// 1. Merge together the kubeconfig itself. This is done with the following hierarchy rules:
// 1. CommandLineLocation - this parsed from the command line, so it must be late bound. If you specify this,
// then no other kubeconfig files are merged. This file must exist.
// 2. If $KUBECONFIG is set, then it is treated as a list of files that should be merged.
// 3. HomeDirectoryLocation
// Empty filenames are ignored. Files with non-deserializable content produced errors.
// The first file to set a particular value or map key wins and the value or map key is never changed.
// This means that the first file to set CurrentContext will have its context preserved. It also means
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment