Actions End-to-end Example

A practical, step-by-step walkthrough of implementing a Custom Action in OpsLevel

Reminder: only Admin users can create and update Custom Actions

Scenario: Lock and unlock deploy pipelines

Internally at OpsLevel, we use Custom Actions to make freezing (or unfreezing) deploys a self-serve action. Whatever the need is—migration or upgrade, active incident, holiday code freeze—we can lock and unlock our pipelines with one click from OpsLevel.

You can apply the patterns below to nearly any operation that kicks off an external workflow and has a state that should be reflected in your catalog.


Before we create and configure any Actions, let's create the right filters so users always see the correct Actions available on their services.

In the screenshot below, we've created filters that target:

  • Services that would ever be in scope for this operation, based on Language and Framework
  • Services that currently have state that maps to the appropriate action, based on a custom tag deploy_freeze

Note: Filters are globally available in OpsLevel. You can create them before you start customizing a new action or from within the Actions menu.

Custom Action Configuration

Action Rules

This is where you define the scope of the action you're creating. For this example, you will need to create two Actions: mirror images based on the tag state. We'll focus on just one of them.

The action rules also includes configuration of the HTTP request that will be sent when the action is triggered. This is where you define:

  1. What URL OpsLevel will send an HTTP request to when the action is triggered
  2. What headers will be sent with the request
  3. What body will be sent with the request

Each of these three sections supports Liquid syntax and variables, so Actions can be configured to be context-aware.

  1. In our example, we're hitting a GitLab repository endpoint to trigger a pipeline. Instead of hardcoding which repo we want to target, we can use a Liquid variable to dynamically insert the the repo key of the first repository attached to this service:
    {{ service.service_repositories\[0\].repository.repo_key }}

  2. In this instance, authentication happens in the payload, not the header. But a pattern like the below is also common.

  3. The payload carries any other inputs to your action. In this case, we're telling the GitLab CLI that main is the target branch and we want to pass the {{service.slug}} and the action freeze to our script —that looks something like this:

    !/usr/bin/env bash

    ACTION=$(echo $PAYLOAD | jq -r '.variables.action')
    SERVICE_SLUG=$(echo $PAYLOAD | jq -r '.service.slug')

    if [ $ACTION == "freeze" ]; then
    glab variable set -R jklabsinc/OpsLevel CI_DEPLOY_FREEZE "true"
    opslevel create service tag --assign $SERVICE_SLUG deploy_freeze "true"

    if [ $ACTION == "unfreeze" ]; then
    glab variable delete -R jklabsinc/OpsLevel CI_DEPLOY_FREEZE
    opslevel create service tag --assign $SERVICE_SLUG deploy_freeze "false"

In the script above, you'll also notice the OpsLevel CLI is being used to flip the relevant tag. This approach works with the filters we described above to ensure that it's not possible to freeze an already frozen pipeline!

Response Details

Use the response message, which supports Liquid and has access to the response payload, to close the loop and spell out next steps for service owners. The placeholder message contains this conditional structure which makes it easy to drop in custom steps for your success and failure states.

{% if response.status >= 200 and response.status < 300 %} ... {% else %} ... {% endif %}

Publish your Action

Your action is almost ready to publish. Two final steps:

  1. Use the toggle found at the bottom of the action configuration (shown above) to publish your action..
  2. Ensure that the relevant services are tagged with the correct starting tag so that they're in-scope for the filters reviewed at the start of this walkthrough. Need to apply tags at scale? Don't forget the OpsLevel CLI.

What's Next?

Questions about this Custom Action or applying similar patterns to your action? Find us on Slack or email us at [email protected].

If you're looking for more inspiration, try out one of our action templates