Merge pull request #1160 from r2d4/kubeconfig-tests
Add test coverage for SetupKubeConfigpull/1169/head
commit
b78fb926bc
|
@ -29,7 +29,7 @@ import (
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
cfg "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
|
||||||
cmdUtil "k8s.io/minikube/cmd/util"
|
cmdUtil "k8s.io/minikube/cmd/util"
|
||||||
"k8s.io/minikube/pkg/minikube/cluster"
|
"k8s.io/minikube/pkg/minikube/cluster"
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
|
@ -161,18 +161,31 @@ func runStart(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
fmt.Println("Setting up kubeconfig...")
|
fmt.Println("Setting up kubeconfig...")
|
||||||
// setup kubeconfig
|
// setup kubeconfig
|
||||||
keepContext := viper.GetBool(keepContext)
|
|
||||||
name := constants.MinikubeContext
|
kubeConfigEnv := os.Getenv(constants.KubeconfigEnvVar)
|
||||||
certAuth := constants.MakeMiniPath("ca.crt")
|
var kubeConfigFile string
|
||||||
clientCert := constants.MakeMiniPath("apiserver.crt")
|
if kubeConfigEnv == "" {
|
||||||
clientKey := constants.MakeMiniPath("apiserver.key")
|
kubeConfigFile = constants.KubeconfigPath
|
||||||
if err := setupKubeconfig(name, kubeHost, certAuth, clientCert, clientKey, keepContext); err != nil {
|
} else {
|
||||||
|
kubeConfigFile = filepath.SplitList(kubeConfigEnv)[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
kubeCfgSetup := &kubeconfig.KubeConfigSetup{
|
||||||
|
ClusterName: constants.MinikubeContext,
|
||||||
|
ClusterServerAddress: kubeHost,
|
||||||
|
ClientCertificate: constants.MakeMiniPath("apiserver.crt"),
|
||||||
|
ClientKey: constants.MakeMiniPath("apiserver.key"),
|
||||||
|
CertificateAuthority: constants.MakeMiniPath("ca.crt"),
|
||||||
|
KeepContext: viper.GetBool(keepContext),
|
||||||
|
KubeConfigFile: kubeConfigFile,
|
||||||
|
}
|
||||||
|
if err := kubeconfig.SetupKubeConfig(kubeCfgSetup); err != nil {
|
||||||
glog.Errorln("Error setting up kubeconfig: ", err)
|
glog.Errorln("Error setting up kubeconfig: ", err)
|
||||||
cmdUtil.MaybeReportErrorAndExit(err)
|
cmdUtil.MaybeReportErrorAndExit(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if keepContext {
|
if kubeCfgSetup.KeepContext {
|
||||||
fmt.Printf("The local Kubernetes cluster has started. The kubectl context has not been altered, kubectl will require \"--context=%s\" to use the local Kubernetes cluster.\n", name)
|
fmt.Printf("The local Kubernetes cluster has started. The kubectl context has not been altered, kubectl will require \"--context=%s\" to use the local Kubernetes cluster.\n", kubeCfgSetup.ClusterName)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Kubectl is now configured to use the cluster.")
|
fmt.Println("Kubectl is now configured to use the cluster.")
|
||||||
}
|
}
|
||||||
|
@ -186,59 +199,6 @@ func calculateDiskSizeInMB(humanReadableDiskSize string) int {
|
||||||
return int(diskSize / units.MB)
|
return int(diskSize / units.MB)
|
||||||
}
|
}
|
||||||
|
|
||||||
// setupKubeconfig reads config from disk, adds the minikube settings, and writes it back.
|
|
||||||
// activeContext is true when minikube is the CurrentContext
|
|
||||||
// If no CurrentContext is set, the given name will be used.
|
|
||||||
func setupKubeconfig(name, server, certAuth, cliCert, cliKey string, keepContext bool) error {
|
|
||||||
|
|
||||||
configEnv := os.Getenv(constants.KubeconfigEnvVar)
|
|
||||||
var configFile string
|
|
||||||
if configEnv == "" {
|
|
||||||
configFile = constants.KubeconfigPath
|
|
||||||
} else {
|
|
||||||
configFile = filepath.SplitList(configEnv)[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.Infoln("Using kubeconfig: ", configFile)
|
|
||||||
|
|
||||||
// read existing config or create new if does not exist
|
|
||||||
config, err := kubeconfig.ReadConfigOrNew(configFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
clusterName := name
|
|
||||||
cluster := cfg.NewCluster()
|
|
||||||
cluster.Server = server
|
|
||||||
cluster.CertificateAuthority = certAuth
|
|
||||||
config.Clusters[clusterName] = cluster
|
|
||||||
|
|
||||||
// user
|
|
||||||
userName := name
|
|
||||||
user := cfg.NewAuthInfo()
|
|
||||||
user.ClientCertificate = cliCert
|
|
||||||
user.ClientKey = cliKey
|
|
||||||
config.AuthInfos[userName] = user
|
|
||||||
|
|
||||||
// context
|
|
||||||
contextName := name
|
|
||||||
context := cfg.NewContext()
|
|
||||||
context.Cluster = clusterName
|
|
||||||
context.AuthInfo = userName
|
|
||||||
config.Contexts[contextName] = context
|
|
||||||
|
|
||||||
// Only set current context to minikube if the user has not used the keepContext flag
|
|
||||||
if !keepContext {
|
|
||||||
config.CurrentContext = contextName
|
|
||||||
}
|
|
||||||
|
|
||||||
// write back to disk
|
|
||||||
if err := kubeconfig.WriteConfig(config, configFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
startCmd.Flags().Bool(keepContext, constants.DefaultKeepContext, "This will keep the existing kubectl context and will create a minikube context.")
|
startCmd.Flags().Bool(keepContext, constants.DefaultKeepContext, "This will keep the existing kubectl context and will create a minikube context.")
|
||||||
startCmd.Flags().String(isoURL, constants.DefaultIsoUrl, "Location of the minikube iso")
|
startCmd.Flags().String(isoURL, constants.DefaultIsoUrl, "Location of the minikube iso")
|
||||||
|
|
|
@ -28,6 +28,73 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type KubeConfigSetup struct {
|
||||||
|
// The name of the cluster for this context
|
||||||
|
ClusterName string
|
||||||
|
|
||||||
|
// ClusterServerAddress is the address of of the kubernetes cluster
|
||||||
|
ClusterServerAddress string
|
||||||
|
|
||||||
|
// ClientCertificate is the path to a client cert file for TLS.
|
||||||
|
ClientCertificate string
|
||||||
|
|
||||||
|
// CertificateAuthority is the path to a cert file for the certificate authority.
|
||||||
|
CertificateAuthority string
|
||||||
|
|
||||||
|
// ClientKey is the path to a client key file for TLS.
|
||||||
|
ClientKey string
|
||||||
|
|
||||||
|
// Should the current context be kept when setting up this one
|
||||||
|
KeepContext bool
|
||||||
|
|
||||||
|
// KubeConfigFile is the path where the kube config is stored
|
||||||
|
KubeConfigFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupKubeconfig reads config from disk, adds the minikube settings, and writes it back.
|
||||||
|
// activeContext is true when minikube is the CurrentContext
|
||||||
|
// If no CurrentContext is set, the given name will be used.
|
||||||
|
func SetupKubeConfig(cfg *KubeConfigSetup) error {
|
||||||
|
glog.Infoln("Using kubeconfig: ", cfg.KubeConfigFile)
|
||||||
|
|
||||||
|
// read existing config or create new if does not exist
|
||||||
|
config, err := ReadConfigOrNew(cfg.KubeConfigFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
clusterName := cfg.ClusterName
|
||||||
|
cluster := api.NewCluster()
|
||||||
|
cluster.Server = cfg.ClusterServerAddress
|
||||||
|
cluster.CertificateAuthority = cfg.CertificateAuthority
|
||||||
|
config.Clusters[clusterName] = cluster
|
||||||
|
|
||||||
|
// user
|
||||||
|
userName := cfg.ClusterName
|
||||||
|
user := api.NewAuthInfo()
|
||||||
|
user.ClientCertificate = cfg.ClientCertificate
|
||||||
|
user.ClientKey = cfg.ClientKey
|
||||||
|
config.AuthInfos[userName] = user
|
||||||
|
|
||||||
|
// context
|
||||||
|
contextName := cfg.ClusterName
|
||||||
|
context := api.NewContext()
|
||||||
|
context.Cluster = cfg.ClusterName
|
||||||
|
context.AuthInfo = userName
|
||||||
|
config.Contexts[contextName] = context
|
||||||
|
|
||||||
|
// Only set current context to minikube if the user has not used the keepContext flag
|
||||||
|
if !cfg.KeepContext {
|
||||||
|
config.CurrentContext = contextName
|
||||||
|
}
|
||||||
|
|
||||||
|
// write back to disk
|
||||||
|
if err := WriteConfig(config, cfg.KubeConfigFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ReadConfigOrNew retrieves Kubernetes client configuration from a file.
|
// ReadConfigOrNew retrieves Kubernetes client configuration from a file.
|
||||||
// If no files exists, an empty configuration is returned.
|
// If no files exists, an empty configuration is returned.
|
||||||
func ReadConfigOrNew(filename string) (*api.Config, error) {
|
func ReadConfigOrNew(filename string) (*api.Config, error) {
|
||||||
|
|
|
@ -27,6 +27,107 @@ import (
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var fakeKubeCfg = []byte(`
|
||||||
|
apiVersion: v1
|
||||||
|
clusters:
|
||||||
|
- cluster:
|
||||||
|
certificate-authority: /home/la-croix/apiserver.crt
|
||||||
|
server: 192.168.1.1:8080
|
||||||
|
name: la-croix
|
||||||
|
contexts:
|
||||||
|
- context:
|
||||||
|
cluster: la-croix
|
||||||
|
user: la-croix
|
||||||
|
name: la-croix
|
||||||
|
current-context: la-croix
|
||||||
|
kind: Config
|
||||||
|
preferences: {}
|
||||||
|
users:
|
||||||
|
- name: la-croix
|
||||||
|
user:
|
||||||
|
client-certificate: /home/la-croix/apiserver.crt
|
||||||
|
client-key: /home/la-croix/apiserver.key
|
||||||
|
`)
|
||||||
|
|
||||||
|
func TestSetupKubeConfig(t *testing.T) {
|
||||||
|
setupCfg := &KubeConfigSetup{
|
||||||
|
ClusterName: "test",
|
||||||
|
ClusterServerAddress: "192.168.1.1:8080",
|
||||||
|
ClientCertificate: "/home/apiserver.crt",
|
||||||
|
ClientKey: "/home/apiserver.key",
|
||||||
|
CertificateAuthority: "/home/apiserver.crt",
|
||||||
|
KeepContext: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
description string
|
||||||
|
cfg *KubeConfigSetup
|
||||||
|
existingCfg []byte
|
||||||
|
expected api.Config
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "new kube config",
|
||||||
|
cfg: setupCfg,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "add to kube config",
|
||||||
|
cfg: setupCfg,
|
||||||
|
existingCfg: fakeKubeCfg,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "use config env var",
|
||||||
|
cfg: setupCfg,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "keep context",
|
||||||
|
cfg: &KubeConfigSetup{
|
||||||
|
ClusterName: "test",
|
||||||
|
ClusterServerAddress: "192.168.1.1:8080",
|
||||||
|
ClientCertificate: "/home/apiserver.crt",
|
||||||
|
ClientKey: "/home/apiserver.key",
|
||||||
|
CertificateAuthority: "/home/apiserver.crt",
|
||||||
|
KeepContext: true,
|
||||||
|
},
|
||||||
|
existingCfg: fakeKubeCfg,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.description, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
tmpDir, err := ioutil.TempDir("", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error making temp directory %s", err)
|
||||||
|
}
|
||||||
|
test.cfg.KubeConfigFile = filepath.Join(tmpDir, "kubeconfig")
|
||||||
|
if len(test.existingCfg) != 0 {
|
||||||
|
ioutil.WriteFile(test.cfg.KubeConfigFile, test.existingCfg, 0600)
|
||||||
|
}
|
||||||
|
err = SetupKubeConfig(test.cfg)
|
||||||
|
if err != nil && !test.err {
|
||||||
|
t.Errorf("Got unexpected error: %s", err)
|
||||||
|
}
|
||||||
|
if err == nil && test.err {
|
||||||
|
t.Errorf("Expected error but got none")
|
||||||
|
}
|
||||||
|
config, err := ReadConfigOrNew(test.cfg.KubeConfigFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error reading kubeconfig file: %s", err)
|
||||||
|
}
|
||||||
|
if test.cfg.KeepContext && config.CurrentContext == test.cfg.ClusterName {
|
||||||
|
t.Errorf("Context was changed even though KeepContext was true")
|
||||||
|
}
|
||||||
|
if !test.cfg.KeepContext && config.CurrentContext != test.cfg.ClusterName {
|
||||||
|
t.Errorf("Context was not switched")
|
||||||
|
}
|
||||||
|
|
||||||
|
os.RemoveAll(tmpDir)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestEmptyConfig(t *testing.T) {
|
func TestEmptyConfig(t *testing.T) {
|
||||||
tmp := tempFile(t, []byte{})
|
tmp := tempFile(t, []byte{})
|
||||||
defer os.Remove(tmp)
|
defer os.Remove(tmp)
|
||||||
|
|
Loading…
Reference in New Issue