Markers¶
Operator Builder uses commented markers as the basis for defining a new API.
The fields for a custom resource kind are created when it finds a +operator-builder
marker in a source manifest.
A workload marker is commented out so the manifest is still valid and can be
used if needed. The marker must begin with +operator-builder followed by some
colon-separated fields:
These markers should always be provided as an in-line comment or as a head
comment. The marker always begins with +operator-builder:field: or
+operator-builder:collection:field: (more on this later).
That is followed by arguments separated by ,. Arguments can be given in any order.
Arguments¶
Arguments come after the actual marker and are separated from the marker name
with a :. They are given in the format of argument=value and separated by
the ,. Additionally, if the argument name is given by itself with no value, it
is assumed to have an implict =true on the end and is treated as a flag.
Below you will find the supported markers and their supported arguments.
Field Markers¶
Defined as +operator-builder:field this marker can be used to define a CRD
field for your workload.
| Field | Type | Required |
|---|---|---|
| name | string | true |
| type | string{string, int, bool} | true |
| default | type | false |
| replace | string | false |
| arbitrary | bool | false |
| description | string | false |
Name (required if Parent is unspecified)¶
The name you want to use for the field in the custom resource that Operator Builder will create. If you're not sure what that means, it will become clear shortly.
Example:
1 | |
Parent (required if Name is unspecified)¶
The parent field in which you wish to substitute. Currently, only metadata.name is supported.
This will allow you to use the parent name as a value in the child resource.
Example:
1 | |
The metadata.name field from the collection workload is also supported:
1 | |
Type (required)¶
The other required field is the type field which specifies the data type for
the value.
The supported data types are:
- bool
- string
- int
- int32
- int64
- float32
- float64
ex. +operator-builder:field:name=myName,type=string
Default (optional)¶
This will make configuration optional for your operator's end user. the supplied value will be used for the default value. If a field has no default, it will be a required field in the custom resource. For example:
1 | |
Replace (optional)¶
There may be some instances where you only want a specific portion of a value to be configurable (such as config maps). In these scenarios you can use the replace argument to specify a search string (or regex) to target for configuration.
Consider the following example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
In this scenario three custom resource fields will be generated. The value from
the environment field will replace the dev portion of myapp-dev. For
example, if prod is provided as a value for the environment field, the
resulting config map will get the label app: myapp-prod. Values from the
configOption and yamlType fields will replace corresponding strings in the
content of config.yaml. The resulting configmap will look as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Arbitrary (optional)¶
If you wish to create a field for a custom resource that does not directly map to a value in a child resource, mark a field as arbitrary.
Here is an example of how to mark a field as arbitrary:
1 2 3 4 5 6 7 8 9 10 | |
On the first line you can see the nginx.installType custom resource field is
marked as arbitrary with the arbitrary marker field. Where you place this
marker is unimportant but it is recommended you put all arbitrary fields at the
beginning of one chosen manifest for ease of maintenance.
This will result in a custom resource sample that looks as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
This arbitrary field will not map to any child resource value. However it can be leveraged by some custom mutation code or by a resource marker such as this:
1 2 3 4 5 6 7 8 | |
The marker on line one indicates the deployment resource only be created if
nginx.installType has a value of deployment (as shown in the custom resource
sample above). In this example, we are providing an option to install the Nginx
Ingress Controller as a deployment or a daemonset.
Description (optional)¶
An optional description can be provided which will be used in the source code as
a Doc String, backticks ` may be used to capture multiline strings (head
comments only).
By injecting documentation to
the CRD, the consumer of the custom resource gets the added benefit by being
able to run kubectl explain against their resource and having documentation
right at their fingertips without having to navigate to API documentation in
order to see the usage of the API. For example:
1 | |
Note: that you can use a single custom resource field name to configure multiple fields in the resource.
Consider the following Deployment:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
In this case, operator-builder will create and add three fields to the custom resource:
- A
productionfield that is a boolean. It will have a default offalseand will inform the value of the label when the deployment is configured. - A
webAppReplicasfield that will default to2and allow the user to specify the number of replicas for the deployment in the custom resource manifest. - A
webAppImagefield that will set the value for the images used in the pods.
Now the end-user of the operator will be able to define a custom resource similar to the following to configure the deployment created:
1 2 3 4 5 6 7 8 | |
Collection Markers¶
A second marker type +operator-builder:collection:field can be used with the
same arguments as a Field Marker. These markers are used to define global fields
for your Collection and can be used in any of its associated components.
If you include any marker on a collection resource it will be treated as a collection marker and will configure a field in the collection's custom resource.
Resource Markers¶
Defined as +operator-builder:resource this marker can be used to control a specific
resource with arguments in the marker.
Note: a resource marker must reference a field defined by a field marker. If you include a resource marker with a unique field name that is not also defined by a field marker you will get an error. You may use an arbitrary field on a field marker if you don't wish to associate the field with a value in a child resource.
| Field | Type | Required |
|---|---|---|
| field | string | true |
| collectionField | string{string, int, bool} | true |
| value | type | true |
| include | bool | true |
Field / CollectionField (required)¶
The conditional field to associate with an action (currently only include).
One of field or collectionField must be provided depending upon if you are
checking a condition against a collection, or a component/standalone workload spec.
The field input relates directly to a given workload marker such as
+operator-builder:field:name=provider would produce a field of provider to be used
in a resource marker with argument field=provider.
ex. +operator-builder:resource:collectionField=provider,value="aws",include ex. +operator-builder:resource:field=provider,value="aws",include=false
Value (required)¶
The conditional value to associate with an action (currently only include - see
above). The value input relates directly to the value of field as it exists
in the API spec requested by the user.
Examples:
1 2 | |
Include (required)¶
The action to perform on the resource. Include will include the resource for
deployment during a control loop given a field or collectionField and a value.
Using this means that the resource will only be included if this condition
is met. If the condition is not met, the resource will not be deployed.
Here are some sample marker examples:
1 2 3 4 | |
With include set to false, the opposite is true and the resource is
excluded from being deployed during a control loop if a condition is met:
Examples:
1 2 | |
At this time, the include argument with field and value can be simply thought of
as (pseudo-code):
1 2 3 4 5 | |
IMPORTANT: A resource marker is not required and should only be used when there is a desire to act upon a resource. If no resource marker is provided, a resource is always deployed during a control loop.
Include Resource On Condition¶
Below is a sample of how to include a resource only if a condition is met. If the condition is not met, the resource is not deployed during the control loop:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Given the below CRD, the resource would be included:
1 2 3 4 5 6 7 | |
Given the below CRD, the resource would NOT be included:
1 2 3 4 5 6 7 | |
Exclude Resource On Condition¶
Below is a sample of how to exclude a resource only if a condition is met. If the condition is not met, the resource is not deployed during the control loop:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Given the below CRD, the resource would be included:
1 2 3 4 5 6 7 | |
Given the below CRD, the resource would NOT be included:
1 2 3 4 5 6 7 | |
Stacking Resource Markers¶
You can include multiple resource markers on a particular resource. For example:
1 2 3 4 5 6 7 8 | |
The purpose of the first marker is to include all nginx ingress contoller
resources when spec.nginx.include: true. The second gives users a choice
to install nginx ingress controller as a deployment or daemonset. When
spec.nginx.installType: deployment the deployment resource is included.
Therefore the custom resource will need to look as follows for this deployment
resource to be created:
1 2 3 4 5 6 7 8 9 10 11 | |
The resulting source code looks as follows. If either if-statement is evaluated as true, the function will return without any object - hence the deployment will not be included.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | |