Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use the go language generator code generator

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)05/31 Report--

This article mainly introduces "how to use the go language generator code generator". In the daily operation, I believe many people have doubts about how to use the go language generator code generator. The editor has consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the doubts about "how to use the go language generator code generator". Next, please follow the editor to study!

Introduction to Code Generator

Client-go provides the corresponding clientset and informer for each k8s built-in resource. So what should we do if we want to monitor and manipulate custom resource objects?

Method 1: use the dynamicClient provided by client-go to manipulate custom resource objects, of course, because dynamicClient is implemented based on RESTClient, so we can use RESTClient to achieve the same purpose.

Method 2: use conde-generator to help us generate the code we need so that we can listen to and manipulate custom resources in the same way that client-go provides for K8s built-in resource objects.

Code-generator

Code-generator is a code generation project provided by Kubernetes that provides the following tools to generate code for resources in Kubernetes:

Deepcopy-gen: generate deep copy method, generate func (t * T) DeepCopy () * T method for each T type. API type needs to implement deep copy.

Client-gen: generate standard clientset for resources

Informer-gen: generates an informer that provides an event mechanism to respond to the events of a resource

Lister-gen: generates a Lister that provides a read-only cache layer for get and list requests (obtained through indexer)

Informer and Lister are the basis for building controllers. Using these four code generators, you can create fully functional production-ready controllers that work the same way as Kubernetes upstream controllers.

Code-generator also includes some other code generators, such as Conversion-gen is responsible for generating conversion functions of internal and external types, and Defaulter-gen is responsible for handling field default values.

Most generators support the-- input-dirs parameter to read a series of input packages, process each type, and then generate code:

1. Part of the code is generated to the directory where the input package is located, such as the deepcopy-gen generator. You can also use the parameter-- output-file-base "zz_generated.deepcopy" to define the output file name.

2. Other code is generated to the directory specified by output-package, such as client-gen, informer-gen, lister-gen, etc.

Example

Next, let's use code-generator for an actual demonstration:

First, let's pull the project locally:

$git clone https://github.com/kubernetes/code-generator.git$ git checkout 0.23.3

Then we go to the cmd directory and see the tools we described above:

Then we install client-gen,deepcopy-gen,infromer-gen,lister-gen, which will be installed in GOPATH's bin directory:

# install $go install. / cmd/ {client-gen,deepcopy-gen,informer-gen,lister-gen} # get the GOPATH path $go env | grep GOPATHGOPATH= "/ Users/Christian/go" # View ls / Users/Christian/go/binclient-gen deepcopy-gen goimports lister-gencontroller-gen defaulter-gen informer-gen type-scaffold

When we find that we have successfully installed, we can use these tools directly. For example, we can use the-- help command to see how to use client-gen:

Of course, usually we don't use a tool alone.

Next let's create our project, where we can emulate the sample controller project:

$mkdir operator-test & & cd operator-test$ go mod init operator-test$ mkdir-p pkg/apis/example.com/v1 ➜operator-test tree. ├── go.mod ├── go.sum └── pkg └── apis example.com └── v1 ├── doc.go ├── register.go └── types.go4 directories, 5 files

Next, let's populate the three go files under v1 (you can copy sample-controller directly and make simple changes to it):

Doc.go is mainly used to declare the use of deepconpy-gen and groupName.

/ / pkg/crd.example.com/v1/doc.go// + k8s:deepcopy-gen=package// + groupName=example.compackage v1

Types.go mainly defines the structure in the go corresponding to the crd resource.

/ / pkg/crd.example.com/v1/types.gopackage v1import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" / / + genclient// + k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object// Bar is a specification for a Bar resourcetype Bar struct {metav1.TypeMeta `json: ", inline" `metav1.ObjectMeta `json: "metadata Omitempty "`Spec BarSpec `json:" spec "`/ Status BarStatus `json:" status "`} / / BarSpec is the spec for a Bar resourcetype BarSpec struct {DeploymentName string `json:" deploymentName "`Image string `json:" image "`Replicas * int32 `json:" replicas "`} / / BarStatus is the status for a Bar resourcetype BarStatus struct {AvailableReplicas int32 `json:" availableReplicas "`} / / + k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object// BarList is a list of Bar resourcestype BarList struct {metav1.TypeMeta `json: " Inline ":" metav1.TypeMeta "`metav1.ListMeta `json:" metadata ":" metav1.ListMeta "`Items [] Bar `json:" items ":" items "`}

Register.go, as its name implies, is a registered resource.

Package v1import (metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"k8s.io/apimachinery/pkg/runtime"k8s.io/apimachinery/pkg/runtime/schema") / / SchemeGroupVersion is group version used to register these objectsvar SchemeGroupVersion = schema.GroupVersion {Group: "example.com" Version: "v1"} / / Kind takes an unqualified kind and returns back a Group qualified GroupKindfunc Kind (kind string) schema.GroupKind {return SchemeGroupVersion.WithKind (kind). GroupKind ()} / / Resource takes an unqualified resource and returns a Group qualified GroupResourcefunc Resource (resource string) schema.GroupResource {return SchemeGroupVersion.WithResource (resource). GroupResource ()} var (/ / SchemeBuilder initializes a scheme builder SchemeBuilder = runtime.NewSchemeBuilder (addKnownTypes) / / AddToScheme is a global function that registers this API group & version to a scheme AddToScheme = SchemeBuilder.AddToScheme) / / Adds the list of known types to Scheme.func addKnownTypes (scheme * runtime.Scheme) error {scheme.AddKnownTypes (SchemeGroupVersion) & Bar {}, & BarList {},) metav1.AddToGroupVersion (scheme, SchemeGroupVersion) return nil}

At this point, we will find that & Bar {}, & BarLis {} will report an error because we have not implemented the deepcopy method for it yet.

Since we need to specify header information when generating code automatically, for convenience, we can copy the hack package under the code-generator project directly to our current project root directory.

Next we use code-generator to automatically generate code for us:

# run code-generator/generate-group.sh./../../github/code-generator/generate-groups.sh all\ # specify group and version, generate deeplycopy and clientoperator-test/pkg/client operator-test/pkg/apis crd.example.com:v1\ # specify header file-- go-header-file=./hack/boilerplate.go.txt\ # specify output location Default is GOPATH--output-base.. / Generating deepcopy funcsGenerating clientset for crd.example.com:v1 at operator-test/pkg/client/clientsetGenerating listers for crd.example.com:v1 at operator-test/pkg/client/listersGenerating informers for crd.example.com:v1 at operator-test/pkg/client/informers

At this point, let's take a look at the project structure:

➜operator-test tree. ├── go.mod ├── go.sum ├── hack │ └── boilerplate.go.txt └── pkg ├── apis │ └── crd.example.com │ └── v1 │ ├── doc.go │ ├── register.go │ ├── types.go │ └── zz_generated.deepcopy.go └── client ├── clientset │ └── versioned │ ├── clientset.go │ ├── doc.go │ ├── fake │ │ ├── clientset_generated.go │ │ ├── doc.go │ │ └── register.go │ ├── scheme │ │ ├── doc.go │ │ └── register.go │ └── typed │ └── crd.example.com │ └── v1 │ ├── bar.go │ ├── crd.example.com_client.go │ ├── doc.go │ ├── fake │ │ ├── doc.go │ │ ├── fake_bar.go │ │ └── fake_crd.example.com_client.go │ └── generated_expansion.go ├── informers │ └── externalversions │ ├── crd.example.com │ │ ├── interface. Go │ │ └── v1 │ │ ├── bar.go │ │ └── interface.go │ ├── factory.go │ ├── generic.go │ └── internalinterfaces │ └── factory_interfaces.go └── listers └── crd.example.com └── v1 ├── bar.go └── expansion_generated.go22 directories 29 files

At this point, we can manipulate our custom resources just as we do with built-in resources.

We first prepare the crd and the corresponding cr. Here, you can copy it directly from the sample-controller project and make simple modifications.

# manifests/example.com_bars.yaml---apiVersion: apiextensions.k8s.io/v1kind: CustomResourceDefinitionmetadata: annotations: controller-gen.kubebuilder.io/version: (devel) creationTimestamp: null name: bars.crd.example.comspec: group: crd.example.com names: kind: Bar listKind: BarList plural: bars singular: bar scope: Namespaced versions:-name: v1 schema: openAPIV3Schema: description: Bar is a specification for a Bar resource Properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the generated submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object spec: description: BarSpec is the spec for a Bar resource properties: deploymentName: type: string image: Type: string replicas: format: int32 type: integer required:-deploymentName-image-replicas type: object required:-spec type: object served: true storage: true# manifests/cr.yaml---apiVersion: crd.example.com/v1kind: Barmetadata: Name: bar-demo namespace: defaultspec: image: "nginx:1.17.1" deploymentName: example-bar replicas: 2

Next, let's write the main function, and then we can use client-go to manipulate crd resources in the same way as our built-in resources.

Package mainimport ("context"fmt" v1 "k8s.io/apimachinery/pkg/apis/meta/v1"k8s.io/client-go/tools/cache"k8s.io/client-go/tools/clientcmd"log" clientSet "operator-test/pkg/client/clientset/versioned"operator-test/pkg/client/informers/externalversions") func main () {config, err: = clientcmd.BuildConfigFromFlags ("") Clientcmd.RecommendedHomeFile) if err! = nil {log.Fatalln (err)} clientset, err: = clientSet.NewForConfig (config) if err! = nil {log.Fatalln (err)} list, err: = clientset.CrdV1 (). Bars ("default") .List (context.TODO (), v1.ListOptions {}) if err! = nil {log.Fatalln (err)} for _ Bar: = range list.Items {fmt.Println (bar.Name)} factory: = externalversions.NewSharedInformerFactory (clientset, 0) factory.Crd (). V1 (). Bars (). Informer (). AddEventHandler (cache.ResourceEventHandlerFuncs {AddFunc: nil, UpdateFunc: nil, DeleteFunc: nil,}) / / todo} / / output result: bar-demo code generates tag

In our example above, we added a lot of tag to the source code, and we used these tag to mark some attributes for the generator to use. These tag fall into two main categories:

Global tag provided by IQ in doc.go 's package statement

Provide local tag on types that need to be processed

The use of tag is as follows:

/ / + tag-name// or / / + tag-name=value

We can see that tag exists in the form of comments, and it is important to note that the location of the tag is very important. Many tag must be directly on the previous line of the type or package statement, while others must be separated by at least one line of white space from the go statement.

Global tag

It must be declared in the doc.go file of the target package, and the general path is pkg/apis///doc.go, as shown below:

/ / generate a deep copy method for any type in the package. You can override this default behavior / / + k8s:deepcopy-gen=package / / groupName in local tag to specify the fully qualified name of the API group / / the v1 version of this API group, and put it in the same package / / + groupName=crd.example.compackage v1.

Note: blank lines cannot be omitted

Local tag

The local tag is either declared directly before the type or in the second comment block before the type. The corresponding type of CR is declared in the following types.go:

/ / generate a client for the current type. If you do not add this note, you cannot generate packages such as lister, informer, etc. / / + genclient// indicates that this type is not based on / status child resources to achieve spec-status separation, and the resulting client does not have a UpdateStatus method / / otherwise, as long as the type has a Status field, it will generate a UpdateStatus method / / + genclient:noStatus// to add for each top-level API type Automatically generate DeepCopy related code / / + k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object// K8S resources Database type Database struct {metav1.TypeMeta `json: ", inline" `Spec DatabaseSpec `json: "metadata,omitempty" `copy `json: "spec" `} / / No deep copy method / / + k8s:deepcopy-gen=false// database specification type DatabaseSpec struct {User string `json: "user" `Password string `json: "password" `Encoding string `json: "encoding Omitempty "`} / / + k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object// database list Since list acquires a list, you need to define the structure type DatabaseList struct {metav1.TypeMeta `json: ", inline" `metav1.ListMeta `json: "metadata" `Items [] Database `json: "items" `}.

In the above definition of CR, some comments are added through tag to automatically generate the relevant code. In addition, for resources at the cluster level, we also need to provide comments as follows:

/ / + Tag under genclient:nonNamespaced// cannot be reduced / / + genclient

In addition, we can control which HTTP methods are provided by the client:

/ / + genclient:noVerbs// + genclient:onlyVerbs=create,delete// + genclient:skipVerbs=get,list,create,update,patch,delete,deleteCollection,watch// only returns Status but not the whole resource / / + Tag under genclient:method=Create,verb=create,result=k8s.io/apimachinery/pkg/apis/meta/v1.Status// cannot be reduced / / + genclient

After using tag to define the code rules that need to be generated, execute the code generation script provided above to automatically generate the corresponding code.

Supplement

In addition to the code generation described above, we can also use the hack/update-condegen.sh script provided by the sample-controller project directly.

#! / usr/bin/env bashset-o errexitset-o nounsetset-o pipefailSCRIPT_ROOT=$ (dirname "${BASH_SOURCE [0]}") /.. # location of the code generator package CODEGEN_PKG=$ {CODEGEN_PKG:-$ (cd "${SCRIPT_ROOT}" Ls-d-1. / vendor/k8s.io/code-generator 2 > / dev/null | | echo.. / code-generator)} # generate-groups.sh # which generators are used, optional values deepcopy,defaulter,client,lister,informer, separated by commas All means all use the import path of # output package # CR defines the path # API group and version bash "${CODEGEN_PKG}" / generate-groups.sh "deepcopy,client,informer Lister "\ k8s.io/sample-controller/pkg/generated k8s.io/sample-controller/pkg/apis\ samplecontroller:v1alpha1\-- output-base" $(dirname "${BASH_SOURCE [0]}") /. "\-- go-header-file" ${SCRIPT_ROOT} "/ hack/boilerplate.go.txt# automatically generated source header appended: #-- go-header-file" $ {SCRIPT_ROOT} "/ hack/custom-boilerplate.go.txt

After executing the above script, all API code is generated in the pkg/apis directory, and clientsets, informers, and listers are generated in the pkg/generated directory. However, you can see from the script that the package for code-generator needs to be placed under the vendor directory. Now that we all use go modules to manage the dependency guarantee, we can put the dependency package under the vendor directory by executing the go mod vendor command.

We can also further provide hack/verify-codegen.sh scripts to determine whether the generated code is up-to-date:

#! / usr/bin/env bashset-o errexitset-o nounsetset-o pipefail# first call update-codegen.sh to generate a new code # and then compare whether the old and new codes are the same SCRIPT_ROOT=$ (dirname "${BASH_SOURCE [0]}") /.. DIFFROOT = "${SCRIPT_ROOT} / pkg" TMP_DIFFROOT= "${SCRIPT_ROOT} / _ tmp/pkg" _ tmp= "${SCRIPT_ROOT} / _ tmp" cleanup () {rm-rf "$ {_ tmp} "} trap" cleanup "EXIT SIGINTcleanupmkdir-p" ${TMP_DIFFROOT} "cp-a" ${DIFFROOT} "/ *" ${TMP_DIFFROOT} "" ${SCRIPT_ROOT} / hack/update-codegen.sh "echo" diffing ${DIFFROOT} against freshly generated codegen "ret=0diff-Naupr" ${DIFFROOT} "${TMP_DIFFROOT}" | ret=$?cp-a "${TMP_DIFFROOT}" / * "${DIFFROOT}" if [[$ret-eq 0]] Then echo "${DIFFROOT} up to date." else echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh "exit 1fi" this is the end of the study on "how to use the go language generator code generator". I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report