Automation Rules

Data can be mapped from Plugin Blueprint entities to User Blueprint entities via automation rules. This mapping allows for a dynamic abstraction layer, where data from various sources can be filtered, manipulated, standardised and centralised according to your needs.

Rely takes a proactive approach by offering pre-configured automation rules for common use cases, which are automatically included when you install certain plugins. These default automation rules leverage:

These rules are designed to streamline processes and ensure seamless integration of plugin data with the most common user blueprints.

Use-Cases

Automation Rule serve two main purposes:

  1. Unified Entity Representation: e.g. different tools such as git providers, incident management tools, observability platforms, etc represent a "Service" in different ways. Automation rules and user blueprints let you aggregate these varied perspectives into a single, cohesive "Service" entity that contains only what you care the most about from each one and reflects your organisations' operational context.

  2. Standardising Cross-Tool Entities: e.g. pull requests and merge requests from both Github and Gitlab can be standardised into a unified format, as can Issues coming from both Jira and Linear. This enables large organisations to maintain uniformity and clarity in their IDP across different team processes and toolsets.

Automation Rule Descriptor

Regardless of whether you're using UI editing or GitOps to manage your automation rules, the definitions are backed by JSON files. Each file is a fully compliant OpenAPI 3 spec file, with our own specific extensions.

You can still use Automation Rules even if you don't use OpenAPI/Swagger.

We use the OpenAPI spec as a base for automation rule configuration, since it's an open spec with official support for extensions. That lets us extend it to be an automation rule descriptor spec with optional usage of actual OpenAPI fields.

All automation rule descriptors have 7 metadata fields:

  • ID: A unique identifier for the rule.

  • Name: A user-friendly display name.

  • Description (Optional): A concise overview of the rule for further context.

  • Arguments / Source Blueprint ID: The identifier for the blueprint, whose entities creation or update trigger the rule.

  • Arguments / Target Blueprint ID: The identifier for the blueprint, whose entities will be affected by the rule.

  • Is Active: Boolean parameter that determines whether the rule is active and should be executed or not.

  • Type: Define the type of rule, only available value for now is automation.

Triggers

Triggers are conditions that initiate the execution of an automation rule. For a trigger to activate, specific events must occur within the system that match the defined criteria in the trigger settings. Here’s how you can set up a trigger:

  • Event: Detail the specific event or action that must occur to meet the trigger conditions, such as the creation or modification of an entity.

  • Conditions: Specify the conditions that must be met for the trigger to activate. These conditions typically include checking a field's value within an entity against a predefined value or expression to ensure only the intended sub-set of entities triggers the automation

Actions

Actions define what happens when a trigger condition is met. They are the operations executed by the automation rule. Currently, there is no limit to the number of actions that can be included in an automation rule.

Actions are executed sequentially in the order they appear within the list of actions. This ensures that each action can depend on the outcomes of previous actions, allowing for complex workflows. Currently there are two type of actions available:

  • UpsertResource: This action ensures that the target entity is updated with the latest data from the source entity by creating a new resource if it does not exist or updating it if it does.

  • FetchResource: This action retrieves data from an existing entity. It can be utilized to gather additional information required for completing an upsert operation or for implementing conditional logic within complex automations.

ThestopFlowIfNotFoundflag available for fetchResource actions can halt further execution of a workflow, thus preventing unnecessary actions or errors in cases where essential data is missing.

Data Manipulation

Automation Rules in Rely leverage the power of the JINJA templating engine, which allows for data manipulation using a syntax resembling Python.

Automation Rules can access data from:

  • The entity that triggered the automation through the data variable, which points to the root of the entity descriptor. This enables the template to dynamically incorporate attributes of the triggering entity into the automation actions.

  • The outputs of previous fetchResource actions within the same rule can be accessed via actions.ACTION-ID-HERE.output. This allows subsequent actions to utilize and build upon the results of earlier actions, enabling complex, dependent workflows that adapt based on prior outputs.

To further explore and experiment with Jinja templating, you can use online resources such as Jinja Live Parser. This tool provides a hands-on way to practice and visualize how Jinja processes data, aiding in the development and testing of your automation rules.

Suggestions

Automation rules can generate suggestions instead of directly creating entities in your software catalog. Suggestions are fully formed entities that are ready to be added to your catalog but require manual approval to be accepted.

Suggestions are designed to give you control over what data is added to your catalog, ensuring it remains relevant and valuable to your organization. This prevents unnecessary clutter or irrelevant data from being included.

To enable the creation of suggestions instead of entities, you can set the createSuggestion flag to true within the UpsertResource action of your automation rule configuration. Once generated, suggestions can be managed through the Discovery tab in Rely.io. Here, you can review, approve, and accept suggestions to be officially added to your catalog.

Most of Rely's default automation rules are configured to generate suggestions by default. This approach ensures that you have the opportunity to review and validate each entity before it becomes a permanent part of your catalog.

Examples

Example 1 (Gitlab Repo -> Service)

When the trigger condition is met, the system either creates a new service entity or updates an existing one using data from the Gitlab repository entity such as the repository ID, README, and the repository link.

{
  "id": "rely.gitlab.v1.repository-to-service",
  "title": "GitLab Repository to Service",
  "description": "This automation creates a service from a GitLab repository",
  "arguments": {
    "sourceBlueprintId": "gitlab.v1.repository",
    "targetBlueprintId": "service"
  },
  "isActive": true,
  "type": "automation",
  "triggers": [
    {
      "type": "onEvent",
      "conditions": [
        {
          "field": "data.blueprintId",
          "operator": "eq",
          "value": "{{ arguments.sourceBlueprintId }}"
        }
      ],
      "event": {
        "resource": "entity",
        "action": [
          "create",
          "update"
        ]
      }
    }
  ],
  "actions": [
    {
      "type": "upsertResource",
      "args": {
        "data": {
          "id": "{{ data.id }}.service",
          "title": "Service {{ data.title }}",
          "relations": {
            "GitlabRepository": {
              "value": "{{ data.id }}"
            }
          },
          "properties": {
            "readme": "{{ data.properties.readme }}",
            "repo-link": "{{ data.properties.url }}"
          },
          "blueprintId": "{{ arguments.targetBlueprintId }}",
          "description": "The resource {{ data.title }}"
        },
        "resourceType": "entity"
      }
    }
  ]
}

Example 2 (ArgoCD Application -> Running Service)

When an ArgoCD application is created or updated, the rule fetches corresponding service and environment entities based on predefined labels (x-rely-service & x-rely-environment) and creates or updates a "Running Service" entity.

This entity is then linked to the environment where it's running in, the specific service it's associated with and the original ArgoCD application.

{
  "id": "rely.argocd.v1.application-to-running-service",
  "title": "ArgoCD Application to Running-Service",
  "description": "",
  "isActive": true,
  "type": "automation",
  "arguments": {
    "sourceBlueprintId": "argocd.v1.application",
    "targetBlueprintId": "running-service"
  },
  "secrets": {},
  "triggers": [
    {
      "type": "onEvent",
      "event": {
        "resource": "entity",
        "action": [
          "create",
          "update"
        ]
      }
    }
  ],
  "actions": [
    {
      "type": "fetchResource",
      "args": {
        "default": {
          "id": "{{ data.properties.labels['x-rely-service'].replace('-', '.') }}.service",
          "properties": {
            "externalUrls": []
          }
        },
        "conditions": [
          {
            "field": "id",
            "value": "{{ data.properties.labels['x-rely-service'].replace('-', '.') }}.service",
            "operator": "eq"
          },
          {
            "field": "blueprintId",
            "value": "service",
            "operator": "eq"
          }
        ],
        "resourceType": "entity",
        "stopFlowIfNotFound": true
      },
      "id": "matching_service"
    },
    {
      "type": "fetchResource",
      "args": {
        "default": {
          "id": "environment.{{ data.properties.labels['x-rely-environment'] }}"
        },
        "conditions": [
          {
            "field": "id",
            "value": "environment.{{ data.properties.labels['x-rely-environment'] }}",
            "operator": "eq"
          },
          {
            "field": "blueprintId",
            "value": "environment",
            "operator": "eq"
          }
        ],
        "resourceType": "entity",
        "stopFlowIfNotFound": true
      },
      "id": "matching_environment"
    },
    {
      "type": "upsertResource",
      "args": {
        "data": {
          "id": "{{ data.id }}.running-service",
          "title": "{{ data.properties.labels['x-rely-service'] }}-{{ data.properties.labels['x-rely-environment'] }}",
          "relations": {
            "service": {
              "value": "{{ actions.matching_service.output.id }}"
            },
            "environment": {
              "value": "{{ actions.matching_environment.output.id }}"
            },
            "argo-application": {
              "value": "{{ data.id }}"
            }
          },
          "properties": {
            "tags": "{{ data.properties.labels }}",
            "base-url": "{{ (data.properties.externalUrls[0] if data.properties and data.properties.externalUrls and data.properties.externalUrls|length > 0 else '') }}",
            "image-tags": "{{ data.properties.images }}",
            "sync-status": "{{ data.properties.status.health }}",
            "last-deployed-at": "{{ data.properties.status.lastSync.finishedAt }}",
            "automatic-deploys-enabled": "{{ data.properties.syncPolicy.automated.prune if data.properties and data.properties.syncPolicy and data.properties.syncPolicy.automated and data.properties.syncPolicy.automated.prune else 'Unknown' }}"
          },
          "blueprintId": "{{ arguments.targetBlueprintId }}",
          "description": ""
        },
        "resourceType": "entity"
      },
      "id": "create_running_service"
    }
  ]
}

Example 3 (Gitlab Pipeline -> Deployment)

This automation rule maps a GitLab pipeline to a "Deployment" entity, specifically targeting production deployments.

It activates when a pipeline, associated with designated repositories and marked for release, is created or updated.

The rule fetches the service related to the pipeline and updates or creates a deployment entity capturing details such as the deployment status, start and finish times, and the individual who triggered the pipeline, enhancing traceability and oversight of deployment activities.

{
  "id": "rely.gitlab.v1.pipeline-to-deployment",
  "title": "GitLab Pipeline to Deployment (Prod): magneto,integrations,flow.engine,applications.config,",
  "description": "",
  "isActive": true,
  "type": "automation",
  "arguments": {
    "sourceBlueprintId": "gitlab.v1.pipeline",
    "targetBlueprintId": "deployment"
  },
  "secrets": {},
  "triggers": [
    {
      "type": "onEvent",
      "conditions": [
        {
          "field": "data.blueprintId",
          "operator": "eq",
          "value": "{{ arguments.sourceBlueprintId }}"
        },
        {
          "field": "data.properties.branch",
          "operator": "like",
          "value": "release%"
        },
        {
          "field": "data.relations.repository.value",
          "operator": "in",
          "value": "magneto,integrations,flow.engine,applications.configuration"
        }
      ],
      "event": {
        "resource": "entity",
        "action": [
          "create",
          "update"
        ]
      }
    }
  ],
  "actions": [
    {
      "type": "fetchResource",
      "args": {
        "conditions": [
          {
            "field": "blueprintId",
            "value": "service",
            "operator": "eq"
          },
          {
            "field": "relations/GitlabRepository/value",
            "value": "{{ data.relations.repository.value }}",
            "operator": "eq"
          }
        ],
        "resourceType": "entity",
        "stopFlowIfNotFound": true
      },
      "id": "fetch_service"
    },
    {
      "type": "upsertResource",
      "args": {
        "data": {
          "id": "{{ data.id }}.deployment",
          "title": "Deployment {{ data.properties.branch }}",
          "relations": {
            "service": {
              "value": "{{ actions.fetch_service.output.id }}"
            },
            "environment": {
              "value": "environment.prod"
            }
          },
          "properties": {
            "startedAt": "{{ data.properties.startedAt }}",
            "finishedAt": "{{ data.properties.finishedAt }}",
            "pipelineId": "{{ data.id | string }}",
            "triggeredBy": "{{ data.properties.triggeredBy }}",
            "pipelineLink": "{{ data.properties.webUrl }}",
            "statusGitlab": "{{ data.properties.status }}",
            "durationGitlab": "{{ data.properties.duration }}"
          },
          "blueprintId": "{{ arguments.targetBlueprintId }}"
        },
        "resourceType": "entity"
      },
      "id": "update_deployment"
    },
    {
      "type": "fetchResource",
      "args": {
        "conditions": [
          {
            "field": "blueprintId",
            "value": "user",
            "operator": "eq"
          },
          {
            "field": "properties/aliases",
            "value": "{{ data.properties.triggeredBy }}",
            "operator": "contains"
          }
        ],
        "resourceType": "entity",
        "stopFlowIfNotFound": true
      },
      "id": "fetch_user"
    },
    {
      "type": "upsertResource",
      "args": {
        "data": {
          "id": "{{ data.id }}.deployment",
          "title": "Deployment {{ data.properties.branch }}",
          "relations": {
            "triggeredByUser": {
              "value": "{{ actions.fetch_user.output.id }}"
            }
          },
          "properties": {},
          "blueprintId": "{{ arguments.targetBlueprintId }}"
        },
        "resourceType": "entity"
      },
      "id": "update_deployment_2"
    },
    {
      "type": "fetchResource",
      "args": {
        "conditions": [
          {
            "field": "blueprintId",
            "value": "running-service",
            "operator": "eq"
          },
          {
            "field": "relations/environment/value",
            "value": "environment.prod",
            "operator": "in"
          },
          {
            "field": "relations/service/value",
            "value": "{{ actions.fetch_service.output.id }}",
            "operator": "in"
          }
        ],
        "resourceType": "entity",
        "stopFlowIfNotFound": true
      },
      "id": "fetch_running_service"
    },
    {
      "type": "upsertResource",
      "args": {
        "data": {
          "id": "{{ data.id }}.deployment",
          "title": "Deployment {{ data.properties.branch }}",
          "relations": {
            "runningService": {
              "value": "{{ actions.fetch_running_service.output.id }}"
            }
          },
          "properties": {},
          "blueprintId": "{{ arguments.targetBlueprintId }}"
        },
        "resourceType": "entity"
      },
      "id": "update_deployment_3"
    }
  ]
}

Learn More

Last updated