Change rendered objects for each cluster with mutations
Add the region of the target cluster to a Deployment, change its replicas, and check the result before convoy applies it.
This guide changes the rendered objects of a Release for its target cluster. You put a region
key in the metadata of the Cluster. Then three mutations change the podinfo Deployment:
- A
goTemplateoverlay adds a region label. - A
jsonPatchsets the replicas. - A
celTransformfrom aConfigMapadds a label and an annotation.
The Release uses manual sync mode. Thus, you can examine the mutated objects before convoy applies them. For the full behavior, see Mutations.
Before you start#
- Make sure that the
GitRepositorypodinfoexists. See Deploy from Git. - Save each example under the file name in its title bar. The commands use these file names.
Steps#
1. Add the region to the Cluster#
This Cluster has the same name as the dev-local example. It adds the metadata key region.
apiVersion: core.convoy.kumodo.io/v1alpha1
kind: Cluster
metadata:
name: dev-local
namespace: default
spec:
connectionMode: inCluster
metadata:
type: kind
role: managed
region: eu-west-1
Apply the
Cluster.kubectl apply -f guides/cluster-dev-local-with-region.yamlMake sure that the
Clusteris ready.kubectl get clusters dev-local
Mutations read spec.metadata as cluster. A change to a Cluster does not start a reconcile of
its Releases. A Release reads the new metadata at its next reconcile.
2. Create the ConfigMap for the CEL transform#
The CEL expression returns a map. convoy merges the map into each matching object. The expression
reads self.name and cluster.region.
# celTransform content sourced from a ConfigMap.
#
# The CEL expression returns a map overlay that is RFC7386-merged onto each
# matched object. Available variables:
# cluster -> the target Cluster's name (cluster.name) + its Spec.Metadata keys
# (e.g. cluster.region)
# self -> the Release's name / namespace / labels / annotations
# object -> the object being mutated
#
# mutations:
# - type: celTransform
# target: { group: apps, version: v1, kind: Deployment }
# from: { kind: ConfigMap, name: mutation-cel-transform, path: transform.cel }
# from.name and from.path may themselves be templated with {.cluster,.self}
# (release-level only, no .object), e.g. name: "{{ .cluster.name }}-transform".
apiVersion: v1
kind: ConfigMap
metadata:
name: mutation-cel-transform
namespace: default
data:
transform.cel: |
{
"metadata": {
"labels": {"convoy.kumodo.io/release": self.name},
"annotations": {"convoy.kumodo.io/region": cluster.region}
}
}
Apply the
ConfigMapin the namespace of the Release.kubectl apply -f mutations/configmap-cel-transform.yaml
In CEL, a read of a missing key is an error. If the Cluster has no region key, the render
stops.
3. Create the Release#
The Release has three mutations. convoy runs them in the order of the list:
goTemplate: an RFC 7386 overlay. It adds the labeltopology.kubernetes.io/regionto theDeploymentand to its pod template. The other fields stay.jsonPatch: an RFC 6902 operation. It changes/spec/replicasto2.celTransform: the expression from theConfigMap.
spec.syncPolicy.automatic is not set. Thus, the Release uses manual sync mode.
apiVersion: core.convoy.kumodo.io/v1alpha1
kind: Release
metadata:
name: podinfo-mutations
namespace: default
mutations:
- type: goTemplate
target:
group: apps
version: v1
kind: Deployment
inline:
- |
metadata:
labels:
topology.kubernetes.io/region: "{{ .cluster.region }}"
spec:
template:
metadata:
labels:
topology.kubernetes.io/region: "{{ .cluster.region }}"
- type: jsonPatch
target:
group: apps
version: v1
kind: Deployment
patches:
- op: replace
path: /spec/replicas
value: 2
- type: celTransform
target:
group: apps
version: v1
kind: Deployment
from:
kind: ConfigMap
name: mutation-cel-transform
path: transform.cel
spec:
clusterRef:
name: dev-local
source:
type: gitRepository
gitRepository:
name: podinfo
namespace: default
ref:
branch: master
content:
type: helm
helm:
path: charts/podinfo
releaseName: podinfo-mutations
syncPolicy:
interval: 1m
Apply the Release.
kubectl apply -f guides/release-podinfo-mutations.yamlExamine the Release.
kubectl get releases podinfo-mutationsMake sure that
APPLIEDisFalse. In manual sync mode, convoy waits for a/syncrequest.
4. Preview the mutated objects#
Show the rendered objects.
kubectl convoy release preview podinfo-mutationsFind the
Deploymentin the output.Make sure that it has the label
topology.kubernetes.io/region: eu-west-1.Make sure that
spec.replicasis2.Make sure that it has the label
convoy.kumodo.io/release: podinfo-mutations.Make sure that it has the annotation
convoy.kumodo.io/region: eu-west-1.
5. Compare with the live objects#
Show the difference between the render and the live objects.
kubectl convoy release diff podinfo-mutationsExamine the status of each object. Before the first apply, each object is
Missing.
For the full result, add -o json.
6. Apply the render#
Send a sync request.
kubectl convoy release sync podinfo-mutationsMonitor the Release until
APPLIEDisTrue.kubectl get releases podinfo-mutations -w
7. Add a mutation with the plugin#
The /mutations subresource holds the list of mutations. Save this list as extra.yaml. It is
not a Kubernetes object.
- type: goTemplate
target:
group: apps
version: v1
kind: Deployment
inline:
- |
metadata:
annotations:
example.convoy.kumodo.io/tier: "{{ if .cluster.tier }}{{ .cluster.tier }}{{ else }}none{{ end }}"The if and else actions replace the default function. The dev-local Cluster has no tier
key. Thus, the value is none.
Add the mutation to the end of the list.
kubectl convoy release mutations add podinfo-mutations -f extra.yamlShow the full list.
kubectl convoy release mutations get podinfo-mutations
mutations add reads the list and writes it again with the new items. mutations set replaces the
full list.
A write to /mutations starts an apply, also in manual sync mode. To examine a change before the
apply, change mutations in the Release manifest. Then use kubectl apply, preview and diff
before you send /sync.
Check the result#
Show the difference again.
kubectl convoy release diff podinfo-mutationsMake sure that the output is
in sync.Read the resolved mutations.
kubectl get releases podinfo-mutations -o jsonpath='{.status.lastAttempted.resolvedMutations}'Make sure that the list has four entries. Each entry has an
index, atypeand acontentHash.
If a mutation fails, Applied is False with reason DeployFailed. An unknown type or
from.kind gives reason Unsupported. Admission does not parse templates or compile CEL. These
errors show only when convoy renders the Release.
Clean up#
Delete the Release.
kubectl delete releases podinfo-mutationsDelete the
ConfigMap.kubectl delete configmap mutation-cel-transform -n default
Next steps#
- Read Mutations for the merge rules and the template context.
- Read Release mutations for all fields.
- Put the resources of a Release in order with sync waves.
- Read Clusters for the cluster metadata.
In the code
convoy v0.9.0
internal/render.ApplyMutationsinternal/render/mutate.go:75internal/render.applyGoTemplateinternal/render/mutate.go:276internal/render.applyJSONPatchinternal/render/mutate.go:175internal/render.applyCELTransforminternal/render/mutate.go:399internal/render.contextValuesinternal/render/mutate.go:328internal/cli/release.runMutationsWriteinternal/cli/release/command.go:468