GetContainerName

// GetContainerName returns the name of the container to attach to, with a fallback.
func (o *AttachOptions) GetContainerName(pod *corev1.Pod) (string, error) {
	c, err := o.containerToAttachTo(pod)
	if err != nil {
		return "", err
	}
	return c.Name, nil
}


reattachMessage

// reattachMessage returns a message to print after attach has completed, or
// the empty string if no message should be printed.
func (o *AttachOptions) reattachMessage(containerName string, rawTTY bool) string {
	if o.Quiet || !o.Stdin || !rawTTY || o.Pod.Spec.RestartPolicy != corev1.RestartPolicyAlways {
		return ""
	}
	if _, path := podcmd.FindContainerByName(o.Pod, containerName); strings.HasPrefix(path, "spec.ephemeralContainers") {
		return fmt.Sprintf("Session ended, the ephemeral container will not be restarted but may be reattached using '%s %s -c %s -i -t' if it is still running", o.CommandName, o.Pod.Name, containerName)
	}
	return fmt.Sprintf("Session ended, resume using '%s %s -c %s -i -t' command when the pod is running", o.CommandName, o.Pod.Name, containerName)
}


NewCmdAuth

// NewCmdAuth returns an initialized Command instance for 'auth' sub command
func NewCmdAuth(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	// Parent command to which all subcommands are added.
	cmds := &cobra.Command{
		Use:   "auth",
		Short: "Inspect authorization",
		Long:  `Inspect authorization`,
		Run:   cmdutil.DefaultSubCommandRun(streams.ErrOut),
	}

	cmds.AddCommand(NewCmdCanI(f, streams))
	cmds.AddCommand(NewCmdReconcile(f, streams))
	cmds.AddCommand(NewCmdWhoAmI(f, streams))

	return cmds
}


NewCmdCanI

// NewCmdCanI returns an initialized Command for 'auth can-i' sub command
func NewCmdCanI(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	o := &CanIOptions{
		IOStreams: streams,
	}

	cmd := &cobra.Command{
		Use:                   "can-i VERB [TYPE | TYPE/NAME | NONRESOURCEURL]",
		DisableFlagsInUseLine: true,
		Short:                 "Check whether an action is allowed",
		Long:                  canILong,
		Example:               canIExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, args))
			cmdutil.CheckErr(o.Validate())
			var err error
			if o.List {
				err = o.RunAccessList()
			} else {
				var allowed bool
				allowed, err = o.RunAccessCheck()
				if err == nil {
					if !allowed {
						os.Exit(1)
					}
				}
			}
			cmdutil.CheckErr(err)
		},
	}

	cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If true, check the specified action in all namespaces.")
	cmd.Flags().BoolVarP(&o.Quiet, "quiet", "q", o.Quiet, "If true, suppress output and just return the exit code.")
	cmd.Flags().StringVar(&o.Subresource, "subresource", o.Subresource, "SubResource such as pod/log or deployment/scale")
	cmd.Flags().BoolVar(&o.List, "list", o.List, "If true, prints all allowed actions.")
	cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "If true, prints allowed actions without headers")
	return cmd
}


Complete

// Complete completes all the required options
func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
	// Set default WarningPrinter if not already set.
	if o.WarningPrinter == nil {
		o.WarningPrinter = printers.NewWarningPrinter(o.ErrOut, printers.WarningPrinterOptions{Color: term.AllowsColorOutput(o.ErrOut)})
	}

	if o.List {
		if len(args) != 0 {
			return errors.New("list option must be specified with no arguments")
		}
	} else {
		if o.Quiet {
			o.Out = io.Discard
		}

		switch len(args) {
		case 2:
			o.Verb = args[0]
			if strings.HasPrefix(args[1], "/") {
				o.NonResourceURL = args[1]
				break
			}
			resourceTokens := strings.SplitN(args[1], "/", 2)
			restMapper, err := f.ToRESTMapper()
			if err != nil {
				return err
			}
			o.Resource = o.resourceFor(restMapper, resourceTokens[0])
			if len(resourceTokens) > 1 {
				o.ResourceName = resourceTokens[1]
			}
		default:
			errString := "you must specify two arguments: verb resource or verb resource/resourceName."
			usageString := "See 'kubectl auth can-i -h' for help and examples."
			return errors.New(fmt.Sprintf("%s\n%s", errString, usageString))
		}
	}

	var err error
	client, err := f.KubernetesClientSet()
	if err != nil {
		return err
	}
	o.AuthClient = client.AuthorizationV1()
	o.DiscoveryClient = client.Discovery()
	o.Namespace = ""
	if !o.AllNamespaces {
		o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
		if err != nil {
			return err
		}
	}

	return nil
}


Validate

// Validate makes sure provided values for CanIOptions are valid
func (o *CanIOptions) Validate() error {
	if o.List {
		if o.Quiet || o.AllNamespaces || o.Subresource != "" {
			return errors.New("list option can't be specified with neither quiet, all-namespaces nor subresource options")
		}
		return nil
	}

	if o.WarningPrinter == nil {
		return fmt.Errorf("WarningPrinter can not be used without initialization")
	}

	if o.NonResourceURL != "" {
		if o.Subresource != "" {
			return fmt.Errorf("--subresource can not be used with NonResourceURL")
		}
		if o.Resource != (schema.GroupVersionResource{}) || o.ResourceName != "" {
			return fmt.Errorf("NonResourceURL and ResourceName can not specified together")
		}
		if !isKnownNonResourceVerb(o.Verb) {
			o.WarningPrinter.Print(fmt.Sprintf("verb '%s' is not a known verb\n", o.Verb))
		}
	} else if !o.Resource.Empty() && !o.AllNamespaces && o.DiscoveryClient != nil {
		if namespaced, err := isNamespaced(o.Resource, o.DiscoveryClient); err == nil && !namespaced {
			if len(o.Resource.Group) == 0 {
				o.WarningPrinter.Print(fmt.Sprintf("resource '%s' is not namespace scoped\n", o.Resource.Resource))
			} else {
				o.WarningPrinter.Print(fmt.Sprintf("resource '%s' is not namespace scoped in group '%s'\n", o.Resource.Resource, o.Resource.Group))
			}
		}
		if !isKnownResourceVerb(o.Verb) {
			o.WarningPrinter.Print(fmt.Sprintf("verb '%s' is not a known verb\n", o.Verb))
		}
	}

	if o.NoHeaders {
		return fmt.Errorf("--no-headers cannot be set without --list specified")
	}
	return nil
}


RunAccessList

// RunAccessList lists all the access current user has
func (o *CanIOptions) RunAccessList() error {
	sar := &authorizationv1.SelfSubjectRulesReview{
		Spec: authorizationv1.SelfSubjectRulesReviewSpec{
			Namespace: o.Namespace,
		},
	}
	response, err := o.AuthClient.SelfSubjectRulesReviews().Create(context.TODO(), sar, metav1.CreateOptions{})
	if err != nil {
		return err
	}

	return o.printStatus(response.Status)
}


RunAccessCheck

// RunAccessCheck checks if user has access to a certain resource or non resource URL
func (o *CanIOptions) RunAccessCheck() (bool, error) {
	var sar *authorizationv1.SelfSubjectAccessReview
	if o.NonResourceURL == "" {
		sar = &authorizationv1.SelfSubjectAccessReview{
			Spec: authorizationv1.SelfSubjectAccessReviewSpec{
				ResourceAttributes: &authorizationv1.ResourceAttributes{
					Namespace:   o.Namespace,
					Verb:        o.Verb,
					Group:       o.Resource.Group,
					Resource:    o.Resource.Resource,
					Subresource: o.Subresource,
					Name:        o.ResourceName,
				},
			},
		}
	} else {
		sar = &authorizationv1.SelfSubjectAccessReview{
			Spec: authorizationv1.SelfSubjectAccessReviewSpec{
				NonResourceAttributes: &authorizationv1.NonResourceAttributes{
					Verb: o.Verb,
					Path: o.NonResourceURL,
				},
			},
		}
	}

	response, err := o.AuthClient.SelfSubjectAccessReviews().Create(context.TODO(), sar, metav1.CreateOptions{})
	if err != nil {
		return false, err
	}
	if response.Status.Allowed {
		fmt.Fprintln(o.Out, "yes")
	} else {
		fmt.Fprint(o.Out, "no")
		if len(response.Status.Reason) > 0 {
			fmt.Fprintf(o.Out, " - %v", response.Status.Reason)
		}
		if len(response.Status.EvaluationError) > 0 {
			fmt.Fprintf(o.Out, " - %v", response.Status.EvaluationError)
		}
		fmt.Fprintln(o.Out)
	}

	return response.Status.Allowed, nil
}


resourceFor

func (o *CanIOptions) resourceFor(mapper meta.RESTMapper, resourceArg string) schema.GroupVersionResource {
	if resourceArg == "*" {
		return schema.GroupVersionResource{Resource: resourceArg}
	}

	fullySpecifiedGVR, groupResource := schema.ParseResourceArg(strings.ToLower(resourceArg))
	gvr := schema.GroupVersionResource{}
	if fullySpecifiedGVR != nil {
		gvr, _ = mapper.ResourceFor(*fullySpecifiedGVR)
	}
	if gvr.Empty() {
		var err error
		gvr, err = mapper.ResourceFor(groupResource.WithVersion(""))
		if err != nil {
			if !nonStandardResourceNames.Has(groupResource.String()) {
				if len(groupResource.Group) == 0 {
					o.WarningPrinter.Print(fmt.Sprintf("the server doesn't have a resource type '%s'\n", groupResource.Resource))
				} else {
					o.WarningPrinter.Print(fmt.Sprintf("the server doesn't have a resource type '%s' in group '%s'\n", groupResource.Resource, groupResource.Group))
				}
			}
			return schema.GroupVersionResource{Resource: resourceArg}
		}
	}

	return gvr
}


printStatus

func (o *CanIOptions) printStatus(status authorizationv1.SubjectRulesReviewStatus) error {
	if status.Incomplete {
		o.WarningPrinter.Print(fmt.Sprintf("the list may be incomplete: %v", status.EvaluationError))
	}

	breakdownRules := []rbacv1.PolicyRule{}
	for _, rule := range convertToPolicyRule(status) {
		breakdownRules = append(breakdownRules, rbacutil.BreakdownRule(rule)...)
	}

	compactRules, err := rbacutil.CompactRules(breakdownRules)
	if err != nil {
		return err
	}
	sort.Stable(rbacutil.SortableRuleSlice(compactRules))

	w := printers.GetNewTabWriter(o.Out)
	defer w.Flush()

	allErrs := []error{}
	if !o.NoHeaders {
		if err := printAccessHeaders(w); err != nil {
			allErrs = append(allErrs, err)
		}
	}

	if err := printAccess(w, compactRules); err != nil {
		allErrs = append(allErrs, err)
	}
	return utilerrors.NewAggregate(allErrs)
}


convertToPolicyRule

func convertToPolicyRule(status authorizationv1.SubjectRulesReviewStatus) []rbacv1.PolicyRule {
	ret := []rbacv1.PolicyRule{}
	for _, resource := range status.ResourceRules {
		ret = append(ret, rbacv1.PolicyRule{
			Verbs:         resource.Verbs,
			APIGroups:     resource.APIGroups,
			Resources:     resource.Resources,
			ResourceNames: resource.ResourceNames,
		})
	}

	for _, nonResource := range status.NonResourceRules {
		ret = append(ret, rbacv1.PolicyRule{
			Verbs:           nonResource.Verbs,
			NonResourceURLs: nonResource.NonResourceURLs,
		})
	}

	return ret
}


printAccessHeaders

func printAccessHeaders(out io.Writer) error {
	columnNames := []string{"Resources", "Non-Resource URLs", "Resource Names", "Verbs"}
	_, err := fmt.Fprintf(out, "%s\n", strings.Join(columnNames, "\t"))
	return err
}


printAccess

func printAccess(out io.Writer, rules []rbacv1.PolicyRule) error {
	for _, r := range rules {
		if _, err := fmt.Fprintf(out, "%s\t%v\t%v\t%v\n", describe.CombineResourceGroup(r.Resources, r.APIGroups), r.NonResourceURLs, r.ResourceNames, r.Verbs); err != nil {
			return err
		}
	}
	return nil
}


isNamespaced

func isNamespaced(gvr schema.GroupVersionResource, discoveryClient discovery.DiscoveryInterface) (bool, error) {
	if gvr.Resource == "*" {
		return true, nil
	}
	apiResourceList, err := discoveryClient.ServerResourcesForGroupVersion(schema.GroupVersion{
		Group: gvr.Group, Version: gvr.Version,
	}.String())
	if err != nil {
		return true, err
	}

	for _, resource := range apiResourceList.APIResources {
		if resource.Name == gvr.Resource {
			return resource.Namespaced, nil
		}
	}

	return false, fmt.Errorf("the server doesn't have a resource type '%s' in group '%s'", gvr.Resource, gvr.Group)
}


isKnownResourceVerb

func isKnownResourceVerb(s string) bool {
	return resourceVerbs.Has(s)
}


isKnownNonResourceVerb

func isKnownNonResourceVerb(s string) bool {
	return nonResourceURLVerbs.Has(s)
}


NewReconcileOptions

// NewReconcileOptions returns a new ReconcileOptions instance
func NewReconcileOptions(ioStreams genericclioptions.IOStreams) *ReconcileOptions {
	return &ReconcileOptions{
		FilenameOptions: &resource.FilenameOptions{},
		PrintFlags:      genericclioptions.NewPrintFlags("reconciled").WithTypeSetter(scheme.Scheme),
		IOStreams:       ioStreams,
	}
}


NewCmdReconcile

// NewCmdReconcile holds the options for 'auth reconcile' sub command
func NewCmdReconcile(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	o := NewReconcileOptions(streams)

	cmd := &cobra.Command{
		Use:                   "reconcile -f FILENAME",
		DisableFlagsInUseLine: true,
		Short:                 "Reconciles rules for RBAC role, role binding, cluster role, and cluster role binding objects",
		Long:                  reconcileLong,
		Example:               reconcileExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(cmd, f, args))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.RunReconcile())
		},
	}

	o.PrintFlags.AddFlags(cmd)

	cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, "identifying the resource to reconcile.")
	cmd.Flags().BoolVar(&o.RemoveExtraPermissions, "remove-extra-permissions", o.RemoveExtraPermissions, "If true, removes extra permissions added to roles")
	cmd.Flags().BoolVar(&o.RemoveExtraSubjects, "remove-extra-subjects", o.RemoveExtraSubjects, "If true, removes extra subjects added to rolebindings")
	cmdutil.AddDryRunFlag(cmd)

	return cmd
}


Complete

// Complete completes all the required options
func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string) error {
	if err := o.FilenameOptions.RequireFilenameOrKustomize(); err != nil {
		return err
	}

	if len(args) > 0 {
		return errors.New("no arguments are allowed")
	}

	dryRun, err := getClientSideDryRun(cmd)
	if err != nil {
		return err
	}
	o.DryRun = dryRun

	namespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return err
	}

	r := f.NewBuilder().
		WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
		ContinueOnError().
		NamespaceParam(namespace).DefaultNamespace().
		FilenameParam(enforceNamespace, o.FilenameOptions).
		Flatten().
		Local().
		Do()

	if err := r.Err(); err != nil {
		return err
	}
	o.Visitor = r

	clientConfig, err := f.ToRESTConfig()
	if err != nil {
		return err
	}
	o.RBACClient, err = rbacv1client.NewForConfig(clientConfig)
	if err != nil {
		return err
	}
	o.NamespaceClient, err = corev1client.NewForConfig(clientConfig)
	if err != nil {
		return err
	}

	if o.DryRun {
		o.PrintFlags.Complete("%s (dry run)")
	}
	printer, err := o.PrintFlags.ToPrinter()
	if err != nil {
		return err
	}

	o.PrintObject = printer.PrintObj
	return nil
}


Validate

// Validate makes sure provided values for ReconcileOptions are valid
func (o *ReconcileOptions) Validate() error {
	if o.Visitor == nil {
		return errors.New("ReconcileOptions.Visitor must be set")
	}
	if o.RBACClient == nil {
		return errors.New("ReconcileOptions.RBACClient must be set")
	}
	if o.NamespaceClient == nil {
		return errors.New("ReconcileOptions.NamespaceClient must be set")
	}
	if o.PrintObject == nil {
		return errors.New("ReconcileOptions.Print must be set")
	}
	if o.Out == nil {
		return errors.New("ReconcileOptions.Out must be set")
	}
	if o.ErrOut == nil {
		return errors.New("ReconcileOptions.Err must be set")
	}
	return nil
}


RunReconcile

// RunReconcile performs the execution
func (o *ReconcileOptions) RunReconcile() error {
	return o.Visitor.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}

		switch t := info.Object.(type) {
		case *rbacv1.Role:
			reconcileOptions := reconciliation.ReconcileRoleOptions{
				Confirm:                !o.DryRun,
				RemoveExtraPermissions: o.RemoveExtraPermissions,
				Role:                   reconciliation.RoleRuleOwner{Role: t},
				Client: reconciliation.RoleModifier{
					NamespaceClient: o.NamespaceClient.Namespaces(),
					Client:          o.RBACClient,
				},
			}
			result, err := reconcileOptions.Run()
			if err != nil {
				return err
			}
			o.printResults(result.Role.GetObject(), nil, nil, result.MissingRules, result.ExtraRules, result.Operation, result.Protected)

		case *rbacv1.ClusterRole:
			reconcileOptions := reconciliation.ReconcileRoleOptions{
				Confirm:                !o.DryRun,
				RemoveExtraPermissions: o.RemoveExtraPermissions,
				Role:                   reconciliation.ClusterRoleRuleOwner{ClusterRole: t},
				Client: reconciliation.ClusterRoleModifier{
					Client: o.RBACClient.ClusterRoles(),
				},
			}
			result, err := reconcileOptions.Run()
			if err != nil {
				return err
			}
			o.printResults(result.Role.GetObject(), nil, nil, result.MissingRules, result.ExtraRules, result.Operation, result.Protected)

		case *rbacv1.RoleBinding:
			reconcileOptions := reconciliation.ReconcileRoleBindingOptions{
				Confirm:             !o.DryRun,
				RemoveExtraSubjects: o.RemoveExtraSubjects,
				RoleBinding:         reconciliation.RoleBindingAdapter{RoleBinding: t},
				Client: reconciliation.RoleBindingClientAdapter{
					Client:          o.RBACClient,
					NamespaceClient: o.NamespaceClient.Namespaces(),
				},
			}
			result, err := reconcileOptions.Run()
			if err != nil {
				return err
			}
			o.printResults(result.RoleBinding.GetObject(), result.MissingSubjects, result.ExtraSubjects, nil, nil, result.Operation, result.Protected)

		case *rbacv1.ClusterRoleBinding:
			reconcileOptions := reconciliation.ReconcileRoleBindingOptions{
				Confirm:             !o.DryRun,
				RemoveExtraSubjects: o.RemoveExtraSubjects,
				RoleBinding:         reconciliation.ClusterRoleBindingAdapter{ClusterRoleBinding: t},
				Client: reconciliation.ClusterRoleBindingClientAdapter{
					Client: o.RBACClient.ClusterRoleBindings(),
				},
			}
			result, err := reconcileOptions.Run()
			if err != nil {
				return err
			}
			o.printResults(result.RoleBinding.GetObject(), result.MissingSubjects, result.ExtraSubjects, nil, nil, result.Operation, result.Protected)

		case *rbacv1beta1.Role,
			*rbacv1beta1.RoleBinding,
			*rbacv1beta1.ClusterRole,
			*rbacv1beta1.ClusterRoleBinding,
			*rbacv1alpha1.Role,
			*rbacv1alpha1.RoleBinding,
			*rbacv1alpha1.ClusterRole,
			*rbacv1alpha1.ClusterRoleBinding:
			return fmt.Errorf("only rbac.authorization.k8s.io/v1 is supported: not %T", t)

		default:
			klog.V(1).Infof("skipping %#v", info.Object.GetObjectKind())
			// skip ignored resources
		}

		return nil
	})
}


printResults

func (o *ReconcileOptions) printResults(object runtime.Object,
	missingSubjects, extraSubjects []rbacv1.Subject,
	missingRules, extraRules []rbacv1.PolicyRule,
	operation reconciliation.ReconcileOperation,
	protected bool) {

	o.PrintObject(object, o.Out)

	caveat := ""
	if protected {
		caveat = ", but object opted out (rbac.authorization.kubernetes.io/autoupdate: false)"
	}
	switch operation {
	case reconciliation.ReconcileNone:
		return
	case reconciliation.ReconcileCreate:
		fmt.Fprintf(o.ErrOut, "\treconciliation required create%s\n", caveat)
	case reconciliation.ReconcileUpdate:
		fmt.Fprintf(o.ErrOut, "\treconciliation required update%s\n", caveat)
	case reconciliation.ReconcileRecreate:
		fmt.Fprintf(o.ErrOut, "\treconciliation required recreate%s\n", caveat)
	}

	if len(missingSubjects) > 0 {
		fmt.Fprintf(o.ErrOut, "\tmissing subjects added:\n")
		for _, s := range missingSubjects {
			fmt.Fprintf(o.ErrOut, "\t\t%+v\n", s)
		}
	}
	if o.RemoveExtraSubjects {
		if len(extraSubjects) > 0 {
			fmt.Fprintf(o.ErrOut, "\textra subjects removed:\n")
			for _, s := range extraSubjects {
				fmt.Fprintf(o.ErrOut, "\t\t%+v\n", s)
			}
		}
	}
	if len(missingRules) > 0 {
		fmt.Fprintf(o.ErrOut, "\tmissing rules added:\n")
		for _, r := range missingRules {
			fmt.Fprintf(o.ErrOut, "\t\t%+v\n", r)
		}
	}
	if o.RemoveExtraPermissions {
		if len(extraRules) > 0 {
			fmt.Fprintf(o.ErrOut, "\textra rules removed:\n")
			for _, r := range extraRules {
				fmt.Fprintf(o.ErrOut, "\t\t%+v\n", r)
			}
		}
	}
}


getClientSideDryRun

func getClientSideDryRun(cmd *cobra.Command) (bool, error) {
	dryRunStrategy, err := cmdutil.GetDryRunStrategy(cmd)
	if err != nil {
		return false, fmt.Errorf("error accessing --dry-run flag for command %s: %v", cmd.Name(), err)
	}
	if dryRunStrategy == cmdutil.DryRunServer {
		return false, fmt.Errorf("--dry-run=server for command %s is not supported yet", cmd.Name())
	}
	return dryRunStrategy == cmdutil.DryRunClient, nil
}


NewWhoAmIFlags

// NewWhoAmIFlags returns a default WhoAmIFlags.
func NewWhoAmIFlags(restClientGetter genericclioptions.RESTClientGetter, streams genericclioptions.IOStreams) *WhoAmIFlags {
	return &WhoAmIFlags{
		RESTClientGetter: restClientGetter,
		PrintFlags:       genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme),
		IOStreams:        streams,
	}
}


AddFlags

// AddFlags registers flags for a cli.
func (flags *WhoAmIFlags) AddFlags(cmd *cobra.Command) {
	flags.PrintFlags.AddFlags(cmd)
}


ToOptions

// ToOptions converts from CLI inputs to runtime inputs.
func (flags *WhoAmIFlags) ToOptions(ctx context.Context, args []string) (*WhoAmIOptions, error) {
	w := &WhoAmIOptions{
		ctx:       ctx,
		IOStreams: flags.IOStreams,
	}

	clientConfig, err := flags.RESTClientGetter.ToRESTConfig()
	if err != nil {
		return nil, err
	}

	w.authV1alpha1Client, err = authenticationv1alpha1client.NewForConfig(clientConfig)
	if err != nil {
		return nil, err
	}

	w.authV1beta1Client, err = authenticationv1beta1client.NewForConfig(clientConfig)
	if err != nil {
		return nil, err
	}

	if !flags.PrintFlags.OutputFlagSpecified() {
		w.resourcePrinterFunc = printTableSelfSubjectAccessReview
	} else {
		printer, err := flags.PrintFlags.ToPrinter()
		if err != nil {
			return nil, err
		}
		w.resourcePrinterFunc = printer.PrintObj
	}

	return w, nil
}


NewCmdWhoAmI

// NewCmdWhoAmI returns an initialized Command for 'auth whoami' sub command. Experimental.
func NewCmdWhoAmI(restClientGetter genericclioptions.RESTClientGetter, streams genericclioptions.IOStreams) *cobra.Command {
	flags := NewWhoAmIFlags(restClientGetter, streams)

	cmd := &cobra.Command{
		Use:                   "whoami",
		DisableFlagsInUseLine: true,
		Short:                 "Experimental: Check self subject attributes",
		Long:                  whoAmILong,
		Example:               whoAmIExample,
		Run: func(cmd *cobra.Command, args []string) {
			o, err := flags.ToOptions(cmd.Context(), args)
			cmdutil.CheckErr(err)
			cmdutil.CheckErr(o.Run())
		},
	}

	flags.AddFlags(cmd)
	return cmd
}


Run

// Run prints all user attributes.
func (o WhoAmIOptions) Run() error {
	var (
		res runtime.Object
		err error
	)

	res, err = o.authV1beta1Client.
		SelfSubjectReviews().
		Create(context.TODO(), &authenticationv1beta1.SelfSubjectReview{}, metav1.CreateOptions{})
	if err != nil && errors.IsNotFound(err) {
		// Fallback to Alpha API if Beta is not enabled
		res, err = o.authV1alpha1Client.
			SelfSubjectReviews().
			Create(context.TODO(), &authenticationv1alpha1.SelfSubjectReview{}, metav1.CreateOptions{})
	}
	if err != nil {
		switch {
		case errors.IsForbidden(err):
			return forbiddenErr
		case errors.IsNotFound(err):
			return notEnabledErr
		default:
			return err
		}
	}
	return o.resourcePrinterFunc(res, o.Out)
}


getUserInfo

func getUserInfo(obj runtime.Object) (authenticationv1.UserInfo, error) {
	switch obj.(type) {
	case *authenticationv1alpha1.SelfSubjectReview:
		return obj.(*authenticationv1alpha1.SelfSubjectReview).Status.UserInfo, nil
	case *authenticationv1beta1.SelfSubjectReview:
		return obj.(*authenticationv1beta1.SelfSubjectReview).Status.UserInfo, nil
	default:
		return authenticationv1.UserInfo{}, fmt.Errorf("unexpected response type %T, expected SelfSubjectReview", obj)
	}
}


printTableSelfSubjectAccessReview

func printTableSelfSubjectAccessReview(obj runtime.Object, out io.Writer) error {
	ui, err := getUserInfo(obj)
	if err != nil {
		return err
	}

	w := printers.GetNewTabWriter(out)
	defer w.Flush()

	_, err = fmt.Fprintf(w, "ATTRIBUTE\tVALUE\n")
	if err != nil {
		return fmt.Errorf("cannot write a header: %w", err)
	}

	if ui.Username != "" {
		_, err := fmt.Fprintf(w, "Username\t%s\n", ui.Username)
		if err != nil {
			return fmt.Errorf("cannot write a username: %w", err)
		}
	}

	if ui.UID != "" {
		_, err := fmt.Fprintf(w, "UID\t%s\n", ui.UID)
		if err != nil {
			return fmt.Errorf("cannot write a uid: %w", err)
		}
	}

	if len(ui.Groups) > 0 {
		_, err := fmt.Fprintf(w, "Groups\t%v\n", ui.Groups)
		if err != nil {
			return fmt.Errorf("cannot write groups: %w", err)
		}
	}

	if len(ui.Extra) > 0 {
		for _, k := range sets.StringKeySet(ui.Extra).List() {
			v := ui.Extra[k]
			_, err := fmt.Fprintf(w, "Extra: %s\t%v\n", k, v)
			if err != nil {
				return fmt.Errorf("cannot write an extra: %w", err)
			}
		}

	}
	return nil
}


NewAutoscaleOptions

// NewAutoscaleOptions creates the options for autoscale
func NewAutoscaleOptions(ioStreams genericclioptions.IOStreams) *AutoscaleOptions {
	return &AutoscaleOptions{
		PrintFlags:      genericclioptions.NewPrintFlags("autoscaled").WithTypeSetter(scheme.Scheme),
		FilenameOptions: &resource.FilenameOptions{},
		RecordFlags:     genericclioptions.NewRecordFlags(),
		Recorder:        genericclioptions.NoopRecorder{},

		IOStreams: ioStreams,
	}
}


NewCmdAutoscale

// NewCmdAutoscale returns the autoscale Cobra command
func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewAutoscaleOptions(ioStreams)

	validArgs := []string{"deployment", "replicaset", "replicationcontroller", "statefulset"}

	cmd := &cobra.Command{
		Use:                   "autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS] --max=MAXPODS [--cpu-percent=CPU]",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Auto-scale a deployment, replica set, stateful set, or replication controller"),
		Long:                  autoscaleLong,
		Example:               autoscaleExample,
		ValidArgsFunction:     completion.SpecifiedResourceTypeAndNameCompletionFunc(f, validArgs),
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, cmd, args))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.Run())
		},
	}

	// bind flag structs
	o.RecordFlags.AddFlags(cmd)
	o.PrintFlags.AddFlags(cmd)
	cmd.Flags().Int32Var(&o.Min, "min", -1, "The lower limit for the number of pods that can be set by the autoscaler. If it's not specified or negative, the server will apply a default value.")
	cmd.Flags().Int32Var(&o.Max, "max", -1, "The upper limit for the number of pods that can be set by the autoscaler. Required.")
	cmd.MarkFlagRequired("max")
	cmd.Flags().Int32Var(&o.CPUPercent, "cpu-percent", -1, "The target average CPU utilization (represented as a percent of requested CPU) over all the pods. If it's not specified or negative, a default autoscaling policy will be used.")
	cmd.Flags().StringVar(&o.Name, "name", "", i18n.T("The name for the newly created object. If not specified, the name of the input resource will be used."))
	cmdutil.AddDryRunFlag(cmd)
	cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, "identifying the resource to autoscale.")
	cmdutil.AddApplyAnnotationFlags(cmd)
	cmdutil.AddFieldManagerFlagVar(cmd, &o.fieldManager, "kubectl-autoscale")
	return cmd
}


Complete

// Complete verifies command line arguments and loads data from the command environment
func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
	var err error
	o.dryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd)
	if err != nil {
		return err
	}
	discoveryClient, err := f.ToDiscoveryClient()
	if err != nil {
		return err
	}
	o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
	o.builder = f.NewBuilder()
	o.scaleKindResolver = scale.NewDiscoveryScaleKindResolver(discoveryClient)
	o.args = args
	o.RecordFlags.Complete(cmd)

	o.Recorder, err = o.RecordFlags.ToRecorder()
	if err != nil {
		return err
	}

	kubeClient, err := f.KubernetesClientSet()
	if err != nil {
		return err
	}
	o.HPAClient = kubeClient.AutoscalingV1()

	o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return err
	}

	o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
		o.PrintFlags.NamePrintFlags.Operation = operation
		cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.dryRunStrategy)

		return o.PrintFlags.ToPrinter()
	}

	return nil
}


Validate

// Validate checks that the provided attach options are specified.
func (o *AutoscaleOptions) Validate() error {
	if o.Max < 1 {
		return fmt.Errorf("--max=MAXPODS is required and must be at least 1, max: %d", o.Max)
	}
	if o.Max < o.Min {
		return fmt.Errorf("--max=MAXPODS must be larger or equal to --min=MINPODS, max: %d, min: %d", o.Max, o.Min)
	}

	return nil
}


Run

// Run performs the execution
func (o *AutoscaleOptions) Run() error {
	r := o.builder.
		Unstructured().
		ContinueOnError().
		NamespaceParam(o.namespace).DefaultNamespace().
		FilenameParam(o.enforceNamespace, o.FilenameOptions).
		ResourceTypeOrNameArgs(false, o.args...).
		Flatten().
		Do()
	if err := r.Err(); err != nil {
		return err
	}

	count := 0
	err := r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}

		mapping := info.ResourceMapping()
		gvr := mapping.GroupVersionKind.GroupVersion().WithResource(mapping.Resource.Resource)
		if _, err := o.scaleKindResolver.ScaleForResource(gvr); err != nil {
			return fmt.Errorf("cannot autoscale a %v: %v", mapping.GroupVersionKind.Kind, err)
		}

		hpa := o.createHorizontalPodAutoscaler(info.Name, mapping)

		if err := o.Recorder.Record(hpa); err != nil {
			klog.V(4).Infof("error recording current command: %v", err)
		}

		if o.dryRunStrategy == cmdutil.DryRunClient {
			count++

			printer, err := o.ToPrinter("created")
			if err != nil {
				return err
			}
			return printer.PrintObj(hpa, o.Out)
		}

		if err := util.CreateOrUpdateAnnotation(o.createAnnotation, hpa, scheme.DefaultJSONEncoder()); err != nil {
			return err
		}

		createOptions := metav1.CreateOptions{}
		if o.fieldManager != "" {
			createOptions.FieldManager = o.fieldManager
		}
		if o.dryRunStrategy == cmdutil.DryRunServer {
			createOptions.DryRun = []string{metav1.DryRunAll}
		}
		actualHPA, err := o.HPAClient.HorizontalPodAutoscalers(o.namespace).Create(context.TODO(), hpa, createOptions)
		if err != nil {
			return err
		}

		count++
		printer, err := o.ToPrinter("autoscaled")
		if err != nil {
			return err
		}
		return printer.PrintObj(actualHPA, o.Out)
	})
	if err != nil {
		return err
	}
	if count == 0 {
		return fmt.Errorf("no objects passed to autoscale")
	}
	return nil
}


createHorizontalPodAutoscaler

func (o *AutoscaleOptions) createHorizontalPodAutoscaler(refName string, mapping *meta.RESTMapping) *autoscalingv1.HorizontalPodAutoscaler {
	name := o.Name
	if len(name) == 0 {
		name = refName
	}

	scaler := autoscalingv1.HorizontalPodAutoscaler{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
		},
		Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
			ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
				APIVersion: mapping.GroupVersionKind.GroupVersion().String(),
				Kind:       mapping.GroupVersionKind.Kind,
				Name:       refName,
			},
			MaxReplicas: o.Max,
		},
	}

	if o.Min > 0 {
		v := int32(o.Min)
		scaler.Spec.MinReplicas = &v
	}
	if o.CPUPercent >= 0 {
		c := int32(o.CPUPercent)
		scaler.Spec.TargetCPUUtilizationPercentage = &c
	}

	return &scaler
}


NewCmdCertificate

// NewCmdCertificate returns `certificate` Cobra command
func NewCmdCertificate(restClientGetter genericclioptions.RESTClientGetter, ioStreams genericclioptions.IOStreams) *cobra.Command {
	cmd := &cobra.Command{
		Use:                   "certificate SUBCOMMAND",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Modify certificate resources."),
		Long:                  i18n.T("Modify certificate resources."),
		Run: func(cmd *cobra.Command, args []string) {
			cmd.Help()
		},
	}

	cmd.AddCommand(NewCmdCertificateApprove(restClientGetter, ioStreams))
	cmd.AddCommand(NewCmdCertificateDeny(restClientGetter, ioStreams))

	return cmd
}


NewCertificateOptions

// NewCertificateOptions creates CertificateOptions struct for `certificate` command
func NewCertificateOptions(ioStreams genericclioptions.IOStreams, operation string) *CertificateOptions {
	return &CertificateOptions{
		PrintFlags: genericclioptions.NewPrintFlags(operation).WithTypeSetter(scheme.Scheme),
		IOStreams:  ioStreams,
	}
}


Complete

// Complete loads data from the command environment
func (o *CertificateOptions) Complete(restClientGetter genericclioptions.RESTClientGetter, cmd *cobra.Command, args []string) error {
	o.csrNames = args
	o.outputStyle = cmdutil.GetFlagString(cmd, "output")

	printer, err := o.PrintFlags.ToPrinter()
	if err != nil {
		return err
	}

	o.PrintObj = func(obj runtime.Object, out io.Writer) error {
		return printer.PrintObj(obj, out)
	}

	o.builder = resource.NewBuilder(restClientGetter)

	clientConfig, err := restClientGetter.ToRESTConfig()
	if err != nil {
		return err
	}

	o.certificatesV1Client, err = v1.NewForConfig(clientConfig)
	if err != nil {
		return err
	}

	return nil
}


Validate

// Validate checks if the provided `certificate` arguments are valid
func (o *CertificateOptions) Validate() error {
	if len(o.csrNames) < 1 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) {
		return fmt.Errorf("one or more CSRs must be specified as <name> or -f <filename>")
	}
	return nil
}


NewCmdCertificateApprove

// NewCmdCertificateApprove returns the `certificate approve` Cobra command
func NewCmdCertificateApprove(restClientGetter genericclioptions.RESTClientGetter, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewCertificateOptions(ioStreams, "approved")

	cmd := &cobra.Command{
		Use:                   "approve (-f FILENAME | NAME)",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Approve a certificate signing request"),
		Long: templates.LongDesc(i18n.T(`
		Approve a certificate signing request.

		kubectl certificate approve allows a cluster admin to approve a certificate
		signing request (CSR). This action tells a certificate signing controller to
		issue a certificate to the requestor with the attributes requested in the CSR.

		SECURITY NOTICE: Depending on the requested attributes, the issued certificate
		can potentially grant a requester access to cluster resources or to authenticate
		as a requested identity. Before approving a CSR, ensure you understand what the
		signed certificate can do.
		`)),
		Example: templates.Examples(i18n.T(`
			# Approve CSR 'csr-sqgzp'
			kubectl certificate approve csr-sqgzp
		`)),
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(restClientGetter, cmd, args))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.RunCertificateApprove(cmdutil.GetFlagBool(cmd, "force")))
		},
	}

	o.PrintFlags.AddFlags(cmd)

	cmd.Flags().Bool("force", false, "Update the CSR even if it is already approved.")
	cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to update")

	return cmd
}


RunCertificateApprove

// RunCertificateApprove approves a certificate signing request
func (o *CertificateOptions) RunCertificateApprove(force bool) error {
	return o.modifyCertificateCondition(
		o.builder,
		force,
		addConditionIfNeeded(string(certificatesv1.CertificateDenied), string(certificatesv1.CertificateApproved), "KubectlApprove", "This CSR was approved by kubectl certificate approve."),
	)
}


NewCmdCertificateDeny

// NewCmdCertificateDeny returns the `certificate deny` Cobra command
func NewCmdCertificateDeny(restClientGetter genericclioptions.RESTClientGetter, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewCertificateOptions(ioStreams, "denied")

	cmd := &cobra.Command{
		Use:                   "deny (-f FILENAME | NAME)",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Deny a certificate signing request"),
		Long: templates.LongDesc(i18n.T(`
		Deny a certificate signing request.

		kubectl certificate deny allows a cluster admin to deny a certificate
		signing request (CSR). This action tells a certificate signing controller to
		not to issue a certificate to the requestor.
		`)),
		Example: templates.Examples(i18n.T(`
			# Deny CSR 'csr-sqgzp'
			kubectl certificate deny csr-sqgzp
		`)),
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(restClientGetter, cmd, args))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.RunCertificateDeny(cmdutil.GetFlagBool(cmd, "force")))
		},
	}

	o.PrintFlags.AddFlags(cmd)

	cmd.Flags().Bool("force", false, "Update the CSR even if it is already denied.")
	cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to update")

	return cmd
}


RunCertificateDeny

// RunCertificateDeny denies a certificate signing request
func (o *CertificateOptions) RunCertificateDeny(force bool) error {
	return o.modifyCertificateCondition(
		o.builder,
		force,
		addConditionIfNeeded(string(certificatesv1.CertificateApproved), string(certificatesv1.CertificateDenied), "KubectlDeny", "This CSR was denied by kubectl certificate deny."),
	)
}


modifyCertificateCondition

func (o *CertificateOptions) modifyCertificateCondition(builder *resource.Builder, force bool, modify func(csr runtime.Object) (runtime.Object, bool, error)) error {
	var found int
	r := builder.
		Unstructured().
		ContinueOnError().
		FilenameParam(false, &o.FilenameOptions).
		ResourceNames("certificatesigningrequests", o.csrNames...).
		RequireObject(true).
		Flatten().
		Latest().
		Do()
	err := r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		for i := 0; ; i++ {
			obj, ok := info.Object.(*unstructured.Unstructured)
			if !ok {
				return fmt.Errorf("expected *unstructured.Unstructured, got %T", obj)
			}
			if want, got := certificatesv1.Kind("CertificateSigningRequest"), obj.GetObjectKind().GroupVersionKind().GroupKind(); want != got {
				return fmt.Errorf("can only handle %s objects, got %s", want.String(), got.String())
			}
			var csr runtime.Object
			// get a typed object
			csr, err = o.certificatesV1Client.CertificateSigningRequests().Get(context.TODO(), obj.GetName(), metav1.GetOptions{})
			if apierrors.IsNotFound(err) {
				return fmt.Errorf("could not find v1 version of %s: %v", obj.GetName(), err)
			}
			if err != nil {
				return err
			}

			modifiedCSR, hasCondition, err := modify(csr)
			if err != nil {
				return err
			}
			if !hasCondition || force {
				if mCSR, ok := modifiedCSR.(*certificatesv1.CertificateSigningRequest); ok {
					_, err = o.certificatesV1Client.CertificateSigningRequests().UpdateApproval(context.TODO(), mCSR.Name, mCSR, metav1.UpdateOptions{})
				} else {
					return fmt.Errorf("can only handle certificates.k8s.io CertificateSigningRequest objects, got %T", mCSR)
				}

				if apierrors.IsConflict(err) && i < 10 {
					if err := info.Get(); err != nil {
						return err
					}
					continue
				}
				if err != nil {
					return err
				}
			}
			break
		}
		found++

		return o.PrintObj(info.Object, o.Out)
	})
	if found == 0 && err == nil {
		fmt.Fprintf(o.Out, "No resources found\n")
	}
	return err
}


addConditionIfNeeded

func addConditionIfNeeded(mustNotHaveConditionType, conditionType, reason, message string) func(runtime.Object) (runtime.Object, bool, error) {
	return func(obj runtime.Object) (runtime.Object, bool, error) {
		if csr, ok := obj.(*certificatesv1.CertificateSigningRequest); ok {
			var alreadyHasCondition bool
			for _, c := range csr.Status.Conditions {
				if string(c.Type) == mustNotHaveConditionType {
					return nil, false, fmt.Errorf("certificate signing request %q is already %s", csr.Name, c.Type)
				}
				if string(c.Type) == conditionType {
					alreadyHasCondition = true
				}
			}
			if alreadyHasCondition {
				return csr, true, nil
			}
			csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1.CertificateSigningRequestCondition{
				Type:           certificatesv1.RequestConditionType(conditionType),
				Status:         corev1.ConditionTrue,
				Reason:         reason,
				Message:        message,
				LastUpdateTime: metav1.Now(),
			})
			return csr, false, nil
		} else {
			return csr, false, nil
		}
	}
}


NewCmdClusterInfo

func NewCmdClusterInfo(restClientGetter genericclioptions.RESTClientGetter, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := &ClusterInfoOptions{
		IOStreams: ioStreams,
	}

	cmd := &cobra.Command{
		Use:     "cluster-info",
		Short:   i18n.T("Display cluster information"),
		Long:    longDescr,
		Example: clusterinfoExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(restClientGetter, cmd))
			cmdutil.CheckErr(o.Run())
		},
	}
	cmd.AddCommand(NewCmdClusterInfoDump(restClientGetter, ioStreams))
	return cmd
}


Complete

func (o *ClusterInfoOptions) Complete(restClientGetter genericclioptions.RESTClientGetter, cmd *cobra.Command) error {
	var err error
	o.Client, err = restClientGetter.ToRESTConfig()
	if err != nil {
		return err
	}

	cmdNamespace := cmdutil.GetFlagString(cmd, "namespace")
	if cmdNamespace == "" {
		cmdNamespace = metav1.NamespaceSystem
	}
	o.Namespace = cmdNamespace

	o.Builder = resource.NewBuilder(restClientGetter)
	return nil
}


Run

func (o *ClusterInfoOptions) Run() error {
	// TODO use generalized labels once they are implemented (#341)
	b := o.Builder.
		WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
		NamespaceParam(o.Namespace).DefaultNamespace().
		LabelSelectorParam("kubernetes.io/cluster-service=true").
		ResourceTypeOrNameArgs(false, []string{"services"}...).
		Latest()
	err := b.Do().Visit(func(r *resource.Info, err error) error {
		if err != nil {
			return err
		}
		printService(o.Out, "Kubernetes control plane", o.Client.Host)

		services := r.Object.(*corev1.ServiceList).Items
		for _, service := range services {
			var link string
			if len(service.Status.LoadBalancer.Ingress) > 0 {
				ingress := service.Status.LoadBalancer.Ingress[0]
				ip := ingress.IP
				if ip == "" {
					ip = ingress.Hostname
				}
				for _, port := range service.Spec.Ports {
					link += "http://" + ip + ":" + strconv.Itoa(int(port.Port)) + " "
				}
			} else {
				name := service.ObjectMeta.Name

				if len(service.Spec.Ports) > 0 {
					port := service.Spec.Ports[0]

					// guess if the scheme is https
					scheme := ""
					if port.Name == "https" || port.Port == 443 {
						scheme = "https"
					}

					// format is <scheme>:<service-name>:<service-port-name>
					name = utilnet.JoinSchemeNamePort(scheme, service.ObjectMeta.Name, port.Name)
				}

				if len(o.Client.GroupVersion.Group) == 0 {
					link = o.Client.Host + "/api/" + o.Client.GroupVersion.Version + "/namespaces/" + service.ObjectMeta.Namespace + "/services/" + name + "/proxy"
				} else {
					link = o.Client.Host + "/api/" + o.Client.GroupVersion.Group + "/" + o.Client.GroupVersion.Version + "/namespaces/" + service.ObjectMeta.Namespace + "/services/" + name + "/proxy"

				}
			}
			name := service.ObjectMeta.Labels["kubernetes.io/name"]
			if len(name) == 0 {
				name = service.ObjectMeta.Name
			}
			printService(o.Out, name, link)
		}
		return nil
	})
	o.Out.Write([]byte("\nTo further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.\n"))
	return err

	// TODO consider printing more information about cluster
}


printService

func printService(out io.Writer, name, link string) {
	ct.ChangeColor(ct.Green, false, ct.None, false)
	fmt.Fprint(out, name)
	ct.ResetColor()
	fmt.Fprint(out, " is running at ")
	ct.ChangeColor(ct.Yellow, false, ct.None, false)
	fmt.Fprint(out, link)
	ct.ResetColor()
	fmt.Fprintln(out, "")
}


NewCmdClusterInfoDump

func NewCmdClusterInfoDump(restClientGetter genericclioptions.RESTClientGetter, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := &ClusterInfoDumpOptions{
		PrintFlags: genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme).WithDefaultOutput("json"),

		IOStreams: ioStreams,
	}

	cmd := &cobra.Command{
		Use:     "dump",
		Short:   i18n.T("Dump relevant information for debugging and diagnosis"),
		Long:    dumpLong,
		Example: dumpExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(restClientGetter, cmd))
			cmdutil.CheckErr(o.Run())
		},
	}

	o.PrintFlags.AddFlags(cmd)

	cmd.Flags().StringVar(&o.OutputDir, "output-directory", o.OutputDir, i18n.T("Where to output the files.  If empty or '-' uses stdout, otherwise creates a directory hierarchy in that directory"))
	cmd.Flags().StringSliceVar(&o.Namespaces, "namespaces", o.Namespaces, "A comma separated list of namespaces to dump.")
	cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If true, dump all namespaces.  If true, --namespaces is ignored.")
	cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodLogsTimeout)
	return cmd
}


setupOutputWriter

func setupOutputWriter(dir string, defaultWriter io.Writer, filename string, fileExtension string) io.Writer {
	if len(dir) == 0 || dir == "-" {
		return defaultWriter
	}
	fullFile := path.Join(dir, filename) + fileExtension
	parent := path.Dir(fullFile)
	cmdutil.CheckErr(os.MkdirAll(parent, 0755))

	file, err := os.Create(fullFile)
	cmdutil.CheckErr(err)
	return file
}


Complete

func (o *ClusterInfoDumpOptions) Complete(restClientGetter genericclioptions.RESTClientGetter, cmd *cobra.Command) error {
	printer, err := o.PrintFlags.ToPrinter()
	if err != nil {
		return err
	}

	o.PrintObj = printer.PrintObj

	config, err := restClientGetter.ToRESTConfig()
	if err != nil {
		return err
	}

	o.CoreClient, err = corev1client.NewForConfig(config)
	if err != nil {
		return err
	}

	o.AppsClient, err = appsv1client.NewForConfig(config)
	if err != nil {
		return err
	}

	o.Timeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd)
	if err != nil {
		return err
	}

	o.Namespace, _, err = restClientGetter.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return err
	}

	o.RESTClientGetter = restClientGetter
	o.LogsForObject = polymorphichelpers.LogsForObjectFn

	return nil
}


Run

func (o *ClusterInfoDumpOptions) Run() error {
	nodes, err := o.CoreClient.Nodes().List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return err
	}

	fileExtension := ".txt"
	if o.PrintFlags.OutputFormat != nil {
		switch *o.PrintFlags.OutputFormat {
		case "json":
			fileExtension = ".json"
		case "yaml":
			fileExtension = ".yaml"
		}
	}

	if err := o.PrintObj(nodes, setupOutputWriter(o.OutputDir, o.Out, "nodes", fileExtension)); err != nil {
		return err
	}

	var namespaces []string
	if o.AllNamespaces {
		namespaceList, err := o.CoreClient.Namespaces().List(context.TODO(), metav1.ListOptions{})
		if err != nil {
			return err
		}
		for ix := range namespaceList.Items {
			namespaces = append(namespaces, namespaceList.Items[ix].Name)
		}
	} else {
		if len(o.Namespaces) == 0 {
			namespaces = []string{
				metav1.NamespaceSystem,
				o.Namespace,
			}
		} else {
			namespaces = o.Namespaces
		}
	}
	for _, namespace := range namespaces {
		// TODO: this is repetitive in the extreme.  Use reflection or
		// something to make this a for loop.
		events, err := o.CoreClient.Events(namespace).List(context.TODO(), metav1.ListOptions{})
		if err != nil {
			return err
		}
		if err := o.PrintObj(events, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "events"), fileExtension)); err != nil {
			return err
		}

		rcs, err := o.CoreClient.ReplicationControllers(namespace).List(context.TODO(), metav1.ListOptions{})
		if err != nil {
			return err
		}
		if err := o.PrintObj(rcs, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "replication-controllers"), fileExtension)); err != nil {
			return err
		}

		svcs, err := o.CoreClient.Services(namespace).List(context.TODO(), metav1.ListOptions{})
		if err != nil {
			return err
		}
		if err := o.PrintObj(svcs, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "services"), fileExtension)); err != nil {
			return err
		}

		sets, err := o.AppsClient.DaemonSets(namespace).List(context.TODO(), metav1.ListOptions{})
		if err != nil {
			return err
		}
		if err := o.PrintObj(sets, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "daemonsets"), fileExtension)); err != nil {
			return err
		}

		deps, err := o.AppsClient.Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
		if err != nil {
			return err
		}
		if err := o.PrintObj(deps, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "deployments"), fileExtension)); err != nil {
			return err
		}

		rps, err := o.AppsClient.ReplicaSets(namespace).List(context.TODO(), metav1.ListOptions{})
		if err != nil {
			return err
		}
		if err := o.PrintObj(rps, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "replicasets"), fileExtension)); err != nil {
			return err
		}

		pods, err := o.CoreClient.Pods(namespace).List(context.TODO(), metav1.ListOptions{})
		if err != nil {
			return err
		}

		if err := o.PrintObj(pods, setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, "pods"), fileExtension)); err != nil {
			return err
		}

		printContainer := func(writer io.Writer, container corev1.Container, pod *corev1.Pod) {
			writer.Write([]byte(fmt.Sprintf("==== START logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
			defer writer.Write([]byte(fmt.Sprintf("==== END logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))

			requests, err := o.LogsForObject(o.RESTClientGetter, pod, &corev1.PodLogOptions{Container: container.Name}, timeout, false)
			if err != nil {
				// Print error and return.
				writer.Write([]byte(fmt.Sprintf("Create log request error: %s\n", err.Error())))
				return
			}

			for _, request := range requests {
				data, err := request.DoRaw(context.TODO())
				if err != nil {
					// Print error and return.
					writer.Write([]byte(fmt.Sprintf("Request log error: %s\n", err.Error())))
					return
				}
				writer.Write(data)
			}
		}

		for ix := range pods.Items {
			pod := &pods.Items[ix]
			initcontainers := pod.Spec.InitContainers
			containers := pod.Spec.Containers
			writer := setupOutputWriter(o.OutputDir, o.Out, path.Join(namespace, pod.Name, "logs"), ".txt")

			for i := range initcontainers {
				printContainer(writer, initcontainers[i], pod)
			}
			for i := range containers {
				printContainer(writer, containers[i], pod)
			}
		}
	}

	dest := o.OutputDir
	if len(dest) > 0 && dest != "-" {
		fmt.Fprintf(o.Out, "Cluster info dumped to %s\n", dest)
	}
	return nil
}


NewDefaultKubectlCommand

// NewDefaultKubectlCommand creates the `kubectl` command with default arguments
func NewDefaultKubectlCommand() *cobra.Command {
	return NewDefaultKubectlCommandWithArgs(KubectlOptions{
		PluginHandler: NewDefaultPluginHandler(plugin.ValidPluginFilenamePrefixes),
		Arguments:     os.Args,
		ConfigFlags:   defaultConfigFlags,
		IOStreams:     genericclioptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr},
	})
}


NewDefaultKubectlCommandWithArgs

// NewDefaultKubectlCommandWithArgs creates the `kubectl` command with arguments
func NewDefaultKubectlCommandWithArgs(o KubectlOptions) *cobra.Command {
	cmd := NewKubectlCommand(o)

	if o.PluginHandler == nil {
		return cmd
	}

	if len(o.Arguments) > 1 {
		cmdPathPieces := o.Arguments[1:]

		// only look for suitable extension executables if
		// the specified command does not already exist
		if foundCmd, foundArgs, err := cmd.Find(cmdPathPieces); err != nil {
			// Also check the commands that will be added by Cobra.
			// These commands are only added once rootCmd.Execute() is called, so we
			// need to check them explicitly here.
			var cmdName string // first "non-flag" arguments
			for _, arg := range cmdPathPieces {
				if !strings.HasPrefix(arg, "-") {
					cmdName = arg
					break
				}
			}

			switch cmdName {
			case "help", cobra.ShellCompRequestCmd, cobra.ShellCompNoDescRequestCmd:
				// Don't search for a plugin
			default:
				if err := HandlePluginCommand(o.PluginHandler, cmdPathPieces, false); err != nil {
					fmt.Fprintf(o.IOStreams.ErrOut, "Error: %v\n", err)
					os.Exit(1)
				}
			}
		} else if err == nil {
			if cmdutil.CmdPluginAsSubcommand.IsEnabled() {
				// Command exists(e.g. kubectl create), but it is not certain that
				// subcommand also exists (e.g. kubectl create networkpolicy)
				if _, ok := allowedCmdsSubcommandPlugin[foundCmd.Name()]; ok {
					var subcommand string
					for _, arg := range foundArgs { // first "non-flag" argument as subcommand
						if !strings.HasPrefix(arg, "-") {
							subcommand = arg
							break
						}
					}
					builtinSubcmdExist := false
					for _, subcmd := range foundCmd.Commands() {
						if subcmd.Name() == subcommand {
							builtinSubcmdExist = true
							break
						}
					}

					if !builtinSubcmdExist {
						if err := HandlePluginCommand(o.PluginHandler, cmdPathPieces, true); err != nil {
							fmt.Fprintf(o.IOStreams.ErrOut, "Error: %v\n", err)
							os.Exit(1)
						}
					}
				}
			}
		}
	}

	return cmd
}


NewDefaultPluginHandler

// NewDefaultPluginHandler instantiates the DefaultPluginHandler with a list of
// given filename prefixes used to identify valid plugin filenames.
func NewDefaultPluginHandler(validPrefixes []string) *DefaultPluginHandler {
	return &DefaultPluginHandler{
		ValidPrefixes: validPrefixes,
	}
}


Lookup

// Lookup implements PluginHandler
func (h *DefaultPluginHandler) Lookup(filename string) (string, bool) {
	for _, prefix := range h.ValidPrefixes {
		path, err := exec.LookPath(fmt.Sprintf("%s-%s", prefix, filename))
		if shouldSkipOnLookPathErr(err) || len(path) == 0 {
			continue
		}
		return path, true
	}
	return "", false
}


Command

func Command(name string, arg ...string) *exec.Cmd {
	cmd := &exec.Cmd{
		Path: name,
		Args: append([]string{name}, arg...),
	}
	if filepath.Base(name) == name {
		lp, err := exec.LookPath(name)
		if lp != "" && !shouldSkipOnLookPathErr(err) {
			// Update cmd.Path even if err is non-nil.
			// If err is ErrDot (especially on Windows), lp may include a resolved
			// extension (like .exe or .bat) that should be preserved.
			cmd.Path = lp
		}
	}
	return cmd
}


Execute

// Execute implements PluginHandler
func (h *DefaultPluginHandler) Execute(executablePath string, cmdArgs, environment []string) error {

	// Windows does not support exec syscall.
	if runtime.GOOS == "windows" {
		cmd := Command(executablePath, cmdArgs...)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		cmd.Stdin = os.Stdin
		cmd.Env = environment
		err := cmd.Run()
		if err == nil {
			os.Exit(0)
		}
		return err
	}

	// invoke cmd binary relaying the environment and args given
	// append executablePath to cmdArgs, as execve will make first argument the "binary name".
	return syscall.Exec(executablePath, append([]string{executablePath}, cmdArgs...), environment)
}


HandlePluginCommand

// HandlePluginCommand receives a pluginHandler and command-line arguments and attempts to find
// a plugin executable on the PATH that satisfies the given arguments.
func HandlePluginCommand(pluginHandler PluginHandler, cmdArgs []string, exactMatch bool) error {
	var remainingArgs []string // all "non-flag" arguments
	for _, arg := range cmdArgs {
		if strings.HasPrefix(arg, "-") {
			break
		}
		remainingArgs = append(remainingArgs, strings.Replace(arg, "-", "_", -1))
	}

	if len(remainingArgs) == 0 {
		// the length of cmdArgs is at least 1
		return fmt.Errorf("flags cannot be placed before plugin name: %s", cmdArgs[0])
	}

	foundBinaryPath := ""

	// attempt to find binary, starting at longest possible name with given cmdArgs
	for len(remainingArgs) > 0 {
		path, found := pluginHandler.Lookup(strings.Join(remainingArgs, "-"))
		if !found {
			if exactMatch {
				// if exactMatch is true, we shouldn't continue searching with shorter names.
				// this is especially for not searching kubectl-create plugin
				// when kubectl-create-foo plugin is not found.
				break
			}
			remainingArgs = remainingArgs[:len(remainingArgs)-1]
			continue
		}

		foundBinaryPath = path
		break
	}

	if len(foundBinaryPath) == 0 {
		return nil
	}

	// invoke cmd binary relaying the current environment and args given
	if err := pluginHandler.Execute(foundBinaryPath, cmdArgs[len(remainingArgs):], os.Environ()); err != nil {
		return err
	}

	return nil
}


NewKubectlCommand

// NewKubectlCommand creates the `kubectl` command and its nested children.
func NewKubectlCommand(o KubectlOptions) *cobra.Command {
	warningHandler := rest.NewWarningWriter(o.IOStreams.ErrOut, rest.WarningWriterOptions{Deduplicate: true, Color: term.AllowsColorOutput(o.IOStreams.ErrOut)})
	warningsAsErrors := false
	// Parent command to which all subcommands are added.
	cmds := &cobra.Command{
		Use:   "kubectl",
		Short: i18n.T("kubectl controls the Kubernetes cluster manager"),
		Long: templates.LongDesc(`
      kubectl controls the Kubernetes cluster manager.

      Find more information at:
            https://kubernetes.io/docs/reference/kubectl/`),
		Run: runHelp,
		// Hook before and after Run initialize and write profiles to disk,
		// respectively.
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			rest.SetDefaultWarningHandler(warningHandler)

			if cmd.Name() == cobra.ShellCompRequestCmd {
				// This is the __complete or __completeNoDesc command which
				// indicates shell completion has been requested.
				plugin.SetupPluginCompletion(cmd, args)
			}

			return initProfiling()
		},
		PersistentPostRunE: func(*cobra.Command, []string) error {
			if err := flushProfiling(); err != nil {
				return err
			}
			if warningsAsErrors {
				count := warningHandler.WarningCount()
				switch count {
				case 0:
					// no warnings
				case 1:
					return fmt.Errorf("%d warning received", count)
				default:
					return fmt.Errorf("%d warnings received", count)
				}
			}
			return nil
		},
	}
	// From this point and forward we get warnings on flags that contain "_" separators
	// when adding them with hyphen instead of the original name.
	cmds.SetGlobalNormalizationFunc(cliflag.WarnWordSepNormalizeFunc)

	flags := cmds.PersistentFlags()

	addProfilingFlags(flags)

	flags.BoolVar(&warningsAsErrors, "warnings-as-errors", warningsAsErrors, "Treat warnings received from the server as errors and exit with a non-zero exit code")

	kubeConfigFlags := o.ConfigFlags
	if kubeConfigFlags == nil {
		kubeConfigFlags = defaultConfigFlags
	}
	kubeConfigFlags.AddFlags(flags)
	matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags)
	matchVersionKubeConfigFlags.AddFlags(flags)
	// Updates hooks to add kubectl command headers: SIG CLI KEP 859.
	addCmdHeaderHooks(cmds, kubeConfigFlags)

	f := cmdutil.NewFactory(matchVersionKubeConfigFlags)

	// Proxy command is incompatible with CommandHeaderRoundTripper, so
	// clear the WrapConfigFn before running proxy command.
	proxyCmd := proxy.NewCmdProxy(f, o.IOStreams)
	proxyCmd.PreRun = func(cmd *cobra.Command, args []string) {
		kubeConfigFlags.WrapConfigFn = nil
	}

	// Avoid import cycle by setting ValidArgsFunction here instead of in NewCmdGet()
	getCmd := get.NewCmdGet("kubectl", f, o.IOStreams)
	getCmd.ValidArgsFunction = utilcomp.ResourceTypeAndNameCompletionFunc(f)

	groups := templates.CommandGroups{
		{
			Message: "Basic Commands (Beginner):",
			Commands: []*cobra.Command{
				create.NewCmdCreate(f, o.IOStreams),
				expose.NewCmdExposeService(f, o.IOStreams),
				run.NewCmdRun(f, o.IOStreams),
				set.NewCmdSet(f, o.IOStreams),
			},
		},
		{
			Message: "Basic Commands (Intermediate):",
			Commands: []*cobra.Command{
				explain.NewCmdExplain("kubectl", f, o.IOStreams),
				getCmd,
				edit.NewCmdEdit(f, o.IOStreams),
				delete.NewCmdDelete(f, o.IOStreams),
			},
		},
		{
			Message: "Deploy Commands:",
			Commands: []*cobra.Command{
				rollout.NewCmdRollout(f, o.IOStreams),
				scale.NewCmdScale(f, o.IOStreams),
				autoscale.NewCmdAutoscale(f, o.IOStreams),
			},
		},
		{
			Message: "Cluster Management Commands:",
			Commands: []*cobra.Command{
				certificates.NewCmdCertificate(f, o.IOStreams),
				clusterinfo.NewCmdClusterInfo(f, o.IOStreams),
				top.NewCmdTop(f, o.IOStreams),
				drain.NewCmdCordon(f, o.IOStreams),
				drain.NewCmdUncordon(f, o.IOStreams),
				drain.NewCmdDrain(f, o.IOStreams),
				taint.NewCmdTaint(f, o.IOStreams),
			},
		},
		{
			Message: "Troubleshooting and Debugging Commands:",
			Commands: []*cobra.Command{
				describe.NewCmdDescribe("kubectl", f, o.IOStreams),
				logs.NewCmdLogs(f, o.IOStreams),
				attach.NewCmdAttach(f, o.IOStreams),
				cmdexec.NewCmdExec(f, o.IOStreams),
				portforward.NewCmdPortForward(f, o.IOStreams),
				proxyCmd,
				cp.NewCmdCp(f, o.IOStreams),
				auth.NewCmdAuth(f, o.IOStreams),
				debug.NewCmdDebug(f, o.IOStreams),
				events.NewCmdEvents(f, o.IOStreams),
			},
		},
		{
			Message: "Advanced Commands:",
			Commands: []*cobra.Command{
				diff.NewCmdDiff(f, o.IOStreams),
				apply.NewCmdApply("kubectl", f, o.IOStreams),
				patch.NewCmdPatch(f, o.IOStreams),
				replace.NewCmdReplace(f, o.IOStreams),
				wait.NewCmdWait(f, o.IOStreams),
				kustomize.NewCmdKustomize(o.IOStreams),
			},
		},
		{
			Message: "Settings Commands:",
			Commands: []*cobra.Command{
				label.NewCmdLabel(f, o.IOStreams),
				annotate.NewCmdAnnotate("kubectl", f, o.IOStreams),
				completion.NewCmdCompletion(o.IOStreams.Out, ""),
			},
		},
	}
	groups.Add(cmds)

	filters := []string{"options"}

	// Hide the "alpha" subcommand if there are no alpha commands in this build.
	alpha := NewCmdAlpha(f, o.IOStreams)
	if !alpha.HasSubCommands() {
		filters = append(filters, alpha.Name())
	}

	templates.ActsAsRootCommand(cmds, filters, groups...)

	utilcomp.SetFactoryForCompletion(f)
	registerCompletionFuncForGlobalFlags(cmds, f)

	cmds.AddCommand(alpha)
	cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), o.IOStreams))
	cmds.AddCommand(plugin.NewCmdPlugin(o.IOStreams))
	cmds.AddCommand(version.NewCmdVersion(f, o.IOStreams))
	cmds.AddCommand(apiresources.NewCmdAPIVersions(f, o.IOStreams))
	cmds.AddCommand(apiresources.NewCmdAPIResources(f, o.IOStreams))
	cmds.AddCommand(options.NewCmdOptions(o.IOStreams.Out))

	// Stop warning about normalization of flags. That makes it possible to
	// add the klog flags later.
	cmds.SetGlobalNormalizationFunc(cliflag.WordSepNormalizeFunc)
	return cmds
}


addCmdHeaderHooks

// addCmdHeaderHooks performs updates on two hooks:
//  1. Modifies the passed "cmds" persistent pre-run function to parse command headers.
//     These headers will be subsequently added as X-headers to every
//     REST call.
//  2. Adds CommandHeaderRoundTripper as a wrapper around the standard
//     RoundTripper. CommandHeaderRoundTripper adds X-Headers then delegates
//     to standard RoundTripper.
//
// For beta, these hooks are updated unless the KUBECTL_COMMAND_HEADERS environment variable
// is set, and the value of the env var is false (or zero).
// See SIG CLI KEP 859 for more information:
//
//	https://github.com/kubernetes/enhancements/tree/master/keps/sig-cli/859-kubectl-headers
func addCmdHeaderHooks(cmds *cobra.Command, kubeConfigFlags *genericclioptions.ConfigFlags) {
	// If the feature gate env var is set to "false", then do no add kubectl command headers.
	if value, exists := os.LookupEnv(kubectlCmdHeaders); exists {
		if value == "false" || value == "0" {
			klog.V(5).Infoln("kubectl command headers turned off")
			return
		}
	}
	klog.V(5).Infoln("kubectl command headers turned on")
	crt := &genericclioptions.CommandHeaderRoundTripper{}
	existingPreRunE := cmds.PersistentPreRunE
	// Add command parsing to the existing persistent pre-run function.
	cmds.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
		crt.ParseCommandHeaders(cmd, args)
		return existingPreRunE(cmd, args)
	}
	wrapConfigFn := kubeConfigFlags.WrapConfigFn
	// Wraps CommandHeaderRoundTripper around standard RoundTripper.
	kubeConfigFlags.WrapConfigFn = func(c *rest.Config) *rest.Config {
		if wrapConfigFn != nil {
			c = wrapConfigFn(c)
		}
		c.Wrap(func(rt http.RoundTripper) http.RoundTripper {
			// Must be separate RoundTripper; not "crt" closure.
			// Fixes: https://github.com/kubernetes/kubectl/issues/1098
			return &genericclioptions.CommandHeaderRoundTripper{
				Delegate: rt,
				Headers:  crt.Headers,
			}
		})
		return c
	}
}


runHelp

func runHelp(cmd *cobra.Command, args []string) {
	cmd.Help()
}


registerCompletionFuncForGlobalFlags

func registerCompletionFuncForGlobalFlags(cmd *cobra.Command, f cmdutil.Factory) {
	cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc(
		"namespace",
		func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
			return utilcomp.CompGetResource(f, "namespace", toComplete), cobra.ShellCompDirectiveNoFileComp
		}))
	cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc(
		"context",
		func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
			return utilcomp.ListContextsInConfig(toComplete), cobra.ShellCompDirectiveNoFileComp
		}))
	cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc(
		"cluster",
		func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
			return utilcomp.ListClustersInConfig(toComplete), cobra.ShellCompDirectiveNoFileComp
		}))
	cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc(
		"user",
		func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
			return utilcomp.ListUsersInConfig(toComplete), cobra.ShellCompDirectiveNoFileComp
		}))
}


NewCmdCompletion

// NewCmdCompletion creates the `completion` command
func NewCmdCompletion(out io.Writer, boilerPlate string) *cobra.Command {
	shells := []string{}
	for s := range completionShells {
		shells = append(shells, s)
	}

	cmd := &cobra.Command{
		Use:                   "completion SHELL",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Output shell completion code for the specified shell (bash, zsh, fish, or powershell)"),
		Long:                  completionLong,
		Example:               completionExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(RunCompletion(out, boilerPlate, cmd, args))
		},
		ValidArgs: shells,
	}

	return cmd
}


RunCompletion

// RunCompletion checks given arguments and executes command
func RunCompletion(out io.Writer, boilerPlate string, cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return cmdutil.UsageErrorf(cmd, "Shell not specified.")
	}
	if len(args) > 1 {
		return cmdutil.UsageErrorf(cmd, "Too many arguments. Expected only the shell type.")
	}
	run, found := completionShells[args[0]]
	if !found {
		return cmdutil.UsageErrorf(cmd, "Unsupported shell type %q.", args[0])
	}

	return run(out, boilerPlate, cmd.Parent())
}


runCompletionBash

func runCompletionBash(out io.Writer, boilerPlate string, kubectl *cobra.Command) error {
	if len(boilerPlate) == 0 {
		boilerPlate = defaultBoilerPlate
	}
	if _, err := out.Write([]byte(boilerPlate)); err != nil {
		return err
	}

	return kubectl.GenBashCompletionV2(out, true)
}


runCompletionZsh

func runCompletionZsh(out io.Writer, boilerPlate string, kubectl *cobra.Command) error {
	zshHead := fmt.Sprintf("#compdef %[1]s\ncompdef _%[1]s %[1]s\n", kubectl.Name())
	out.Write([]byte(zshHead))

	if len(boilerPlate) == 0 {
		boilerPlate = defaultBoilerPlate
	}
	if _, err := out.Write([]byte(boilerPlate)); err != nil {
		return err
	}

	return kubectl.GenZshCompletion(out)
}


runCompletionFish

func runCompletionFish(out io.Writer, boilerPlate string, kubectl *cobra.Command) error {
	if len(boilerPlate) == 0 {
		boilerPlate = defaultBoilerPlate
	}
	if _, err := out.Write([]byte(boilerPlate)); err != nil {
		return err
	}

	return kubectl.GenFishCompletion(out, true)
}


runCompletionPwsh

func runCompletionPwsh(out io.Writer, boilerPlate string, kubectl *cobra.Command) error {
	if len(boilerPlate) == 0 {
		boilerPlate = defaultBoilerPlate
	}

	if _, err := out.Write([]byte(boilerPlate)); err != nil {
		return err
	}

	return kubectl.GenPowerShellCompletionWithDesc(out)
}


NewCmdConfig

// NewCmdConfig creates a command object for the "config" action, and adds all child commands to it.
func NewCmdConfig(pathOptions *clientcmd.PathOptions, streams genericclioptions.IOStreams) *cobra.Command {
	if len(pathOptions.ExplicitFileFlag) == 0 {
		pathOptions.ExplicitFileFlag = clientcmd.RecommendedConfigPathFlag
	}

	cmd := &cobra.Command{
		Use:                   "config SUBCOMMAND",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Modify kubeconfig files"),
		Long: templates.LongDesc(i18n.T(`
			Modify kubeconfig files using subcommands like "kubectl config set current-context my-context"

			The loading order follows these rules:

			1. If the --`) + pathOptions.ExplicitFileFlag + i18n.T(` flag is set, then only that file is loaded. The flag may only be set once and no merging takes place.
			2. If $`) + pathOptions.EnvVar + i18n.T(` environment variable is set, then it is used as a list of paths (normal path delimiting rules for your system). These paths are merged. When a value is modified, it is modified in the file that defines the stanza. When a value is created, it is created in the first file that exists. If no files in the chain exist, then it creates the last file in the list.
			3. Otherwise, `) + path.Join("${HOME}", pathOptions.GlobalFileSubpath) + i18n.T(` is used and no merging takes place.`)),
		Run: cmdutil.DefaultSubCommandRun(streams.ErrOut),
	}

	// file paths are common to all sub commands
	cmd.PersistentFlags().StringVar(&pathOptions.LoadingRules.ExplicitPath, pathOptions.ExplicitFileFlag, pathOptions.LoadingRules.ExplicitPath, "use a particular kubeconfig file")

	// TODO(juanvallejo): update all subcommands to work with genericclioptions.IOStreams
	cmd.AddCommand(NewCmdConfigView(streams, pathOptions))
	cmd.AddCommand(NewCmdConfigSetCluster(streams.Out, pathOptions))
	cmd.AddCommand(NewCmdConfigSetCredentials(streams.Out, pathOptions))
	cmd.AddCommand(NewCmdConfigSetContext(streams.Out, pathOptions))
	cmd.AddCommand(NewCmdConfigSet(streams.Out, pathOptions))
	cmd.AddCommand(NewCmdConfigUnset(streams.Out, pathOptions))
	cmd.AddCommand(NewCmdConfigCurrentContext(streams.Out, pathOptions))
	cmd.AddCommand(NewCmdConfigUseContext(streams.Out, pathOptions))
	cmd.AddCommand(NewCmdConfigGetContexts(streams, pathOptions))
	cmd.AddCommand(NewCmdConfigGetClusters(streams.Out, pathOptions))
	cmd.AddCommand(NewCmdConfigGetUsers(streams, pathOptions))
	cmd.AddCommand(NewCmdConfigDeleteCluster(streams.Out, pathOptions))
	cmd.AddCommand(NewCmdConfigDeleteContext(streams.Out, streams.ErrOut, pathOptions))
	cmd.AddCommand(NewCmdConfigDeleteUser(streams, pathOptions))
	cmd.AddCommand(NewCmdConfigRenameContext(streams.Out, pathOptions))

	return cmd
}


toBool

func toBool(propertyValue string) (bool, error) {
	boolValue := false
	if len(propertyValue) != 0 {
		var err error
		boolValue, err = strconv.ParseBool(propertyValue)
		if err != nil {
			return false, err
		}
	}

	return boolValue, nil
}


helpErrorf

func helpErrorf(cmd *cobra.Command, format string, args ...interface{}) error {
	cmd.Help()
	msg := fmt.Sprintf(format, args...)
	return fmt.Errorf("%s", msg)
}


NewCmdConfigCurrentContext

// NewCmdConfigCurrentContext returns a Command instance for 'config current-context' sub command
func NewCmdConfigCurrentContext(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
	options := &CurrentContextOptions{ConfigAccess: configAccess}

	cmd := &cobra.Command{
		Use:     "current-context",
		Short:   i18n.T("Display the current-context"),
		Long:    currentContextLong,
		Example: currentContextExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(RunCurrentContext(out, options))
		},
	}

	return cmd
}


RunCurrentContext

// RunCurrentContext performs the execution of 'config current-context' sub command
func RunCurrentContext(out io.Writer, options *CurrentContextOptions) error {
	config, err := options.ConfigAccess.GetStartingConfig()
	if err != nil {
		return err
	}

	if config.CurrentContext == "" {
		err = fmt.Errorf("current-context is not set")
		return err
	}

	fmt.Fprintf(out, "%s\n", config.CurrentContext)
	return nil
}


NewCmdConfigDeleteCluster

// NewCmdConfigDeleteCluster returns a Command instance for 'config delete-cluster' sub command
func NewCmdConfigDeleteCluster(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
	cmd := &cobra.Command{
		Use:                   "delete-cluster NAME",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Delete the specified cluster from the kubeconfig"),
		Long:                  i18n.T("Delete the specified cluster from the kubeconfig."),
		Example:               deleteClusterExample,
		ValidArgsFunction:     completion.ClusterCompletionFunc,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(runDeleteCluster(out, configAccess, cmd))
		},
	}

	return cmd
}


runDeleteCluster

func runDeleteCluster(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.Clusters[name]
	if !ok {
		return fmt.Errorf("cannot delete cluster %s, not in %s", name, configFile)
	}

	delete(config.Clusters, name)

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

	fmt.Fprintf(out, "deleted cluster %s from %s\n", name, configFile)

	return nil
}


NewCmdConfigDeleteContext

// NewCmdConfigDeleteContext returns a Command instance for 'config delete-context' sub command
func NewCmdConfigDeleteContext(out, errOut io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
	cmd := &cobra.Command{
		Use:                   "delete-context NAME",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Delete the specified context from the kubeconfig"),
		Long:                  i18n.T("Delete the specified context from the kubeconfig."),
		Example:               deleteContextExample,
		ValidArgsFunction:     completion.ContextCompletionFunc,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(runDeleteContext(out, errOut, configAccess, cmd))
		},
	}

	return cmd
}


runDeleteContext

func runDeleteContext(out, errOut 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)
	}

	if config.CurrentContext == name {
		fmt.Fprint(errOut, "warning: this removed your active context, use \"kubectl config use-context\" to select a different one\n")
	}

	delete(config.Contexts, name)

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

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

	return nil
}


NewDeleteUserOptions

// NewDeleteUserOptions creates the options for the command
func NewDeleteUserOptions(ioStreams genericclioptions.IOStreams, configAccess clientcmd.ConfigAccess) *DeleteUserOptions {
	return &DeleteUserOptions{
		configAccess: configAccess,
		IOStreams:    ioStreams,
	}
}


NewCmdConfigDeleteUser

// NewCmdConfigDeleteUser returns a Command instance for 'config delete-user' sub command
func NewCmdConfigDeleteUser(streams genericclioptions.IOStreams, configAccess clientcmd.ConfigAccess) *cobra.Command {
	o := NewDeleteUserOptions(streams, configAccess)

	cmd := &cobra.Command{
		Use:                   "delete-user NAME",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Delete the specified user from the kubeconfig"),
		Long:                  i18n.T("Delete the specified user from the kubeconfig."),
		Example:               deleteUserExample,
		ValidArgsFunction:     completion.UserCompletionFunc,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(cmd, args))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.Run())
		},
	}

	return cmd
}


Complete

// Complete sets up the command to run
func (o *DeleteUserOptions) Complete(cmd *cobra.Command, args []string) error {
	config, err := o.configAccess.GetStartingConfig()
	if err != nil {
		return err
	}
	o.config = config

	if len(args) != 1 {
		return cmdutil.UsageErrorf(cmd, "user to delete is required")
	}
	o.user = args[0]

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

	return nil
}


Validate

// Validate ensures the command has enough info to run
func (o *DeleteUserOptions) Validate() error {
	_, ok := o.config.AuthInfos[o.user]
	if !ok {
		return fmt.Errorf("cannot delete user %s, not in %s", o.user, o.configFile)
	}

	return nil
}


Run

// Run performs the command
func (o *DeleteUserOptions) Run() error {
	delete(o.config.AuthInfos, o.user)

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

	fmt.Fprintf(o.Out, "deleted user %s from %s\n", o.user, o.configFile)

	return nil
}


NewCmdConfigGetClusters

// NewCmdConfigGetClusters creates a command object for the "get-clusters" action, which
// lists all clusters defined in the kubeconfig.
func NewCmdConfigGetClusters(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
	cmd := &cobra.Command{
		Use:     "get-clusters",
		Short:   i18n.T("Display clusters defined in the kubeconfig"),
		Long:    i18n.T("Display clusters defined in the kubeconfig."),
		Example: getClustersExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(runGetClusters(out, configAccess))
		},
	}

	return cmd
}


runGetClusters

func runGetClusters(out io.Writer, configAccess clientcmd.ConfigAccess) error {
	config, err := configAccess.GetStartingConfig()
	if err != nil {
		return err
	}

	fmt.Fprintf(out, "NAME\n")
	for name := range config.Clusters {
		fmt.Fprintf(out, "%s\n", name)
	}

	return nil
}


NewCmdConfigGetContexts

// NewCmdConfigGetContexts creates a command object for the "get-contexts" action, which
// retrieves one or more contexts from a kubeconfig.
func NewCmdConfigGetContexts(streams genericclioptions.IOStreams, configAccess clientcmd.ConfigAccess) *cobra.Command {
	options := &GetContextsOptions{
		configAccess: configAccess,

		IOStreams: streams,
	}

	cmd := &cobra.Command{
		Use:                   "get-contexts [(-o|--output=)name)]",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Describe one or many contexts"),
		Long:                  getContextsLong,
		Example:               getContextsExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(options.Complete(cmd, args))
			cmdutil.CheckErr(options.Validate())
			cmdutil.CheckErr(options.RunGetContexts())
		},
	}

	cmd.Flags().BoolVar(&options.noHeaders, "no-headers", options.noHeaders, "When using the default or custom-column output format, don't print headers (default print headers).")
	cmd.Flags().StringVarP(&options.outputFormat, "output", "o", options.outputFormat, `Output format. One of: (name).`)
	return cmd
}


Complete

// Complete assigns GetContextsOptions from the args.
func (o *GetContextsOptions) Complete(cmd *cobra.Command, args []string) error {
	supportedOutputTypes := sets.NewString("", "name")
	if !supportedOutputTypes.Has(o.outputFormat) {
		return fmt.Errorf("--output %v is not available in kubectl config get-contexts; resetting to default output format", o.outputFormat)
	}
	o.contextNames = args
	o.nameOnly = false
	if o.outputFormat == "name" {
		o.nameOnly = true
	}
	o.showHeaders = true
	if cmdutil.GetFlagBool(cmd, "no-headers") || o.nameOnly {
		o.showHeaders = false
	}

	return nil
}


Validate

// Validate ensures the of output format
func (o *GetContextsOptions) Validate() error {
	return nil
}


RunGetContexts

// RunGetContexts implements all the necessary functionality for context retrieval.
func (o GetContextsOptions) RunGetContexts() error {
	config, err := o.configAccess.GetStartingConfig()
	if err != nil {
		return err
	}

	out, found := o.Out.(*tabwriter.Writer)
	if !found {
		out = printers.GetNewTabWriter(o.Out)
		defer out.Flush()
	}

	// Build a list of context names to print, and warn if any requested contexts are not found.
	// Do this before printing the headers so it doesn't look ugly.
	allErrs := []error{}
	toPrint := []string{}
	if len(o.contextNames) == 0 {
		for name := range config.Contexts {
			toPrint = append(toPrint, name)
		}
	} else {
		for _, name := range o.contextNames {
			_, ok := config.Contexts[name]
			if ok {
				toPrint = append(toPrint, name)
			} else {
				allErrs = append(allErrs, fmt.Errorf("context %v not found", name))
			}
		}
	}
	if o.showHeaders {
		err = printContextHeaders(out, o.nameOnly)
		if err != nil {
			allErrs = append(allErrs, err)
		}
	}

	sort.Strings(toPrint)
	for _, name := range toPrint {
		err = printContext(name, config.Contexts[name], out, o.nameOnly, config.CurrentContext == name)
		if err != nil {
			allErrs = append(allErrs, err)
		}
	}

	return utilerrors.NewAggregate(allErrs)
}


printContextHeaders

func printContextHeaders(out io.Writer, nameOnly bool) error {
	columnNames := []string{"CURRENT", "NAME", "CLUSTER", "AUTHINFO", "NAMESPACE"}
	if nameOnly {
		columnNames = columnNames[:1]
	}
	_, err := fmt.Fprintf(out, "%s\n", strings.Join(columnNames, "\t"))
	return err
}


printContext

func printContext(name string, context *clientcmdapi.Context, w io.Writer, nameOnly, current bool) error {
	if nameOnly {
		_, err := fmt.Fprintf(w, "%s\n", name)
		return err
	}
	prefix := " "
	if current {
		prefix = "*"
	}
	_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", prefix, name, context.Cluster, context.AuthInfo, context.Namespace)
	return err
}


NewGetUsersOptions

// NewGetUsersOptions creates the options for the command
func NewGetUsersOptions(ioStreams genericclioptions.IOStreams, configAccess clientcmd.ConfigAccess) *GetUsersOptions {
	return &GetUsersOptions{
		configAccess: configAccess,
		IOStreams:    ioStreams,
	}
}


NewCmdConfigGetUsers

// NewCmdConfigGetUsers creates a command object for the "get-users" action, which
// lists all users defined in the kubeconfig.
func NewCmdConfigGetUsers(streams genericclioptions.IOStreams, configAccess clientcmd.ConfigAccess) *cobra.Command {
	o := NewGetUsersOptions(streams, configAccess)

	cmd := &cobra.Command{
		Use:     "get-users",
		Short:   i18n.T("Display users defined in the kubeconfig"),
		Long:    i18n.T("Display users defined in the kubeconfig."),
		Example: getUsersExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Run())
		},
	}

	return cmd
}


Run

// Run performs the command
func (o *GetUsersOptions) Run() error {
	config, err := o.configAccess.GetStartingConfig()
	if err != nil {
		return err
	}

	users := make([]string, 0, len(config.AuthInfos))
	for user := range config.AuthInfos {
		users = append(users, user)
	}
	sort.Strings(users)

	fmt.Fprintf(o.Out, "NAME\n")
	for _, user := range users {
		fmt.Fprintf(o.Out, "%s\n", user)
	}

	return nil
}


newNavigationSteps

func newNavigationSteps(path string) (*navigationSteps, error) {
	steps := []navigationStep{}
	individualParts := strings.Split(path, ".")

	currType := reflect.TypeOf(clientcmdapi.Config{})
	currPartIndex := 0
	for currPartIndex < len(individualParts) {
		switch currType.Kind() {
		case reflect.Map:
			// if we're in a map, we need to locate a name.  That name may contain dots, so we need to know what tokens are legal for the map's value type
			// for example, we could have a set request like: `set clusters.10.10.12.56.insecure-skip-tls-verify true`.  We enter this case with
			// steps representing 10, 10, 12, 56, insecure-skip-tls-verify.  The name is "10.10.12.56", so we want to collect all those parts together and
			// store them as a single step.  In order to do that, we need to determine what set of tokens is a legal step AFTER the name of the map key
			// This set of reflective code pulls the type of the map values, uses that type to look up the set of legal tags.  Those legal tags are used to
			// walk the list of remaining parts until we find a match to a legal tag or the end of the string.  That name is used to burn all the used parts.
			mapValueType := currType.Elem().Elem()
			mapValueOptions, err := getPotentialTypeValues(mapValueType)
			if err != nil {
				return nil, err
			}
			nextPart := findNameStep(individualParts[currPartIndex:], sets.StringKeySet(mapValueOptions))

			steps = append(steps, navigationStep{nextPart, mapValueType})
			currPartIndex += len(strings.Split(nextPart, "."))
			currType = mapValueType

		case reflect.Struct:
			nextPart := individualParts[currPartIndex]

			options, err := getPotentialTypeValues(currType)
			if err != nil {
				return nil, err
			}
			fieldType, exists := options[nextPart]
			if !exists {
				return nil, fmt.Errorf("unable to parse %v after %v at %v", path, steps, currType)
			}

			steps = append(steps, navigationStep{nextPart, fieldType})
			currPartIndex += len(strings.Split(nextPart, "."))
			currType = fieldType
		default:
			return nil, fmt.Errorf("unable to parse one or more field values of %v", path)
		}
	}

	return &navigationSteps{steps, 0}, nil
}


pop

func (s *navigationSteps) pop() navigationStep {
	if s.moreStepsRemaining() {
		s.currentStepIndex++
		return s.steps[s.currentStepIndex-1]
	}
	return navigationStep{}
}


moreStepsRemaining

func (s *navigationSteps) moreStepsRemaining() bool {
	return len(s.steps) > s.currentStepIndex
}


findNameStep

// findNameStep takes the list of parts and a set of valid tags that can be used after the name.  It then walks the list of parts
// until it find a valid "next" tag or until it reaches the end of the parts and then builds the name back up out of the individual parts
func findNameStep(parts []string, typeOptions sets.String) string {
	if len(parts) == 0 {
		return ""
	}

	numberOfPartsInStep := findKnownValue(parts[1:], typeOptions) + 1
	// if we didn't find a known value, then the entire thing must be a name
	if numberOfPartsInStep == 0 {
		numberOfPartsInStep = len(parts)
	}
	nextParts := parts[0:numberOfPartsInStep]

	return strings.Join(nextParts, ".")
}


getPotentialTypeValues

// getPotentialTypeValues takes a type and looks up the tags used to represent its fields when serialized.
func getPotentialTypeValues(typeValue reflect.Type) (map[string]reflect.Type, error) {
	if typeValue.Kind() == reflect.Pointer {
		typeValue = typeValue.Elem()
	}

	if typeValue.Kind() != reflect.Struct {
		return nil, fmt.Errorf("%v is not of type struct", typeValue)
	}

	ret := make(map[string]reflect.Type)

	for fieldIndex := 0; fieldIndex < typeValue.NumField(); fieldIndex++ {
		fieldType := typeValue.Field(fieldIndex)
		yamlTag := fieldType.Tag.Get("json")
		yamlTagName := strings.Split(yamlTag, ",")[0]

		ret[yamlTagName] = fieldType.Type
	}

	return ret, nil
}


findKnownValue

func findKnownValue(parts []string, valueOptions sets.String) int {
	for i := range parts {
		if valueOptions.Has(parts[i]) {
			return i
		}
	}

	return -1
}


NewCmdConfigRenameContext

// NewCmdConfigRenameContext creates a command object for the "rename-context" action
func NewCmdConfigRenameContext(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
	options := &RenameContextOptions{configAccess: configAccess}

	cmd := &cobra.Command{
		Use:                   renameContextUse,
		DisableFlagsInUseLine: true,
		Short:                 renameContextShort,
		Long:                  renameContextLong,
		Example:               renameContextExample,
		ValidArgsFunction:     completion.ContextCompletionFunc,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(options.Complete(cmd, args, out))
			cmdutil.CheckErr(options.Validate())
			cmdutil.CheckErr(options.RunRenameContext(out))
		},
	}
	return cmd
}


Complete

// Complete assigns RenameContextOptions from the args.
func (o *RenameContextOptions) Complete(cmd *cobra.Command, args []string, out io.Writer) error {
	if len(args) != 2 {
		return helpErrorf(cmd, "Unexpected args: %v", args)
	}

	o.contextName = args[0]
	o.newName = args[1]
	return nil
}


Validate

// Validate makes sure that provided values for command-line options are valid
func (o RenameContextOptions) Validate() error {
	if len(o.newName) == 0 {
		return errors.New("You must specify a new non-empty context name")
	}
	return nil
}


RunRenameContext

// RunRenameContext performs the execution for 'config rename-context' sub command
func (o RenameContextOptions) RunRenameContext(out io.Writer) error {
	config, err := o.configAccess.GetStartingConfig()
	if err != nil {
		return err
	}

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

	context, exists := config.Contexts[o.contextName]
	if !exists {
		return fmt.Errorf("cannot rename the context %q, it's not in %s", o.contextName, configFile)
	}

	_, newExists := config.Contexts[o.newName]
	if newExists {
		return fmt.Errorf("cannot rename the context %q, the context %q already exists in %s", o.contextName, o.newName, configFile)
	}

	config.Contexts[o.newName] = context
	delete(config.Contexts, o.contextName)

	if config.CurrentContext == o.contextName {
		config.CurrentContext = o.newName
	}

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

	fmt.Fprintf(out, "Context %q renamed to %q.\n", o.contextName, o.newName)
	return nil
}


NewCmdConfigSet

// NewCmdConfigSet returns a Command instance for 'config set' sub command
func NewCmdConfigSet(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
	options := &setOptions{configAccess: configAccess}

	cmd := &cobra.Command{
		Use:                   "set PROPERTY_NAME PROPERTY_VALUE",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Set an individual value in a kubeconfig file"),
		Long:                  setLong,
		Example:               setExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(options.complete(cmd))
			cmdutil.CheckErr(options.run())
			fmt.Fprintf(out, "Property %q set.\n", options.propertyName)
		},
	}

	f := cmd.Flags().VarPF(&options.setRawBytes, "set-raw-bytes", "", "When writing a []byte PROPERTY_VALUE, write the given string directly without base64 decoding.")
	f.NoOptDefVal = "true"
	return cmd
}


run

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
}


complete

func (o *setOptions) complete(cmd *cobra.Command) error {
	endingArgs := cmd.Flags().Args()
	if len(endingArgs) != 2 {
		return helpErrorf(cmd, "Unexpected args: %v", endingArgs)
	}

	o.propertyValue = endingArgs[1]
	o.propertyName = endingArgs[0]
	return nil
}


validate

func (o setOptions) validate() error {
	if len(o.propertyValue) == 0 {
		return errors.New("you cannot use set to unset a property")
	}

	if len(o.propertyName) == 0 {
		return errors.New("you must specify a property")
	}

	return nil
}


modifyConfig

func modifyConfig(curr reflect.Value, steps *navigationSteps, propertyValue string, unset bool, setRawBytes bool) error {
	currStep := steps.pop()

	actualCurrValue := curr
	if curr.Kind() == reflect.Pointer {
		actualCurrValue = curr.Elem()
	}

	switch actualCurrValue.Kind() {
	case reflect.Map:
		if !steps.moreStepsRemaining() && !unset {
			return fmt.Errorf("can't set a map to a value: %v", actualCurrValue)
		}

		mapKey := reflect.ValueOf(currStep.stepValue)
		mapValueType := curr.Type().Elem().Elem()

		if !steps.moreStepsRemaining() && unset {
			actualCurrValue.SetMapIndex(mapKey, reflect.Value{})
			return nil
		}

		currMapValue := actualCurrValue.MapIndex(mapKey)

		needToSetNewMapValue := currMapValue.Kind() == reflect.Invalid
		if needToSetNewMapValue {
			if unset {
				return fmt.Errorf("current map key `%v` is invalid", mapKey.Interface())
			}
			currMapValue = reflect.New(mapValueType.Elem()).Elem().Addr()
			actualCurrValue.SetMapIndex(mapKey, currMapValue)
		}

		err := modifyConfig(currMapValue, steps, propertyValue, unset, setRawBytes)
		if err != nil {
			return err
		}

		return nil

	case reflect.String:
		if steps.moreStepsRemaining() {
			return fmt.Errorf("can't have more steps after a string. %v", steps)
		}
		actualCurrValue.SetString(propertyValue)
		return nil

	case reflect.Slice:
		if steps.moreStepsRemaining() {
			return fmt.Errorf("can't have more steps after bytes. %v", steps)
		}
		innerKind := actualCurrValue.Type().Elem().Kind()
		if innerKind != reflect.Uint8 {
			return fmt.Errorf("unrecognized slice type. %v", innerKind)
		}

		if unset {
			actualCurrValue.Set(reflect.Zero(actualCurrValue.Type()))
			return nil
		}

		if setRawBytes {
			actualCurrValue.SetBytes([]byte(propertyValue))
		} else {
			val, err := base64.StdEncoding.DecodeString(propertyValue)
			if err != nil {
				return fmt.Errorf("error decoding input value: %v", err)
			}
			actualCurrValue.SetBytes(val)
		}
		return nil

	case reflect.Bool:
		if steps.moreStepsRemaining() {
			return fmt.Errorf("can't have more steps after a bool. %v", steps)
		}
		boolValue, err := toBool(propertyValue)
		if err != nil {
			return err
		}
		actualCurrValue.SetBool(boolValue)
		return nil

	case reflect.Struct:
		for fieldIndex := 0; fieldIndex < actualCurrValue.NumField(); fieldIndex++ {
			currFieldValue := actualCurrValue.Field(fieldIndex)
			currFieldType := actualCurrValue.Type().Field(fieldIndex)
			currYamlTag := currFieldType.Tag.Get("json")
			currFieldTypeYamlName := strings.Split(currYamlTag, ",")[0]

			if currFieldTypeYamlName == currStep.stepValue {
				thisMapHasNoValue := (currFieldValue.Kind() == reflect.Map && currFieldValue.IsNil())

				if thisMapHasNoValue {
					newValue := reflect.MakeMap(currFieldValue.Type())
					currFieldValue.Set(newValue)

					if !steps.moreStepsRemaining() && unset {
						return nil
					}
				}

				if !steps.moreStepsRemaining() && unset {
					// if we're supposed to unset the value or if the value is a map that doesn't exist, create a new value and overwrite
					newValue := reflect.New(currFieldValue.Type()).Elem()
					currFieldValue.Set(newValue)
					return nil
				}

				return modifyConfig(currFieldValue.Addr(), steps, propertyValue, unset, setRawBytes)
			}
		}

		return fmt.Errorf("unable to locate path %#v under %v", currStep, actualCurrValue)

	}

	panic(fmt.Errorf("unrecognized type: %v", actualCurrValue))
}


NewCmdConfigSetCluster

// NewCmdConfigSetCluster returns a Command instance for 'config set-cluster' sub command
func NewCmdConfigSetCluster(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
	options := &setClusterOptions{configAccess: configAccess}

	cmd := &cobra.Command{
		Use:                   fmt.Sprintf("set-cluster NAME [--%v=server] [--%v=path/to/certificate/authority] [--%v=true] [--%v=example.com]", clientcmd.FlagAPIServer, clientcmd.FlagCAFile, clientcmd.FlagInsecure, clientcmd.FlagTLSServerName),
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Set a cluster entry in kubeconfig"),
		Long:                  setClusterLong,
		Example:               setClusterExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(options.complete(cmd))
			cmdutil.CheckErr(options.run())
			fmt.Fprintf(out, "Cluster %q set.\n", options.name)
		},
	}

	options.insecureSkipTLSVerify.Default(false)

	cmd.Flags().Var(&options.server, clientcmd.FlagAPIServer, clientcmd.FlagAPIServer+" for the cluster entry in kubeconfig")
	cmd.Flags().Var(&options.tlsServerName, clientcmd.FlagTLSServerName, clientcmd.FlagTLSServerName+" for the cluster entry in kubeconfig")
	f := cmd.Flags().VarPF(&options.insecureSkipTLSVerify, clientcmd.FlagInsecure, "", clientcmd.FlagInsecure+" for the cluster entry in kubeconfig")
	f.NoOptDefVal = "true"
	cmd.Flags().Var(&options.certificateAuthority, clientcmd.FlagCAFile, "Path to "+clientcmd.FlagCAFile+" file for the cluster entry in kubeconfig")
	cmd.MarkFlagFilename(clientcmd.FlagCAFile)
	f = cmd.Flags().VarPF(&options.embedCAData, clientcmd.FlagEmbedCerts, "", clientcmd.FlagEmbedCerts+" for the cluster entry in kubeconfig")
	f.NoOptDefVal = "true"
	cmd.Flags().Var(&options.proxyURL, clientcmd.FlagProxyURL, clientcmd.FlagProxyURL+" for the cluster entry in kubeconfig")

	return cmd
}


run

func (o setClusterOptions) 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
}