CUE based Addon Application

    • Utilize the flexible and concise syntax of the CUE language, rich built-in functions and its parameter verification capabilities, to render and deploy the application and auxiliary resources with parameters and metadata of addon.
    • An addon may contain multiple Definitions and CRD Operators. They can be selectively installed according to parameters of the addon.

    This doc will introduce how to define addon application by writing CUE files.

    Application description files contain two parts: application template files and resource files (they are in the resources/ folder).

    The most important part in the application template is output field, which must place a KubeVela application as follows:

    In this example, the name of the namespace defined in spec.components[0].properties.objects[0] of this application is determined by parameter.namespace, which means that its name will be dynamically rendered by the namespace parameter when the addon is enabled. If you want the created namespace to be my-namespace, you can run the following command:

    1. vela addon enable <addon-name> namespace=my-namespace

    After rendered, the resulting application is:

    1. kind: Application
    2. metadata:
    3. spec:
    4. components:
    5. - name: namespace
    6. type: k8s-objects
    7. properties:
    8. objects:
    9. - apiVersion: v1
    10. kind: Namespace
    11. metadata:
    12. name: my-namespace

    You can refer to the to learn language details.

    In the example above, we use the parameter namespace to set the name of Kubernetes namespace resource. Actually, we also need a parameter definition file (parameter.cue) to declare what parameters this addon has. For example,

    1. parameter: {
    2. //+usage=namespace to create
    3. namespace: string
    4. }

    When enabling the addon, you can set the parameters declared in the parameter definition file by appending the parameters to the command, as follows:

    1. vela addon enable <addon-Name> <parameter-name-1=value> <parameter-name-2=value>

    KubeVela has supported CUE package in an addon, which means you can define any CUE files containing data or schema inside the resources/ folder and reference them in application CUE file as a while package. This also help you avoid defining all content in one template file.

    Continuing with the example above, we split the CUE blocks that define the namesapce component under the resources/ folder, the folder structure is as follows:

    1. ├── resources/
    2. └── namespace.cue
    3. ├── README.md
    4. ├── metadata.yaml
    5. ├── parameter.cue
    6. └── template.cue

    The namespace.cue file is as follows:

    1. // resources/namespace.cue
    2. package main
    3. namespace: {
    4. type: "k8s-objects"
    5. name: "example-namespace"
    6. properties: objects: [{
    7. apiVersion: "v1"
    8. kind: "Namespace"
    9. metadata: name: parameter.namespace
    10. }]
    11. }

    After enabled this addon with command $ vela addon enable <addon-name> namespace=my-namespace clusters=local,cluser1, the resulting application is:

    1. apiVersion: core.oam.dev/v1beta1
    2. kind: Application
    3. metadata:
    4. name: example
    5. namespace: vela-system
    6. spec:
    7. components:
    8. - name: namespace
    9. type: k8s-objects
    10. properties:
    11. - apiVersion: v1
    12. kind: Namespace
    13. metadata:
    14. name: my-namespace

    Please notice: Only those CUE files with header can be reference by template.cue, this can be used to help you filter CUE files that you don’t want to use in the rendering context.

    We just use namespace as example here, other resources of an operator can also be defined in KubeVela application in the same way. This also gives your addon re-usability and validation capability powered by the CUE.

    This section will introduce the way of writing application description file to implement several core features of addon.

    If you want the resources in the addon to be installed not only in the control-plane, but also in managed clusters, you can use the topology policy in your application as shown below. The parameter clusters field will be filled when the addon is enabled with the clusters parameter specified.

    1. package main
    2. output: {
    3. apiVersion: "core.oam.dev/v1beta1"
    4. kind: "Application"
    5. spec: {
    6. components:{...}
    7. policies: [{
    8. type: "topology"
    9. name: "deploy-topology"
    10. properties: {
    11. if parameter.clusters != _|_ {
    12. clusters: parameter.clusters
    13. }
    14. if parameter.clusters == _|_ {
    15. clusterLabelSelector: {}
    16. }
    17. }
    18. }]
    19. }}

    If you execute the command to enable the addon as follows:

    1. $ vela addon enable <addon-name> clusters=local,cluser1

    The rendering result will be:

    1. kind: Application
    2. metadata:
    3. name: addon-example
    4. namespace: vela-system
    5. spec:
    6. components: ...
    7. policies:
    8. - type: "topology"
    9. name: "deploy-topology"
    10. properties:
    11. clusters:
    12. - local
    13. - cluster1

    After enabling the addon, the KubeVela controller will install components to the local and cluster1 clusters as defined in the application’s topology policy.

    If you need to enable the addon in all clusters, you can enable the addon by not setting the cluster parameter as follows:

    1. $ vela addon enable <addon-name>

    The rendering result is :

    1. kind: Application
    2. metadata:
    3. name: addon-example
    4. namespace: vela-system
    5. spec:
    6. components: ...
    7. policies:
    8. - type: "topology"
    9. name: "deploy-topology"
    10. properties:
    11. clusterLabelSelector: {}

    Since an empty ({}) clusterLabelSelector topology will choose all exist clusters as target, so the components in the application will be dispatched to all clusters including both the control-plane and the managed clusters.

    You can also define some auxiliary resources in the outputs field of the template.cue file. These resources will only be applied to the control plane.

    You can also run the cue eval *.cue resources/*.cue -e output -d yaml command from local to see the result of resource rendering.

    In addition to dynamically rendering the application by parameters, you can also read fields defined in metadata.yaml for rendering. For example, you can define a template.cue file as follows:

    1. output: {
    2. apiVersion: "core.oam.dev/v1beta1"
    3. kind: "Application"
    4. spec: {
    5. components: [
    6. {
    7. type: "webservice"
    8. image: "oamdev/vela-apiserver:" + context.metadata.version
    9. },
    10. ]
    11. }
    12. }

    When rendering, the fields defined in metadata.yaml will be put into the CUE block of context and rendered together with other CUE files. For example, the metadata.yaml is:

    1. ...
    2. name: velaux
    3. version: 1.2.4
    4. ...

    Resulting application is:

    1. apiVersion: core.oam.dev/v1beta1
    2. kind: Application
    3. metadata:
    4. name: addon-example
    5. namespace: "vela-system"
    6. spec:
    7. components:
    8. - type: webservice
    9. properties:
    10. image: "oamdev/vela-apiserver:v1.2.4"

    The image tag becomes the addon’s version which the context.metadata.version field points to. The real example is VelaUX. Other available fields of metadata please refer to .

    When the addon is enabled, template.cue, parameter.cue and the resource files will be gathered with the addon metadata in metadata.yaml to render out the resources and apply them.

    If you want to bind a Definition to a component in the application, to dynamically enable the ability of one Definition, you can do it by setting addon.oam.dev/bind-component annotation on the Definition.

    An actual example is addon.

    ComponentDefinition kustomize in this addon is:

    1. kustomize: {
    2. attributes: workload: type: "autodetects.core.oam.dev"
    3. description: "kustomize can fetching, building, updating and applying Kustomize manifests from git repo."
    4. type: "component"
    5. annotations: {
    6. "addon.oam.dev/ignore-without-component": "fluxcd-kustomize-controller"
    7. }
    8. }
    9. ...

    This Definition has an annotation "addon.oam.dev/bind-component": "fluxcd-kustomize-controller", which means, bind the ComponentDefinition to fluxcd-kustomize-controller component.

    The template.cue of this addon is:

    1. //...
    2. kustomizeController: {
    3. type: "webService"
    4. Name: "fluxcd-kustomize-controller",
    5. //....
    6. }
    7. gitOpsController: [...]
    8. if parameter.onlyHelmComponents == false {
    9. gitOpsController: [kustomizeController]
    10. }
    11. output: {
    12. apiVersion: "core.oam.dev/v1beta1"
    13. kind: "Application"
    14. spec: {
    15. //...
    16. components: [
    17. helmController,
    18. sourceController,
    19. ] + gitOpsController
    20. //...
    21. }
    22. }
    23. //...

    If you enable this addon by following the command:

      An example is addon. All files included in this addon are all CUE typed.