Stitch Rules
A Stitch rule is a customization rule that can either transform the content of the provided configuration file or generate it. A rule comprises of conditions (the 'when') and processors (the 'how').
Deploy uses a YAML definition of rules for Stitch, provided the YAML file follows a naming convention, is of the valid YAML format, and has the root property kind
set to the value Rules
. See the example below.
kind: Rules
metadata:
namespace: example-namespace
spec:
- name: "exampleName"
condition:
deployedType: k8s.Resources
expression: "#ctx.deployedApplication.environment.name == 'DevEnv'"
processor:
...
Namespaces
Namespaces are used for easier categorization of customizations, and are defined in the root property metadata
and sub property namespace
, as shown in the sample YAML file above.
The namespace name cannot contain a colon character (:) as it is used for resolution of macros.
You must specify a system-wide unique combination of the name and namespace.
Conditions
The condition
property of the Stitch rule determines whether a rule will be applied or not in a specific deployment. This property is mandatory and shouldn't be empty for the repository validation to pass (or the repository synchronization will fail). There are a few condition types that can be used.
Supported condition types are:
- deployedType - condition that checks if specified deployed type is same as the type of deployed in deployment
- expression - condition that checks if specified expression is satisfied. SpEL expressions is used here with two variables and a few utility classes:
-
ctx
- the deployment context as defined by the Java interfacecom.xebialabs.deployit.plugin.stitch.service.engine.context.DeploymentContext
Method Description Return type Returns getDeployed
Returns deployed for deployment. Deployed
Deployed that is being deployed. getPreviousDeployed
Returns deployed from previous deployment. Deployed
Deployed that was deployed before this deployment. getCurrentDeployed
Returns current deployed for create, update or rollback. Deployed
Deployed that is currently being deployed. Value may be different than getDeployed
for rollback action.getDeployedApplication
Returns deployed application for deployment. DeployedApplication
Deployed application that is being deployed. getPreviousDeployedApplication
Returns previously deployed application. DeployedApplication
Deployed application that was deployed in previous deployment. getCurrentDeployedApplication
Returns current deployed application for create, update or rollback. DeployedApplication
Deployed application that is currently being deployed. Value may be different than getDeployedApplication
for rollback action.For more information on Deployed
andDeployedApplication
types see deployment context -
input
- the deployment context as defined by the Java interfacecom.xebialabs.deployit.plugin.stitch.service.engine.context.InputContext
Method Description Parameters Return type Returns pathExistsWithValue
Returns true if path exists and has assigned value to it. String value of pathExpression
.boolean
Evaluated flag for given path. getStringValue
Returns String
value in given path. If path doesn't exist or isn't single valuenull
will be returned.String value of pathExpression
.String
Evaluated String
value for givenpathExpression
.getBooleanValue
Returns boolean
value in given path. If path doesn't exist or isn't single valuenull
will be returned.String value of pathExpression
.boolean
Evaluated boolean
value for givenpathExpression
.getIntegerValue
Returns Integer
value in given path. If path doesn't exist or isn't single valuenull
will be returned.String value of pathExpression
.Integer
Evaluated Integer
value for givenpathExpression
.getLongValue
Returns Long
value in given path. If path doesn't exist or isn't single valuenull
will be returned.String value of pathExpression
.Long
Evaluated Long
value for givenpathExpression
.getDoubleValue
Returns Double
value in given path. If path doesn't exist or isn't single valuenull
will be returned.String value of pathExpression
.Double
Evaluated Double
value for givenpathExpression
.getJsonNode
Returns JsonNode
value in given path. If path doesn't exist or isn't single valuenull
will be returned.String value of pathExpression
.JsonNode
Evaluated JsonNode
value for givenpathExpression
.getStringList
Returns List
ofString
for given path. If path doesn't exist or isn't single valuenull
will be returned.String value of pathExpression
.List
Evaluated List
value for givenpathExpression
.getBooleanList
Returns List
ofboolean
for given path. If path doesn't exist or isn't single valuenull
will be returned.String value of pathExpression
.List
Evaluated List
value for givenpathExpression
.getIntegerList
Returns List
ofInteger
for given path. If path doesn't exist or isn't single valuenull
will be returned.String value of pathExpression
.List
Evaluated List
value for givenpathExpression
.getLongList
Returns List
ofLong
for given path. If path doesn't exist or isn't single valuenull
will be returned.String value of pathExpression
.List
Evaluated List
value for givenpathExpression
.getDoubleList
Returns List
ofDouble
for given path. If path doesn't exist or isn't single valuenull
will be returned.String value of pathExpression
.List
Evaluated List
value for givenpathExpression
.getJsonNodeList
Returns List
ofJsonNode
for given path. If path doesn't exist or isn't single valuenull
will be returned.String value of pathExpression
.List
Evaluated List
value for givenpathExpression
. -
Utility classes are extensions that make SpEL much simpler. Please refer for stitch-extensibility Here are existing extensions and implemented methods that you can use out of the box:
@currentDeployed
,@deployed
,@previousDeployed
container
- returns the id of the deployed containerdeployable
- returns the id of the deployableid
- returns the id of the deployedname
- returns the name of the deployed
-
If the value is not presented as per the above methods , returns 'null'.
nameEquals
- return true or false if the name equals to the given stringnameMatches
- return true or false if the name matches the given regexnameContains
- return true or false if the name contains the given substringget
- every method above also callsget
to resolve the deployed, and the return type slightly differs depending on the utility class:@currentDeployed.get
- same asctx.getCurrentDeployed
@previousDeployed.get
- same asctx.getPreviousDeployed
@deployed.get
- calls@currentDeployed.get
and, if that value isnull
, calls@previousDeployed.get
For example, calling @currentDeployed.id
actually calls #ctx.getCurrentDeployed().getId()
@currentDeployedApplication
,@deployedApplication
,@previousDeployedApplication
-
version
- returns the version of the deployed application -
id
- returns the id of the deployed application -
name
- returns the name of the deployed application
-
If the value is not presented as per the above methods , returns 'null'.
nameEquals
- return true or false if the name equals to the given stringnameMatches
- return true or false if the name matches the given regexnameContains
- return true or false if the name contains the given substringget
- every method above also callsget
to resolve the deployed application, and the return slightly differs depending on the utility class:@currentDeployedApplication.get
- same asctx.getCurrentDeployedApplication
@previousDeployedApplication.get
- same asctx.getPreviousDeployedApplication
@deployedApplication.get
- calls@currentDeployedApplication.get
and, if that value isnull
, calls@previousDeployedApplication.get
For Example calling @currentDeployedApplication.nameEquals('test-app')
actually calls #ctx.getCurrentDeployedApplication().getName().equals('test-app')
@environment
dictionaries
- returns the list of dictionaries providing placeholder values that are associated with the environmentmembers
- returns the set of containers that are members of the environmentpatchDictionaries
- returns the list of patch dictionariesgetDictionary
- returns the dictionary for the given idgetDictionaryValue
- returns the value in the dictionary for the given dictionary id and keygetMember
- returns the container for the given idid
- returns the id of the environmentname
- returns the name of the environment
If the value is not presented as per the above methods , returns 'null'.
-
nameEquals
- return true or false if the name equals to the given string -
nameMatches
- return true or false if the name matches the given regex -
nameContains
- return true or false if the name contains the given substring -
get
- every method above also callsget
to resolve the environment, and the return type is described below:@environment.get
- callsctx.getCurrentDeployedApplication.getEnvironment
and, if that value isnull
, callsctx.getPreviousDeployedApplication.getEnvironment
-
@dictionary
containsKey
- returns true or false if the dictionary contains a value for the given keygetValue
- returns the value for the given keyget
- every method above also callsget
to resolve the dictionary, and the return type is a consolidated dictionary containing every dictionary related to the deployed application and container
-
@k8s
isDeployment
- returns true or false if thekind
value from the input context is equal to "Deployment"isService
- returns true or false if thekind
value from the input context is equal to "Service"isIngress
- returns true or false if thekind
value from the input context is equal to "Ingress"isPersistentVolume
- returns true or false if thekind
value from the input context is equal to "PersistentVolume"isSecret
- returns true or false if thekind
value from the input context is equal to "Secret"isConfigMap
- returns true or false if thekind
value from the input context is equal to "ConfigMap"isKind
- returns true or false if thekind
value from the input context is equal to the given value
-
@pathString
value
- returns the value of the given path from the input contextvalueEquals
- returns true or false if the given path from the input context is equal to the given valuevalueContains
- returns true or false if the given path from the input context contains the given valuevalueMatches
- returns true or false if the given path from the input context matches the given regex
-
preProcessing - special condition that if its value evaluates to
true
then rule can be applied in preprocessing stitch transformation, see stitch preprocessing and postprocessing transformation -
postProcessing - special condition that if its value evaluates to
true
then rule can be applied in postprocessing stitch transformation, see stitch preprocessing and postprocessing transformation
If you specify an unsupported condition type, the validation won't pass.
Pay special attention to the null
checks in the condition expressions. Missing checks could lead to runtime errors while fetching fields which might have null
values in them. For example having #ctx.deployedApplication.version
could lead to NullPointerException
when a rule is run against Rollback or Revert deployments.
null
checks are not required while using already implemented methods of existing utility classes
Given below are few examples of the expression condition.
- Condition to compare the deployed application version:
...
expression: "#ctx.deployedApplication != null && #ctx.deployedApplication.version.name == '2.0'"
...
- or using utility classes
...
expression: "@deployedApplication.version == '2.0'"
...
- Condition to compare the deployed application name
...
expression: "(#ctx.currentDeployed != null && #ctx.currentDeployed.name == 'MyApplication') || (#ctx.previousDeployed != null && #ctx.previousDeployed.name == 'MyApplication')"
...
- Or using utility classes
...
expression: "@deployed.nameEquals('MyApplication')"
...
- Condition to compare the environment name
...
expression: "#ctx.deployedApplication != null && #ctx.deployedApplication.enviornment.name.contains('k8s')"
...
- Or using utility classes
...
expression: "@environment.nameContains('k8s')"
...
- Condition to compare the container value
- Depending on the container type, different parameters will be available. While using this type of comparison, be sure the parameter exists on the container.
...
expression: "@environment.getMember('myContainer') != null && @environment.getMember('myContainer').name == 'MyName'"
...
- Condition to compare the dictionary value
- searching specific dictionary
...
expression: "@environment.getDictionaryValue('myDictionary', 'myKey') == 'myValue'"
...
- or directly using the dictionary utility class (now it will search through every dictionary related to the used environment)
...
expression: "@dictionary.getValue('myKey') == 'myValue'"
...
- Condition to check if the input JSON or YAML document has a
kind
field with the String value of'Service'
...
expression: "#input.getStringValue('$.kind') == 'Service'"
...
- Condition to check if the input JSON or YAML document has an existing
spec.template.spec.containers
path with'petclinic'
as a name field (notice the JsonPath filters used)
...
expression: "#input.pathExistsWithValue(\"$.spec.template.spec.containers[?(@.name == 'petclinic')]\")"
...
- Combined condition to check if the input JSON or YAML document has the
$.spec.template.spec.containers[*].name
field of that has value equal to#ctx.getDeployedApplication().getEnvironment().getName()
...
expression: "#input.getStringList(\"$.spec.template.spec.containers[*].name\").contains(#ctx.getCurrentApplication().getEnvironment().getName())"
...
- Condition to check if input JSON or YAML document has a value of
88
on$.spec.template.spec.containers[?(@.name == 'front-end')].ports[*].containerPort
path
...
expression: "#input.getIntegerValue('$.spec.template.spec.containers[?(@.name == 'front-end')].ports[*].containerPort' == 88)"
...
- Condition to check if input JSON or YAML document has a value in
$.spec.template.spec.containers
array withname
field of'front-end'
(notice combination of JsonPath and SpEL Collection Projections used in example)
...
expression: "#input.getJsonNodeList('$.spec.template.spec.containers[*].![get('name').asText()].contains('front-end')"
...
In order for a rule to be applied, all the conditions must be satisfied. See processors.
Limitation
If the Stitch rules are updated between the Initial Deployment and Update Deployment, the result of Stitch processing during Update Deployment may not be as expected. For example, if changes are made to the pre-processing rules after the Initial Deployment and these changes use the modified rules as part of the Update Deployment, then the result of Stitch processing may not reflect the updated Stitch rules.