mirror of https://github.com/k3s-io/k3s
Move ModifyConfig (and some related functions) into the clientcmd pkg.
parent
660050631e
commit
86293810af
|
@ -0,0 +1,396 @@
|
||||||
|
/*
|
||||||
|
Copyright 2014 The Kubernetes Authors 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 clientcmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
|
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConfigAccess is used by subcommands and methods in this package to load and modify the appropriate config files
|
||||||
|
type ConfigAccess interface {
|
||||||
|
// GetLoadingPrecedence returns the slice of files that should be used for loading and inspecting the config
|
||||||
|
GetLoadingPrecedence() []string
|
||||||
|
// GetStartingConfig returns the config that subcommands should being operating against. It may or may not be merged depending on loading rules
|
||||||
|
GetStartingConfig() (*clientcmdapi.Config, error)
|
||||||
|
// GetDefaultFilename returns the name of the file you should write into (create if necessary), if you're trying to create a new stanza as opposed to updating an existing one.
|
||||||
|
GetDefaultFilename() string
|
||||||
|
// IsExplicitFile indicates whether or not this command is interested in exactly one file. This implementation only ever does that via a flag, but implementations that handle local, global, and flags may have more
|
||||||
|
IsExplicitFile() bool
|
||||||
|
// GetExplicitFile returns the particular file this command is operating against. This implementation only ever has one, but implementations that handle local, global, and flags may have more
|
||||||
|
GetExplicitFile() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PathOptions struct {
|
||||||
|
// GlobalFile is the full path to the file to load as the global (final) option
|
||||||
|
GlobalFile string
|
||||||
|
// EnvVar is the env var name that points to the list of kubeconfig files to load
|
||||||
|
EnvVar string
|
||||||
|
// ExplicitFileFlag is the name of the flag to use for prompting for the kubeconfig file
|
||||||
|
ExplicitFileFlag string
|
||||||
|
|
||||||
|
// GlobalFileSubpath is an optional value used for displaying help
|
||||||
|
GlobalFileSubpath string
|
||||||
|
|
||||||
|
LoadingRules *ClientConfigLoadingRules
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *PathOptions) GetEnvVarFiles() []string {
|
||||||
|
if len(o.EnvVar) == 0 {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
envVarValue := os.Getenv(o.EnvVar)
|
||||||
|
if len(envVarValue) == 0 {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.SplitList(envVarValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *PathOptions) GetLoadingPrecedence() []string {
|
||||||
|
if envVarFiles := o.GetEnvVarFiles(); len(envVarFiles) > 0 {
|
||||||
|
return envVarFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
return []string{o.GlobalFile}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *PathOptions) GetStartingConfig() (*clientcmdapi.Config, error) {
|
||||||
|
// don't mutate the original
|
||||||
|
loadingRules := *o.LoadingRules
|
||||||
|
loadingRules.Precedence = o.GetLoadingPrecedence()
|
||||||
|
|
||||||
|
clientConfig := NewNonInteractiveDeferredLoadingClientConfig(&loadingRules, &ConfigOverrides{})
|
||||||
|
rawConfig, err := clientConfig.RawConfig()
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return clientcmdapi.NewConfig(), nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &rawConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *PathOptions) GetDefaultFilename() string {
|
||||||
|
if o.IsExplicitFile() {
|
||||||
|
return o.GetExplicitFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
if envVarFiles := o.GetEnvVarFiles(); len(envVarFiles) > 0 {
|
||||||
|
if len(envVarFiles) == 1 {
|
||||||
|
return envVarFiles[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// if any of the envvar files already exists, return it
|
||||||
|
for _, envVarFile := range envVarFiles {
|
||||||
|
if _, err := os.Stat(envVarFile); err == nil {
|
||||||
|
return envVarFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, return the last one in the list
|
||||||
|
return envVarFiles[len(envVarFiles)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.GlobalFile
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *PathOptions) IsExplicitFile() bool {
|
||||||
|
if len(o.LoadingRules.ExplicitPath) > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *PathOptions) GetExplicitFile() string {
|
||||||
|
return o.LoadingRules.ExplicitPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultPathOptions() *PathOptions {
|
||||||
|
ret := &PathOptions{
|
||||||
|
GlobalFile: RecommendedHomeFile,
|
||||||
|
EnvVar: RecommendedConfigPathEnvVar,
|
||||||
|
ExplicitFileFlag: RecommendedConfigPathFlag,
|
||||||
|
|
||||||
|
GlobalFileSubpath: path.Join(RecommendedHomeDir, RecommendedFileName),
|
||||||
|
|
||||||
|
LoadingRules: NewDefaultClientConfigLoadingRules(),
|
||||||
|
}
|
||||||
|
ret.LoadingRules.DoNotResolvePaths = true
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyConfig takes a Config object, iterates through Clusters, AuthInfos, and Contexts, uses the LocationOfOrigin if specified or
|
||||||
|
// uses the default destination file to write the results into. This results in multiple file reads, but it's very easy to follow.
|
||||||
|
// Preferences and CurrentContext should always be set in the default destination file. Since we can't distinguish between empty and missing values
|
||||||
|
// (no nil strings), we're forced have separate handling for them. In the kubeconfig cases, newConfig should have at most one difference,
|
||||||
|
// that means that this code will only write into a single file. If you want to relativizePaths, you must provide a fully qualified path in any
|
||||||
|
// modified element.
|
||||||
|
func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, relativizePaths bool) error {
|
||||||
|
startingConfig, err := configAccess.GetStartingConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to find all differences, locate their original files, read a partial config to modify only that stanza and write out the file.
|
||||||
|
// Special case the test for current context and preferences since those always write to the default file.
|
||||||
|
if reflect.DeepEqual(*startingConfig, newConfig) {
|
||||||
|
// nothing to do
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if startingConfig.CurrentContext != newConfig.CurrentContext {
|
||||||
|
if err := writeCurrentContext(configAccess, newConfig.CurrentContext); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(startingConfig.Preferences, newConfig.Preferences) {
|
||||||
|
if err := writePreferences(configAccess, newConfig.Preferences); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search every cluster, authInfo, and context. First from new to old for differences, then from old to new for deletions
|
||||||
|
for key, cluster := range newConfig.Clusters {
|
||||||
|
startingCluster, exists := startingConfig.Clusters[key]
|
||||||
|
if !reflect.DeepEqual(cluster, startingCluster) || !exists {
|
||||||
|
destinationFile := cluster.LocationOfOrigin
|
||||||
|
if len(destinationFile) == 0 {
|
||||||
|
destinationFile = configAccess.GetDefaultFilename()
|
||||||
|
}
|
||||||
|
|
||||||
|
configToWrite := GetConfigFromFileOrDie(destinationFile)
|
||||||
|
t := *cluster
|
||||||
|
|
||||||
|
configToWrite.Clusters[key] = &t
|
||||||
|
configToWrite.Clusters[key].LocationOfOrigin = destinationFile
|
||||||
|
if relativizePaths {
|
||||||
|
if err := RelativizeClusterLocalPaths(configToWrite.Clusters[key]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, context := range newConfig.Contexts {
|
||||||
|
startingContext, exists := startingConfig.Contexts[key]
|
||||||
|
if !reflect.DeepEqual(context, startingContext) || !exists {
|
||||||
|
destinationFile := context.LocationOfOrigin
|
||||||
|
if len(destinationFile) == 0 {
|
||||||
|
destinationFile = configAccess.GetDefaultFilename()
|
||||||
|
}
|
||||||
|
|
||||||
|
configToWrite := GetConfigFromFileOrDie(destinationFile)
|
||||||
|
configToWrite.Contexts[key] = context
|
||||||
|
|
||||||
|
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, authInfo := range newConfig.AuthInfos {
|
||||||
|
startingAuthInfo, exists := startingConfig.AuthInfos[key]
|
||||||
|
if !reflect.DeepEqual(authInfo, startingAuthInfo) || !exists {
|
||||||
|
destinationFile := authInfo.LocationOfOrigin
|
||||||
|
if len(destinationFile) == 0 {
|
||||||
|
destinationFile = configAccess.GetDefaultFilename()
|
||||||
|
}
|
||||||
|
|
||||||
|
configToWrite := GetConfigFromFileOrDie(destinationFile)
|
||||||
|
t := *authInfo
|
||||||
|
configToWrite.AuthInfos[key] = &t
|
||||||
|
configToWrite.AuthInfos[key].LocationOfOrigin = destinationFile
|
||||||
|
if relativizePaths {
|
||||||
|
if err := RelativizeAuthInfoLocalPaths(configToWrite.AuthInfos[key]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, cluster := range startingConfig.Clusters {
|
||||||
|
if _, exists := newConfig.Clusters[key]; !exists {
|
||||||
|
destinationFile := cluster.LocationOfOrigin
|
||||||
|
if len(destinationFile) == 0 {
|
||||||
|
destinationFile = configAccess.GetDefaultFilename()
|
||||||
|
}
|
||||||
|
|
||||||
|
configToWrite := GetConfigFromFileOrDie(destinationFile)
|
||||||
|
delete(configToWrite.Clusters, key)
|
||||||
|
|
||||||
|
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, context := range startingConfig.Contexts {
|
||||||
|
if _, exists := newConfig.Contexts[key]; !exists {
|
||||||
|
destinationFile := context.LocationOfOrigin
|
||||||
|
if len(destinationFile) == 0 {
|
||||||
|
destinationFile = configAccess.GetDefaultFilename()
|
||||||
|
}
|
||||||
|
|
||||||
|
configToWrite := GetConfigFromFileOrDie(destinationFile)
|
||||||
|
delete(configToWrite.Contexts, key)
|
||||||
|
|
||||||
|
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, authInfo := range startingConfig.AuthInfos {
|
||||||
|
if _, exists := newConfig.AuthInfos[key]; !exists {
|
||||||
|
destinationFile := authInfo.LocationOfOrigin
|
||||||
|
if len(destinationFile) == 0 {
|
||||||
|
destinationFile = configAccess.GetDefaultFilename()
|
||||||
|
}
|
||||||
|
|
||||||
|
configToWrite := GetConfigFromFileOrDie(destinationFile)
|
||||||
|
delete(configToWrite.AuthInfos, key)
|
||||||
|
|
||||||
|
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeCurrentContext takes three possible paths.
|
||||||
|
// If newCurrentContext is the same as the startingConfig's current context, then we exit.
|
||||||
|
// If newCurrentContext has a value, then that value is written into the default destination file.
|
||||||
|
// If newCurrentContext is empty, then we find the config file that is setting the CurrentContext and clear the value from that file
|
||||||
|
func writeCurrentContext(configAccess ConfigAccess, newCurrentContext string) error {
|
||||||
|
if startingConfig, err := configAccess.GetStartingConfig(); err != nil {
|
||||||
|
return err
|
||||||
|
} else if startingConfig.CurrentContext == newCurrentContext {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if configAccess.IsExplicitFile() {
|
||||||
|
file := configAccess.GetExplicitFile()
|
||||||
|
currConfig := GetConfigFromFileOrDie(file)
|
||||||
|
currConfig.CurrentContext = newCurrentContext
|
||||||
|
if err := WriteToFile(*currConfig, file); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(newCurrentContext) > 0 {
|
||||||
|
destinationFile := configAccess.GetDefaultFilename()
|
||||||
|
config := GetConfigFromFileOrDie(destinationFile)
|
||||||
|
config.CurrentContext = newCurrentContext
|
||||||
|
|
||||||
|
if err := WriteToFile(*config, destinationFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're supposed to be clearing the current context. We need to find the first spot in the chain that is setting it and clear it
|
||||||
|
for _, file := range configAccess.GetLoadingPrecedence() {
|
||||||
|
if _, err := os.Stat(file); err == nil {
|
||||||
|
currConfig := GetConfigFromFileOrDie(file)
|
||||||
|
|
||||||
|
if len(currConfig.CurrentContext) > 0 {
|
||||||
|
currConfig.CurrentContext = newCurrentContext
|
||||||
|
if err := WriteToFile(*currConfig, file); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.New("no config found to write context")
|
||||||
|
}
|
||||||
|
|
||||||
|
func writePreferences(configAccess ConfigAccess, newPrefs clientcmdapi.Preferences) error {
|
||||||
|
if startingConfig, err := configAccess.GetStartingConfig(); err != nil {
|
||||||
|
return err
|
||||||
|
} else if reflect.DeepEqual(startingConfig.Preferences, newPrefs) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if configAccess.IsExplicitFile() {
|
||||||
|
file := configAccess.GetExplicitFile()
|
||||||
|
currConfig := GetConfigFromFileOrDie(file)
|
||||||
|
currConfig.Preferences = newPrefs
|
||||||
|
if err := WriteToFile(*currConfig, file); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range configAccess.GetLoadingPrecedence() {
|
||||||
|
currConfig := GetConfigFromFileOrDie(file)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(currConfig.Preferences, newPrefs) {
|
||||||
|
currConfig.Preferences = newPrefs
|
||||||
|
if err := WriteToFile(*currConfig, file); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.New("no config found to write preferences")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfigFromFileOrDie tries to read a kubeconfig file and if it can't, it calls exit. One exception, missing files result in empty configs, not an exit
|
||||||
|
func GetConfigFromFileOrDie(filename string) *clientcmdapi.Config {
|
||||||
|
config, err := LoadFromFile(filename)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
glog.FatalDepth(1, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if config == nil {
|
||||||
|
return clientcmdapi.NewConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
|
cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/rollout"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/rollout"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
|
@ -225,7 +226,7 @@ Find more information at https://github.com/kubernetes/kubernetes.`,
|
||||||
cmds.AddCommand(NewCmdLabel(f, out))
|
cmds.AddCommand(NewCmdLabel(f, out))
|
||||||
cmds.AddCommand(NewCmdAnnotate(f, out))
|
cmds.AddCommand(NewCmdAnnotate(f, out))
|
||||||
|
|
||||||
cmds.AddCommand(cmdconfig.NewCmdConfig(cmdconfig.NewDefaultPathOptions(), out))
|
cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), out))
|
||||||
cmds.AddCommand(NewCmdClusterInfo(f, out))
|
cmds.AddCommand(NewCmdClusterInfo(f, out))
|
||||||
cmds.AddCommand(NewCmdApiVersions(f, out))
|
cmds.AddCommand(NewCmdApiVersions(f, out))
|
||||||
cmds.AddCommand(NewCmdVersion(f, out))
|
cmds.AddCommand(NewCmdVersion(f, out))
|
||||||
|
|
|
@ -17,50 +17,16 @@ limitations under the License.
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type PathOptions struct {
|
func NewCmdConfig(pathOptions *clientcmd.PathOptions, out io.Writer) *cobra.Command {
|
||||||
// GlobalFile is the full path to the file to load as the global (final) option
|
|
||||||
GlobalFile string
|
|
||||||
// EnvVar is the env var name that points to the list of kubeconfig files to load
|
|
||||||
EnvVar string
|
|
||||||
// ExplicitFileFlag is the name of the flag to use for prompting for the kubeconfig file
|
|
||||||
ExplicitFileFlag string
|
|
||||||
|
|
||||||
// GlobalFileSubpath is an optional value used for displaying help
|
|
||||||
GlobalFileSubpath string
|
|
||||||
|
|
||||||
LoadingRules *clientcmd.ClientConfigLoadingRules
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigAccess is used by subcommands and methods in this package to load and modify the appropriate config files
|
|
||||||
type ConfigAccess interface {
|
|
||||||
// GetLoadingPrecedence returns the slice of files that should be used for loading and inspecting the config
|
|
||||||
GetLoadingPrecedence() []string
|
|
||||||
// GetStartingConfig returns the config that subcommands should being operating against. It may or may not be merged depending on loading rules
|
|
||||||
GetStartingConfig() (*clientcmdapi.Config, error)
|
|
||||||
// GetDefaultFilename returns the name of the file you should write into (create if necessary), if you're trying to create a new stanza as opposed to updating an existing one.
|
|
||||||
GetDefaultFilename() string
|
|
||||||
// IsExplicitFile indicates whether or not this command is interested in exactly one file. This implementation only ever does that via a flag, but implementations that handle local, global, and flags may have more
|
|
||||||
IsExplicitFile() bool
|
|
||||||
// GetExplicitFile returns the particular file this command is operating against. This implementation only ever has one, but implementations that handle local, global, and flags may have more
|
|
||||||
GetExplicitFile() string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCmdConfig(pathOptions *PathOptions, out io.Writer) *cobra.Command {
|
|
||||||
if len(pathOptions.ExplicitFileFlag) == 0 {
|
if len(pathOptions.ExplicitFileFlag) == 0 {
|
||||||
pathOptions.ExplicitFileFlag = clientcmd.RecommendedConfigPathFlag
|
pathOptions.ExplicitFileFlag = clientcmd.RecommendedConfigPathFlag
|
||||||
}
|
}
|
||||||
|
@ -95,345 +61,6 @@ The loading order follows these rules:
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultPathOptions() *PathOptions {
|
|
||||||
ret := &PathOptions{
|
|
||||||
GlobalFile: clientcmd.RecommendedHomeFile,
|
|
||||||
EnvVar: clientcmd.RecommendedConfigPathEnvVar,
|
|
||||||
ExplicitFileFlag: clientcmd.RecommendedConfigPathFlag,
|
|
||||||
|
|
||||||
GlobalFileSubpath: path.Join(clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName),
|
|
||||||
|
|
||||||
LoadingRules: clientcmd.NewDefaultClientConfigLoadingRules(),
|
|
||||||
}
|
|
||||||
ret.LoadingRules.DoNotResolvePaths = true
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PathOptions) GetEnvVarFiles() []string {
|
|
||||||
if len(o.EnvVar) == 0 {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
envVarValue := os.Getenv(o.EnvVar)
|
|
||||||
if len(envVarValue) == 0 {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filepath.SplitList(envVarValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PathOptions) GetLoadingPrecedence() []string {
|
|
||||||
if envVarFiles := o.GetEnvVarFiles(); len(envVarFiles) > 0 {
|
|
||||||
return envVarFiles
|
|
||||||
}
|
|
||||||
|
|
||||||
return []string{o.GlobalFile}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PathOptions) GetStartingConfig() (*clientcmdapi.Config, error) {
|
|
||||||
// don't mutate the original
|
|
||||||
loadingRules := *o.LoadingRules
|
|
||||||
loadingRules.Precedence = o.GetLoadingPrecedence()
|
|
||||||
|
|
||||||
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&loadingRules, &clientcmd.ConfigOverrides{})
|
|
||||||
rawConfig, err := clientConfig.RawConfig()
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return clientcmdapi.NewConfig(), nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &rawConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PathOptions) GetDefaultFilename() string {
|
|
||||||
if o.IsExplicitFile() {
|
|
||||||
return o.GetExplicitFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
if envVarFiles := o.GetEnvVarFiles(); len(envVarFiles) > 0 {
|
|
||||||
if len(envVarFiles) == 1 {
|
|
||||||
return envVarFiles[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// if any of the envvar files already exists, return it
|
|
||||||
for _, envVarFile := range envVarFiles {
|
|
||||||
if _, err := os.Stat(envVarFile); err == nil {
|
|
||||||
return envVarFile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, return the last one in the list
|
|
||||||
return envVarFiles[len(envVarFiles)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return o.GlobalFile
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PathOptions) IsExplicitFile() bool {
|
|
||||||
if len(o.LoadingRules.ExplicitPath) > 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PathOptions) GetExplicitFile() string {
|
|
||||||
return o.LoadingRules.ExplicitPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModifyConfig takes a Config object, iterates through Clusters, AuthInfos, and Contexts, uses the LocationOfOrigin if specified or
|
|
||||||
// uses the default destination file to write the results into. This results in multiple file reads, but it's very easy to follow.
|
|
||||||
// Preferences and CurrentContext should always be set in the default destination file. Since we can't distinguish between empty and missing values
|
|
||||||
// (no nil strings), we're forced have separate handling for them. In the kubeconfig cases, newConfig should have at most one difference,
|
|
||||||
// that means that this code will only write into a single file. If you want to relativizePaths, you must provide a fully qualified path in any
|
|
||||||
// modified element.
|
|
||||||
func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, relativizePaths bool) error {
|
|
||||||
startingConfig, err := configAccess.GetStartingConfig()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to find all differences, locate their original files, read a partial config to modify only that stanza and write out the file.
|
|
||||||
// Special case the test for current context and preferences since those always write to the default file.
|
|
||||||
if reflect.DeepEqual(*startingConfig, newConfig) {
|
|
||||||
// nothing to do
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if startingConfig.CurrentContext != newConfig.CurrentContext {
|
|
||||||
if err := writeCurrentContext(configAccess, newConfig.CurrentContext); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(startingConfig.Preferences, newConfig.Preferences) {
|
|
||||||
if err := writePreferences(configAccess, newConfig.Preferences); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search every cluster, authInfo, and context. First from new to old for differences, then from old to new for deletions
|
|
||||||
for key, cluster := range newConfig.Clusters {
|
|
||||||
startingCluster, exists := startingConfig.Clusters[key]
|
|
||||||
if !reflect.DeepEqual(cluster, startingCluster) || !exists {
|
|
||||||
destinationFile := cluster.LocationOfOrigin
|
|
||||||
if len(destinationFile) == 0 {
|
|
||||||
destinationFile = configAccess.GetDefaultFilename()
|
|
||||||
}
|
|
||||||
|
|
||||||
configToWrite := getConfigFromFileOrDie(destinationFile)
|
|
||||||
t := *cluster
|
|
||||||
|
|
||||||
configToWrite.Clusters[key] = &t
|
|
||||||
configToWrite.Clusters[key].LocationOfOrigin = destinationFile
|
|
||||||
if relativizePaths {
|
|
||||||
if err := clientcmd.RelativizeClusterLocalPaths(configToWrite.Clusters[key]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := clientcmd.WriteToFile(*configToWrite, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, context := range newConfig.Contexts {
|
|
||||||
startingContext, exists := startingConfig.Contexts[key]
|
|
||||||
if !reflect.DeepEqual(context, startingContext) || !exists {
|
|
||||||
destinationFile := context.LocationOfOrigin
|
|
||||||
if len(destinationFile) == 0 {
|
|
||||||
destinationFile = configAccess.GetDefaultFilename()
|
|
||||||
}
|
|
||||||
|
|
||||||
configToWrite := getConfigFromFileOrDie(destinationFile)
|
|
||||||
configToWrite.Contexts[key] = context
|
|
||||||
|
|
||||||
if err := clientcmd.WriteToFile(*configToWrite, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, authInfo := range newConfig.AuthInfos {
|
|
||||||
startingAuthInfo, exists := startingConfig.AuthInfos[key]
|
|
||||||
if !reflect.DeepEqual(authInfo, startingAuthInfo) || !exists {
|
|
||||||
destinationFile := authInfo.LocationOfOrigin
|
|
||||||
if len(destinationFile) == 0 {
|
|
||||||
destinationFile = configAccess.GetDefaultFilename()
|
|
||||||
}
|
|
||||||
|
|
||||||
configToWrite := getConfigFromFileOrDie(destinationFile)
|
|
||||||
t := *authInfo
|
|
||||||
configToWrite.AuthInfos[key] = &t
|
|
||||||
configToWrite.AuthInfos[key].LocationOfOrigin = destinationFile
|
|
||||||
if relativizePaths {
|
|
||||||
if err := clientcmd.RelativizeAuthInfoLocalPaths(configToWrite.AuthInfos[key]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := clientcmd.WriteToFile(*configToWrite, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, cluster := range startingConfig.Clusters {
|
|
||||||
if _, exists := newConfig.Clusters[key]; !exists {
|
|
||||||
destinationFile := cluster.LocationOfOrigin
|
|
||||||
if len(destinationFile) == 0 {
|
|
||||||
destinationFile = configAccess.GetDefaultFilename()
|
|
||||||
}
|
|
||||||
|
|
||||||
configToWrite := getConfigFromFileOrDie(destinationFile)
|
|
||||||
delete(configToWrite.Clusters, key)
|
|
||||||
|
|
||||||
if err := clientcmd.WriteToFile(*configToWrite, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, context := range startingConfig.Contexts {
|
|
||||||
if _, exists := newConfig.Contexts[key]; !exists {
|
|
||||||
destinationFile := context.LocationOfOrigin
|
|
||||||
if len(destinationFile) == 0 {
|
|
||||||
destinationFile = configAccess.GetDefaultFilename()
|
|
||||||
}
|
|
||||||
|
|
||||||
configToWrite := getConfigFromFileOrDie(destinationFile)
|
|
||||||
delete(configToWrite.Contexts, key)
|
|
||||||
|
|
||||||
if err := clientcmd.WriteToFile(*configToWrite, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, authInfo := range startingConfig.AuthInfos {
|
|
||||||
if _, exists := newConfig.AuthInfos[key]; !exists {
|
|
||||||
destinationFile := authInfo.LocationOfOrigin
|
|
||||||
if len(destinationFile) == 0 {
|
|
||||||
destinationFile = configAccess.GetDefaultFilename()
|
|
||||||
}
|
|
||||||
|
|
||||||
configToWrite := getConfigFromFileOrDie(destinationFile)
|
|
||||||
delete(configToWrite.AuthInfos, key)
|
|
||||||
|
|
||||||
if err := clientcmd.WriteToFile(*configToWrite, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeCurrentContext takes three possible paths.
|
|
||||||
// If newCurrentContext is the same as the startingConfig's current context, then we exit.
|
|
||||||
// If newCurrentContext has a value, then that value is written into the default destination file.
|
|
||||||
// If newCurrentContext is empty, then we find the config file that is setting the CurrentContext and clear the value from that file
|
|
||||||
func writeCurrentContext(configAccess ConfigAccess, newCurrentContext string) error {
|
|
||||||
if startingConfig, err := configAccess.GetStartingConfig(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if startingConfig.CurrentContext == newCurrentContext {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if configAccess.IsExplicitFile() {
|
|
||||||
file := configAccess.GetExplicitFile()
|
|
||||||
currConfig := getConfigFromFileOrDie(file)
|
|
||||||
currConfig.CurrentContext = newCurrentContext
|
|
||||||
if err := clientcmd.WriteToFile(*currConfig, file); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(newCurrentContext) > 0 {
|
|
||||||
destinationFile := configAccess.GetDefaultFilename()
|
|
||||||
config := getConfigFromFileOrDie(destinationFile)
|
|
||||||
config.CurrentContext = newCurrentContext
|
|
||||||
|
|
||||||
if err := clientcmd.WriteToFile(*config, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// we're supposed to be clearing the current context. We need to find the first spot in the chain that is setting it and clear it
|
|
||||||
for _, file := range configAccess.GetLoadingPrecedence() {
|
|
||||||
if _, err := os.Stat(file); err == nil {
|
|
||||||
currConfig := getConfigFromFileOrDie(file)
|
|
||||||
|
|
||||||
if len(currConfig.CurrentContext) > 0 {
|
|
||||||
currConfig.CurrentContext = newCurrentContext
|
|
||||||
if err := clientcmd.WriteToFile(*currConfig, file); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.New("no config found to write context")
|
|
||||||
}
|
|
||||||
|
|
||||||
func writePreferences(configAccess ConfigAccess, newPrefs clientcmdapi.Preferences) error {
|
|
||||||
if startingConfig, err := configAccess.GetStartingConfig(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if reflect.DeepEqual(startingConfig.Preferences, newPrefs) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if configAccess.IsExplicitFile() {
|
|
||||||
file := configAccess.GetExplicitFile()
|
|
||||||
currConfig := getConfigFromFileOrDie(file)
|
|
||||||
currConfig.Preferences = newPrefs
|
|
||||||
if err := clientcmd.WriteToFile(*currConfig, file); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, file := range configAccess.GetLoadingPrecedence() {
|
|
||||||
currConfig := getConfigFromFileOrDie(file)
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(currConfig.Preferences, newPrefs) {
|
|
||||||
currConfig.Preferences = newPrefs
|
|
||||||
if err := clientcmd.WriteToFile(*currConfig, file); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.New("no config found to write preferences")
|
|
||||||
}
|
|
||||||
|
|
||||||
// getConfigFromFileOrDie tries to read a kubeconfig file and if it can't, it calls exit. One exception, missing files result in empty configs, not an exit
|
|
||||||
func getConfigFromFileOrDie(filename string) *clientcmdapi.Config {
|
|
||||||
config, err := clientcmd.LoadFromFile(filename)
|
|
||||||
if err != nil && !os.IsNotExist(err) {
|
|
||||||
glog.FatalDepth(1, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config == nil {
|
|
||||||
return clientcmdapi.NewConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
func toBool(propertyValue string) (bool, error) {
|
func toBool(propertyValue string) (bool, error) {
|
||||||
boolValue := false
|
boolValue := false
|
||||||
if len(propertyValue) != 0 {
|
if len(propertyValue) != 0 {
|
||||||
|
|
|
@ -770,12 +770,12 @@ func testConfigCommand(args []string, startingConfig clientcmdapi.Config, t *tes
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
cmd := NewCmdConfig(NewDefaultPathOptions(), buf)
|
cmd := NewCmdConfig(clientcmd.NewDefaultPathOptions(), buf)
|
||||||
cmd.SetArgs(argsToUse)
|
cmd.SetArgs(argsToUse)
|
||||||
cmd.Execute()
|
cmd.Execute()
|
||||||
|
|
||||||
// outBytes, _ := ioutil.ReadFile(fakeKubeFile.Name())
|
// outBytes, _ := ioutil.ReadFile(fakeKubeFile.Name())
|
||||||
config := getConfigFromFileOrDie(fakeKubeFile.Name())
|
config := clientcmd.GetConfigFromFileOrDie(fakeKubeFile.Name())
|
||||||
|
|
||||||
return buf.String(), *config
|
return buf.String(), *config
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type createAuthInfoOptions struct {
|
type createAuthInfoOptions struct {
|
||||||
configAccess ConfigAccess
|
configAccess clientcmd.ConfigAccess
|
||||||
name string
|
name string
|
||||||
authPath util.StringFlag
|
authPath util.StringFlag
|
||||||
clientCertificate util.StringFlag
|
clientCertificate util.StringFlag
|
||||||
|
@ -69,7 +69,7 @@ kubectl config set-credentials cluster-admin --username=admin --password=uXFGweU
|
||||||
# Embed client certificate data in the "cluster-admin" entry
|
# Embed client certificate data in the "cluster-admin" entry
|
||||||
kubectl config set-credentials cluster-admin --client-certificate=~/.kube/admin.crt --embed-certs=true`
|
kubectl config set-credentials cluster-admin --client-certificate=~/.kube/admin.crt --embed-certs=true`
|
||||||
|
|
||||||
func NewCmdConfigSetAuthInfo(out io.Writer, configAccess ConfigAccess) *cobra.Command {
|
func NewCmdConfigSetAuthInfo(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||||
options := &createAuthInfoOptions{configAccess: configAccess}
|
options := &createAuthInfoOptions{configAccess: configAccess}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -122,7 +122,7 @@ func (o createAuthInfoOptions) run() error {
|
||||||
authInfo := o.modifyAuthInfo(*startingStanza)
|
authInfo := o.modifyAuthInfo(*startingStanza)
|
||||||
config.AuthInfos[o.name] = &authInfo
|
config.AuthInfos[o.name] = &authInfo
|
||||||
|
|
||||||
if err := ModifyConfig(o.configAccess, *config, true); err != nil {
|
if err := clientcmd.ModifyConfig(o.configAccess, *config, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type createClusterOptions struct {
|
type createClusterOptions struct {
|
||||||
configAccess ConfigAccess
|
configAccess clientcmd.ConfigAccess
|
||||||
name string
|
name string
|
||||||
server util.StringFlag
|
server util.StringFlag
|
||||||
apiVersion util.StringFlag
|
apiVersion util.StringFlag
|
||||||
|
@ -54,7 +54,7 @@ kubectl config set-cluster e2e --certificate-authority=~/.kube/e2e/kubernetes.ca
|
||||||
kubectl config set-cluster e2e --insecure-skip-tls-verify=true`
|
kubectl config set-cluster e2e --insecure-skip-tls-verify=true`
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdConfigSetCluster(out io.Writer, configAccess ConfigAccess) *cobra.Command {
|
func NewCmdConfigSetCluster(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||||
options := &createClusterOptions{configAccess: configAccess}
|
options := &createClusterOptions{configAccess: configAccess}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -108,7 +108,7 @@ func (o createClusterOptions) run() error {
|
||||||
cluster := o.modifyCluster(*startingStanza)
|
cluster := o.modifyCluster(*startingStanza)
|
||||||
config.Clusters[o.name] = &cluster
|
config.Clusters[o.name] = &cluster
|
||||||
|
|
||||||
if err := ModifyConfig(o.configAccess, *config, true); err != nil {
|
if err := clientcmd.ModifyConfig(o.configAccess, *config, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type createContextOptions struct {
|
type createContextOptions struct {
|
||||||
configAccess ConfigAccess
|
configAccess clientcmd.ConfigAccess
|
||||||
name string
|
name string
|
||||||
cluster util.StringFlag
|
cluster util.StringFlag
|
||||||
authInfo util.StringFlag
|
authInfo util.StringFlag
|
||||||
|
@ -43,7 +43,7 @@ Specifying a name that already exists will merge new fields on top of existing v
|
||||||
kubectl config set-context gce --user=cluster-admin`
|
kubectl config set-context gce --user=cluster-admin`
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdConfigSetContext(out io.Writer, configAccess ConfigAccess) *cobra.Command {
|
func NewCmdConfigSetContext(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||||
options := &createContextOptions{configAccess: configAccess}
|
options := &createContextOptions{configAccess: configAccess}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -90,7 +90,7 @@ func (o createContextOptions) run() error {
|
||||||
context := o.modifyContext(*startingStanza)
|
context := o.modifyContext(*startingStanza)
|
||||||
config.Contexts[o.name] = &context
|
config.Contexts[o.name] = &context
|
||||||
|
|
||||||
if err := ModifyConfig(o.configAccess, *config, true); err != nil {
|
if err := clientcmd.ModifyConfig(o.configAccess, *config, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,13 +19,15 @@ package config
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CurrentContextOptions struct {
|
type CurrentContextOptions struct {
|
||||||
ConfigAccess ConfigAccess
|
ConfigAccess clientcmd.ConfigAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -34,7 +36,7 @@ const (
|
||||||
kubectl config current-context`
|
kubectl config current-context`
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdConfigCurrentContext(out io.Writer, configAccess ConfigAccess) *cobra.Command {
|
func NewCmdConfigCurrentContext(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||||
options := &CurrentContextOptions{ConfigAccess: configAccess}
|
options := &CurrentContextOptions{ConfigAccess: configAccess}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
|
|
@ -64,7 +64,7 @@ func (test currentContextTest) run(t *testing.T) {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pathOptions := NewDefaultPathOptions()
|
pathOptions := clientcmd.NewDefaultPathOptions()
|
||||||
pathOptions.GlobalFile = fakeKubeFile.Name()
|
pathOptions.GlobalFile = fakeKubeFile.Name()
|
||||||
pathOptions.EnvVar = ""
|
pathOptions.EnvVar = ""
|
||||||
options := CurrentContextOptions{
|
options := CurrentContextOptions{
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/util/flag"
|
"k8s.io/kubernetes/pkg/util/flag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type setOptions struct {
|
type setOptions struct {
|
||||||
configAccess ConfigAccess
|
configAccess clientcmd.ConfigAccess
|
||||||
propertyName string
|
propertyName string
|
||||||
propertyValue string
|
propertyValue string
|
||||||
setRawBytes flag.Tristate
|
setRawBytes flag.Tristate
|
||||||
|
@ -45,7 +46,7 @@ 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_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. Binary fields such as 'certificate-authority-data' expect a base64 encoded string unless the --set-raw-bytes flag is used.`
|
PROPERTY_VALUE is the new value you wish to set. Binary fields such as 'certificate-authority-data' expect a base64 encoded string unless the --set-raw-bytes flag is used.`
|
||||||
|
|
||||||
func NewCmdConfigSet(out io.Writer, configAccess ConfigAccess) *cobra.Command {
|
func NewCmdConfigSet(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||||
options := &setOptions{configAccess: configAccess}
|
options := &setOptions{configAccess: configAccess}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -96,7 +97,7 @@ func (o setOptions) run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ModifyConfig(o.configAccess, *config, false); err != nil {
|
if err := clientcmd.ModifyConfig(o.configAccess, *config, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,17 +23,19 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
type unsetOptions struct {
|
type unsetOptions struct {
|
||||||
configAccess ConfigAccess
|
configAccess clientcmd.ConfigAccess
|
||||||
propertyName string
|
propertyName string
|
||||||
}
|
}
|
||||||
|
|
||||||
const unset_long = `Unsets an individual value in a kubeconfig file
|
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.`
|
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, configAccess ConfigAccess) *cobra.Command {
|
func NewCmdConfigUnset(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||||
options := &unsetOptions{configAccess: configAccess}
|
options := &unsetOptions{configAccess: configAccess}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -77,7 +79,7 @@ func (o unsetOptions) run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ModifyConfig(o.configAccess, *config, false); err != nil {
|
if err := clientcmd.ModifyConfig(o.configAccess, *config, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,15 +23,16 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type useContextOptions struct {
|
type useContextOptions struct {
|
||||||
configAccess ConfigAccess
|
configAccess clientcmd.ConfigAccess
|
||||||
contextName string
|
contextName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCmdConfigUseContext(out io.Writer, configAccess ConfigAccess) *cobra.Command {
|
func NewCmdConfigUseContext(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||||
options := &useContextOptions{configAccess: configAccess}
|
options := &useContextOptions{configAccess: configAccess}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -68,7 +69,7 @@ func (o useContextOptions) run() error {
|
||||||
|
|
||||||
config.CurrentContext = o.contextName
|
config.CurrentContext = o.contextName
|
||||||
|
|
||||||
if err := ModifyConfig(o.configAccess, *config, true); err != nil {
|
if err := clientcmd.ModifyConfig(o.configAccess, *config, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type ViewOptions struct {
|
type ViewOptions struct {
|
||||||
ConfigAccess ConfigAccess
|
ConfigAccess clientcmd.ConfigAccess
|
||||||
Merge flag.Tristate
|
Merge flag.Tristate
|
||||||
Flatten bool
|
Flatten bool
|
||||||
Minify bool
|
Minify bool
|
||||||
|
@ -50,7 +50,7 @@ kubectl config view
|
||||||
kubectl config view -o jsonpath='{.users[?(@.name == "e2e")].user.password}'`
|
kubectl config view -o jsonpath='{.users[?(@.name == "e2e")].user.password}'`
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdConfigView(out io.Writer, ConfigAccess ConfigAccess) *cobra.Command {
|
func NewCmdConfigView(out io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||||
options := &ViewOptions{ConfigAccess: ConfigAccess}
|
options := &ViewOptions{ConfigAccess: ConfigAccess}
|
||||||
// Default to yaml
|
// Default to yaml
|
||||||
defaultOutputFormat := "yaml"
|
defaultOutputFormat := "yaml"
|
||||||
|
|
Loading…
Reference in New Issue