Beispiel #1
0
func runDeleteContext(out io.Writer, configAccess clientcmd.ConfigAccess, cmd *cobra.Command) error {
	config, err := configAccess.GetStartingConfig()
	if err != nil {
		return err
	}

	args := cmd.Flags().Args()
	if len(args) != 1 {
		cmd.Help()
		return nil
	}

	configFile := configAccess.GetDefaultFilename()
	if configAccess.IsExplicitFile() {
		configFile = configAccess.GetExplicitFile()
	}

	name := args[0]
	_, ok := config.Contexts[name]
	if !ok {
		return fmt.Errorf("cannot delete context %s, not in %s", name, configFile)
	}

	delete(config.Contexts, name)

	if err := clientcmd.ModifyConfig(configAccess, *config, true); err != nil {
		return err
	}

	fmt.Fprintf(out, "deleted context %s from %s", name, configFile)

	return nil
}
Beispiel #2
0
func (o LogoutOptions) RunLogout() error {
	token := o.Config.BearerToken

	client, err := client.New(o.Config)
	if err != nil {
		return err
	}

	userInfo, err := whoAmI(client)
	if err != nil {
		return err
	}

	if err := client.OAuthAccessTokens().Delete(token); err != nil {
		return err
	}

	newConfig := *o.StartingKubeConfig

	for key, value := range newConfig.AuthInfos {
		if value.Token == token {
			value.Token = ""
			newConfig.AuthInfos[key] = value
			// don't break, its possible that more than one user stanza has the same token.
		}
	}

	if err := kclientcmd.ModifyConfig(o.PathOptions, newConfig, true); err != nil {
		return err
	}

	fmt.Fprintf(o.Out, "Logged %q out on %q\n", userInfo.Name, o.Config.Host)

	return nil
}
func (o setOptions) run() error {
	err := o.validate()
	if err != nil {
		return err
	}

	config, err := o.configAccess.GetStartingConfig()
	if err != nil {
		return err
	}
	steps, err := newNavigationSteps(o.propertyName)
	if err != nil {
		return err
	}

	setRawBytes := false
	if o.setRawBytes.Provided() {
		setRawBytes = o.setRawBytes.Value()
	}

	err = modifyConfig(reflect.ValueOf(config), steps, o.propertyValue, false, setRawBytes)
	if err != nil {
		return err
	}

	if err := clientcmd.ModifyConfig(o.configAccess, *config, false); err != nil {
		return err
	}

	return nil
}
Beispiel #4
0
func (o unsetOptions) run() error {
	err := o.validate()
	if err != nil {
		return err
	}

	config, err := o.configAccess.GetStartingConfig()
	if err != nil {
		return err
	}

	steps, err := newNavigationSteps(o.propertyName)
	if err != nil {
		return err
	}
	err = modifyConfig(reflect.ValueOf(config), steps, "", true, true)
	if err != nil {
		return err
	}

	if err := clientcmd.ModifyConfig(o.configAccess, *config, false); err != nil {
		return err
	}

	return nil
}
// Save all the information present in this helper to a config file. An explicit config
// file path can be provided, if not use the established conventions about config
// loading rules. Will create a new config file if one can't be found at all. Will only
// succeed if all required info is present.
func (o *LoginOptions) SaveConfig() (bool, error) {
	if len(o.Username) == 0 {
		return false, fmt.Errorf("Insufficient data to merge configuration.")
	}

	globalExistedBefore := true
	if _, err := os.Stat(o.PathOptions.GlobalFile); os.IsNotExist(err) {
		globalExistedBefore = false
	}

	newConfig, err := config.CreateConfig(o.Project, o.Config)
	if err != nil {
		return false, err
	}

	cwd, err := os.Getwd()
	if err != nil {
		return false, err
	}
	baseDir, err := cmdutil.MakeAbs(filepath.Dir(o.PathOptions.GetDefaultFilename()), cwd)
	if err != nil {
		return false, err
	}
	if err := config.RelativizeClientConfigPaths(newConfig, baseDir); err != nil {
		return false, err
	}

	configToWrite, err := config.MergeConfig(*o.StartingKubeConfig, *newConfig)
	if err != nil {
		return false, err
	}

	if err := kclientcmd.ModifyConfig(o.PathOptions, *configToWrite, true); err != nil {
		if !os.IsPermission(err) {
			return false, err
		}

		out := &bytes.Buffer{}
		cmderr.PrintError(errors.ErrKubeConfigNotWriteable(o.PathOptions.GetDefaultFilename(), o.PathOptions.IsExplicitFile(), err), out)
		return false, fmt.Errorf("%v", out)
	}

	created := false
	if _, err := os.Stat(o.PathOptions.GlobalFile); err == nil {
		created = created || !globalExistedBefore
	}

	return created, nil
}
func (o useContextOptions) run() error {
	config, err := o.configAccess.GetStartingConfig()
	if err != nil {
		return err
	}

	err = o.validate(config)
	if err != nil {
		return err
	}

	config.CurrentContext = o.contextName

	if err := clientcmd.ModifyConfig(o.configAccess, *config, true); err != nil {
		return err
	}

	return nil
}
Beispiel #7
0
func updateKubeconfig(config util.AdminConfig, name, endpoint string, entKeyPairs *entityKeyPairs, dryRun bool) error {
	po := config.PathOptions()
	kubeconfig, err := po.GetStartingConfig()
	if err != nil {
		return err
	}

	// Populate API server endpoint info.
	cluster := clientcmdapi.NewCluster()
	// Prefix "https" as the URL scheme to endpoint.
	if !strings.HasPrefix(endpoint, "https://") {
		endpoint = fmt.Sprintf("https://%s", endpoint)
	}
	cluster.Server = endpoint
	cluster.CertificateAuthorityData = certutil.EncodeCertPEM(entKeyPairs.ca.Cert)

	// Populate credentials.
	authInfo := clientcmdapi.NewAuthInfo()
	authInfo.ClientCertificateData = certutil.EncodeCertPEM(entKeyPairs.admin.Cert)
	authInfo.ClientKeyData = certutil.EncodePrivateKeyPEM(entKeyPairs.admin.Key)
	authInfo.Username = AdminCN

	// Populate context.
	context := clientcmdapi.NewContext()
	context.Cluster = name
	context.AuthInfo = name

	// Update the config struct with API server endpoint info,
	// credentials and context.
	kubeconfig.Clusters[name] = cluster
	kubeconfig.AuthInfos[name] = authInfo
	kubeconfig.Contexts[name] = context

	if !dryRun {
		// Write the update kubeconfig.
		if err := clientcmd.ModifyConfig(po, *kubeconfig, true); err != nil {
			return err
		}
	}

	return nil
}
Beispiel #8
0
func (o createClusterOptions) run() error {
	err := o.validate()
	if err != nil {
		return err
	}

	config, err := o.configAccess.GetStartingConfig()
	if err != nil {
		return err
	}

	startingStanza, exists := config.Clusters[o.name]
	if !exists {
		startingStanza = clientcmdapi.NewCluster()
	}
	cluster := o.modifyCluster(*startingStanza)
	config.Clusters[o.name] = &cluster

	if err := clientcmd.ModifyConfig(o.configAccess, *config, true); err != nil {
		return err
	}

	return nil
}
func (o createAuthInfoOptions) run() error {
	err := o.validate()
	if err != nil {
		return err
	}

	config, err := o.configAccess.GetStartingConfig()
	if err != nil {
		return err
	}

	startingStanza, exists := config.AuthInfos[o.name]
	if !exists {
		startingStanza = clientcmdapi.NewAuthInfo()
	}
	authInfo := o.modifyAuthInfo(*startingStanza)
	config.AuthInfos[o.name] = &authInfo

	if err := clientcmd.ModifyConfig(o.configAccess, *config, true); err != nil {
		return err
	}

	return nil
}
Beispiel #10
0
// RunProject contains all the necessary functionality for the OpenShift cli project command
func (o ProjectOptions) RunProject() error {
	config := o.Config
	clientCfg := o.ClientConfig
	out := o.Out

	var currentProject string
	currentContext := config.Contexts[config.CurrentContext]
	if currentContext != nil {
		currentProject = currentContext.Namespace
	}

	// No argument provided, we will just print info
	if len(o.ProjectName) == 0 {
		if len(currentProject) > 0 {
			if o.DisplayShort {
				fmt.Fprintln(out, currentProject)
				return nil
			}

			client, kubeclient, err := o.ClientFn()
			if err != nil {
				return err
			}

			switch err := confirmProjectAccess(currentProject, client, kubeclient); {
			case clientcmd.IsForbidden(err):
				return fmt.Errorf("you do not have rights to view project %q.", currentProject)
			case kapierrors.IsNotFound(err):
				return fmt.Errorf("the project %q specified in your config does not exist.", currentProject)
			case err != nil:
				return err
			}

			defaultContextName := cliconfig.GetContextNickname(currentContext.Namespace, currentContext.Cluster, currentContext.AuthInfo)

			// if they specified a project name and got a generated context, then only show the information they care about.  They won't recognize
			// a context name they didn't choose
			if config.CurrentContext == defaultContextName {
				fmt.Fprintf(out, "Using project %q on server %q.\n", currentProject, clientCfg.Host)

			} else {
				fmt.Fprintf(out, "Using project %q from context named %q on server %q.\n", currentProject, config.CurrentContext, clientCfg.Host)
			}

		} else {
			if o.DisplayShort {
				return fmt.Errorf("no project has been set")
			}
			fmt.Fprintf(out, "No project has been set. Pass a project name to make that the default.\n")
		}
		return nil
	}

	// We have an argument that can be either a context or project
	argument := o.ProjectName

	contextInUse := ""
	namespaceInUse := ""

	// Check if argument is an existing context, if so just set it as the context in use.
	// If not a context then we will try to handle it as a project.
	if context, contextExists := config.Contexts[argument]; !o.ProjectOnly && contextExists {
		contextInUse = argument
		namespaceInUse = context.Namespace

		config.CurrentContext = argument

	} else {
		if !o.SkipAccessValidation {
			client, kubeclient, err := o.ClientFn()
			if err != nil {
				return err
			}

			if err := confirmProjectAccess(argument, client, kubeclient); err != nil {
				if isNotFound, isForbidden := kapierrors.IsNotFound(err), clientcmd.IsForbidden(err); isNotFound || isForbidden {
					var msg string
					if isForbidden {
						msg = fmt.Sprintf("You are not a member of project %q.", argument)
					} else {
						msg = fmt.Sprintf("A project named %q does not exist on %q.", argument, clientCfg.Host)
					}

					projects, err := getProjects(client, kubeclient)
					if err == nil {
						switch len(projects) {
						case 0:
							msg += "\nYou are not a member of any projects. You can request a project to be created with the 'new-project' command."
						case 1:
							msg += fmt.Sprintf("\nYou have one project on this server: %s", api.DisplayNameAndNameForProject(&projects[0]))
						default:
							msg += "\nYour projects are:"
							for _, project := range projects {
								msg += fmt.Sprintf("\n* %s", api.DisplayNameAndNameForProject(&project))
							}
						}
					}

					if hasMultipleServers(config) {
						msg += "\nTo see projects on another server, pass '--server=<server>'."
					}
					return errors.New(msg)
				}
				return err
			}
		}
		projectName := argument

		kubeconfig, err := cliconfig.CreateConfig(projectName, o.ClientConfig)
		if err != nil {
			return err
		}

		merged, err := cliconfig.MergeConfig(config, *kubeconfig)
		if err != nil {
			return err
		}
		config = *merged

		namespaceInUse = projectName
		contextInUse = merged.CurrentContext
	}

	if err := kclientcmd.ModifyConfig(o.PathOptions, config, true); err != nil {
		return err
	}

	if o.DisplayShort {
		fmt.Fprintln(out, namespaceInUse)
		return nil
	}

	// calculate what name we'd generate for the context.  If the context has the same name, don't drop it into the output, because the user won't
	// recognize the name since they didn't choose it.
	defaultContextName := cliconfig.GetContextNickname(namespaceInUse, config.Contexts[contextInUse].Cluster, config.Contexts[contextInUse].AuthInfo)

	switch {
	// if there is no namespace, then the only information we can provide is the context and server
	case (len(namespaceInUse) == 0):
		fmt.Fprintf(out, "Now using context named %q on server %q.\n", contextInUse, clientCfg.Host)

	// inform them that they are already in the project they are trying to switch to
	case currentProject == namespaceInUse:
		fmt.Fprintf(out, "Already on project %q on server %q.\n", currentProject, clientCfg.Host)

	// if they specified a project name and got a generated context, then only show the information they care about.  They won't recognize
	// a context name they didn't choose
	case (argument == namespaceInUse) && (contextInUse == defaultContextName):
		fmt.Fprintf(out, "Now using project %q on server %q.\n", namespaceInUse, clientCfg.Host)

	// in all other cases, display all information
	default:
		fmt.Fprintf(out, "Now using project %q from context named %q on server %q.\n", namespaceInUse, contextInUse, clientCfg.Host)

	}

	return nil
}
Beispiel #11
0
func modifyConfig(configAccess clientcmd.ConfigAccess, suppliedConfig *clientcmdapi.Config) error {
	config, err := configAccess.GetStartingConfig()
	if err != nil {
		return err
	}

	for name, authInfo := range suppliedConfig.AuthInfos {
		initial, ok := config.AuthInfos[name]
		if !ok {
			initial = clientcmdapi.NewAuthInfo()
		}
		modifiedAuthInfo := *initial

		var setToken, setBasic bool

		if len(authInfo.ClientCertificate) > 0 {
			modifiedAuthInfo.ClientCertificate = authInfo.ClientCertificate
		}
		if len(authInfo.ClientCertificateData) > 0 {
			modifiedAuthInfo.ClientCertificateData = authInfo.ClientCertificateData
		}

		if len(authInfo.ClientKey) > 0 {
			modifiedAuthInfo.ClientKey = authInfo.ClientKey
		}
		if len(authInfo.ClientKeyData) > 0 {
			modifiedAuthInfo.ClientKeyData = authInfo.ClientKeyData
		}

		if len(authInfo.Token) > 0 {
			modifiedAuthInfo.Token = authInfo.Token
			setToken = len(modifiedAuthInfo.Token) > 0
		}

		if len(authInfo.Username) > 0 {
			modifiedAuthInfo.Username = authInfo.Username
			setBasic = setBasic || len(modifiedAuthInfo.Username) > 0
		}
		if len(authInfo.Password) > 0 {
			modifiedAuthInfo.Password = authInfo.Password
			setBasic = setBasic || len(modifiedAuthInfo.Password) > 0
		}

		// If any auth info was set, make sure any other existing auth types are cleared
		if setToken || setBasic {
			if !setToken {
				modifiedAuthInfo.Token = ""
			}
			if !setBasic {
				modifiedAuthInfo.Username = ""
				modifiedAuthInfo.Password = ""
			}
		}
		config.AuthInfos[name] = &modifiedAuthInfo
	}

	for name, cluster := range suppliedConfig.Clusters {
		initial, ok := config.Clusters[name]
		if !ok {
			initial = clientcmdapi.NewCluster()
		}
		modifiedCluster := *initial

		if len(cluster.Server) > 0 {
			modifiedCluster.Server = cluster.Server
		}
		if cluster.InsecureSkipTLSVerify {
			modifiedCluster.InsecureSkipTLSVerify = cluster.InsecureSkipTLSVerify
			// Specifying insecure mode clears any certificate authority
			if modifiedCluster.InsecureSkipTLSVerify {
				modifiedCluster.CertificateAuthority = ""
				modifiedCluster.CertificateAuthorityData = nil
			}
		}
		if len(cluster.CertificateAuthorityData) > 0 {
			modifiedCluster.CertificateAuthorityData = cluster.CertificateAuthorityData
			modifiedCluster.InsecureSkipTLSVerify = false
		}
		if len(cluster.CertificateAuthority) > 0 {
			modifiedCluster.CertificateAuthority = cluster.CertificateAuthority
			modifiedCluster.InsecureSkipTLSVerify = false
		}
		config.Clusters[name] = &modifiedCluster
	}

	for name, context := range suppliedConfig.Contexts {
		initial, ok := config.Contexts[name]
		if !ok {
			initial = clientcmdapi.NewContext()
		}
		modifiedContext := *initial

		if len(context.Cluster) > 0 {
			modifiedContext.Cluster = context.Cluster
		}
		if len(context.AuthInfo) > 0 {
			modifiedContext.AuthInfo = context.AuthInfo
		}
		if len(context.Namespace) > 0 {
			modifiedContext.Namespace = context.Namespace
		}
		config.Contexts[name] = &modifiedContext
	}

	if err := clientcmd.ModifyConfig(configAccess, *config, true); err != nil {
		return err
	}

	return nil
}