@installdoc/ansible-gas-station
Version:
An Ansible playbook that provisions your network with software from GitHub Awesome lists, developed with disaster recovery in mind ⛽🔥🤤
367 lines (341 loc) • 15.2 kB
YAML
version: '3'
vars:
COLLECTION_DEPS: collection_dependencies
MAIN_TASKS_PATH: tasks/main.yml
META_PATH: meta/main.yml
MOLECULE_RESULTS_PATH: molecule/.results
REQUIREMENTS_PATH: requirements.yml
ROLE_NAME: '{{.GALAXY_NAMESPACE}}.{{.GALAXY_ROLE_NAME}}'
SAMPLE_PROJECT: https://github.com/ProfessorManhattan/ansible-snapd
VARIABLES_PATH: .variables.json
tasks:
build:none:
log:
start: Skipping build stage because Ansible project's do not require building
cmds:
- task: :donothing
collection-dependencies:
deps:
- :install:software:jq
- :install:software:yq
env:
COLLECTIONS:
sh: jq --arg collections "$(yq eval -o=json '.collections' {{.REQUIREMENTS_PATH}})" '.{{.COLLECTION_DEPS}} = ($collections | fromjson) |
.{{.COLLECTION_DEPS}}[] | "<a href=\"" + .source + "/" + (.name | split(".") | join("/")) + "\" title=\"" + .name +
" collection on Ansible Galaxy\" target=\"_blank\"><img alt=\"" + .name + " Ansible Galaxy badge\"
src=\"https://img.shields.io/badge/Ansible%20Galaxy-" + .name + "-000000?logo=ansible&logoColor=white&style=for-the-badge\"></a>"'
-r {{.VARIABLES_PATH}} | jq --raw-input --slurp 'split("\n") | .[0:((. | length) - 1)]'
TMP:
sh: mktemp
log:
error: Failed to generate documentation variable for collection dependencies
start: Generating documentation variable for collection dependencies
success: Generated documentation variable for collection dependencies
cmds:
- |
jq --arg collections "$COLLECTIONS" '.{{.COLLECTION_DEPS}} = ($collections | fromjson)' '{{.VARIABLES_PATH}}' > "$TMP"
mv "$TMP" '{{.VARIABLES_PATH}}'
collection-dependencies:markdown:
deps:
- :install:software:jq
vars:
COLLECTION_LENGTH:
sh: jq -r '.{{.COLLECTION_DEPS}} | length' '{{.VARIABLES_PATH}}'
FILE_PATH: .autodoc/{{.COLLECTION_DEPS}}.md
env:
MULTIPLE_COLLECTION_TEXT: "### Galaxy Collections\n\nThis role is dependent on multiple Ansible Galaxy collections.
The collections along with a links to their source are listed below.\n\n{{\"{{\"}}{{.COLLECTION_DEPS}}{{\"}}\"}}"
SINGLE_COLLECTION_TEXT: "### Galaxy Collection\n\nThis role is dependent on the following Ansible Galaxy
collection:\n\n{{\"{{\"}}{{.COLLECTION_DEPS}}{{\"}}\"}}"
log:
error: Failed to generate documentation partial for collection dependencies
start: Generating documentation partial for collection dependencies
success: Generated documentation partial for collection dependencies
cmds:
- mkdir -p '{{dir .FILE_PATH}}'
- |
{{if (eq .COLLECTION_LENGTH "0")}}
echo '' > '{{.FILE_PATH}}'
{{else if (eq .COLLECTION_LENGTH "1")}}
echo "$SINGLE_COLLECTION_TEXT" > '{{.FILE_PATH}}'
{{else}}
echo "$MULTIPLE_COLLECTION_TEXT" > '{{.FILE_PATH}}'
{{end}}
sources:
- '{{.FILE_PATH}}'
- '{{.VARIABLES_PATH}}'
galaxy:import:
log:
error: Error occurred while importing Ansible Galaxy role
start: Triggering Ansible Galaxy import
success: Successfully imported role on Ansible Galaxy
cmds:
- |
GITHUB_ROLE_SLUG="$(jq -r '.blueprint.repository.github' package.json | sed 's/.*\///')"
{{.PYTHON_HANDLE}} ansible-galaxy role import --token "$ANSIBLE_GALAXY_TOKEN" {{.GITHUB_ORG}} "$GITHUB_ROLE_SLUG"
status:
- '[ -z "$ANSIBLE_GALAXY_TOKEN" ]'
galaxy:requirements:
run: once
cmds:
- task: galaxy:requirements:install
sources:
- requirements.yml
preconditions:
- sh: test -f requirements.yml
msg: The requirements.yml file is missing! It should be present even if it is empty (which should almost never be the case).
galaxy:requirements:install:
log:
error: Error encountered while installing the Ansible Galaxy requirements specified in `requirements.yml`
start: Installing the Ansible Galaxy requirements specified in `requirements.yml`
success: Installed the Ansible Galaxy requirements specified in `requirements.yml`
cmds:
- cmd: '{{.PYTHON_HANDLE}} ansible-galaxy install -r requirements.yml --ignore-errors'
ignore_error: true
status:
- '[[ "${container:=}" == "docker" ]]'
init:
cmds:
- ansible-galaxy init --role-skeleton=/path/to/skeleton role_name
keywords:sync:
deps:
- :install:npm:prettier
- :install:software:jq
- :install:software:yq
summary: |
# Sync Galaxy Tags with `package.json` Keywords
This task syncs the Ansible Galaxy tags found in `meta/main.yml` with the keywords in the `package.json`
file. The Ansible Galaxy tags are capped to a maximum of 20 tags.
env:
MERGED_TAGS:
sh: jq -s --argjson galaxy "$(yq e -o=j '.galaxy_info.galaxy_tags' meta/main.yml)" '.[0].keywords + $galaxy | sort | unique' package.json
MERGED_TAGS_LENGTH:
sh: jq -s --argjson galaxy "$(yq e -o=j '.galaxy_info.galaxy_tags' meta/main.yml)" '.[0].keywords + $galaxy | sort | unique | length' package.json
log:
error: Error encountered while running the `package.json` / `meta/main.yml` synchronization logic
start: Synchronizing the keywords in `package.json` and `meta/main.yml`
success: Synchronized the keywords in `package.json` and `meta/main.yml`
cmds:
- |
GALAXY_INFO="$(yq e -o=j meta/main.yml)"
OPTIONAL_TAGS="$(jq '.keywords' .config/common-keywords.json)"
TMP="$(mktemp)"
RESULT="$MERGED_TAGS"
if [ "$MERGED_TAGS_LENGTH" -gt 20 ]; then
function updateList() {
REMOVE_KEY="$(jq -n --argjson optional "$OPTIONAL_TAGS" '$optional['"$1"']')"
RESULT="$(jq -n --argjson remove "$REMOVE_KEY" --argjson jq "$RESULT" '$jq | del(.[] | select(. == $remove))')"
}
LOOP_COUNT="$((MERGED_TAGS_LENGTH-20))"
for i in $(seq "$LOOP_COUNT"); do
updateList "$i"
done
fi
jq -r --argjson result "$MERGED_TAGS" '.keywords = $result' package.json > "$TMP"
mv "$TMP" package.json
{{.NPX_HANDLE}}prettier --write package.json > /dev/null
mkdir -p .cache/megabytelabs
jq -n --argjson result "$RESULT" --argjson gi "$GALAXY_INFO" '$gi | .galaxy_info.galaxy_tags = $result' > .cache/megabytelabs/galaxy-meta.json
yq eval -P .cache/megabytelabs/galaxy-meta.json > meta/main.yml
- '{{.NPX_HANDLE}}prettier --write meta/main.yml > /dev/null'
- task: :fix:yaml:dashes
vars:
CLI_ARGS: meta/main.yml
mod-ansible-autodoc:
cmds:
- task: mod-ansible-autodoc:generate
- task: mod-ansible-autodoc:variables
mod-ansible-autodoc:ansible-autodoc-fork:
cmds:
- task: :install:software:pipx
- task: :install:python:pipx
vars:
PACKAGE: ansible-autodoc-fork
mod-ansible-autodoc:generate:
deps:
- :install:python:requirements
- :install:software:jq
- mod-ansible-autodoc:ansible-autodoc-fork
env:
ACTIONS_DESCRIPTION:
sh: jq -r '.autodoc_actions_description' '{{.VARIABLES_PATH}}'
# PATH:
# sh: echo "$PATH:$(poetry env info | grep 'Python /' | sed 's/Python //')"
TAGS_DESCRIPTION:
sh: jq -r '.autodoc_tags_description' '{{.VARIABLES_PATH}}'
TODO_DESCRIPTION:
sh: jq -r '.autodoc_todo_description' '{{.VARIABLES_PATH}}'
VARIABLES_DESCRIPTION:
sh: jq -r '.autodoc_variables_description' '{{.VARIABLES_PATH}}'
log:
error: Error encountered while generating documentation partials with `mod-ansible-autodoc`
start: Compiling `mod-ansible-autodoc` documentation from comments in the play *.yml files
success: Successfully generated documentation partials with `mod-ansible-autodoc`
cmds:
- >
{{.PYTHON_HANDLE}}mod-ansible-autodoc --actions-title '## Features' --actions-description "$ACTIONS_DESCRIPTION"
--tags-title '### Tags' --tags-description "$TAGS_DESCRIPTION" --todo-title '### TODO'
--todo-description "$TODO_DESCRIPTION" --variables-title '## Variables' --variables-description
"$VARIABLES_DESCRIPTION" --variable-example-comment-prefix '#💬'
- mkdir -p .autodoc
- mv ansible_actions.md ansible_tags.md ansible_todo.md ansible_variables.json ansible_variables.md .autodoc
sources:
- '{{.VARIABLES_PATH}}'
- defaults/**/*.yml
- tasks/**/*.yml
- vars/**/*.yml
mod-ansible-autodoc:variables:
deps:
- :install:software:jq
log:
error: Failed to merge `.autodoc/ansible_variables.json` into `.variables.json`
start: Merging `.autodoc/ansible_variables.json` into `.variables.json`
success: Successfully merged `.autodoc/ansible_variables.json` into `.variables.json`
cmds:
- |
ROLE_VARIABLES="$(jq -r '.role_variables' .autodoc/ansible_variables.json)"
TMP="$(mktemp)"
jq --arg vars "$ROLE_VARIABLES" '.role_variables = ($vars | fromjson)' '{{.VARIABLES_PATH}}' > "$TMP"
mv "$TMP" '{{.VARIABLES_PATH}}'
prepare:
log:
error: Failed to ensure GitLab and GitHub are in sync
start: Preparing for Ansible Galaxy upload
success: GitLab and GitHub are in sync
cmds:
- task: :git:remotes
- git pull origin master
- git push github master
publish:
cmds:
- task: galaxy:import
quickstart:
deps:
- :ansible:symlink:{{.REPOSITORY_SUBTYPE}}
- task: :install:python:requirements
vars:
INSTALL_OPTIONS: --no-dev
vars:
INSTALLING:
sh: if test -f install_in_progress; then echo 'true'; else echo 'false'; fi
log:
error: Error occurred while running the Ansible play
start: Running the Ansible play locally
success: Successfully ran the Ansible play locally
cmds:
- cp test/{{OS}}/inventory inventory
- if [ ! -f ansible.cfg.bak ]; then cp ansible.cfg ansible.cfg.bak; fi
- cp test/{{OS}}/ansible.cfg ansible.cfg
- touch install_in_progress
- |
.config/log info 'Prompting for sudo password which is required to run the playbook'
{{.PYTHON_HANDLE}}ansible-playbook --ask-sudo-pass{{if eq .INSTALLING 'false'}} --skip-tags "skip_on_init" playbooks/init.yml{{else}} main.yml{{end}}
- if [ -f ansible.cfg.bak ]; then mv ansible.cfg.bak ansible.cfg; fi
- if [ -f inventory ]; then rm inventory; fi
sync:requirements:
deps:
- :install:software:jq
- :install:software:yq
log:
error: Failed to synchronize role dependencies in `{{.META_PATH}}` to `{{.REQUIREMENTS_PATH}}`
start: Ensuring role dependencies in `{{.META_PATH}}` are also listed in `{{.REQUIREMENTS_PATH}}`
success: Successfully ensured role dependencies in `{{.META_PATH}}` are also listed in `{{.REQUIREMENTS_PATH}}`
cmds:
- |
ROLES="$(yq eval '.roles' '{{.REQUIREMENTS_PATH}}')"
yq eval -o=json '.dependencies' '{{.META_PATH}}' | jq -rc '.[] .role' | while read ROLE_NAME; do
if [[ ! "$ROLES" =~ "$ROLE_NAME" ]]; then
yq eval -i -P '.roles = .roles + {"name": "'"$ROLE_NAME"'"}' '{{.REQUIREMENTS_PATH}}'
fi
done
- task: :fix:yaml:dashes
vars:
CLI_ARGS: '{{.REQUIREMENTS_PATH}}'
update:galaxy-id:
log:
error: Failed to look up or inject the Ansible Galaxy project ID into `package.json`
start: Adding Ansible Galaxy project ID to `package.json` (if available)
success: Successfully ensured Ansible Galaxy project ID is in `package.json` (if the project is on Ansible Galaxy)
cmds:
- |
TMP="$(mktemp)"
PROJECT_ID="$(ansible-galaxy info '{{.ROLE_NAME}}' 2> /dev/null | grep -E 'id: [0-9]' | cut -d ' ' -f2)"
if [ "$PROJECT_ID" ]; then
jq --arg a "$PROJECT_ID" '.blueprint.ansible_galaxy_project_id = $a' package.json > "$TMP"
mv "$TMP" package.json
fi
status:
- jq -e 'has("blueprint.ansible_galaxy_project_id")' package.json
update:variables:
cmds:
- task: :ansible:ansibler:ansibler
- task: update:variables:descriptions
update:variables:descriptions:
deps:
- :install:software:jq
- :install:software:yq
vars:
ALT_PREFIX: This repository is the home of an [Ansible](https://www.ansible.com/) role that
DESCRIPTION:
sh: yq e '.galaxy_info.description' '{{.META_PATH}}'
DESCRIPTION_LOWER: '{{lower (trunc 1 .DESCRIPTION)}}{{substr 1 (len .DESCRIPTION) .DESCRIPTION}}'
SUBHEADER_PREFIX: An Ansible role that
env:
ALT: '{{.ALT_PREFIX}} {{.DESCRIPTION_LOWER}}'
GALAXY_INFO:
sh: yq e -o=json '.galaxy_info' '{{.META_PATH}}'
SUBHEADER: '{{.SUBHEADER_PREFIX}} {{.DESCRIPTION_LOWER}}'
TMP:
sh: mktemp
log:
error: Failed to inject `.variables.json` with description variables
start: Injecting description variables into `.variables.json`
success: Successfully updated `.variables.json` with description variables
cmds:
- jq -S --arg alt "$ALT" --arg galaxyinfo "$GALAXY_INFO" --arg subheader "$SUBHEADER" '.alternative_description = $alt |
.galaxy_info = ($galaxyinfo | fromjson) | .subheader_description = $subheader' '{{.VARIABLES_PATH}}' > "$TMP"
- mv "$TMP" '{{.VARIABLES_PATH}}'
sources:
- '.common/variables.{{.REPOSITORY_SUBTYPE}}.json'
- '{{.META_PATH}}'
- package.json
preconditions:
- sh: type jq > /dev/null
msg: jq is not installed.
- sh: type yq > /dev/null
msg: yq is not installed.
- sh: 'test -f "{{.META_PATH}}"'
msg: 'The `{{.META_PATH}}` file is missing. A properly populated `{{.META_PATH}}` is required. You can find an
example of one at {{.SAMPLE_PROJECT}}.'
- sh: 'test -f "{{.VARIABLES_PATH}}"'
msg: 'The `{{.VARIABLES_PATH}}` file is missing!'
update:variables:playbook:
cmds:
- task: :ansible:playbook:docs
vault:lint:file:
summary: |
# Check for unencrypted Ansible Vault files
This task is leveraged by `lint-staged` to ensure that any file that matches `**/*vault.yml` is encrypted
with Ansible Vault.
log:
error: '`{{.CLI_ARGS}}` is not encrypted! All files matching `**/*vault.yml` must be encrypted by `ansible-vault`.'
start: Checking if `{{.CLI_ARGS}}` is encrypted with `ansible-vault`
success: Ensured `{{.CLI_ARGS}}` is encrypted
cmds:
- |
head -1 '{{.CLI_ARGS}}' | grep --quiet '^\$ANSIBLE_VAULT;' || {
if [ -s '{{.CLI_ARGS}}' ]; then
exit 1
fi
}
verify:
deps:
- :install:software:poetry
log:
error: Failed to connect to Ansible Galaxy with provided token
start: Verifying connection can be made to Ansible Galaxy
success: Successfully connected to Ansible Galaxy
cmds:
- poetry update ansible
- poetry run ansible-galaxy role setup --token "$ANSIBLE_GALAXY_TOKEN" null null null null --list