client-gen代码生成器
client-gen代码生成器是一种为资源生成ClientSet客户端的工具。ClientSet对Group(资源组)、Version(资源版本)、Resource(资源)进行了封装,可以针对资源执行生成资源操作方法(create、update、delete、get等),这些方法由client-gen代码生成器自动生成。
client-gen代码生成器的代码生成策略与Kubernetes的其他代码生成器类似,都通过Tags来识别一个包是否需要生成代码及确定生成代码的方式。
相比其他代码生成器,client-gen代码生成器支持的Tags更多,可扩展性非常高。
生成基本的资源操作方法(Verbs),例如create、update、delete、get、list、patch、watch等方法。另外,如果存在Status字段,则生成UpdateStatus函数。其Tags形式如下
//+genclient
生成基本的资源操作函数,不生成Namespaced函数。其Tags形式如下:
//+genclient:nonNamespaced
即便存在Status字段,也不生成UpdateStatus函数。其Tags形式如下:
//+genclient:noStatus
不生成基本的资源操作方法(Verbs)。其Tags形式如下:
//+genclient:noVerbs
仅生成指定的基本操作方法,例如create、get方法。其Tags形式如下:
//+genclient:onlyVerbs=create,get
生成基本的资源操作方法(Verbs),但排除watch方法。其Tags形式如下:
//+genclient:skipVerbs=watch
生成相关扩展(Extensions)函数,例如生成UpdateScale函数。在UpdateScale函数中会对scale子资源进行update(更新)操作。input和result是用于设置输入和输出的参数。其Tags形式如下:
//+genclient:method=UpdateScale,verbs=update,subresource=scale,input =Scale,result=Scale
下面介绍client-gen的使用示例和生成规则。
1.client-gen的使用示例
构建client-gen二进制文件,执行client-gen二进制文件并给定资源的目录路径作为输入源,解析输入源中的Tags,生成ClientSet代码。构建client-gen二进制文件的执行命令如下:
make all WHAT=vendor/k8s.io/code-generator/cmd/client-gen
构建完成,将client-gen二进制文件存放在_output/bin/client-gen下。生成过程分为两步:第1步,将apis下的资源目录作为输入源(即k8s.io/kubernetes/pkg/apis);第2步,将api下的资源目录作为输入源(即k8s.io/kubernetes/vendor/k8s.io/api)。执行命令如下:
$ ./output/bin/client-gen
--input-base=k8s.io/kubernetes/pkg/apis\
--input=api/,admissionregistration/,apps/,auditregistration/,authe ntication/,authorization/,autoscaling/,batch/,certificates/,coordination/, extensions/, events/, networking/, node/, policy/, rbac/,sc settings/, storage/
$./ output/bin/client-gen --output-base $GOPATH/src/k8s.io/kubernetes/vendor \
--output-package=k8s.io/client-go \
--clientset-name=kubernetes \ --input-base=k8s.io/kubernetes/vendor/k8s.io/api \
--input=core/v1, admissionregistration/vlbetal, apps/v1, apps/v1beta1 ,apps/v1beta2, auditregistration/v1alpha1, authentication/v1, authentica tion/v1beta1, authorization/v1, authorization/v1beta1, autoscaling/v1, au toscaling/v2beta1,autoscaling/v2beta2,batch/v1,batch/v1beta1,batch/v2 alpha1, certificates/v1beta1, coordination/v1beta1, coordination/v1, extensions/v1beta1, events/v1beta1, networking/v1, networking/v1beta1, node/ v 1alpha1, node/v1beta1, policy/v1beta1, rbac/v1, rbac/v1beta1, rbac/v1alpha 1, scheduling/v1alpha1, scheduling/v1beta1, scheduling/v1, settings/v1alp ha1, storage/v1beta1, storage/v1, storage/v1alpha1 \ --go-header-file$GOPATH/src/k8s.io/kubernetes/hack/boilerplate/ boilerplate.generatego.txt
执行以上命令,会在$GOPATH/src/k8s.io/kubernetes/vendor/k8s.io/client-go/kubernetes下生成ClientSet代码。
提示 :除手动构建client-gen代码生成器并生成代码外,也可以执行Kubernetes提供的代码生成脚本,后者的代码生成过程与上述过程完全相同。Kubernetes代码生成脚本的路径为hack/update-codegen.sh。
最后,介绍一下client-gen二进制文件参数,如表5-3所示。
2.client-gen的生成规则
以Pod资源对象为例,Pod资源定义//+genclient标签,该标签负责生成Pod资源基本的资源操作方法(Verbs),例如create、update、delete、get、list、patch、watch等方法,代码示例如下:
代码路径:vendor/k8s.io/api/core/v1/types.go
type Pod struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` Spec PodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
Status PodStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
每一个代码生成器都提供了一个GenerateType函数,它是代码生成器的核心逻辑。在该函数中,util.ParseClientGenTags会解析并验证Tags,当Tags中含有get代码标记时,则为资源对象生成Get函数。代码示例如下:
代码路径:vendor/k8s.io/code-generator/cmd/client-gen/generators/generator_for_type.go
func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { generateApply := len(g.applyConfigurationPackage) > 0
defaultVerbTemplates := buildDefaultVerbTemplates(generateApply) subresourceDefaultVerbTemplates := buildSubresourceDefaultVerbTemplates(generateApply)
sw := generator.NewSnippetWriter(w, c, "$", "$")
pkg := filepath.Base(t.Name.Package)
tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) if err != nil {
return err }
... sw.Do(getterComment, m)
if tags.NonNamespaced { sw.Do(getterNonNamespaced, m)
...
当tags.HasVerb("get")含有get代码标记时,为资源对象生成Get函数,通过Go语言标准库text/template模板语言将资源信息渲染到getTemplate模板中,代码示例如下
var getTemplate = `
// Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any. func (c *$.type|privatePlural$) Get(ctx context.Context, name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error
result = &$.resultType|raw${} err = c.client.Get().
$if .namespaced$Namespace(c.ns).$end$ Resource("$.type|resource$").
Name(name).
VersionedParams(&options, $.schemeParameterCodec|raw$). Do(ctx).
Into(result) return
}
lister-gen代码生成器
lister-gen代码生成器是一种为资源生成Lister的工具。Lister为每一个Kubernetes资源提供Lister功能(即提供get和list方法)。get和list方法为客户端提供只读的本地缓存数据。以上功能由lister-gen代码生成器自动生成。
lister-gen代码生成器的代码生成策略与Kubernetes的其他代码生成器类似,都通过Tags来识别一个包是否需要生成代码及确定生成代码的方式。
lister-gen代码生成器与其他代码生成器相比,其并没有可用的Tags,它依赖于client-gen的代码生成器//+genclient标签。
下面介绍lister-gen的使用示例和生成规则。
1.lister-gen的使用示例
构建lister-gen二进制文件,执行lister-gen二进制文件并给定资源的目录路径作为输入源。构建lister-gen二进制文件的执行命令如下:
make all WHAT=vendor/k8s.io/code-generator/cmd/lister-gen
构建完成,将lister-gen二进制文件存放在_output/bin/lister-gen下。生成过程的执行命令如下:
./ _output/bin/lister-gen --output-base
$GOPATH/src/k8s.io/kubernetes/vendor \
--output-package k8s.io/client-go/listers
--input-dirs
k8s.io/api/admissionregistration/v1beta1,k8s.io/api/admission/v1beta1
,k8s.io/api/apps/v1,k8s.io/api/apps/v1beta1,k8s.io/api/apps/v1beta2,k
8s.io/api/auditregistration/v1alpha1,k8s.io/api/authentication/v1, k8s
.io/api/authentication/v1beta1,k8s.io/api/authorization/v1,k8s.io/api
/authorization/v1beta1,k8s.io/api/autoscaling/v1,k8s.io/api/autoscali
ng/v2beta1,k8s.io/api/autoscaling/v2beta2,k8s.io/api/batch/v1,k8s.io/
api/batch/v1beta1,k8s.io/api/batch/v2alpha1,k8s.io/api/certificates/v
1beta1, k8s.io/api/coordination/v1, k8s.io/api/coordination/v1beta1, k8s
.io/api/core/v1,k8s.io/api/events/v1beta1,k8s.io/api/extensions/v1bet
al,k8s.io/api/imagepolicy/v1alpha1,k8s.io/api/networking/v1, k8s.io/ap
i/networking/v1beta1,k8s.io/api/node/v1alpha1,k8s.io/api/node/v1beta1
,k8s.io/api/policy/v1beta1,k8s.io/api/rbac/v1,k8s.io/api/rbac/v1alpha
1,k8s.io/api/rbac/v1beta1,k8s.io/api/scheduling/v1,k8s.io/api/schedul
ing/v1alpha1,k8s.io/api/scheduling/v1beta1,k8s.io/api/settings/v1alph
al,k8s.io/api/storage/v1,k8s.io/api/storage/v1alpha1,k8s.io/api/stora
ge/v1beta1
--go-header-file
$GOPATH/src/k8s.io/kubernetes/hack/boilerplate/boilerplate.generatego.txt
执行以上命令,会在$GOPATH/src/k8s.io/kubernetes/vendor/k8s.io/client-go/listers下生成Listers代码。
提示 :除手动构建lister-gen代码生成器并生成代码外,也可以执行Kubernetes提供的代码生成脚本,后者的代码生成过程与上述过程完全相同。Kubernetes代码生成脚本的路径为hack/update-codegen.sh。
最后,介绍一下lister-gen二进制文件参数
2.lister-gen的生成规则
lister-gen代码生成器并没有本身可用的Tags,它依赖于client-gen代码生成器的//+genclient标签。当判断是否需要生成某资源类型时,分为3个过滤条件:第一,该资源类型拥有//+genclient标签;第二,该资源类型拥有list字段;第三,该资源类型拥有get字段。满足过滤条件以后,为该资源类型生成list和get方法。代码示例如下:
代码路径:vendor/k8s.io/code-generator/cmd/lister-gen/generators/lister.go
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
if err != nil {
klog.Fatalf("Failed loading boilerplate: %v", err)
}
var packageList generator.Packages
for _, inputDir := range arguments.InputDirs {
p := context.Universe.Package(inputDir)
objectMeta, internal, err := objectMetaForPackage(p)
if err != nil {
klog.Fatal(err)
}
if objectMeta == nil {
// no types in this package had genclient
continue
} ...
}
提示 :lister-gen代码生成器基于gengo实现
informer-gen代码生成器
informer-gen代码生成器是一种为资源生成Informer的工具。Informer为client-go提供了与Kubernetes API Server通信的机制,这些功能由informer-gen代码生成器自动生成。
informer-gen代码生成器的代码生成策略与Kubernetes的其他代码生成器的类似,都是通过Tags来识别一个包是否需要生成代码及确定生成代码的方式。
informer-gen代码生成器与其他代码生成器相比,其并没有可用的Tags,它依赖于client-gen代码生成器的//+genclient标签,类似于lister-gen代码生成器。
下面介绍informer-gen的使用示例和生成规则。
1.informer-gen的使用示例
构建informer-gen二进制文件,执行informer-gen二进制文件并给定资源的目录路径作为输入源。构建informer-gen二进制文件的执行命令如下:
make all WHAT=vendor/k8s.io/code-generator/cmd/informer-gen
构建完成,informer-gen二进制文件存放在_output/bin/informer-gen下。生成过程的执行命令如下:
$./output/bin/informer-gen --output-base
$GOPATH/src/k8s.io/kubernetes/vendor \
--output-package k8s.io/client-go/informers \
--single-directory
--input-dirs
k8s.io/api/admissionregistration/v1beta1,k8s.io/api/admission/v1beta1
, k8s.io/api/apps/v1,k8s.io/api/apps/v1beta1,k8s.io/api/apps/v1beta2,k
8s.io/api/auditregistration/v1alpha1,k8s.io/api/authentication/v1,k8s
.io/api/authentication/v1beta1,k8s.io/api/authorization/v1,k8s.io/api
/authorization/v1beta1,k8s.io/api/autoscaling/v1,k8s.io/api/autoscali
ng/v2beta1,k8s.io/api/autoscaling/v2beta2,k8s.io/api/batch/v1,k8s.io/
api/batch/v1beta1,k8s.io/api/batch/v2alpha1,k8s.io/api/certificates/v
1beta1, k8s.io/api/coordination/v1,k8s.io/api/coordination/v1beta1, k8s
.io/api/core/v1,k8s.io/api/events/v1beta1,k8s.io/api/extensions/v1bet
a1, k8s.io/api/imagepolicy/v1alpha1, k8s.io/api/networking/v1, k8s.io/ap
i/networking/v1beta1,k8s.io/api/node/v1alpha1,k8s.io/api/node/v1beta1
, k8s.io/api/policy/v1beta1,k8s.io/api/rbac/v1,k8s.io/api/rbac/v1alpha
1, k8s.io/api/rbac/v1beta1,k8s.io/api/scheduling/v1,k8s.io/api/schedul
ing/v1alpha1,k8s.io/api/scheduling/v1betal,k8s.io/api/settings/v1alph
a1,k8s.io/api/storage/v1,k8s.io/api/storage/v1alpha1,k8s.io/api/stora
ge/v1beta1
--versioned-clientset-package k8s.io/client-go/kubernetes
--listers-package k8s.io/client-go/listers \
--go-header-file
$GOPATH/src/k8s.i0/kubernetes/hack/boilerplate/boilerplate.generatego.txt
执行以上命令,会在$GOPATH/src/k8s.io/kubernetes/vendor/k8s.io/client-go/informers下生成Informers代码。
提示 :除手动构建informer-gen代码生成器并生成代码外,也可以执行Kubernetes提供的代码生成脚本,后者的代码生成过程与上述过程完全相同。Kubernetes代码生成脚本的路径为hack/update-codegen.sh。
最后,介绍一下informer-gen二进制文件参数说明
2.informer-gen的生成规则
informer-gen代码生成器并没有本身可用的Tags,它依赖于client-gen代码生成器的//+genclient标签。当判断是否需要生成某资源类型时,分为4个过滤条件:第一,该资源类型拥有//+genclient标签;第二,该资源类型不能拥有//+genclient:noVerbs标签;第三,该资源类型拥有list字段;第四,该资源类型拥有watch字段。满足过滤条件以后,为该资源类型生成Informer相关方法。代码示例如下:
代码路径:vendor/k8s.io/code-generator/cmd/informer-gen/generators/packages.go
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
...
var typesToGenerate []*types.Type
for _, t := range p.Types {
tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if !tags.GenerateClient || tags.NoVerbs || !tags.HasVerb("list") || !tags.HasVerb("watch") {
continue
}
typesToGenerate = append(typesToGenerate, t)
...
提示 :informer-gen代码生成器基于gengo实现