How to extend a Custom Resource Definition for a GO Operator?

That blog post is about some basics how to extend a Custom Resource Definition in a GO Operator.

For an Operator implementation you need a Custom Resource Definition  and a controller implementation.

The Custom Resource Definition for an operator is the basic first step to extend the Kubernetes API with your own functionalities. Usually you create a Custom Resource Definition  before you write the controller for your operator.

That blog post is structured in:

  1. Understand a bit how the  Operator SDK supports you during the implementation of a Custom Resource Definition works
  2. Extend an existing  Custom Resource Definition by adding a new section and a new attribute

The 45 min live stream about “Debugging a GO Operator and extend spec section of a custom resource definition” also cover the topic in that blog post.

Understand how the Operator SDK supports you during the implementation of Custom Resource Definition works

The Operator SDK creates for you all needed code to write your own Custom Resource Definition for your Operator. I use as an example for the usage of the Operator SDK  the code in the GitHub project Example Tenancy Frontend Operator.

In that example code you find a file called tenancyfrontend_types.go. In that file we define the content of our Custom Resource Definition. The concrete Custom Resource Definition is saved in the file tenancyfrontends.multitenancy.example.net. The tenancyfrontends.multitenancy.example.net will be automated created for you by the Operator SDK.

The following code is an extraction of the tenancyfrontends.multitenancy.example.net file.

REMEMBER: You never have to touch that, because this file is automatically created for you.

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    controller-gen.kubebuilder.io/version: v0.8.0
  creationTimestamp: null
  name: tenancyfrontends.multitenancy.example.net
spec:
  group: multitenancy.example.net
  names:
    kind: TenancyFrontend
    listKind: TenancyFrontendList
    plural: tenancyfrontends
    singular: tenancyfrontend

You find an example outline for creating a Kubernetes object for your Custom Resource Definition in the file multitenancy_v1alpha1_tenancyfrontend.yaml. You just use the kubectl apply -f  to create an object based on your Custom Resource Definition. The following code shows an example to create an object of the TenancyFrontend Custom Resource Definition in Kubernetes.

apiVersion: multitenancy.example.net/v1alpha1
kind: TenancyFrontend
metadata:
  name: tenancyfrontendsample
spec:
  # TODO(user): Add fields here
  size: 1
  displayname: MyFrontendDisplayname

The following diagram extracts some content of the tenancyfrontend_types.go file. The focus of this diagram is to display the dependencies of the structs which do represent the Custom Resource Definition in the GO source code.

With that understanding we will later extend the TenancyFrontend Custom Resource Definition .

kind: TenancyFrontend
metadata:
  name: tenancyfrontendsample

  • The TenancyFrontendStatus and TenancyFrontendSpec to contain the own defined values you plan to use inside your controller implementation of the Operator. When an object of the TenancyFrontend  Custom Resource Definition will be created, the controller will create one Pod for the application and the headline of the frontend application will display the text MyFrontendDisplayname.
spec:
  # TODO(user): Add fields here
  size: 1
  displayname: MyFrontendDisplayname

Extend an existing  Custom Resource Definition by adding a new section and a new attribute

In this example we just want to add an additional section into our existing specification. You find the final example code in the following GitHub project: Example Tenancy Frontend Operator in the cdr-def-example branch.

The image below does reflect the changes in dependencies which will be made in the next steps, when you add the MySection to the Custom Resource Definition.

Step 1: Create a new struct called TenancyFrontendMySection in the tenancyfrontend_types.go file

Source code in the example

// TenancyFrontendMySection defines the desired state of TenancyFrontend
type TenancyFrontendMySection struct {
    MyValue string `json:"myvalue,omitempty"`
}

Step 2: Add the name of the struct TenancyFrontendMySection to the TenancyFrontend struct in the tenancyfrontend_types.go file

Source code in the example

// TenancyFrontend is the Schema for the tenancyfrontends API
type TenancyFrontend struct {
    metav1.TypeMeta   `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`

    Spec      TenancyFrontendSpec      `json:"spec,omitempty"`
    Status    TenancyFrontendStatus    `json:"status,omitempty"`
    MySection TenancyFrontendMySection `json:"mysection,omitempty"`
}

Step 3: Run make generate command

make generate

That command changes the zz_generated.deepcopy.go file for you.

Source code in the example

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TenancyFrontend) DeepCopyInto(out *TenancyFrontend) {
    *out = *in
    out.TypeMeta = in.TypeMeta
    in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
    out.Spec = in.Spec
    out.Status = in.Status
    out.MySection = in.MySection
}

...

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TenancyFrontendMySection) DeepCopyInto(out *TenancyFrontendMySection) {
    *out = *in
}

...

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenancyFrontendMySection.
func (in *TenancyFrontendMySection) DeepCopy() *TenancyFrontendMySection {
    if in == nil {
        return nil
    }
    out := new(TenancyFrontendMySection)
    in.DeepCopyInto(out)
    return out
}

Step 4: Run make manifests command

make manifests

That command changes the file multitenancy_v1alpha1_tenancyfrontend.yaml

Source code in the example

         mysection:
            description: TenancyFrontendMySection defines the desired state of TenancyFrontend
            properties:
              myvalue:
                type: string
            type: object

Step 5: Use the newly defined entry in the controller reconcile function of the Operator

  • Example code:

Source code in the example

...
    logger.Info("Info: The new vaule [" + tenancyfrontend.MySection.MyValue + "]")
...

Step 6: Update the multitenancy_v1alpha1_tenancyfrontend.yaml file

apiVersion: multitenancy.example.net/v1alpha1
kind: TenancyFrontend
metadata:
  name: tenancyfrontendsample
mysection:
  myvalue: Hello-this-is-my-value-for-the-new-section
spec:
  # TODO(user): Add fields here
  size: 1
  displayname: MyFrontendDisplayname

Step 7: Start the operator locally and ensure you are connect to a Kubernetes Cluster

make install run

Step 8: Apply a new Custom Resource object

kubectl apply -f config/samples/multitenancy_v1alpha1_tenancyfrontend.yaml

Step 9: Verify the new value for your section is shown

1.647000486675238e+09   INFO    controller.tenancyfrontend  Verify if a CRD of TenancyFrontend exists   {"reconciler group": "multitenancy.example.net", "reconciler kind": "TenancyFrontend", "name": "tenancyfrontendsample", "namespace": "default"}
1.647000762421584e+09   INFO    controller.tenancyfrontend  Info: The new vaule [Hello-this-is-my-value-for-the-new-section]    {"reconciler group": "multitenancy.example.net", "reconciler kind": "TenancyFrontend", "name": "tenancyfrontendsample", "namespace": "default"}

  • Example when you use debug

Summary

It is awesome and powerful how easy it is to customize the content for the Custom Resource Definition when you use the Operator SDK.


I hope this was useful to you and let’s see what’s next?

Greetings,

Thomas

#operator, #go, #operatorsdk, #kubernetes, #buildlabs4saas, #crd, #customresourcedefinition, #operatorlearningjourney

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.