Config as Code (opslevel.yml)

You can define OpsLevel services and ownership info by placing an opslevel.yml file in your git repos. OpsLevel will automatically synchronize these files whenever they change.

In addition to defining services through OpsLevel’s UI and GraphQL API, you can also define services by placing a YAML file named opslevel.yml in a service’s repo. Leveraging our Git Repository Integrations, OpsLevel will automatically synchronize the contents of the opslevel.yml file whenever it changes. This config-as-code mechanism allows developers to retain their existing Git-based development workflows to keep this data up-to-date.

In addition to services, opslevel.yml can also track ownership and metadata about repositories. The contents of opslevel.yml differ depending on if it’s tracking a service or a repository. The schema below highlights these differences.

🚧

YAML Specification

OpsLevel uses YAML 1.1, to ensure that values are treated as strings it is highly recommended to use quotes (") around values. This ensures that tag values such as false are not converted to Booleans

Aliases

opslevel.yml uses human readable identifiers to specify the owner, or tier of a service or repository, as well as the lifecycle stage of a service. For example, an opslevel.yml that specifies the team that owns a service looks like:

service:
  name: Order Processor
  owner: orders_team

The identifier orders_team is an alias. Aliases are automatically generated by OpsLevel for teams, tiers, and lifecycles.

Finding the alias for a team

Navigate to a Team page. There you can find the team alias.

Teams Alias

Finding the alias for a tier

Navigate to the Account page. From there you will see a list of all your Service Tiers and their aliases. Currently, only users with the Admin role have access to the Account page. Non-Admin users can access this information with the OpsLevel CLI using the opslevel list tier command.

Tier Alias

Finding the alias for a lifecycle

Similar to Service Tiers, navigate to the Account page. From there you will see a list of all your Service Lifecycles and their aliases. Currently, only users with the Admin role have access to the Account page. Non-Admin users can access this information with the OpsLevel CLI using the opslevel list lifecycle command.

Lifecycle Alias

Alias Stability

Aliases are stable identifiers. If you rename an entity that has an alias (e.g., a team), OpsLevel will generate a new alias. However, the old alias will still be valid so any existing references to it from other opslevel.yml files will continue to work.

Converting an existing service to use opslevel.yml

If you have a service already defined in OpsLevel and want it to be managed with opslevel.yml, first ensure the service is already connected to a repo. When a service is connected to a repo, OpsLevel will know how to merge a newly detected opslevel.yml with the service. After the repo is connected to the service, you can download the service’s YAML file and commit it to the repo.

Step 1: Visit a service’s Operation tab and select the repository your service lives in from the Repository Center by clicking Edit and + Add Repository.

Repository Center Repository Center

Step 2: From the service page click the Download YAML button.

Download

Step 3: Copy or Download the YAML and commit to the repo you selected in Step 1.

Download YAML contents

Converting an existing repository to use opslevel.yml

You can use opslevel.yml to manage properties directly on a repository, such as: owner, tier, and tags.

Step 1: Select a repository that was imported using one of our Git Repository Integrations.

Step 2: From the repository page click the Download YAML button.

Download

Step 3: Copy or Download the YAML and commit to this repo.

Download YAML contents

Schema

The following tables provide an in depth list of all the properties supported by opslevel.yml.

Note: opslevel.yml currently only supports one top-level field of either repository or service. In the event that both are specified, the service section will take precedence.

Service

AttributeRequiredDescription
nametrueThe name of the service.
descriptionfalseThe service description.
ownerfalseThe owner of the service. Must provide a valid team alias. Please refer to the Aliases section for more details.
lifecyclefalseThe lifecycle the service is currently in. Must provide a valid lifecycle alias. Please refer to the Aliases section for more details.
tierfalseThe tier of the service. Must provide a valid tier alias. Please refer to the Aliases section for more details.
systemfalseThe system the service belongs to.
productfalseThe product the service belongs to.
languagefalseThe core language the service is written in.
frameworkfalseThe core framework used for the service.
aliasesfalseA list of all user defined aliases for this service.
tagsfalseA list of all key value tags defined for this service. Please refer to Tags section below for more details.
toolsfalseA list of all tools used by this service. Please refer to Tools section below for more details.
repositoriesfalseA list of all repositories associated with this service. Please refer to Repositories section below for more details.
dependenciesfalseA list of all dependencies for this service. Please refer to Dependencies section below for more details.
alert sourcesfalseA list of all alert sources for this service. Please refer to Alert Sources section below for more details.
propertiesfalseAn object consisting of Property Definitions aliases as keys and values to be set on the service. Please refer to Custom Service Properties section for more details.

Repository

AttributeRequiredDescription
ownerfalseThe owner of the repository. Must provide a valid team alias. Please refer to the Aliases section for more details.
tierfalseThe tier of the repository. Must provide a valid tier alias. Please refer to the Aliases section for more details.
tagsfalseA list of all key value tags defined for this repository. Please refer to Tags section below for more details.

Attributes

Tags

AttributeRequiredDescription
keytrueThe tag key.
valuetrueThe tag value.

Tools

AttributeRequiredDescription
categorytrueThe category the tool belongs to. Valid categories are admin, api_documentation, code, continuous_integration, deployment, errors, feature_flag, health_checks, incidents, issue_tracking, logs, metrics, orchestrator, resiliency, runbooks, security_scans, status_page, wiki, and other.
urltrueThe url pointing to the tool.
namefalseThe display name used for the tool
environmentfalseThe environment this tool is used in. ex. Production, Staging.

Repositories

AttributeRequiredDescription
nametrueThe repository name. The format needs to include the Organization/Group/Workspace that it belongs to, e.g. my-github-org/my-repo, my-gitlab-group/my-repo, my-bitbucket-workspace/my-repo.
providertrueThe git provider where your repository is stored.
display_namefalseThe repository name displayed on the service page.
pathfalseThe path repository containing the opslevel.yml and where repository checks are applied. This is useful in monorepo situations where multiple services are contained in one repository.

Dependencies

AttributeRequiredDescription
aliastrueThe alias of the service.
notesfalseAdditional information about the dependency.

Alert Sources

AttributeRequiredDescription
typetrueThe type of integration where the alert source was created from. Options include datadog, opsgenie and pagerduty.
external_idtrueThe unique identifier from the integrated tool where the alert source came from. For example, a Pagerduty external_id would be the Pagerduty service's service.id

JSON Schema

You can automatically validate your opslevel.yml file as part of your CI using the following JSON schema: opslevel.schema.yml

You can run the following command which uses ajv-cli.

ajv test -s opslevel.schema.yml -d opslevel.yml --valid

Locking

When a service or repository is managed by opslevel.yml, certain fields are locked. This locking applies across all methods of modifying the service, whether in the UI or various methods that go through the GraphQL API. This ensures that there is never a conflict between what’s defined in opslevel.yml and what’s defined in OpsLevel.

For services the name, description, owner, tier, system, lifecycle stage, language, and framework fields are all locked for editing.

For repositories the owner and tier fields are locked for editing.

Service and repository properties that are lists, such as tools, tags, aliases, dependencies, and repositories, can have new entries added in the UI, though existing entries defined in opslevel.yml will be locked.

As shown in the image below, to tell whether a service or repository is managed by opslevel.yml, you can look for a lock icon on the respective information page.

Locked Service

Service Locked

Locked Repository

Repository Locked

Locked Service Dependency

Dependency Locked

Service locked from being added to a System

Service locked from being added to System

Service locked from being added to a System

Resyncing the opslevel.yml

If a config file error occurs due to a change elsewhere (ex. a service dependency has been renamed or alias has been deleted), the Resync button can be used to update the service with the latest fetched opslevel.yml after making the necessary change (ex. add the referenced alias to the correct service). This can be more convenient in some cases instead of unnecessary commits to trigger OpsLevel to re-evaluate the opslevel.yml.

Select "Resync" to update the service based on the latest fetched opslevel.yml

Select "Resync" to update the service based on the latest fetched opslevel.yml

Example service opslevel.yml

version: 1
service:
  name: Shopping Cart Service
  lifecycle: generally_available
  tier: tier_1
  system: web
  product: Retail Website
  owner: order_management_team
  language: Ruby
  framework: Rails
  description: Allows users to add/remove products in their virtual shopping carts
    prior to placing an order.
  aliases:
  - cart
  tags:
  - key: db
    value: mysql
  - key: kafka-topic
    value: cart-additions
  repositories:
  - name: DunderMifflin/shopping_cart
    path: "/"
    provider: github
    display_name: Cart Service Code
  - name: DunderMifflin/TerraformRepo
    path: "/production/shopping_cart"
    provider: bitbucket
    display_name: Terraform Config
  tools:
  - name: Confluence
    category: runbooks
    url: http://company.atlassian.com/confluence/runbooks
  - name: PagerDuty
    category: incidents
    url: https://your_account.pagerduty.com/services/PH99999
    environment: Production
  - name: Datadog
    category: metrics
    url: https://app.datadog.com/your_dashboard?env=prod
    environment: Production
  - name: Datadog
    category: metrics
    url: https://app.datadog.com/your_dashboard?env=staging
    environment: Staging
  dependencies:
    - alias: recommendation_service
      notes: Provides products recommendations to enhance the users shopping experience
    - alias: suggestions_service
  alert_sources:
    - type: pagerduty
      external_id: ABCD123
    - type: opsgenie
      external_id: 1234567-abcd-1234-abcdefgh1234
    - type: datadog
      external_id: 1234567

Example repository opslevel.yml

version: 1
repository:
  tier: tier_1
  owner: order_management_team
  tags:
  - key: version
    value: v1.0.0

Templating

If your organization uses template repositories for creating new services or repositories, you will benefit from using opslevel.defaults.yml as a templating mechanism.

opslevel.defaults.yml allows you to specify default values for your services or repositories that will be applied once you add an opslevel.yml file. Values set in the opslevel.defaults.yml file will be overwritten by values from the opslevel.yml file.

It is recommended you add an opslevel.defaults.yml file to your template repository with some basic defaults set; these are often in the form of a default language/framework, default tags, default tools, and possibly more.

Format

The format of opslevel.defaults.yml is identical to that of opslevel.yml. The only difference is that the opslevel.defaults.yml file limits which values you can set.

Values you can set from opslevel.defaults.yml:

ServiceRepository
tiertier
ownerowner
systemtags
tags
description
lifecycle
product
language
framework
repositories
tools

Like with opslevel.yml, you can validate your opslevel.defaults.yml file using the following JSON schema: opslevel.defaults.schema.yml.

FAQs

Where do I put the opslevel.yml file?

Just add your opslevel.yml file(s) to your repo. If you specify a service definition in this file and this repo isn’t already mapped to a service in OpsLevel, a new service will be created.

Note: OpsLevel will only look for files that use the .yml extension.

I have two services that are both locked by the same repo and opslevel.yml, how do I delete the duplicate service if it’s a duplicate?

If you attach a repo to a service that is already locking a different service, we will apply the opslevel.yml to the new service and subsequently lock it.

Attaching a Repo that is already attached to a Service will lock the second Service

In order to delete this service, you must first delete the repository connection on the duplicate service, which will unlock the service and allow you to delete it.

Deleting attached Repo will unlock the duplicate Service

How can I get a list of all opslevel.yml errors?

Our GraphQL API can return these errors on the configErrors field under Service and Repository objects.

If you have more questions?

Just send us an email at [email protected].