kubectl的代码在源码包的cmd包下的kubectl文件夹,只有一个kubectl.go
kubectl的入口
kubectl的入口代码非常简单,只有一个kubectl.go(在源码的cmd下的kubectl文件夹)
1 | func main() { |
当调用cmd.NewDefaultKubectlCommand()
生成command对象时,会调用k8s.io/kubectl/cmd.go,可以发现在这个cmd.go的同级别下有好多kubectl子命令的文件夹,其实这些很多都是cobra生成的代码,cmd.go当然也是cobra自动生成的文件
cobra
简介
cobra使用的就是子命令模式,然后附带一个二进制的cobra命令帮助生成框架,只需要开发者填入具体功能就行
概念
- Command代表执行动作,比如git clone的clone动作
- Args就是执行参数,比如git clone后面跟着的仓库地址就是参数,参数是属于子命令的
- Flags是动作的标识符,通常
-f
啊或者--name
这种都是标识符
安装
用下面这条命令安装cobra依赖库
1 | go get -u "github.com/spf13/cobra/cobra" |
但是不会有二进制的cobra命令,查看github发现二进制的cobra命令已经搬到cobra-cli去了
所以再安装下cobra-cli
1 | go get -u "github.com/spf13/cobra-cli" |
在gopath下的bin中就能找到cobra-cli这个二进制命令了,但是为了要能随时随地使用这个命令,还需要将它放在/usr/local/bin下(我是macOS系统),在gopath执行下面的命令
1 | sudo cp cobra-cli /usr/local/bin/cobra |
我将其改名成cobra了,所以在终端直接用cobra就可以了
初始化
新版的cobra初始化有了一些变化,首先我创建一个mycobra文件夹,在文件夹下
1 | go mod init mycobra |
然后用cobra
1 | cobra init . |
看到文件夹下会有这些文件
1 | LICENSE cmd go.mod go.sum main.go |
这样cobra的整个框架就搭好了,cmd文件夹就是我们存放子命令的实现的地方
main.go里非常简单
1 | /* |
只是调用了cmd包下的Execute方法,打开cmd包发现只有一个root.go,毫无疑问这就是根命令了(因为我们还没有添加过任何子命令),等先说完添加子命令后,将会分析cmd包下的逻辑
添加子命令
只需要执行一下cobra-cli的add命令,这里假设我增加一个get子命令
1 | cobra add get |
就可以发现cmd底下多了一个get.go
如何编写代码
发现其实每个子命令都对应一个cobra.Command结构体
1 | // getCmd represents the get command |
Use字段代表子命令名称,Short是短简介,Long是长简介,Run是一个函数对象,当然就对应着这个子命令执行的具体逻辑。整个结构体的运行阶段还不止Run这一个,查看结构体定义会发现还有好多阶段
1 | // The *Run functions are executed in the following order: |
其中可供调用的就是PersistentPreRun、PreRun、Run、PostRun、PersistentPostRun这五个阶段
还可以使用 Command结构体 的 Args 字段指定位置参数的验证
下面的验证符是内置的:
NoArgs
- 如果有任何位置参数,该命令将报告错误。ArbitraryArgs
- 命令将接受任意参数OnlyValidArgs
- 如果 Command 的ValidArgs
字段中不存在该位置参数,则该命令将报告错误。MinimumNArgs(int)
- 如果不存在至少 N 个位置参数,则该命令将报告错误。MaximumNArgs(int)
- 如果存在超过 N 个位置参数,则该命令将报告错误。ExactArgs(int)
- 如果不存在 N 个位置参数,则该命令将报告错误。ExactValidArgs(int)
- 如果没有确切的 N 个位置参数,或者如果 Command 的 ValidArgs 字段中不存在该位置参数,则该命令将报告并出错。RangeArgs(min, max)
- 如果 args 的数目不在期望的 args 的最小和最大数目之间,则该命令将报告并出错。
在Command结构体填入Args: cobra.MinimumNArgs(1)
就可以指定子命令必须接受一个及一个以上的参数