Kubectl的启动入口和命令参数的解析过程
本文主要想探讨一下,Kubectl的命令解析过程。首先会介绍Kubectl使用的Go CLI库Cobra的概念和使用,然后会介绍主菜——kubectl的命令参数解析过程。
Cobra
Cobra是一个现代的Go CLI库。具有如下的特性:
支持嵌入的子命令
智能提示
命令补全
全局、本地、级联标记符
兼容POSIX标记符(短标记符和长标记符)
等等
一个Cobra命令支持如下的格式:
应用CLI 名称 动词 名词 --形容词
或者
应用CLI名称 命令 参数 --标记符
命令是Cobra程序的核心,命令可以有子命令,会执行一些操作。
标记符类似于自然语言的修饰词语,会对命令的行为产生影响。
子命令
对于每个根命令对象,可以通过AddCommand方法添加自己的子命令。可以在子命令里添加本地标识符和级联标识符。
TODO:增加示例
Kubectl
Kubectl的main函数:
command := cmd.NewDefaultKubectlCommand()
if err := cli.RunNoErrOutput(command); err != nil {
// Pretty-print the error and exit with an error.
util.CheckErr(err)
}
上述代码首先创建了一个cobra.Command对象,然后调用Kubectl封装的RunNoErrOutput方法,进入Command对象的执行。
KubectlCommand有两个新建对象的方法,分别是NewDefaultKubectlCommand()和NewDefaultKubectlCommandWithArgs(o KubectlOptions)。两者的区别是,前者携带默认的KubectlOptions对象,后者需要传入一个KubectlOptions对象。
KubectlOptions对象是Kubectl Command的配置对象,其中包括的配置有插件、命令行参数、通用配置和输入输出流,其结构体定义如下:
type KubectlOptions struct {
PluginHandler PluginHandler
Arguments []string
ConfigFlags *genericclioptions.ConfigFlags
genericclioptions.IOStreams
}
其中PluginHandler是插件接口,包括两个方法LookUp()和Execute(),LookUp方法用于查找插件,Execute方法则会加载找到的插件。
命令
这一块首先探讨Kubectl的命令构成。
首先从NewKubectlCommand(o KubectlOptions)方法入手,上述两个创建KubectlCommand的方法最终都会调用到这里。
func NewKubectlCommand(o KubectlOptions) *cobra.Command {
// root cmd
cmds := &cobra.Command {...}
// global flag
f := cmdutil.NewFactory(...)
proxyCmd := proxy.NewCmdProxy(f, o.IOStreams)
getCmd := get.NewCmdGet("kubectl", f, o.IOStreams)
// 按照分组添加command
groups := templates.CommandGroups{...}
groups.Add(cmds)
// 将group中的命令添加到cmds下
templates.ActsAsRootCommand(cmds, filters, groups...)
// 配置自动补全
utilcomp.SetFactoryForCompletion(f)
registerCompletionFuncForGlobalFlags(cmds, f)
// 添加其他子command
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))
}
参数以及标识符
将全局的flag作为参数传入各个子command,在子command中再向其中添加标识符。