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.DeploymentContextMethod Description Return type Returns getDeployedReturns deployed for deployment. DeployedDeployed that is being deployed. getPreviousDeployedReturns deployed from previous deployment. DeployedDeployed that was deployed before this deployment. getCurrentDeployedReturns current deployed for create, update or rollback. DeployedDeployed that is currently being deployed. Value may be different than getDeployedfor rollback action.getDeployedApplicationReturns deployed application for deployment. DeployedApplicationDeployed application that is being deployed. getPreviousDeployedApplicationReturns previously deployed application. DeployedApplicationDeployed application that was deployed in previous deployment. getCurrentDeployedApplicationReturns current deployed application for create, update or rollback. DeployedApplicationDeployed application that is currently being deployed. Value may be different than getDeployedApplicationfor rollback action.For more information on DeployedandDeployedApplicationtypes see deployment context -
input- the deployment context as defined by the Java interfacecom.xebialabs.deployit.plugin.stitch.service.engine.context.InputContextMethod Description Parameters Return type Returns pathExistsWithValueReturns true if path exists and has assigned value to it. String value of pathExpression.booleanEvaluated flag for given path. getStringValueReturns Stringvalue in given path. If path doesn't exist or isn't single valuenullwill be returned.String value of pathExpression.StringEvaluated Stringvalue for givenpathExpression.getBooleanValueReturns booleanvalue in given path. If path doesn't exist or isn't single valuenullwill be returned.String value of pathExpression.booleanEvaluated booleanvalue for givenpathExpression.getIntegerValueReturns Integervalue in given path. If path doesn't exist or isn't single valuenullwill be returned.String value of pathExpression.IntegerEvaluated Integervalue for givenpathExpression.getLongValueReturns Longvalue in given path. If path doesn't exist or isn't single valuenullwill be returned.String value of pathExpression.LongEvaluated Longvalue for givenpathExpression.getDoubleValueReturns Doublevalue in given path. If path doesn't exist or isn't single valuenullwill be returned.String value of pathExpression.DoubleEvaluated Doublevalue for givenpathExpression.getJsonNodeReturns JsonNodevalue in given path. If path doesn't exist or isn't single valuenullwill be returned.String value of pathExpression.JsonNodeEvaluated JsonNodevalue for givenpathExpression.getStringListReturns ListofStringfor given path. If path doesn't exist or isn't single valuenullwill be returned.String value of pathExpression.ListEvaluated Listvalue for givenpathExpression.getBooleanListReturns Listofbooleanfor given path. If path doesn't exist or isn't single valuenullwill be returned.String value of pathExpression.ListEvaluated Listvalue for givenpathExpression.getIntegerListReturns ListofIntegerfor given path. If path doesn't exist or isn't single valuenullwill be returned.String value of pathExpression.ListEvaluated Listvalue for givenpathExpression.getLongListReturns ListofLongfor given path. If path doesn't exist or isn't single valuenullwill be returned.String value of pathExpression.ListEvaluated Listvalue for givenpathExpression.getDoubleListReturns ListofDoublefor given path. If path doesn't exist or isn't single valuenullwill be returned.String value of pathExpression.ListEvaluated Listvalue for givenpathExpression.getJsonNodeListReturns ListofJsonNodefor given path. If path doesn't exist or isn't single valuenullwill be returned.String value of pathExpression.ListEvaluated Listvalue 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,@previousDeployedcontainer- 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 callsgetto 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.getand, 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 callsgetto 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.getand, if that value isnull, calls@previousDeployedApplication.get
For Example calling @currentDeployedApplication.nameEquals('test-app') actually calls #ctx.getCurrentDeployedApplication().getName().equals('test-app')
@environmentdictionaries- 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 callsgetto resolve the environment, and the return type is described below:@environment.get- callsctx.getCurrentDeployedApplication.getEnvironmentand, if that value isnull, callsctx.getPreviousDeployedApplication.getEnvironment
-
@dictionarycontainsKey- 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 callsgetto resolve the dictionary, and the return type is a consolidated dictionary containing every dictionary related to the deployed application and container
-
@k8sisDeployment- returns true or false if thekindvalue from the input context is equal to "Deployment"isService- returns true or false if thekindvalue from the input context is equal to "Service"isIngress- returns true or false if thekindvalue from the input context is equal to "Ingress"isPersistentVolume- returns true or false if thekindvalue from the input context is equal to "PersistentVolume"isSecret- returns true or false if thekindvalue from the input context is equal to "Secret"isConfigMap- returns true or false if thekindvalue from the input context is equal to "ConfigMap"isKind- returns true or false if thekindvalue from the input context is equal to the given value
-
@pathStringvalue- 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
truethen rule can be applied in preprocessing stitch transformation, see stitch preprocessing and postprocessing transformation -
postProcessing - special condition that if its value evaluates to
truethen 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
kindfield 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.containerspath 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[*].namefield 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
88on$.spec.template.spec.containers[?(@.name == 'front-end')].ports[*].containerPortpath
...
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.containersarray withnamefield 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.