609 lines
27 KiB
YAML
609 lines
27 KiB
YAML
---
|
|
version: '3'
|
|
|
|
vars:
|
|
COLLECTION_DEPS: collection_dependencies
|
|
MAIN_TASKS_PATH: tasks/main.yml
|
|
META_PATH: meta/main.yml
|
|
MOLECULE_RESULTS_PATH: molecule/.results
|
|
PRE_SHARED_VAULT_KEY: YTtEnhPWtftHFcP3HneVmz6vX2qMqAwobTDAbvDwrdyunAaDCQ
|
|
REQUIREMENTS_PATH: requirements.yml
|
|
ROLE_NAME: '{{.GALAXY_NAMESPACE}}.{{.GALAXY_ROLE_NAME}}'
|
|
SAMPLE_PROJECT: https://github.com/megabyte-labs/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:
|
|
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:
|
|
- |
|
|
if [ -f ~/.netrc ]; then
|
|
chmod 600 ~/.netrc
|
|
fi
|
|
- cmd: '{{.PYTHON_HANDLE}} ansible-galaxy install -r requirements.yml --ignore-errors'
|
|
ignore_error: true
|
|
sources:
|
|
- requirements.yml
|
|
|
|
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
|
|
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
|
|
- task: :fix:prettier
|
|
vars:
|
|
CLI_ARGS: meta/main.yml
|
|
- task: :fix:yaml:dashes
|
|
vars:
|
|
CLI_ARGS: meta/main.yml
|
|
|
|
mod-ansible-autodoc:
|
|
todo: Add ansible-autodoc-fork to the includes of the package
|
|
cmds:
|
|
- |
|
|
if [ -n "$CI" ]; then
|
|
pip3 install ansible-autodoc-fork
|
|
fi
|
|
- task: mod-ansible-autodoc:generate
|
|
- task: mod-ansible-autodoc:variables
|
|
|
|
mod-ansible-autodoc:generate:
|
|
deps:
|
|
- :install:pipx:mod-ansible-autodoc
|
|
- :install:software:jq
|
|
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:
|
|
deps:
|
|
- :ci:commit:config
|
|
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:
|
|
- :install:software:jq
|
|
- :symlink:{{.REPOSITORY_SUBTYPE}}
|
|
- task: :install:python:requirements
|
|
vars:
|
|
INSTALL_OPTIONS: --no-dev
|
|
cmds:
|
|
- git reset --hard HEAD
|
|
- |
|
|
if ! git pull origin master; then
|
|
git config url."https://gitlab.com/".insteadOf git@gitlab.com:
|
|
git config url."https://github.com/".insteadOf git@github.com:
|
|
git pull origin master || true
|
|
fi
|
|
- task: quickstart:environment
|
|
- task: quickstart:map
|
|
- task: quickstart:demo
|
|
|
|
quickstart:cli:
|
|
deps:
|
|
- :install:software:openssl
|
|
summary: |
|
|
# Ansible Quickstart CLI
|
|
|
|
Use this task if you already know the inventory file you would like to run the
|
|
`main.yml` playbook on. The unique feature is that this task will first run
|
|
`playbooks/init.yml` (and skip any task tagged with `skip_on_init`), reboot,
|
|
and then run the normal `main.yml`. This allows you to provision a single computer
|
|
that serves both as the client and host of Ansible (since some software requires
|
|
reboots).
|
|
|
|
{{.QUICKSTART_VAULT_SECURITY}}
|
|
vars:
|
|
INVENTORY: '{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}inventories/local.yml{{end}}'
|
|
QUICKSTART_VAULT_SECURITY: |
|
|
## Ansible Vault Password Security
|
|
|
|
To achieve automation wherever possible, we save your Ansible Vault password
|
|
on disk during the installation process (i.e. to preserve the information
|
|
inbetween reboots).
|
|
|
|
To make it more secure, we employ the following measures:
|
|
1. The password is forcibly removed anytime the ansible-playbook command fails
|
|
2. It is passed in via the `ANSIBLE_VAULT_PASSWORD` variable to minimize the possibility
|
|
of the password displaying in the terminal or getting added to the command history.
|
|
3. It is stored in `~/.VAULT_PASSWORD` so you can easily spot it if something
|
|
goes wrong.
|
|
env:
|
|
ANSIBLE_CALLBACKS_ENABLED: 'junit, ansible.posix.profile_tasks, ansible.posix.timer, sentry'
|
|
ANSIBLE_STDOUT_CALLBACK: community.general.yaml
|
|
ANSIBLE_VAULT_PASSWORD_FILE: ~/.VAULT_PASSWORD
|
|
JUNIT_FAIL_ON_CHANGE: true
|
|
JUNIT_HIDE_TASK_ARGUMENTS: true
|
|
JUNIT_OUTPUT_DIR: .results/junit
|
|
QUICKSTART_PLAYBOOK_MATCH: |
|
|
# Playbook Matching Inventory File Name
|
|
|
|
A playbook with the same file name as the selected inventory was found in the
|
|
`playbooks/` directory. When the file names match up, this "quick start" script
|
|
will use the matching playbook file instead of the `main.yml` playbook found in
|
|
the root of the repository.
|
|
QUICKSTART_VAULT_SECURITY: '{{.QUICKSTART_VAULT_SECURITY}}'
|
|
log:
|
|
error: Error occurred while running the Ansible play
|
|
start: Running the Ansible play locally
|
|
success: Successfully ran the Ansible play locally
|
|
cmds:
|
|
- cmd: |
|
|
if [ ! -f "$ANSIBLE_VAULT_PASSWORD_FILE" ]; then
|
|
.config/log info 'Adding `~/ANSIBLE_PLAYBOOK_CONTINUE.sh` to run on reboot'
|
|
echo "#!/usr/env/bin bash" > ~/ANSIBLE_PLAYBOOK_CONTINUE.sh
|
|
echo "" > ~/ANSIBLE_PLAYBOOK_CONTINUE.sh
|
|
echo "cd $PWD" >> ~/ANSIBLE_PLAYBOOK_CONTINUE.sh
|
|
echo 'task ansible:quickstart:cli -- {{.INVENTORY}}' >> ~/ANSIBLE_PLAYBOOK_CONTINUE.sh
|
|
if [ -z "$ANSIBLE_VAULT_PASSWORD" ]; then
|
|
MD_TMP="$(mktemp)"
|
|
echo "$QUICKSTART_VAULT_SECURITY" > "$MD_TMP"
|
|
.config/log md "$MD_TMP"
|
|
.config/log info 'Read about security measures above.'
|
|
.config/log prompt 'What is your Ansible Vault password?'
|
|
export ANSIBLE_VAULT_PASSWORD="$(.config/log password 'Enter Vault password (leave empty if there is not a password yet)..')"
|
|
fi
|
|
fi
|
|
.config/log info 'Writing the `ANSIBLE_VAULT_PASSWORD` to temporary file in user home directory'
|
|
echo "$ANSIBLE_VAULT_PASSWORD" > ~/.VAULT_PASSWORD
|
|
INVENTORY="{{.INVENTORY}}"
|
|
INVENTORY_SLUG="$(echo "$INVENTORY" | sed 's/inventories\/\(.*\).yml/\1/')"
|
|
if [[ '{{.INVENTORY}}' == 'inventories/quickstart.yml' ]]; then
|
|
if [ -f '/etc/qubes-rpc' ] && [[ "$(whoami)" == 'user' ]]; then
|
|
.config/log info 'Assuming `ANSIBLE_USER` name to be `user` since this is Qubes'
|
|
export ANSIBLE_USER="user"
|
|
elif [ -z "$ANSIBLE_USER" ]; then
|
|
WHOAMI="$(whoami)"
|
|
.config/log prompt 'In the next step, select a user with `sudo` privileges'
|
|
if ! .config/log confirm 'Run playbook with `'"${WHOAMI}"'`?'; then
|
|
export ANSIBLE_USER="$(.config/log input 'Enter the username of the admin account you wish to use..')"
|
|
else
|
|
export ANSIBLE_USER="$WHOAMI"
|
|
fi
|
|
else
|
|
.config/log info '`ANSIBLE_USER` is set to `'"$ANSIBLE_USER"'`'
|
|
fi
|
|
if [ -z "$ANSIBLE_PASSWORD" ]; then
|
|
if sudo -n echo &> /dev/null; then
|
|
.config/log info 'Assuming passwordless sudo since `sudo -n echo` was truthy'
|
|
.config/log info 'Bypassing `ANSIBLE_PASSWORD` prompt'
|
|
else
|
|
.config/log prompt 'Enter the `sudo` password for your selected user (`'"$ANSIBLE_USER"'`)'
|
|
export ANSIBLE_PASSWORD="$(.config/log password 'Enter password (or just press enter if there is none)..')"
|
|
fi
|
|
else
|
|
.config/log info '`ANSIBLE_PASSWORD` is present as an environment variable.. bypassing password prompt'
|
|
fi
|
|
if [ -z "$MOLECULE_GROUP" ]; then
|
|
if [ -f '/etc/qubes-rpc' ]; then
|
|
.config/log info 'Machine is a Qubes dom0 environment'
|
|
export MOLECULE_GROUP="qubes"
|
|
else
|
|
.config/log info 'Assuming machine to be macOS/Linux'
|
|
export MOLECULE_GROUP="standard"
|
|
fi
|
|
fi
|
|
fi
|
|
if [ -f local/requirements.txt ]; then
|
|
pip3 install -r local/requirements.txt
|
|
else
|
|
.config/log warn 'The `local/requirements.txt` file is missing'
|
|
fi
|
|
if [ -f "playbooks/${INVENTORY_SLUG}.yml" ]; then
|
|
PLAY_TMP="$(mktemp)" && echo "$QUICKSTART_PLAYBOOK_MATCH" > "$PLAY_TMP" && .config/log md "$PLAY_TMP"
|
|
{{.PYTHON_HANDLE}}ansible-playbook --skip-tags "dotfiles,mas" -vvv -i {{.INVENTORY}} "playbooks/${INVENTORY_SLUG}.yml" || EXIT_CODE="$?"
|
|
else
|
|
.config/log info 'Using the `main.yml` playbook because there is no playbook located in `'"playbooks/${INVENTORY_SLUG}.yml"'`'
|
|
{{.PYTHON_HANDLE}}ansible-playbook --skip-tags "dotfiles,mas" -vvv -i {{.INVENTORY}} main.yml || EXIT_CODE="$?"
|
|
fi
|
|
#if [ -n "$EXIT_CODE" ]; then
|
|
# .config/log error 'There was an error while running the playbook.'
|
|
# .config/log warn 'Ensure there are no secrets in plain text (if you choose to upload the logs so our developers can fix this issue).'
|
|
# .config/log confirm 'Upload the playbook log so the developers can debug?'
|
|
# # sentry-cli
|
|
#fi
|
|
ignore_error: true
|
|
- sleep 5
|
|
- .config/log info 'Ensuring the temporary vault password file is forcibly removed'
|
|
- rm -f ~/.VAULT_PASSWORD
|
|
- rm -f ~/ANSIBLE_PLAYBOOK_CONTINUE.sh
|
|
|
|
quickstart:demo:
|
|
cmds:
|
|
- task: quickstart:cli
|
|
status:
|
|
- '[ -f files/inventory-map.json ]'
|
|
|
|
quickstart:environment:
|
|
cmds:
|
|
- task: :ansible:playbook:environment:cli
|
|
vars:
|
|
CLI_ARGS:
|
|
sh: echo "$ENV"
|
|
status:
|
|
- '[ -z "$ENV" ]'
|
|
|
|
quickstart:map:
|
|
deps:
|
|
- :install:pipx:getmac
|
|
- :install:software:gum
|
|
- :install:software:jq
|
|
summary: |
|
|
# Quickstart Mapping
|
|
|
|
This task is a helper task that attempts to automatically select the appropriate
|
|
Ansible inventory based on the MAC address. If the mapping entry is not already
|
|
saved, this task will guide the user through a series of prompts.
|
|
|
|
{{.MAC_ADDRESS_EXPLANATION}}
|
|
vars:
|
|
INVENTORY_OPTIONS:
|
|
sh: echo "\""$(find ./inventories/ -mindepth 1 -maxdepth 1 | sed 's/\.\/inventories\//inventories\//' | jq -R '[.]' | jq -s -c -r 'add | join("\" \"")')"\""
|
|
INVENTORY_OPTIONS_LENGTH:
|
|
sh: find ./inventories/ -mindepth 1 -maxdepth 1 | sed 's/\.\/inventories\///' | jq -R '[.]' | jq -s -c -r 'add | length'
|
|
MAC_ADDRESS_EXPLANATION: |
|
|
## Mapping MAC Addresses to Inventory Files
|
|
|
|
In order to achieve a completely automated flow, we have the ability
|
|
to define a map of MAC addresses and inventory files in the `files/`
|
|
folder.
|
|
|
|
You can get your MAC address by using the `getmac` program that this
|
|
task installs or you can run the following on Linux:
|
|
|
|
```
|
|
cat /sys/class/net/$(ip route show default | awk '/default/ {print $5}')/address
|
|
```
|
|
|
|
On Windows, if you are provisioning with Docker (the default "Quick Start" method)
|
|
and if you make sure you are running it on either a clean system or have no other
|
|
Docker containers running, then the MAC address will be:
|
|
|
|
```
|
|
02:42:ac:11:00:02
|
|
```
|
|
|
|
If you wanted to run the Quick Start method on Windows, you could create a file in
|
|
`files/inventory-map.json` that looks something like this:
|
|
|
|
```
|
|
{
|
|
"02:42:ac:11:00:02": "inventories/workstation.yml"
|
|
}
|
|
```
|
|
|
|
This configuration would instruct the script to automatically use the `inventories/workstation.yml`
|
|
inventory. If your MAC address is missing, the script will open an interactive prompt and include
|
|
the ability to save your MAC address to the file for later use.
|
|
env:
|
|
INVENTORY_EXPLANATION: |
|
|
# Which Inventory Should I Use?
|
|
|
|
A special / great starting point is the `quickstart.yml` inventory which allows you to pass your username
|
|
and password through a prompt. It is intended to be used to provision one machine at a time from that machine.
|
|
It is also intended to be used with the **Quick Start** links at the top of the README.md. It can be used to
|
|
provision any of our supported operating systems.
|
|
|
|
## TLDR: Choose `quickstart.yml`
|
|
MAC_ADDRESS_EXPLANATION: '{{.MAC_ADDRESS_EXPLANATION}}'
|
|
cmds:
|
|
- |
|
|
PATH="$PATH:$HOME/.local/bin"
|
|
# MAC_ADDRESS="$(cat /sys/class/net/$(ip route show default | awk '/default/ {print $5}')/address)" # Does not work on macOS
|
|
MAC_ADDRESS="$(getmac)"
|
|
TARGET_INV="$(jq --arg macAddress "$MAC_ADDRESS" -r '.[$macAddress]' files/inventory-map.json)"
|
|
if [[ "$TARGET_INV" == '' ]]; then
|
|
.config/log warn 'Initializing `files/inventory-map.json` since it appears to be an empty file'
|
|
echo '{}' > files/inventory-map.json
|
|
fi
|
|
if [ "$TARGET_INV" != 'null' ] && [ "$TARGET_INV" != '' ]; then
|
|
.config/log info "Provisioning with "'`'"$TARGET_INV"'`'
|
|
task ansible:quickstart:cli -- "$TARGET_INV"
|
|
else
|
|
MD_TMP="$(mktemp)"
|
|
echo "$MAC_ADDRESS_EXPLANATION" > "$MD_TMP"
|
|
.config/log md "$MD_TMP"
|
|
.config/log warn "MAC address missing from inventory-map.json ($MAC_ADDRESS). Details printed above."
|
|
if [ '{{.INVENTORY_OPTIONS_LENGTH}}' != '0' ]; then
|
|
.config/log prompt 'Given the information above, would you like to save your MAC address to the `files/inventory-map.json` file?'
|
|
if .config/log confirm 'Save MAC address?'; then
|
|
INV_TMP="$(mktemp)" && echo "$INVENTORY_EXPLANATION" > "$INV_TMP" && .config/log md "$INV_TMP"
|
|
.config/log prompt 'Which inventory file would you like the associate the MAC address with?'
|
|
INVENTORY_FILE="$(.config/log choose {{.INVENTORY_OPTIONS}})"
|
|
TMP="$(mktemp)"
|
|
.config/log info 'Generating new `files/inventory-map.json` file'
|
|
jq --arg inventory "$INVENTORY_FILE" --arg macaddr "$MAC_ADDRESS" '.[$macaddr] = $inventory' files/inventory-map.json > "$TMP"
|
|
mv "$TMP" files/inventory-map.json
|
|
.config/log success "Successfully associated the selected inventory with this machine's MAC address (remember to git add / commit)"
|
|
task ansible:quickstart:cli -- "$INVENTORY_FILE"
|
|
else
|
|
INV_TMP="$(mktemp)" && echo "$INVENTORY_EXPLANATION" > "$INV_TMP" && .config/log md "$INV_TMP"
|
|
.config/log prompt 'Which inventory file would you like to use?'
|
|
INVENTORY_FILE="$(.config/log choose {{.INVENTORY_OPTIONS}})"
|
|
task ansible:quickstart:cli -- "$INVENTORY_FILE"
|
|
fi
|
|
else
|
|
.config/log error 'There are no inventories defined in the `inventories/` folder.'
|
|
.config/log info 'Try running `task environment` to link to sample environments'
|
|
exit 1
|
|
fi
|
|
fi
|
|
status:
|
|
- '[ ! -f files/inventory-map.json ]'
|
|
|
|
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
|