# How to user code-generator

In this article, we will focus on how to use the K8s [code-generator](https://github.com/kubernetes/code-generator) from scratch.

Let's assume we want to create CRD in group "foo.com", and there is a type called "HelloType" with a "message" field in the spec:

```yaml
# Definition
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:  
  name: hellotypes.foo.com
spec:  
  group: foo.com  
  version: v1
  scope: Namespaced  
  names:    
    kind: HelloType   
    shortNames: ht
    plural: hellotypes
    singular: hellotype
# HelloType
---
apiVersion: foo.com/v1
kind: HelloType 
metadata: 
  name: superman-hello
spec:
  message: hello world
```

There are two steps to generate the CRD resource code:

1. Write the type definition code with code generator tags
2. Run run the generator to create the client codes which include: clientset, informers, listers for your customer resource

## Write type definition code

* `cd $GOPATH/src`&#x20;
* `mkdir -p github.com/superman/demo`&#x20;
* `cd $GOPATH/src/github.com/superman/demo`&#x20;
* Create the skeleton files as below under `$GOPATH/src/github.com/superman/demo`

```
pkg/
├── apis
    └── foo
        └── v1
            ├── doc.go
            ├── register.go
            └── types.go
```

### doc.go

{% code title="doc.go" %}

```go
// +k8s:deepcopy-gen=package
// +k8s:defaulter-gen=TypeMeta
// +groupName=foo.com

package v1
```

{% endcode %}

{% hint style="info" %}
This file provide controls of the global tags that will apply to every type in the same version with default setting.

The tags compose of two parts, the function name and the value to pass in normally. For example in`+k8s:deepcopy-gen=package`, `deepcopy-gen` is the function to call for generating the deep copies codes for types. `package`denotes applying the function to the whole v1 package in this case.
{% endhint %}

### types.go

{% code title="types.go" %}

```go
package v1

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// HelloType is a top-level type
type HelloType struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty"`
	
	// +optional
	Status HelloTypeStatus `json:"status,omitempty"`
	// This is where you can define
	// your own custom spec
	Spec HelloSpec `json:"spec,omitempty"`
}

// custom spec 
type HelloSpec struct {
	Message string `json:"message,omitempty"`
}

// custom status
type HelloTypeStatus struct {
	Name string
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// no client needed for list as it's been created in above
type HelloTypeList struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ListMeta `son:"metadata,omitempty"`

	Items []HelloType `json:"items"`
}
```

{% endcode %}

{% hint style="info" %}
`+genclient` means generating API client for the type.

`+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object`means when generating deepcopy for the type, use runtime.Object interface.

`+optional` indicates the field is optional. The data can be empty for the field.
{% endhint %}

### register.go

{% code title="register.go" %}

```go
package v1

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

// Define your schema name and the version
var SchemeGroupVersion = schema.GroupVersion{
	Group:   "foo.com",
	Version: "v1",
}

var (
	SchemeBuilder      runtime.SchemeBuilder
	localSchemeBuilder = &SchemeBuilder
	AddToScheme        = localSchemeBuilder.AddToScheme
)

func init() {
	// We only register manually written functions here. The registration of the
	// generated functions takes place in the generated files. The separation
	// makes the code compile even when the generated files are missing.
	localSchemeBuilder.Register(addKnownTypes)
}

// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
	return SchemeGroupVersion.WithResource(resource).GroupResource()
}

// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
	scheme.AddKnownTypes(
		SchemeGroupVersion,
		&HelloType{},
		&HelloTypeList{},
	)

	scheme.AddKnownTypes(
		SchemeGroupVersion,
		&metav1.Status{},
	)

	metav1.AddToGroupVersion(
		scheme,
		SchemeGroupVersion,
	)

	return nil
}
```

{% endcode %}

{% hint style="info" %}
The `register.go` file contains the functions registering the new types we just created to the schema so the API server can recognize them.
{% endhint %}

## Run code-generator to create client codes

```
go get -u k8s.io/code-generator/... 
go get k8s.io/apimachinery
cd $GOPATH/src/k8s.io/code-generator 
./generate-groups.sh all "github.com/superman/demo/pkg/client" "github.com/superman/demo/pkg/apis" "foo:v1"
```

{% hint style="info" %}
The usage of `generate-groups.sh`. More details could be found [here](https://github.com/kubernetes/code-generator/blob/master/generate-groups.sh).

```
Usage: $(basename "$0") <generators> <output-package> <apis-package> <groups-versions> ...
  <generators>        the generators comma separated to run (deepcopy,defaulter,client,lister,informer) or "all".
  <output-package>    the output package name (e.g. github.com/example/project/pkg/generated).
  <apis-package>      the external types dir (e.g. github.com/example/api or github.com/example/project/pkg/apis).
  <groups-versions>   the groups and their versions in the format "groupA:v1,v2 groupB:v1 groupC:v2", relative
                      to <api-package>.
  ...                 arbitrary flags passed to all generator binaries.
```

{% endhint %}

After above steps, you will see the following file structure:

```
kubo@jumper:~/GoProjects/src/github.com/superman/demo/pkg$ tree client/
client/
├── clientset
│   └── versioned
│       ├── clientset.go
│       ├── doc.go
│       ├── fake
│       │   ├── clientset_generated.go
│       │   ├── doc.go
│       │   └── register.go
│       ├── scheme
│       │   ├── doc.go
│       │   └── register.go
│       └── typed
│           └── foo
│               └── v1
│                   ├── doc.go
│                   ├── fake
│                   │   ├── doc.go
│                   │   ├── fake_foo_client.go
│                   │   └── fake_hellotype.go
│                   ├── foo_client.go
│                   ├── generated_expansion.go
│                   └── hellotype.go
├── informers
│   └── externalversions
│       ├── factory.go
│       ├── foo
│       │   ├── interface.go
│       │   └── v1
│       │       ├── hellotype.go
│       │       └── interface.go
│       ├── generic.go
│       └── internalinterfaces
│           └── factory_interfaces.go
└── listers
    └── foo
        └── v1
            ├── expansion_generated.go
            └── hellotype.go

16 directories, 22 files
```

**References**:

{% embed url="<https://itnext.io/how-to-generate-client-codes-for-kubernetes-custom-resource-definitions-crd-b4b9907769ba>" %}

{% embed url="<https://medium.com/@trstringer/create-kubernetes-controllers-for-core-and-custom-resources-62fc35ad64a3>" %}

{% embed url="<https://github.com/kubernetes/sample-controller>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://daniel-guo.gitbook.io/notebook/k8s-related/extend-k8s/crds/how-to-user-code-generator.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
