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") }
// 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") }
// ChangeUser changes the user used by the current CLI session. func (c *CLI) ChangeUser(name string) *CLI { adminClientConfig, err := testutil.GetClusterAdminClientConfig(c.adminConfigPath) if err != nil { FatalErr(err) } _, _, clientConfig, err := testutil.GetClientForUser(*adminClientConfig, name) if err != nil { FatalErr(err) } kubeConfig, err := config.CreateConfig(c.Namespace(), clientConfig) if err != nil { FatalErr(err) } c.configPath = filepath.Join(c.outputDir, name+".kubeconfig") err = clientcmd.WriteToFile(*kubeConfig, c.configPath) if err != nil { FatalErr(err) } c.username = name e2e.Logf("configPath is now %q", c.configPath) return c }
func (test currentContextTest) run(t *testing.T) { fakeKubeFile, _ := ioutil.TempFile("", "") defer os.Remove(fakeKubeFile.Name()) err := clientcmd.WriteToFile(test.startingConfig, fakeKubeFile.Name()) if err != nil { t.Fatalf("unexpected error: %v", err) } pathOptions := NewDefaultPathOptions() pathOptions.GlobalFile = fakeKubeFile.Name() pathOptions.EnvVar = "" options := CurrentContextOptions{ ConfigAccess: pathOptions, } buf := bytes.NewBuffer([]byte{}) err = RunCurrentContext(buf, []string{}, &options) if len(test.expectedError) != 0 { if err == nil { t.Errorf("Did not get %v", test.expectedError) } else { if !strings.Contains(err.Error(), test.expectedError) { t.Errorf("Expected %v, but got %v", test.expectedError, err) } } return } if err != nil { t.Errorf("Unexpected error: %v", err) } }
func (test getContextsTest) run(t *testing.T) { fakeKubeFile, _ := ioutil.TempFile("", "") defer os.Remove(fakeKubeFile.Name()) err := clientcmd.WriteToFile(test.startingConfig, fakeKubeFile.Name()) if err != nil { t.Fatalf("unexpected error: %v", err) } pathOptions := clientcmd.NewDefaultPathOptions() pathOptions.GlobalFile = fakeKubeFile.Name() pathOptions.EnvVar = "" buf := bytes.NewBuffer([]byte{}) options := GetContextsOptions{ configAccess: pathOptions, } cmd := NewCmdConfigGetContexts(buf, options.configAccess) if test.nameOnly { cmd.Flags().Set("output", "name") } if test.noHeader { cmd.Flags().Set("no-headers", "true") } cmd.Run(cmd, test.names) if len(test.expectedOut) != 0 { if buf.String() != test.expectedOut { t.Errorf("Expected %v, but got %v", test.expectedOut, buf.String()) } return } if err != nil { t.Errorf("Unexpected error: %v", err) } }
func writeClientConfigToKubeConfig(config kclient.Config, path string) error { kubeConfig := &clientcmdapi.Config{ Clusters: map[string]*clientcmdapi.Cluster{"myserver": {Server: config.Host, CertificateAuthority: config.CAFile, CertificateAuthorityData: config.CAData}}, AuthInfos: map[string]*clientcmdapi.AuthInfo{"myuser": {Token: config.BearerToken}}, Contexts: map[string]*clientcmdapi.Context{"mycontext": {Cluster: "myserver", AuthInfo: "myuser"}}, CurrentContext: "mycontext", } if err := os.MkdirAll(filepath.Dir(path), os.FileMode(0755)); err != nil { return err } if err := clientcmd.WriteToFile(*kubeConfig, path); err != nil { return err } return nil }
func WriteKubeconfigToDisk(filepath string, kubeconfig *clientcmdapi.Config) error { // Make sure the dir exists or can be created if err := os.MkdirAll(path.Dir(filepath), KubernetesDirPermissions); err != nil { return fmt.Errorf("failed to create directory %q [%v]", path.Dir(filepath), err) } // If err == nil, the file exists. Oops, we don't allow the file to exist already, fail. if _, err := os.Stat(filepath); err == nil { return fmt.Errorf("kubeconfig file %s already exists, but must not exist.", filepath) } if err := clientcmd.WriteToFile(*kubeconfig, filepath); err != nil { return fmt.Errorf("failed to write to %q [%v]", filepath, err) } fmt.Printf("[kubeconfig] Wrote KubeConfig file to disk: %q\n", filepath) return nil }
func WriteKubeconfigIfNotExists(name string, kubeconfig *clientcmdapi.Config) error { if err := os.MkdirAll(kubeadmapi.GlobalEnvParams.KubernetesDir, 0700); err != nil { return fmt.Errorf("failed to create directory %q [%v]", kubeadmapi.GlobalEnvParams.KubernetesDir, err) } filename := path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, fmt.Sprintf("%s.conf", name)) // Create and open the file, only if it does not already exist. f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0600) if err != nil { return fmt.Errorf("failed to create %q, it already exists [%v]", filename, err) } f.Close() if err := clientcmd.WriteToFile(*kubeconfig, filename); err != nil { return fmt.Errorf("failed to write to %q [%v]", filename, err) } fmt.Printf("[kubeconfig] Wrote KubeConfig file to disk: %q\n", filename) return nil }
func WriteKubeconfigIfNotExists(name string, kubeconfig *clientcmdapi.Config) error { envParams := kubeadmapi.GetEnvParams() if err := os.MkdirAll(envParams["kubernetes_dir"], 0700); err != nil { return fmt.Errorf("<util/kubeconfig> failed to create directory %q [%v]", envParams["kubernetes_dir"], err) } filename := path.Join(envParams["kubernetes_dir"], fmt.Sprintf("%s.conf", name)) // Create and open the file, only if it does not already exist. f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0600) if err != nil { return fmt.Errorf("<util/kubeconfig> failed to create %q, it already exists [%v]", filename, err) } f.Close() if err := clientcmd.WriteToFile(*kubeconfig, filename); err != nil { return fmt.Errorf("<util/kubeconfig> failed to write to %q [%v]", filename, err) } fmt.Printf("<util/kubeconfig> created %q\n", filename) return nil }
func (test deleteContextTest) run(t *testing.T) { fakeKubeFile, _ := ioutil.TempFile("", "") defer os.Remove(fakeKubeFile.Name()) err := clientcmd.WriteToFile(test.config, fakeKubeFile.Name()) if err != nil { t.Fatalf("unexpected error: %v", err) } pathOptions := clientcmd.NewDefaultPathOptions() pathOptions.GlobalFile = fakeKubeFile.Name() pathOptions.EnvVar = "" buf := bytes.NewBuffer([]byte{}) cmd := NewCmdConfigDeleteContext(buf, pathOptions) cmd.SetArgs([]string{test.contextToDelete}) if err := cmd.Execute(); err != nil { t.Fatalf("unexpected error executing command: %v", err) } expectedOutWithFile := fmt.Sprintf(test.expectedOut, fakeKubeFile.Name()) if expectedOutWithFile != buf.String() { t.Errorf("expected output %s, but got %s", expectedOutWithFile, buf.String()) return } // Verify context was removed from kubeconfig file config, err := clientcmd.LoadFromFile(fakeKubeFile.Name()) if err != nil { t.Fatalf("unexpected error loading kubeconfig file: %v", err) } contexts := make([]string, 0, len(config.Contexts)) for k := range config.Contexts { contexts = append(contexts, k) } if !reflect.DeepEqual(test.expectedContexts, contexts) { t.Errorf("expected contexts %v, but found %v in kubeconfig", test.expectedContexts, contexts) } }
func testConfigCommand(args []string, startingConfig clientcmdapi.Config, t *testing.T) (string, clientcmdapi.Config) { fakeKubeFile, _ := ioutil.TempFile("", "") defer os.Remove(fakeKubeFile.Name()) err := clientcmd.WriteToFile(startingConfig, fakeKubeFile.Name()) if err != nil { t.Fatalf("unexpected error: %v", err) } argsToUse := make([]string, 0, 2+len(args)) argsToUse = append(argsToUse, "--kubeconfig="+fakeKubeFile.Name()) argsToUse = append(argsToUse, args...) buf := bytes.NewBuffer([]byte{}) cmd := NewCmdConfig(clientcmd.NewDefaultPathOptions(), buf, buf) cmd.SetArgs(argsToUse) cmd.Execute() // outBytes, _ := ioutil.ReadFile(fakeKubeFile.Name()) config := clientcmd.GetConfigFromFileOrDie(fakeKubeFile.Name()) return buf.String(), *config }
func (test getClustersTest) run(t *testing.T) { fakeKubeFile, _ := ioutil.TempFile("", "") defer os.Remove(fakeKubeFile.Name()) err := clientcmd.WriteToFile(test.config, fakeKubeFile.Name()) if err != nil { t.Fatalf("unexpected error: %v", err) } pathOptions := clientcmd.NewDefaultPathOptions() pathOptions.GlobalFile = fakeKubeFile.Name() pathOptions.EnvVar = "" buf := bytes.NewBuffer([]byte{}) cmd := NewCmdConfigGetClusters(buf, pathOptions) if err := cmd.Execute(); err != nil { t.Fatalf("unexpected error executing command: %v", err) } if len(test.expected) != 0 { if buf.String() != test.expected { t.Errorf("expected %v, but got %v", test.expected, buf.String()) } return } }
// 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 }
// bootstrapClientCert requests a client cert for kubelet if the kubeconfigPath file does not exist. // The kubeconfig at bootstrapPath is used to request a client certificate from the API server. // On success, a kubeconfig file referencing the generated key and obtained certificate is written to kubeconfigPath. // The certificate and key file are stored in certDir. func bootstrapClientCert(kubeconfigPath string, bootstrapPath string, certDir string, nodeName types.NodeName) error { // Short-circuit if the kubeconfig file already exists. // TODO: inspect the kubeconfig, ensure a rest client can be built from it, verify client cert expiration, etc. _, err := os.Stat(kubeconfigPath) if err == nil { glog.V(2).Infof("Kubeconfig %s exists, skipping bootstrap", kubeconfigPath) return nil } if !os.IsNotExist(err) { glog.Errorf("Error reading kubeconfig %s, skipping bootstrap: %v", kubeconfigPath, err) return err } glog.V(2).Info("Using bootstrap kubeconfig to generate TLS client cert, key and kubeconfig file") bootstrapClientConfig, err := loadRESTClientConfig(bootstrapPath) if err != nil { return fmt.Errorf("unable to load bootstrap kubeconfig: %v", err) } bootstrapClient, err := unversionedcertificates.NewForConfig(bootstrapClientConfig) if err != nil { return fmt.Errorf("unable to create certificates signing request client: %v", err) } success := false // Get the private key. keyPath, err := filepath.Abs(filepath.Join(certDir, defaultKubeletClientKeyFile)) if err != nil { return fmt.Errorf("unable to build bootstrap key path: %v", err) } keyData, generatedKeyFile, err := loadOrGenerateKeyFile(keyPath) if err != nil { return err } if generatedKeyFile { defer func() { if !success { if err := os.Remove(keyPath); err != nil { glog.Warningf("Cannot clean up the key file %q: %v", keyPath, err) } } }() } // Get the cert. certPath, err := filepath.Abs(filepath.Join(certDir, defaultKubeletClientCertificateFile)) if err != nil { return fmt.Errorf("unable to build bootstrap client cert path: %v", err) } certData, err := csr.RequestNodeCertificate(bootstrapClient.CertificateSigningRequests(), keyData, nodeName) if err != nil { return err } if err := certutil.WriteCert(certPath, certData); err != nil { return err } defer func() { if !success { if err := os.Remove(certPath); err != nil { glog.Warningf("Cannot clean up the cert file %q: %v", certPath, err) } } }() // Get the CA data from the bootstrap client config. caFile, caData := bootstrapClientConfig.CAFile, []byte{} if len(caFile) == 0 { caData = bootstrapClientConfig.CAData } // Build resulting kubeconfig. kubeconfigData := clientcmdapi.Config{ // Define a cluster stanza based on the bootstrap kubeconfig. Clusters: map[string]*clientcmdapi.Cluster{"default-cluster": { Server: bootstrapClientConfig.Host, InsecureSkipTLSVerify: bootstrapClientConfig.Insecure, CertificateAuthority: caFile, CertificateAuthorityData: caData, }}, // Define auth based on the obtained client cert. AuthInfos: map[string]*clientcmdapi.AuthInfo{"default-auth": { ClientCertificate: certPath, ClientKey: keyPath, }}, // Define a context that connects the auth info and cluster, and set it as the default Contexts: map[string]*clientcmdapi.Context{"default-context": { Cluster: "default-cluster", AuthInfo: "default-auth", Namespace: "default", }}, CurrentContext: "default-context", } // Marshal to disk if err := clientcmd.WriteToFile(kubeconfigData, kubeconfigPath); err != nil { return err } success = true return nil }
func FakeKubeconfigFiles() ([]string, error) { kubeconfigs := []clientcmdapi.Config{ { Clusters: map[string]*clientcmdapi.Cluster{ "syndicate": { Server: "https://10.20.30.40", }, }, AuthInfos: map[string]*clientcmdapi.AuthInfo{ "syndicate": { Token: "badge", }, }, Contexts: map[string]*clientcmdapi.Context{ "syndicate": { Cluster: "syndicate", AuthInfo: "syndicate", }, }, CurrentContext: "syndicate", }, { Clusters: map[string]*clientcmdapi.Cluster{ "ally": { Server: "ally256.example.com:80", }, }, AuthInfos: map[string]*clientcmdapi.AuthInfo{ "ally": { Token: "souvenir", }, }, Contexts: map[string]*clientcmdapi.Context{ "ally": { Cluster: "ally", AuthInfo: "ally", }, }, CurrentContext: "ally", }, { Clusters: map[string]*clientcmdapi.Cluster{ "ally": { Server: "https://ally64.example.com", }, "confederate": { Server: "10.8.8.8", }, }, AuthInfos: map[string]*clientcmdapi.AuthInfo{ "ally": { Token: "souvenir", }, "confederate": { Token: "totem", }, }, Contexts: map[string]*clientcmdapi.Context{ "ally": { Cluster: "ally", AuthInfo: "ally", }, "confederate": { Cluster: "confederate", AuthInfo: "confederate", }, }, CurrentContext: "confederate", }, } kubefiles := []string{} for _, cfg := range kubeconfigs { fakeKubeFile, _ := ioutil.TempFile("", "") err := clientcmd.WriteToFile(cfg, fakeKubeFile.Name()) if err != nil { return nil, err } kubefiles = append(kubefiles, fakeKubeFile.Name()) } return kubefiles, nil }
func (o CreateKubeConfigOptions) CreateKubeConfig() (*clientcmdapi.Config, error) { glog.V(4).Infof("creating a .kubeconfig with: %#v", o) // read all the referenced filenames caData, err := readFiles(o.APIServerCAFiles, []byte("\n")) if err != nil { return nil, err } certData, err := ioutil.ReadFile(o.CertFile) if err != nil { return nil, err } keyData, err := ioutil.ReadFile(o.KeyFile) if err != nil { return nil, err } certConfig, err := crypto.GetTLSCertificateConfig(o.CertFile, o.KeyFile) if err != nil { return nil, err } // determine all the nicknames clusterNick, err := cliconfig.GetClusterNicknameFromURL(o.APIServerURL) if err != nil { return nil, err } userNick, err := cliconfig.GetUserNicknameFromCert(clusterNick, certConfig.Certs...) if err != nil { return nil, err } contextNick := cliconfig.GetContextNickname(o.ContextNamespace, clusterNick, userNick) credentials := make(map[string]*clientcmdapi.AuthInfo) credentials[userNick] = &clientcmdapi.AuthInfo{ ClientCertificateData: certData, ClientKeyData: keyData, } clusters := make(map[string]*clientcmdapi.Cluster) clusters[clusterNick] = &clientcmdapi.Cluster{ Server: o.APIServerURL, CertificateAuthorityData: caData, } contexts := make(map[string]*clientcmdapi.Context) contexts[contextNick] = &clientcmdapi.Context{Cluster: clusterNick, AuthInfo: userNick, Namespace: o.ContextNamespace} createPublic := (len(o.PublicAPIServerURL) > 0) && o.APIServerURL != o.PublicAPIServerURL if createPublic { publicClusterNick, err := cliconfig.GetClusterNicknameFromURL(o.PublicAPIServerURL) if err != nil { return nil, err } publicContextNick := cliconfig.GetContextNickname(o.ContextNamespace, publicClusterNick, userNick) clusters[publicClusterNick] = &clientcmdapi.Cluster{ Server: o.PublicAPIServerURL, CertificateAuthorityData: caData, } contexts[publicContextNick] = &clientcmdapi.Context{Cluster: publicClusterNick, AuthInfo: userNick, Namespace: o.ContextNamespace} } kubeConfig := &clientcmdapi.Config{ Clusters: clusters, AuthInfos: credentials, Contexts: contexts, CurrentContext: contextNick, } glog.V(3).Infof("Generating '%s' API client config as %s\n", userNick, o.KubeConfigFile) // Ensure the parent dir exists if err := os.MkdirAll(filepath.Dir(o.KubeConfigFile), os.FileMode(0755)); err != nil { return nil, err } if err := clientcmd.WriteToFile(*kubeConfig, o.KubeConfigFile); err != nil { return nil, err } return kubeConfig, nil }