Focus on the target

Our goal is to see how kubectl create -f nginx_pod.yaml works.

directory

  1. Main entry

  2. Matching of passed arguments with subcommands

  3. Initialization of kubectl commands

  4. View the create subcommand

  5. The creation logic of runCreate

main

func main(a) {
 	// If you do not call rand.Seed, the rand function returns the same value each time you rerun the main function
	// Seed is a random Seed. Each time you use a timestamp as a Seed, randomness is guaranteed
	rand.Seed(time.Now().UnixNano())

  // create the default parameters of the kubectl command
	command := cmd.NewDefaultKubectlCommand()

	// TODO: once we switch everything over to Cobra commands, we can go back to calling
	// cliflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
	// normalize func and add the go flag set by hand.
	pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
	// cliflag.InitFlags()
  
  // Log initialization and exit
	logs.InitLogs()
	defer logs.FlushLogs()

  / / run the command
	iferr := command.Execute(); err ! =nil {
		os.Exit(1)}}Copy the code

match

// The k8S command line tool uses cobra library, with command prompt and other powerful functions, much more powerful than the go language flag, please refer to github.com/spf13/cobra
func NewDefaultKubectlCommand(a) *cobra.Command {
	return NewDefaultKubectlCommandWithArgs(NewDefaultPluginHandler(plugin.ValidPluginFilenamePrefixes), os.Args, os.Stdin, os.Stdout, os.Stderr)
}

func NewDefaultKubectlCommandWithArgs(pluginHandler PluginHandler, args []string, in io.Reader, out, errout io.Writer) *cobra.Command {
  // Initialize NewKubectlCommand with standard input, output, error output
	cmd := NewKubectlCommand(in, out, errout)

	if pluginHandler == nil {
		return cmd
	}

	if len(args) > 1 {
    // Here is the parameter passed, namely the create-f nginx_pod.yaml part
		cmdPathPieces := args[1:]

		Call COBRA's Find to match args
		if_, _, err := cmd.Find(cmdPathPieces); err ! =nil {
			iferr := HandlePluginCommand(pluginHandler, cmdPathPieces); err ! =nil {
				fmt.Fprintf(errout, "%v\n", err)
				os.Exit(1)}}}return cmd
}
Copy the code

command

The code is long, so I’ll pick the key points

func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
	warningHandler := rest.NewWarningWriter(err, rest.WarningWriterOptions{Deduplicate: true, Color: term.AllowsColorOutput(err)})
	warningsAsErrors := false

	// Create the main command
	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/overview/`),
		Run: runHelp,
		// After initialization, the hook before running the instruction
		PersistentPreRunE: func(*cobra.Command, []string) error {
			rest.SetDefaultWarningHandler(warningHandler)
      Profile.pprof = profile.pprof = profile.pprof = profile.pprof = profile.pprof = profile.pprof = profile.pprof = profile.pprof
			return initProfiling()
		},
    // Run the hook after the instruction
		PersistentPostRunE: func(*cobra.Command, []string) error {
      // Save pPROF performance metrics
			iferr := flushProfiling(); err ! =nil {
				return err
			}
      // Prints the number of warnings
			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
		},
    The kubectl completion bash command is used to view the automatic completion function
    Specific installation / / https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion for reference
		BashCompletionFunction: bashCompletionFunc,
	}

  // Instantiate the Factory interface, Factory mode
	f := cmdutil.NewFactory(matchVersionKubeConfigFlags)

	// omit the instantiated procedure code

  Kubectl defines seven classes of commands, combined with Message and the package names of each subcommand
	groups := templates.CommandGroups{
		{
      // 1. Basic commands, including create/expose/run/set
			Message: "Basic Commands (Beginner):",
			Commands: []*cobra.Command{
				create.NewCmdCreate(f, ioStreams),
				expose.NewCmdExposeService(f, ioStreams),
				run.NewCmdRun(f, ioStreams),
				set.NewCmdSet(f, ioStreams),
			},
		},
		{
      // 2. Intermediate commands including explain/get/edit/delete
			Message: "Basic Commands (Intermediate):",
			Commands: []*cobra.Command{
				explain.NewCmdExplain("kubectl", f, ioStreams),
				get.NewCmdGet("kubectl", f, ioStreams),
				edit.NewCmdEdit(f, ioStreams),
				delete.NewCmdDelete(f, ioStreams),
			},
		},
		{
      // 3. Deploy commands, including rollout/scale/autoscale
			Message: "Deploy Commands:",
			Commands: []*cobra.Command{
				rollout.NewCmdRollout(f, ioStreams),
				scale.NewCmdScale(f, ioStreams),
				autoscale.NewCmdAutoscale(f, ioStreams),
			},
		},
		{
      / / 4. Cluster management commands, including cerfificate/cluster - info/top/cordon/drain/tapping taint
			Message: "Cluster Management Commands:",
			Commands: []*cobra.Command{
				certificates.NewCmdCertificate(f, ioStreams),
				clusterinfo.NewCmdClusterInfo(f, ioStreams),
				top.NewCmdTop(f, ioStreams),
				drain.NewCmdCordon(f, ioStreams),
				drain.NewCmdUncordon(f, ioStreams),
				drain.NewCmdDrain(f, ioStreams),
				taint.NewCmdTaint(f, ioStreams),
			},
		},
		{
      / / 5. Troubleshooting and debugging, including the describe/logs/attach/exec/port - forward/proxy/cp/auth
			Message: "Troubleshooting and Debugging Commands:",
			Commands: []*cobra.Command{
				describe.NewCmdDescribe("kubectl", f, ioStreams),
				logs.NewCmdLogs(f, ioStreams),
				attach.NewCmdAttach(f, ioStreams),
				cmdexec.NewCmdExec(f, ioStreams),
				portforward.NewCmdPortForward(f, ioStreams),
				proxy.NewCmdProxy(f, ioStreams),
				cp.NewCmdCp(f, ioStreams),
				auth.NewCmdAuth(f, ioStreams),
			},
		},
		{
      / / 6. High command, including the diff/apply/patch/replace/wait/convert/kustomize
			Message: "Advanced Commands:",
			Commands: []*cobra.Command{
				diff.NewCmdDiff(f, ioStreams),
				apply.NewCmdApply("kubectl", f, ioStreams),
				patch.NewCmdPatch(f, ioStreams),
				replace.NewCmdReplace(f, ioStreams),
				wait.NewCmdWait(f, ioStreams),
				convert.NewCmdConvert(f, ioStreams),
				kustomize.NewCmdKustomize(ioStreams),
			},
		},
		{
      // 7. Set commands, including label, annotate, and completion
			Message: "Settings Commands:",
			Commands: []*cobra.Command{
				label.NewCmdLabel(f, ioStreams),
				annotate.NewCmdAnnotate("kubectl", f, ioStreams),
				completion.NewCmdCompletion(ioStreams.Out, ""),
			},
		},
	}
	groups.Add(cmds)

	filters := []string{"options"}

	// alpha related subcommand
	alpha := cmdpkg.NewCmdAlpha(f, ioStreams)
	if! alpha.HasSubCommands() { filters =append(filters, alpha.Name())
	}

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

  // Code completion is relevant
	for name, completion := range bashCompletionFlags {
		ifcmds.Flag(name) ! =nil {
			if cmds.Flag(name).Annotations == nil {
				cmds.Flag(name).Annotations = map[string] []string{}
			}
			cmds.Flag(name).Annotations[cobra.BashCompCustom] = append(
				cmds.Flag(name).Annotations[cobra.BashCompCustom],
				completion,
			)
		}
	}

  / / add the rest of the command, including the alpha/config/plugins/version/API - versions/API - resources/options
	cmds.AddCommand(alpha)
	cmds.AddCommand(cmdconfig.NewCmdConfig(f, clientcmd.NewDefaultPathOptions(), ioStreams))
	cmds.AddCommand(plugin.NewCmdPlugin(f, ioStreams))
	cmds.AddCommand(version.NewCmdVersion(f, ioStreams))
	cmds.AddCommand(apiresources.NewCmdAPIVersions(f, ioStreams))
	cmds.AddCommand(apiresources.NewCmdAPIResources(f, ioStreams))
	cmds.AddCommand(options.NewCmdOptions(ioStreams.Out))

	return cmds
}
Copy the code

create

func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
  // Options for the create subcommand
	o := NewCreateOptions(ioStreams)

  // Description of the create subcommand
	cmd := &cobra.Command{
		Use:                   "create -f FILENAME",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Create a resource from a file or from stdin."),
		Long:                  createLong,
		Example:               createExample,
    // Validate parameters and run
		Run: func(cmd *cobra.Command, args []string) {
			if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) {
				ioStreams.ErrOut.Write([]byte("Error: must specify one of -f and -k\n\n"))
				defaultRunFunc := cmdutil.DefaultSubCommandRun(ioStreams.ErrOut)
				defaultRunFunc(cmd, args)
				return
			}
			cmdutil.CheckErr(o.Complete(f, cmd))
			cmdutil.CheckErr(o.ValidateArgs(cmd, args))
      // The core running code logic is RunCreate here
			cmdutil.CheckErr(o.RunCreate(f, cmd))
		},
	}

	o.RecordFlags.AddFlags(cmd)

	usage := "to use to create the resource"
  / / to join filename option flag - f, save to o.F ilenameOptions. The Filenames, corresponding to the above
	cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
	cmdutil.AddValidateFlags(cmd)
	cmd.Flags().BoolVar(&o.EditBeforeCreate, "edit", o.EditBeforeCreate, "Edit the API resource before creating")
	cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows"."Only relevant if --edit=true. Defaults to the line ending native to your platform.")
	cmdutil.AddApplyAnnotationFlags(cmd)
	cmdutil.AddDryRunFlag(cmd)
	cmd.Flags().StringVarP(&o.Selector, "selector"."l", o.Selector, "Selector (label query) to filter on, supports '=', '==', and '! ='.(e.g. -l key1=value1,key2=value2)")
	cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to POST to the server. Uses the transport specified by the kubeconfig file.")
	cmdutil.AddFieldManagerFlagVar(cmd, &o.fieldManager, "kubectl-create")

	o.PrintFlags.AddFlags(cmd)

	// subcommand to create, specifying the create object
	cmd.AddCommand(NewCmdCreateNamespace(f, ioStreams))
	cmd.AddCommand(NewCmdCreateQuota(f, ioStreams))
	cmd.AddCommand(NewCmdCreateSecret(f, ioStreams))
	cmd.AddCommand(NewCmdCreateConfigMap(f, ioStreams))
	cmd.AddCommand(NewCmdCreateServiceAccount(f, ioStreams))
	cmd.AddCommand(NewCmdCreateService(f, ioStreams))
	cmd.AddCommand(NewCmdCreateDeployment(f, ioStreams))
	cmd.AddCommand(NewCmdCreateClusterRole(f, ioStreams))
	cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, ioStreams))
	cmd.AddCommand(NewCmdCreateRole(f, ioStreams))
	cmd.AddCommand(NewCmdCreateRoleBinding(f, ioStreams))
	cmd.AddCommand(NewCmdCreatePodDisruptionBudget(f, ioStreams))
	cmd.AddCommand(NewCmdCreatePriorityClass(f, ioStreams))
	cmd.AddCommand(NewCmdCreateJob(f, ioStreams))
	cmd.AddCommand(NewCmdCreateCronJob(f, ioStreams))
	return cmd
}
Copy the code

runCreate

func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error {
	// f is the Factory passed in, which encapsulates the client interacting with Kube-Apiserver
  
	schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
	iferr ! =nil {
		return err
	}

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

  // Instantiate Builder
	r := f.NewBuilder().
		Unstructured().
		Schema(schema).
		ContinueOnError().
		NamespaceParam(cmdNamespace).DefaultNamespace().
  	// Visitor is not supported for simple local files, but also for standard input and HTTP/HTTPS
		FilenameParam(enforceNamespace, &o.FilenameOptions).
		LabelSelectorParam(o.Selector).
		Flatten().
		Do()
	err = r.Err()
	iferr ! =nil {
		return err
	}

	count := 0
  // Call the visit function to create the resource
	err = r.Visit(func(info *resource.Info, err error) error {
		// Print the result XXXX created
		return o.PrintObj(info.Object)
	})
	return nil
}
Copy the code

Making: github.com/Junedayday/…

Blog: junes.tech/

Public id: Golangcoding