mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2026-01-10 22:21:40 +00:00
As the Vault pipeline and release processes evolve over time, so too must the tooling that drives them. Historically we've utilized a combination of CI features and shell scripts that are wrapped into make targets to drive our CI. While this approach has worked, it requires careful consideration of what features to use (bash in CI almost never matches bash in developer machines, etc.) and often requires a deep understanding of several CLI tools (jq, etc). `make` itself also has limitations in user experience, e.g. passing flags. As we're all in on Github Actions as our pipeline coordinator, continuing to utilize and build CLI tools to perform our pipeline tasks makes sense. This PR adds a new CLI tool called `pipeline` which we can use to build new isolated tasks that we can string together in Github Actions. We intend to use this utility as the interface for future release automation work, see VAULT-27514. For the first task in this new `pipeline` tool, I've chosen to build two small sub-commands: * `pipeline releases list-versions` - Allows us to list Vault versions between a range. The range is configurable either by setting `--upper` and/or `--lower` bounds, or by using the `--nminus` to set the N-X to go back from the current branches version. As CE and ENT do not have version parity we also consider the `--edition`, as well as none-to-many `--skip` flags to exclude specific versions. * `pipeline generate enos-dynamic-config` - Which creates dynamic enos configuration based on the branch and the current list of release versions. It takes largely the same flags as the `release list-versions` command, however it also expects a `--dir` for the enos directory and a `--file` where the dynamic configuration will be written. This allows us to dynamically update and feed the latest versions into our sampling algorithm to get coverage over all supported prior versions. We then integrate these new tools into the pipeline itself and cache the dynamic config on a weekly basis. We also cache the pipeline tool itself as it will likely become a repository for pipeline specific tooling. The caching strategy for the `pipeline` tool itself will make most workflows that require it super fast. Signed-off-by: Ryan Cragun <me@ryan.ec>
230 lines
11 KiB
YAML
230 lines
11 KiB
YAML
---
|
|
name: enos
|
|
|
|
on:
|
|
# Only trigger this working using workflow_call. This workflow requires many
|
|
# secrets that must be inherited from the caller workflow.
|
|
workflow_call:
|
|
inputs:
|
|
# The name of the artifact that we're going to use for testing. This should
|
|
# match exactly to build artifacts uploaded to Github and Artifactory.
|
|
build-artifact-name:
|
|
required: true
|
|
type: string
|
|
# The maximum number of scenarios to include in the test sample.
|
|
sample-max:
|
|
default: 1
|
|
type: number
|
|
# The name of the enos scenario sample that defines compatible scenarios we can
|
|
# can test with.
|
|
sample-name:
|
|
required: true
|
|
type: string
|
|
runs-on:
|
|
# NOTE: The value should be JSON encoded as that's the only way we can
|
|
# pass arrays with workflow_call.
|
|
type: string
|
|
required: false
|
|
default: '"ubuntu-latest"'
|
|
ssh-key-name:
|
|
type: string
|
|
default: ${{ github.event.repository.name }}-ci-ssh-key
|
|
vault-edition:
|
|
required: false
|
|
type: string
|
|
default: ce
|
|
# The Git commit SHA used as the revision when building vault
|
|
vault-revision:
|
|
required: true
|
|
type: string
|
|
vault-version:
|
|
required: true
|
|
type: string
|
|
|
|
jobs:
|
|
metadata:
|
|
runs-on: ${{ fromJSON(inputs.runs-on) }}
|
|
outputs:
|
|
build-date: ${{ steps.metadata.outputs.build-date }}
|
|
sample: ${{ steps.metadata.outputs.sample }}
|
|
vault-version: ${{ steps.metadata.outputs.vault-version }}
|
|
steps:
|
|
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
|
with:
|
|
ref: ${{ inputs.vault-revision }}
|
|
- uses: hashicorp/action-setup-enos@v1
|
|
with:
|
|
github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
|
- uses: ./.github/actions/create-dynamic-config
|
|
with:
|
|
github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
|
vault-version: ${{ inputs.vault-version }}
|
|
vault-edition: ${{ inputs.vault-edition }}
|
|
- id: metadata
|
|
run: |
|
|
build_date=$(make ci-get-date)
|
|
sample_seed=$(date +%s)
|
|
if ! sample=$(enos scenario sample observe "${{ inputs.sample-name }}" --chdir ./enos --min 1 --max "${{ inputs.sample-max }}" --seed "${sample_seed}" --format json | jq -c ".observation.elements"); then
|
|
echo "failed to do sample observation: $sample" 2>&1
|
|
exit 1
|
|
fi
|
|
if [[ "${{ inputs.vault-edition }}" == "ce" ]]; then
|
|
vault_version="${{ inputs.vault-version }}"
|
|
else
|
|
# shellcheck disable=2001
|
|
vault_version="$(sed 's/+ent/+${{ inputs.vault-edition }}/g' <<< '${{ inputs.vault-version }}')"
|
|
fi
|
|
sample_seed=$(date +%s)
|
|
sample=$(enos scenario sample observe "${{ inputs.sample-name }}" --chdir ./enos --min 1 --max "${{ inputs.sample-max }}" --seed "${sample_seed}" --format json | jq -c ".observation.elements")
|
|
{
|
|
echo "build-date=${build_date}"
|
|
echo "vault-version=${vault_version}"
|
|
echo "sample=${sample}"
|
|
echo "sample-seed=${sample_seed}" # This isn't used outside of here but is nice to know for duplicating observations
|
|
} | tee -a "$GITHUB_OUTPUT"
|
|
|
|
# Run the Enos test scenario(s)
|
|
run:
|
|
needs: metadata
|
|
name: run ${{ matrix.scenario.id.filter }}
|
|
strategy:
|
|
fail-fast: false # don't fail as that can skip required cleanup steps for jobs
|
|
matrix:
|
|
include: ${{ fromJSON(needs.metadata.outputs.sample) }}
|
|
runs-on: ${{ fromJSON(inputs.runs-on) }}
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
|
# Pass in enos variables
|
|
ENOS_VAR_aws_region: ${{ matrix.attributes.aws_region }}
|
|
ENOS_VAR_aws_ssh_keypair_name: ${{ inputs.ssh-key-name }}
|
|
ENOS_VAR_aws_ssh_private_key_path: ./support/private_key.pem
|
|
ENOS_VAR_tfc_api_token: ${{ secrets.TF_API_TOKEN }}
|
|
ENOS_VAR_artifactory_username: ${{ secrets.ARTIFACTORY_USER }}
|
|
ENOS_VAR_artifactory_token: ${{ secrets.ARTIFACTORY_TOKEN }}
|
|
ENOS_VAR_terraform_plugin_cache_dir: ./support/terraform-plugin-cache
|
|
ENOS_VAR_vault_artifact_path: ./support/downloads/${{ inputs.build-artifact-name }}
|
|
ENOS_VAR_vault_build_date: ${{ needs.metadata.outputs.build-date }}
|
|
ENOS_VAR_vault_product_version: ${{ needs.metadata.outputs.vault-version }}
|
|
ENOS_VAR_vault_revision: ${{ inputs.vault-revision }}
|
|
ENOS_VAR_vault_upgrade_initial_version: ${{ matrix.attributes.upgrade_initial_version }}
|
|
ENOS_VAR_consul_license_path: ./support/consul.hclic
|
|
ENOS_VAR_vault_license_path: ./support/vault.hclic
|
|
ENOS_VAR_distro_version_amzz: ${{ matrix.attributes.distro_version_amzn }}
|
|
ENOS_VAR_distro_version_leap: ${{ matrix.attributes.distro_version_leap }}
|
|
ENOS_VAR_distro_version_rhel: ${{ matrix.attributes.distro_version_rhel }}
|
|
ENOS_VAR_distro_version_sles: ${{ matrix.attributes.distro_version_sles }}
|
|
ENOS_VAR_distro_version_ubuntu: ${{ matrix.attributes.distro_version_ubuntu }}
|
|
ENOS_DEBUG_DATA_ROOT_DIR: /tmp/enos-debug-data
|
|
steps:
|
|
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
|
with:
|
|
ref: ${{ inputs.vault-revision }}
|
|
- uses: hashicorp/setup-terraform@v3
|
|
with:
|
|
# the Terraform wrapper will break Terraform execution in Enos because
|
|
# it changes the output to text when we expect it to be JSON.
|
|
terraform_wrapper: false
|
|
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
|
with:
|
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_CI }}
|
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_CI }}
|
|
aws-region: ${{ matrix.attributes.aws_region }}
|
|
role-to-assume: ${{ secrets.AWS_ROLE_ARN_CI }}
|
|
role-skip-session-tagging: true
|
|
role-duration-seconds: 3600
|
|
- uses: hashicorp/action-setup-enos@v1
|
|
with:
|
|
github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
|
- uses: ./.github/actions/create-dynamic-config
|
|
with:
|
|
github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
|
vault-version: ${{ inputs.vault-version }}
|
|
vault-edition: ${{ inputs.vault-edition }}
|
|
- name: Prepare scenario dependencies
|
|
id: prepare_scenario
|
|
run: |
|
|
mkdir -p "./enos/support/terraform-plugin-cache"
|
|
echo "${{ secrets.SSH_KEY_PRIVATE_CI }}" > "./enos/support/private_key.pem"
|
|
chmod 600 "./enos/support/private_key.pem"
|
|
echo "debug_data_artifact_name=enos-debug-data_$(echo "${{ matrix.scenario }}" | sed -e 's/ /_/g' | sed -e 's/:/=/g')" >> "$GITHUB_OUTPUT"
|
|
- if: contains(inputs.sample-name, 'build')
|
|
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
|
with:
|
|
name: ${{ inputs.build-artifact-name }}
|
|
path: ./enos/support/downloads
|
|
- if: contains(inputs.sample-name, 'ent')
|
|
name: Configure Vault license
|
|
run: echo "${{ secrets.VAULT_LICENSE }}" > ./enos/support/vault.hclic || true
|
|
- if: contains(matrix.scenario.id.filter, 'consul_edition:ent')
|
|
name: Configure Consul license
|
|
run: |
|
|
echo "matrix.scenario.id.filter: ${{ matrix.scenario.id.filter }}"
|
|
echo "${{ secrets.CONSUL_LICENSE }}" > ./enos/support/consul.hclic || true
|
|
- id: launch
|
|
name: enos scenario launch ${{ matrix.scenario.id.filter }}
|
|
# Continue once and retry to handle occasional blips when creating infrastructure.
|
|
continue-on-error: true
|
|
run: enos scenario launch --timeout 60m0s --chdir ./enos ${{ matrix.scenario.id.filter }}
|
|
- if: steps.launch.outcome == 'failure'
|
|
id: launch_retry
|
|
name: Retry enos scenario launch ${{ matrix.scenario.id.filter }}
|
|
run: enos scenario launch --timeout 60m0s --chdir ./enos ${{ matrix.scenario.id.filter }}
|
|
- name: Upload Debug Data
|
|
if: failure()
|
|
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
|
|
with:
|
|
# The name of the artifact is the same as the matrix scenario name with the spaces replaced with underscores and colons replaced by equals.
|
|
name: ${{ steps.prepare_scenario.outputs.debug_data_artifact_name }}
|
|
path: ${{ env.ENOS_DEBUG_DATA_ROOT_DIR }}
|
|
retention-days: 30
|
|
continue-on-error: true
|
|
- if: ${{ always() }}
|
|
id: destroy
|
|
name: enos scenario destroy ${{ matrix.scenario.id.filter }}
|
|
continue-on-error: true
|
|
run: enos scenario destroy --timeout 60m0s --chdir ./enos ${{ matrix.scenario.id.filter }}
|
|
- if: steps.destroy.outcome == 'failure'
|
|
id: destroy_retry
|
|
name: Retry enos scenario destroy ${{ matrix.scenario.id.filter }}
|
|
continue-on-error: true
|
|
run: enos scenario destroy --timeout 60m0s --chdir ./enos ${{ matrix.scenario.id.filter }}
|
|
- name: Clean up Enos runtime directories
|
|
id: cleanup
|
|
if: ${{ always() }}
|
|
continue-on-error: true
|
|
run: |
|
|
rm -rf /tmp/enos*
|
|
rm -rf ./enos/support
|
|
rm -rf ./enos/.enos
|
|
# Send slack notifications to #feed-vault-enos-failures any of our enos scenario commands fail.
|
|
# There is an incoming webhook set up on the "Enos Vault Failure Bot" Slackbot:
|
|
# https://api.slack.com/apps/A05E31CH1LG/incoming-webhooks
|
|
- if: ${{ always() && ! cancelled() }}
|
|
name: Notify launch failed
|
|
uses: hashicorp/actions-slack-status@v2.0.1
|
|
with:
|
|
failure-message: "enos scenario launch ${{ matrix.scenario.id.filter}} failed. \nTriggering event: `${{ github.event_name }}` \nActor: `${{ github.actor }}`"
|
|
status: ${{ steps.launch.outcome }}
|
|
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
- if: ${{ always() && ! cancelled() }}
|
|
name: Notify retry launch failed
|
|
uses: hashicorp/actions-slack-status@v2.0.1
|
|
with:
|
|
failure-message: "retry enos scenario launch ${{ matrix.scenario.id.filter}} failed. \nTriggering event: `${{ github.event_name }}` \nActor: `${{ github.actor }}`"
|
|
status: ${{ steps.launch_retry.outcome }}
|
|
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
- if: ${{ always() && ! cancelled() }}
|
|
name: Notify destroy failed
|
|
uses: hashicorp/actions-slack-status@v2.0.1
|
|
with:
|
|
failure-message: "enos scenario destroy ${{ matrix.scenario.id.filter}} failed. \nTriggering event: `${{ github.event_name }}` \nActor: `${{ github.actor }}`"
|
|
status: ${{ steps.destroy.outcome }}
|
|
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
- if: ${{ always() && ! cancelled() }}
|
|
name: Notify retry destroy failed
|
|
uses: hashicorp/actions-slack-status@v2.0.1
|
|
with:
|
|
failure-message: "retry enos scenario destroy ${{ matrix.scenario.id.filter}} failed. \nTriggering event: `${{ github.event_name }}` \nActor: `${{ github.actor }}`"
|
|
status: ${{ steps.destroy_retry.outcome }}
|
|
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
|