Skip to main content
Version: Deploy 22.1

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.

note

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 interface com.xebialabs.deployit.plugin.stitch.service.engine.context.DeploymentContext

      MethodDescriptionReturn typeReturns
      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 getDeployed for 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 getDeployedApplication for rollback action.
      For more information on Deployed and DeployedApplication types see deployment context
    • input - the deployment context as defined by the Java interface com.xebialabs.deployit.plugin.stitch.service.engine.context.InputContext

      MethodDescriptionParametersReturn typeReturns
      pathExistsWithValueReturns true if path exists and has assigned value to it.String value of pathExpression.booleanEvaluated flag for given path.
      getStringValueReturns String value in given path. If path doesn't exist or isn't single value null will be returned.String value of pathExpression.StringEvaluated String value for given pathExpression.
      getBooleanValueReturns boolean value in given path. If path doesn't exist or isn't single value null will be returned.String value of pathExpression.booleanEvaluated boolean value for given pathExpression.
      getIntegerValueReturns Integer value in given path. If path doesn't exist or isn't single value null will be returned.String value of pathExpression.IntegerEvaluated Integer value for given pathExpression.
      getLongValueReturns Long value in given path. If path doesn't exist or isn't single value null will be returned.String value of pathExpression.LongEvaluated Long value for given pathExpression.
      getDoubleValueReturns Double value in given path. If path doesn't exist or isn't single value null will be returned.String value of pathExpression.DoubleEvaluated Double value for given pathExpression.
      getJsonNodeReturns JsonNode value in given path. If path doesn't exist or isn't single value null will be returned.String value of pathExpression.JsonNodeEvaluated JsonNode value for given pathExpression.
      getStringListReturns List of String for given path. If path doesn't exist or isn't single value null will be returned.String value of pathExpression.ListEvaluated List value for given pathExpression.
      getBooleanListReturns List of boolean for given path. If path doesn't exist or isn't single value null will be returned.String value of pathExpression.ListEvaluated List value for given pathExpression.
      getIntegerListReturns List of Integer for given path. If path doesn't exist or isn't single value null will be returned.String value of pathExpression.ListEvaluated List value for given pathExpression.
      getLongListReturns List of Long for given path. If path doesn't exist or isn't single value null will be returned.String value of pathExpression.ListEvaluated List value for given pathExpression.
      getDoubleListReturns List of Double for given path. If path doesn't exist or isn't single value null will be returned.String value of pathExpression.ListEvaluated List value for given pathExpression.
      getJsonNodeListReturns List of JsonNode for given path. If path doesn't exist or isn't single value null will be returned.String value of pathExpression.ListEvaluated List value for given pathExpression.
    • 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 container
        • deployable - returns the id of the deployable
        • id - returns the id of the deployed
        • name - returns the name of the deployed
note

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 calls get to resolve the deployed, and the return type slightly differs depending on the utility class:
    • @currentDeployed.get - same as ctx.getCurrentDeployed
    • @previousDeployed.get - same as ctx.getPreviousDeployed
    • @deployed.get - calls @currentDeployed.get and, if that value is null, 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

note

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 calls get to resolve the deployed application, and the return slightly differs depending on the utility class:
    • @currentDeployedApplication.get - same as ctx.getCurrentDeployedApplication
    • @previousDeployedApplication.get - same as ctx.getPreviousDeployedApplication
    • @deployedApplication.get - calls @currentDeployedApplication.get and, if that value is null, 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 environment
    • members - returns the set of containers that are members of the environment
    • patchDictionaries - returns the list of patch dictionaries
    • getDictionary - returns the dictionary for the given id
    • getDictionaryValue - returns the value in the dictionary for the given dictionary id and key
    • getMember - returns the container for the given id
    • id - returns the id of the environment
    • name - returns the name of the environment
note

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 calls get to resolve the environment, and the return type is described below:

    • @environment.get - calls ctx.getCurrentDeployedApplication.getEnvironment and, if that value is null, calls ctx.getPreviousDeployedApplication.getEnvironment
  • @dictionary

    • containsKey - returns true or false if the dictionary contains a value for the given key
    • getValue - returns the value for the given key
    • get - every method above also calls get 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 the kind value from the input context is equal to "Deployment"
    • isService - returns true or false if the kind value from the input context is equal to "Service"
    • isIngress - returns true or false if the kind value from the input context is equal to "Ingress"
    • isPersistentVolume - returns true or false if the kind value from the input context is equal to "PersistentVolume"
    • isSecret - returns true or false if the kind value from the input context is equal to "Secret"
    • isConfigMap - returns true or false if the kind value from the input context is equal to "ConfigMap"
    • isKind - returns true or false if the kind value from the input context is equal to the given value
  • @pathString

    • value - returns the value of the given path from the input context
    • valueEquals - returns true or false if the given path from the input context is equal to the given value
    • valueContains - returns true or false if the given path from the input context contains the given value
    • valueMatches - 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

note

If you specify an unsupported condition type, the validation won't pass.

note

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.

note

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 with name 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')"
...
note

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.