Automation Rules

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 5 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.

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

  • Type: Define the type of rule (automation) .

Arguments

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

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

Example

  "arguments": {
    "sourceBlueprintId": "gitlab.v1.repository",
    "targetBlueprintId": "service"
  }

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:

  • Type: Only available type for automations is onEvent.

  • Event: Specify the exact event or action needed to trigger the automation. Currently, this is limited to the creation, modification, or both, of an entity.

  • Conditions: Define the criteria that must be met for the trigger to activate based on the event's details. This typically involves checking a field's value within an entity against a predefined value or expression to ensure only the desired entities trigger the automation.

Example:

"triggers": [
    {
      "type": "onEvent",
      "conditions": [
        {
          "field": "data.blueprintId",
          "operator": "eq",
          "value": "{{ arguments.sourceBlueprintId }}"
        }
      ],
      "event": {
        "resource": "entity",
        "action": [
          "create",
          "update"
        ]
      }
    }
  ]

Actions

Actions are the operations executed by the automation rule when a trigger condition is met. 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.

  • HttpRequest: This action sends an HTTP request to an external service or API. It allows for communication with third-party services, enabling the automation to interact with external systems, retrieve data, or send updates. The HttpRequest action can be configured to perform GET, POST, PUT, or DELETE operations, depending on the needs of the automation workflow.

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.

Example:

"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"
      }
    }
  ]

Data Manipulation

Automation Rules in Rely leverage the power of the JINJA2 templating engine, which allows for data manipulation using a syntax resembling Python. To use Jinja in your templates, you need to enclose expressions in double curly braces: {{ ... }}.

Automation Rules can access data from:

  • The entity that triggered the automation: This data is accessible 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. For example, you can reference an entity’s name with {{ data.id }}.

  • The outputs of previous fetchResource actions within the same rule: These outputs 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. For instance, if a previous action has an ID of fetch_user, you can access its output with {{ actions.fetch_user.output }}.

  • The automation rule descriptor itself: Fields at the root of the descriptor can be directly referenced. For example, to reference the source blueprint ID, you would use {{ arguments.sourceBlueprintId }}.

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 a new repository being found or a known one is updated, the automation either creates a new service entity or updates an existing one using 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",
  "isActive": true,
  "type": "automation",
  "arguments": {
    "sourceBlueprintId": "gitlab.v1.repository",
    "targetBlueprintId": "service"
  },
  "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