Skip to main content

Buildkite DSL

Expeditor’s Buildkite DSL is a custom YAML DSL written on top of Buildkite’s existing YAML DSL. The DSL is contained within the expeditor keyspace and is intended to provide shortcuts and additional Chef-specific functionality beyond what is available from Buildkite.

steps.#.expeditor

accounts

Note

Only supported on private pipelines.

Warning

If you are using the docker executor, you must use the default chefes/buildkite or chefes/buildkite-windows images in order to leverage this functionality.

Automatically configure the CLI associated with one or more of the supported account types in the execution runtime of a single Buildkite job.

  • aws Configure the aws CLI with the temporary STS credentials (as a profile) for the specified AWS account.
    steps:
      - label: a job that uses the aws CLI to interact with an AWS account
        commands:
          - aws --profile chef-example s3 ls
        expeditor:
          accounts:
            - aws/chef-example
  • github Configure the git CLI to use a custom git credential helper that will fetch a temporary access token to the specified GitHub organization. This functionality currently only supports the chef GitHub organization.
    steps:
      - label: a job that uses the git CLI to fetch from a private GitHub repository
        commands:
          - git clone https://github.com/chef/private-repository.git
        expeditor:
          accounts:
            - github/chef

cache

Automatically configure the CLI associated with an S3 bucket to cache repository level directories before and after the execution runtime of a single Buildkite job step.

Note

This will only cache from the root of your repository.

Warning

You must enable the cache as a yaml array.
.expeditor/foo.pipeline.yml
---
steps:
  - label: "default usage: run S3 cp to cache directories"
    expeditor:
      cached_folders:
      - foo/
  - label: "default usage: run S3 cp to cache directories"
    expeditor:
      cached_folders: [ "bar/" ]

secrets

Note

Only supported on private pipelines.

Warning

If you are using the docker executor, you must use the default chefes/buildkite or chefes/buildkite-windows images in order to leverage this functionality.

Grant permission for a Buildkite step to access secrets stored in Chef’s internal Vault instance. Please check out our best practices for writing Bash scripts for guidance on which of the two patterns below you should use.

  • Pattern 1: Only inject Vault credentials. This pattern will only inject the VAULT_ADDR, VAULT_NAMESPACE, and VAULT_TOKEN environment variables. This allows your step to make calls to Vault to fetch the secrets you need. If you are running in an executor where the vault CLI is not available to you, we recommend you use Pattern 2.
    ---
    steps:
      - label: "Bash script that needs access to Vault"
        command:
          - .expeditor/buildkite/my_script.sh
        expeditor:
          executor:
            docker:
          secrets: true
  • Pattern 2: Pre-fetch the secrets and inject them as environment variables. This pattern will leverage Buildkite hooks to pre-fetch the secrets from Vault and make them available to your step as environment variables. For full details on how to reference secrets using this format, please check out the Secrets DSL reference documentation.
    ---
    steps:
      - label: "test that needs access to Vault"
        command:
          - echo \$MY_SECRET
        expeditor:
          secrets:
            GITHUB_TOKEN:
              account: github/chef
              field: token
            MY_SECRET:
              path: /secrets/my-app/my-secrets
              field: my-secrets

executor

For Buildkite pipelines managed with Expeditor, you select where to run your step by specifying an executor. The executor allows you to specify the where and how you want to run your step but how, combining the concept of Buildkite agent tags with plugins into a single entity.

Note

There is no default executor. If you do not specify an executor, we fall back to default Buildkite behavior of scheduling you on the default queue.

Each executor has its own settings, but there are four settings that are available to all executors:

  • host-os (string)
  • os-version (string)
  • privileged (boolean)
  • single-use (boolean)

docker

The docker executor is a modified shim for the docker Buildkite Plugin. It supports all the settings that the plugin supports. We highly encourage that you use the docker executor whenever possible as it simplifies the management of the CI instances and makes it easier to limit and/or reproduce environment-specific errors.

Global Setting Supported
host-os Yes: linux or windows
os-version No. The docker executor is only supported on the default (latest) version of each host-os.
privileged Yes. When true the container will be scheduled on an instance where Docker User Namespaces are disabled and containers can be run in privileged mode.
single-use No. Docker containers are (by design) already single use.
.expeditor/foo.pipeline.yml
---
steps:
  - label: "default usage: run the chefes/buildkite linux container on a linux host"
    expeditor:
      executor:
        docker:
  - label: "run the chefes/buildkite container in privileged mode on a linux host"
    expeditor:
      executor:
        docker:
          privileged: true
  - label: "run the chefes/buildkite-windows container on a windows host"
    expeditor:
      executor:
        docker:
          host-os: windows
  - label: "Run the chefes/buildkite-windows container in privileged mode on a windows host"
    expeditor:
      executor:
        docker:
          privileged: true
          host-os: windows
  - label: "default usage but specifying one of the docker-plugin settings"
    expeditor:
      executor:
        docker:
          environment:
            - FOO=bar

Unless an image setting is specified, the docker executor will use one of three Chef Release Engineering maintained Docker images which come pre-installed with the supported versions of all the programming languages used in Chef projects, as well as some other common utilities.

Release Engineering does not manage tags for these images. If you’d like to control which iteration of the image you’d like to use we recommend you manage that using the image_sha256 setting in the expeditor.defaults.executor keyspace at the top of your pipeline definition, and update it automatically by executing a bash action in response to the docker_image_published workload for the appropriate image. You can see this pattern in use in the chef/automate GitHub repository.

.expeditor/config.yml
subscriptions:
  - workload: docker_image_published:chefes/buildkite:*
    actions:
      - bash:.expeditor/update_docker_image_version_in_verify_pipeline.sh
.expeditor/update_docker_image_version_in_verify_pipeline.sh
#!/bin/bash

set -eou pipefail

# only bump the sha256 digest for the "latest" tag
if [[ "$EXPEDITOR_TAG" != "latest" ]]; then
  exit 0
fi

branch="expeditor/bump-chefes-buildkite"
git checkout -b "$branch"

sed -i -r "s|image_sha256: .+|image_sha256: ${EXPEDITOR_SHA256_DIGEST#"sha256:"}|" .expeditor/verify.pipeline.yml

git add .expeditor/verify.pipeline.yml

# give a friendly message for the commit and make sure it's noted for any future audit of our codebase that no
# DCO sign-off is needed for this sort of PR since it contains no intellectual property
dco_safe_git_commit "Bump chefes/buildkite version"

open_pull_request

# Get back to the release branch and cleanup the leftovers - any changed files left over at the end of this script will get committed to the release branch.
git checkout -
git branch -D "$branch"
.expeditor/verify.pipeline.yml
expeditor:
  defaults:
    executor:
      docker:
        image_sha256: a7e1fa7fc3e1d9b91b6d025c5a099b9975c22be24b54275c4857ccb7bfdb89a9

steps:
  - label: "run a thing in docker"
    expeditor:
      executor:
        docker:

linux

The linux executor will simply run your step on an available Amazon Linux 2 machine.

Note

We highly recommend using the linux executor vs no executor at all. It allows us to manage default behavior more efficiently.
Global Setting Supported
host-os No. We only support Amazon Linux 2.
os-version No. We only support Amazon Linux 2.
privileged Yes. When true the job will be run on a machine where the running user (buildkite-agent) has sudo permissions for ALL commands.
single-use Yes. When true the job will be run on a machine that will be terminated after the job is complete, even if the job is unsuccessful. This setting should only be used in situations where your test cannot be run in a container and modifies the instance in some unrecoverable way.
steps:
  - label: "simple executor"
    expeditor:
      executor:
        linux:
  - label: "run on a privileged machine"
    expeditor:
      executor:
        linux:
          privileged: true
  - label: "run on a single use machine"
    expeditor:
      executor:
        linux:
          single-use: true
  - label: "run on a privileged, single-use machine"
    expeditor:
      executor:
        linux:
          privileged: true
          single-use: true

macos

The macos executor will run your step on an available Mac OS machine. Under the covers, we use our own Anka Buildkite plugin to launch ephemeral containers of either 10.15, 11, or 12. By default, we run your step in a Mac OS 10.15 container. You may pass any of the defined Anka Buildkite plugin settings to the macos executor.

Global Setting Supported
host-os No.
os-version Yes: 10.15, 11, or 12.
privileged No. There are no permission escalations available within Anka at this time.
single-use No. Anka VMs are (by design) already single use.
steps:
  - label: "run command on latest macos"
    expeditor:
      executor:
        macos:
  - label: "run command on macos 10.15"
    expeditor:
      executor:
        macos:
          os-version: "10.15"

windows

The windows executor will run your step on an available Windows Server 2019 or Windows Server 2016 machine. By default, we run your step in a Windows Server 2019 machine.

Global Setting Supported
host-os No.
os-version Yes: 2019 or 2016.
privileged Yes. When true the job will be run on a machine where the buildkite-agent user is a member of the Administrators group..
single-use Yes. When true the job will be run on a machine that will be terminated after the job is complete, even if the job is unsuccessful. This setting should only be used in situations where your test cannot be run in a container and modifies the instance in some unrecoverable way.
steps:
  - label: "run on the default (windows 2019)"
    expeditor:
      executor:
        windows:
  - label: "run on windows 2016"
    expeditor:
      executor:
        windows:
          os-version: "2016"
  - label: "run on a privileged machine"
    expeditor:
      executor:
        windows:
          privileged: true
  - label: "run on a single use machine"
    expeditor:
      executor:
        windows:
          single-use: true
  - label: "run on a privileged, single-use machine"
    expeditor:
      executor:
        windows:
          privileged: true
          single-use: true

expeditor

accounts

Automatically configure the CLI associated with one or more of the supported account types in the execution runtime of a every Buildkite job in a pipeline.

---
expeditor:
  accounts:
    - github/chef

steps:
  - command: make test1
  - command: make test2
  - command: make test3

If there is one or more steps where you don’t need or want an account that is specified in expeditor.defaults.accounts, you can reject it at the step level using by prefixing it with a bang (!).

---
expeditor:
  accounts:
    - github/chef

steps:
  - command: make test1
  - command: make test2
  - command: make test3
    expeditor:
      accounts:
        - !github

cache

Automatically configure the CLI associated with an S3 bucket to cache repository level directories before and after the execution runtime of every Buildkite job step.

Note

This will only cache from the root of your repository.
.expeditor/foo.pipeline.yml
---
expeditor:
  cached_folders:
  - foo/

steps:
  - label: "default usage: run S3 sync to cache directories"
    command: test 1
    command: test 2

If there is one or more steps where you do not need to cache directories, you can reject it at the step level by adding adding a bang (!) in front of the directory you’d like skipped.

Note

The directory you want skipped must be quoted match exactly the globally specified directory per the example below.
.expeditor/foo.pipeline.yml
---
expeditor:
  cached_folders:
  - foo/

steps:
  - label: "default usage: run S3 cp to cache directories"
    command: test 1
    command: test 2

  - label: "default usage: skip S3 cp for directory foo/"
    command: test 1
    expeditor:
      cached_folders:
      - "!foo/"
      - bar/

defaults

The expeditor.defaults keyspace provides you a means to automatically inject certain step-level configuration across all your steps.

buildkite

Specify settings that are part of the native Buildkite DSL that should applied to every step in your pipeline definition file. If there is a conflict, Expeditor will default to the value specified in the step.

Note

By default, Expeditor automatically adds a 10 minute default timeout to all pipelines. For public pipelines, this can be increased up to 60 minutes.
---
expeditor:
  defaults:
    buildkite:
      timeout_in_minutes: 15

steps:
  - command: make short-test
  - command: make another-short-test
  - command: make long-test
    timeout_in_minutes: 30

In the example above, the fully processed pipeline definition file would look like this:

---
steps:
  - command: make short-test
    timeout_in_minutes: 15
  - command: make another-short-test
    timeout_in_minutes: 15
  - command: make long-test
    timeout_in_minutes: 30

executor

Specify default settings for executors used in steps.

Note

This does not apply a default executor to all your steps.
expeditor:
  defaults:
    executor:
      docker:
        image_sha256: a7e1fa7fc3e1d9b91b6d025c5a099b9975c22be24b54275c4857ccb7bfdb89a9

steps:
  - command: make short-test
    expeditor:
      executor:
        linux:
  - command: make another-short-test
    expeditor:
      executor:
        docker:
  - command: make long-test
    expeditor:
      executor:
        docker:

The example below is logically equivalent to one above, except that the image_sha256 value is specified once instead of N times.

steps:
  - command: make short-test
    expeditor:
      executor:
        linux:
  - command: make another-short-test
    expeditor:
      executor:
        docker:
          image_sha256: a7e1fa7fc3e1d9b91b6d025c5a099b9975c22be24b54275c4857ccb7bfdb89a9
  - command: make long-test
    expeditor:
      executor:
        docker:
          image_sha256: a7e1fa7fc3e1d9b91b6d025c5a099b9975c22be24b54275c4857ccb7bfdb89a9

secrets

If you would like to have an environment variable secret injected into every step in your pipeline definition, you can specify the secret in the expeditor.secrets keyspace.

---
expeditor:
  secrets:
    GITHUB_TOKEN:
      account: github/chef
      field: token

steps:
  - command: make test1
  - command: make test2
  - command: make test3