516 lines
24 KiB
YAML
516 lines
24 KiB
YAML
|
---
|
||
|
version: '3'
|
||
|
|
||
|
tasks:
|
||
|
collections:download:
|
||
|
cmds:
|
||
|
- |
|
||
|
PATH="$PATH:$HOME/.local/bin"
|
||
|
ansible-galaxy collection download -r requirements.yml
|
||
|
|
||
|
docs:
|
||
|
deps:
|
||
|
- docs:roles
|
||
|
- docs:tags
|
||
|
|
||
|
docs:roles:
|
||
|
deps:
|
||
|
- :install:software:jq
|
||
|
- :install:software:yq
|
||
|
log:
|
||
|
error: Failed to acquire README chart data for the roles
|
||
|
start: Scanning roles folder and generating chart data
|
||
|
success: Finished populating roles folder chart data
|
||
|
cmds:
|
||
|
- |
|
||
|
TMP="$(mktemp)"
|
||
|
jq --arg name "Role Name" --arg description "Description" --arg github 'GitHub ' \
|
||
|
'.role_var_chart = [[$name, $description, $github]]' .variables.json > "$TMP"
|
||
|
mv "$TMP" .variables.json
|
||
|
for ROLE_PATH in roles/*/*; do
|
||
|
if [[ "$ROLE_PATH" != *"roles/deprecated/"* ]] && [[ "$ROLE_PATH" != *"roles/cloud/"* ]] && [[ "$ROLE_PATH" != *"roles/helpers/"* ]]; then
|
||
|
if [ "$(yq e '.galaxy_info.project.documentation' "${ROLE_PATH}/meta/main.yml")" != 'null' ]; then
|
||
|
DOCUMENTATION_LINK="*[Documentation]($(yq e '.galaxy_info.project.documentation' "${ROLE_PATH}/meta/main.yml" | sed 's/null//'))* | "
|
||
|
else
|
||
|
DOCUMENTATION_LINK=""
|
||
|
fi
|
||
|
if [ "$(yq e '.galaxy_info.project.homepage' "${ROLE_PATH}/meta/main.yml")" != 'null' ]; then
|
||
|
HOMEPAGE_LINK="*[Homepage]($(yq e '.galaxy_info.project.homepage' "${ROLE_PATH}/meta/main.yml"))* | "
|
||
|
else
|
||
|
HOMEPAGE_LINK=""
|
||
|
fi
|
||
|
GITHUB_URL="$(yq e '.galaxy_info.project.github' "${ROLE_PATH}/meta/main.yml")"
|
||
|
if [ "$GITHUB_URL" == 'Not open-source' ]; then
|
||
|
GITHUB_SHIELD="**❌ Closed source**"
|
||
|
elif [ "$GITHUB_URL" != 'null' ]; then
|
||
|
GITHUB_PATH="$(echo "$GITHUB_URL" | sed 's/https:\/\/github.com\///' | sed 's/\/$//')"
|
||
|
GITHUB_OWNER="$(echo "$GITHUB_PATH" | sed 's/\/.*$//')"
|
||
|
GITHUB_PROJECT_SLUG="$(echo "$GITHUB_PATH" | sed 's/^.*\///')"
|
||
|
GITHUB_SHIELD="[![GitHub Repo stars](https://img.shields.io/github/stars/$GITHUB_OWNER/$GITHUB_PROJECT_SLUG?style=social)]($GITHUB_URL)"
|
||
|
else
|
||
|
UPSTREAM_URL="$(yq e '.galaxy_info.project.upstream' "${ROLE_PATH}/meta/main.yml")"
|
||
|
if [ "$UPSTREAM_URL" != 'null' ]; then
|
||
|
GITHUB_SHIELD="**[✅ Open-source]($UPSTREAM_URL)**"
|
||
|
else
|
||
|
GITHUB_SHIELD="*N/A*"
|
||
|
fi
|
||
|
fi
|
||
|
SOFTWARE_NAME="$(jq -r '.blueprint.name' "${ROLE_PATH}/package.json")"
|
||
|
DESCRIPTION="$(jq -r '.blueprint.overview' "${ROLE_PATH}/package.json")"
|
||
|
ROLE_GITHUB_LINK="*[Role on GitHub]($(jq -r '.blueprint.repository.github' "${ROLE_PATH}/package.json"))*"
|
||
|
ANSIBLE_GALAXY_NAMESPACE="$(yq e '.galaxy_info.namespace' "${ROLE_PATH}/meta/main.yml")"
|
||
|
ANSIBLE_GALAXY_ROLE_NAME="$(yq e '.galaxy_info.role_name' "${ROLE_PATH}/meta/main.yml")"
|
||
|
ROLE_ANSIBLE_GALAXY_URL="https://galaxy.ansible.com/${ANSIBLE_GALAXY_NAMESPACE}/${ANSIBLE_GALAXY_ROLE_NAME}"
|
||
|
if [ "$ANSIBLE_GALAXY_NAMESPACE" != 'null' ] && [ "$ANSIBLE_GALAXY_ROLE_NAME" != 'null' ]; then
|
||
|
URL_LINK="**[${SOFTWARE_NAME}](${ROLE_ANSIBLE_GALAXY_URL})**"
|
||
|
else
|
||
|
URL_LINK="**${SOFTWARE_NAME}**"
|
||
|
fi
|
||
|
if [ "$(jq -r '.blueprint.ansible_galaxy_project_id' "${ROLE_PATH}/package.json")" == 'null' ]; then
|
||
|
ROLE_GITHUB_LINK=""
|
||
|
fi
|
||
|
DESCRIPTION_LINKS="(${HOMEPAGE_LINK}${DOCUMENTATION_LINK}${ROLE_GITHUB_LINK})"
|
||
|
if [ "$DESCRIPTION_LINKS" != "()" ]; then
|
||
|
DESCRIPTION_LINKS=" $(echo "$DESCRIPTION_LINKS" | sed 's/ | )$/)/')"
|
||
|
else
|
||
|
DESCRIPTION_LINKS=""
|
||
|
fi
|
||
|
TMP="$(mktemp)"
|
||
|
jq --arg name "${URL_LINK}" --arg description "${DESCRIPTION}${DESCRIPTION_LINKS}" --arg github "${GITHUB_SHIELD}" \
|
||
|
'.role_var_chart = .role_var_chart + [[$name, $description, $github]]' .variables.json > "$TMP"
|
||
|
mv "$TMP" .variables.json
|
||
|
fi
|
||
|
done
|
||
|
|
||
|
docs:tags:
|
||
|
deps:
|
||
|
- :install:npm:leasot
|
||
|
summary: |
|
||
|
```shell
|
||
|
# @description Processes leasot data and returns .variables.json data including charts written in @appnest/readme format
|
||
|
#
|
||
|
# @arg $1 The file that the leasot JSON was written to
|
||
|
# @arg $2 The tag being processed
|
||
|
function populateChartVar() {
|
||
|
...
|
||
|
}
|
||
|
```
|
||
|
vars:
|
||
|
DOC_IDS: '@binaryapp,@binarycli,@brew,@cask,@chrome,@firefox,@gem,@helm,@npm,@pypi,@vscode'
|
||
|
log:
|
||
|
error: Failed to acquire package information from comments via `leasot`
|
||
|
start: Scanning and acquiring package information in comments via `leasot`
|
||
|
success: Acquired package information from comments
|
||
|
cmds:
|
||
|
- |
|
||
|
function populateChartVar() {
|
||
|
CHART='[["Package", "Description", "GitHub "]'
|
||
|
jq --arg tag "$(echo $2 | tr '[a-z]' '[A-Z]')" -r '.[] | select(.tag == $tag) | .
|
||
|
| del(. ["file", "ref", "line", "tag"]) | .text' "$1" | while read COMMENT; do
|
||
|
if [ "$CHART" != '[' ]; then
|
||
|
CHART="${CHART},"
|
||
|
fi
|
||
|
LINK="$(echo $COMMENT | sed 's/ - .*//')"
|
||
|
URL_LINK="$(echo "$LINK" | sed 's/@tui //' | sed 's/@service //' | sed 's/@binary //' | sed 's/@cli //' | sed 's/@application //' | sed 's/@menubar //' | sed 's/@webapp //' | sed 's/^\[\([^)]*\)\](\([^)]*\)).*$/\[\1\](\2)/' | sed 's/ $//' | sed 's/\/$//')"
|
||
|
if [[ "$LINK" == *"[GitHub](NO_GITHUB_REPOSITORY_LINK)"* ]] || [[ "$LINK" != *"https://github.com"* ]]; then
|
||
|
GITHUB_SHIELD="*N/A*"
|
||
|
else
|
||
|
GITHUB_PATH="$(echo "$LINK" | sed 's/.*\[GitHub\](https:\/\/github.com\/\([^|]*\)).*/\1/' | \
|
||
|
sed 's/.*\[.*\](https:\/\/github.com\/\([^)]*\)).*/\1/' | sed 's/\/$//')"
|
||
|
GITHUB_OWNER="$(echo "$GITHUB_PATH" | sed 's/\/.*$//')"
|
||
|
GITHUB_PROJECT_SLUG="$(echo "$GITHUB_PATH" | sed 's/^.*\///')"
|
||
|
GITHUB_URL="https://github.com/${GITHUB_OWNER}/${GITHUB_PROJECT_SLUG}"
|
||
|
GITHUB_SHIELD="[![GitHub Repo stars](https://img.shields.io/github/stars/$GITHUB_OWNER/$GITHUB_PROJECT_SLUG?style=social)]($GITHUB_URL)"
|
||
|
fi
|
||
|
if [[ "$LINK" == *"[Documentation]"* ]]; then
|
||
|
DOCUMENTATION_LINK="*[Documentation]("$(echo "$LINK" | sed 's/.*\[Documentation\](\([^)]*\)).*/\1/')")* | "
|
||
|
else
|
||
|
DOCUMENTATION_LINK=""
|
||
|
fi
|
||
|
if [[ "$LINK" == *"[Homepage]"* ]]; then
|
||
|
HOMEPAGE_LINK="*[Homepage]("$(echo "$LINK" | sed 's/.*\[Homepage\](\([^)]*\)).*/\1/' | sed 's/ $//')")* | "
|
||
|
else
|
||
|
HOMEPAGE_LINK=""
|
||
|
fi
|
||
|
if [[ "$LINK" == *"[Helm]"* ]] || [[ "$LINK" == *"[Operator]"* ]]; then
|
||
|
REFERENCE_LINK="*[Helm Reference]("$(echo "$LINK" | sed 's/.*\[Helm\](\([^)]*\)).*/\1/' | sed 's/.*\[Operator\](\([^)]*\)).*/\1/')")* | "
|
||
|
else
|
||
|
REFERENCE_LINK=""
|
||
|
fi
|
||
|
DESCRIPTION_LINKS="(${HOMEPAGE_LINK}${DOCUMENTATION_LINK}${REFERENCE_LINK})"
|
||
|
if [ "$DESCRIPTION_LINKS" != "()" ]; then
|
||
|
DESCRIPTION_LINKS=" $(echo "$DESCRIPTION_LINKS" | sed 's/ | )$/)/')"
|
||
|
else
|
||
|
DESCRIPTION_LINKS=""
|
||
|
fi
|
||
|
DESCRIPTION="$(echo $COMMENT | sed 's/.* - //' | sed 's/\"/\\\"/g')"
|
||
|
CHART="${CHART}[\"**$URL_LINK**\",\"${DESCRIPTION}${DESCRIPTION_LINKS}\",\"$GITHUB_SHIELD\"]"
|
||
|
done
|
||
|
CHART="${CHART}]"
|
||
|
TMP_CHART="$(mktemp)"
|
||
|
KEY="$(echo $2 | sed 's/^@//')"
|
||
|
jq --arg chart "$CHART" --arg key "${KEY}_var_chart" '.[$key] = ($chart | fromjson)' .variables.json > "$TMP_CHART"
|
||
|
mv "$TMP_CHART" .variables.json
|
||
|
}
|
||
|
TMP="$(mktemp)"
|
||
|
leasot --tags '{{.DOC_IDS}}' --reporter json './environments/prod/group_vars/**/*.yml' > "$TMP" || true
|
||
|
VARIABLES_JSON="$(jq '.' .variables.json)"
|
||
|
for ID in {{replace "," " " .DOC_IDS}}; do
|
||
|
populateChartVar "$TMP" "$ID"
|
||
|
done
|
||
|
|
||
|
environment:
|
||
|
desc: Prompts for which environment to use and then symlinks to it
|
||
|
hide: '{{ne (print .REPOSITORY_TYPE "-" .REPOSITORY_SUBTYPE) "ansible-playbook"}}'
|
||
|
summary: |
|
||
|
# Switch environments using an interactive dialogue
|
||
|
|
||
|
Ansible does not really provide any great ways to switch between environments (or sets of
|
||
|
`host_vars/`, `group_vars/` etc.). If you place all the files and folders you wish to constitute
|
||
|
as an environment inside a folder named as the name of the environment then you can use
|
||
|
this task to handle the symlinking and switching between environments.
|
||
|
|
||
|
**Example of opening the interactive prompt:**
|
||
|
`task ansible:environment`
|
||
|
|
||
|
**You can directly switch enironments to `environments/prod/` by running:**
|
||
|
`task ansible:environment -- prod`
|
||
|
cmds:
|
||
|
- task: environment:{{if .CLI_ARGS}}cli{{else}}prompt{{end}}
|
||
|
|
||
|
environment:cli:
|
||
|
log:
|
||
|
error: Encountered an error while switching environments to `{{.CLI_ARGS}}`
|
||
|
start: Switching environment to `{{.CLI_ARGS}}`
|
||
|
success: Successfully switched environment to `{{.CLI_ARGS}}`
|
||
|
cmds:
|
||
|
- |
|
||
|
{{if .CLI_ARGS}}
|
||
|
for ITEM in environments/{{.CLI_ARGS}}/*; do
|
||
|
ITEM="$(echo $ITEM | sed 's/.*\///')"
|
||
|
if test -L "$ITEM" || ! test -e "$ITEM"; then
|
||
|
rm -f "$ITEM"
|
||
|
ln -s "./environments/{{.CLI_ARGS}}/$ITEM" "$ITEM"
|
||
|
.config/log success "Successfully symlinked "'`'"$ITEM"'`'" from ./environments/{{.CLI_ARGS}}/$ITEM"
|
||
|
else
|
||
|
.config/log warn "$ITEM exists in the root and was not a symlink so it was skipped to prevent possible data loss"
|
||
|
fi
|
||
|
done
|
||
|
{{else}}
|
||
|
exit 69
|
||
|
{{end}}
|
||
|
- .config/log finish 'Success `environment:cli`'
|
||
|
|
||
|
environment:prompt:
|
||
|
env:
|
||
|
MARKDOWN: |
|
||
|
# Symlink Environment
|
||
|
|
||
|
Answer the prompt below to switch between environments. Each environment
|
||
|
should be a folder with folders and files you wish to link to from the root
|
||
|
of the project. They should normally consist of a host_vars, group_vars,
|
||
|
inventory, and files folder (but can contain any files/folders you wish to link).
|
||
|
Each environment should have its own folder in the `environments/` folder titled
|
||
|
as the name of the environment. After you select an answer, the script will
|
||
|
symlink all of the items in the environments folder to the root as long as there
|
||
|
is not anything except a symlink to the target location (i.e. it will overwrite
|
||
|
symlinks but not files).
|
||
|
|
||
|
cmds:
|
||
|
- TMP="$(mktemp)" && echo "$MARKDOWN" > "$TMP" && .config/log md "$TMP"
|
||
|
- task: environment:prompt:continue
|
||
|
|
||
|
environment:prompt:continue:
|
||
|
interactive: true
|
||
|
deps:
|
||
|
- :install:software:gum
|
||
|
- :install:software:jq
|
||
|
cmds:
|
||
|
- |
|
||
|
ENVIRONMENT_OPTIONS="$(find ./environments -maxdepth 1 -mindepth 1 | sed 's/\.\/environments\///' | jq -R '[.]' | jq -s -c -r 'add | join(" ")')"
|
||
|
.config/log prompt 'Select an environment from the `environments/` folder to symlink to'
|
||
|
ENV_OPTION="$(gum choose $(echo $ENVIRONMENT_OPTIONS))"
|
||
|
task ansible:playbook:environment:cli -- "$ENV_OPTION"
|
||
|
|
||
|
find-missing:files:
|
||
|
desc: Find roles that are missing files
|
||
|
hide: '{{ne (print .REPOSITORY_TYPE "-" .REPOSITORY_SUBTYPE) "ansible-playbook"}}'
|
||
|
summary: |
|
||
|
# Find roles that are missing any given file
|
||
|
|
||
|
This task scans through all the folders in the roles/ directory and checks
|
||
|
for the presence of a file that you pass in through the CLI.
|
||
|
|
||
|
**Example usage:**
|
||
|
`task find-missing -- logo.png`
|
||
|
|
||
|
The example above will look through all the folders two levels deep (e.g. `./roles/tools/nmap`,
|
||
|
`./roles/system/snapd`) in the roles folder and display any roles that are missing the file.
|
||
|
log:
|
||
|
error: Failed to scan the `/roles/*` folders for roles missing `{{.CLI_ARGS}}`
|
||
|
start: Determining which roles in the `/roles/*` folders are missing `{{.CLI_ARGS}}`
|
||
|
success: Finished scanning for roles missing `{{.CLI_ARGS}}` (if there are any then they should be listed above)
|
||
|
cmds:
|
||
|
- |
|
||
|
FILES=$(find ./roles -mindepth 2 -maxdepth 2 -type d '!' -exec test -e "{}/{{.CLI_ARGS}}" ';' -print)
|
||
|
.config/log info 'Found '"$(echo "$FILES" | wc -l | xargs)"' roles missing {{.CLI_ARGS}}'
|
||
|
echo "$FILES"
|
||
|
preconditions:
|
||
|
- sh: test -d roles
|
||
|
msg: The `roles/` folder is missing. Is the project set up right?
|
||
|
|
||
|
find-missing:roles:
|
||
|
summary: |
|
||
|
# Find roles that are not in main.yml
|
||
|
|
||
|
This task will collect all the role paths in the `roles/` folder and return a list
|
||
|
of roles that are not present in the `main.yml` file.
|
||
|
|
||
|
If you want to scan something other than `main.yml`, you can pass the file in as a
|
||
|
CLI argument like so:
|
||
|
|
||
|
**Example scanning file other than `main.yml`:**
|
||
|
`task ansible:playbook:find-missing:roles -- playbooks/qubes.yml`
|
||
|
cmds:
|
||
|
- |
|
||
|
TMP="$(mktemp)"
|
||
|
RESULTS="$(mktemp)"
|
||
|
while read ROLE; do
|
||
|
ROLE_TITLE="$(echo "$ROLE" | sed 's/^.\///')"
|
||
|
if ! grep "$ROLE_TITLE" '{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}main.yml{{end}}' > /dev/null; then
|
||
|
echo "$ROLE_TITLE" >> "$RESULTS"
|
||
|
fi
|
||
|
done< <(find ./roles -maxdepth 2 -mindepth 2)
|
||
|
if grep ".*" "$RESULTS"; then
|
||
|
.config/log info 'The roles missing from `{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}main.yml{{end}}` are:'
|
||
|
cat "$RESULTS"
|
||
|
else
|
||
|
.config/log info 'All of the roles are included in `{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}main.yml{{end}}`'
|
||
|
fi
|
||
|
|
||
|
remotes:
|
||
|
deps:
|
||
|
- :install:software:git
|
||
|
- :install:software:jq
|
||
|
summary: |
|
||
|
# Ensures each role is added as a remote and a sub-repo (if applicable)
|
||
|
|
||
|
This task cycles through all the roles in the `/roles` folder and ensures
|
||
|
they are added as remotes. This helps with managing the git trees used
|
||
|
for combining the many role repositories into the playbook mono-repository.
|
||
|
|
||
|
It also adds a remote for a private submodule that is intended to store
|
||
|
files that are not meant to be shared. The remote is named `private`.
|
||
|
run: once
|
||
|
log:
|
||
|
error: Failed to set remotes for one or more of the roles in the `/roles/*` folders
|
||
|
start: Adding git remotes for all of the roles in the `/roles/*` folders
|
||
|
success: Successfully added git remotes for all of the roles in the `/roles/*` folders
|
||
|
cmds:
|
||
|
- git init -q
|
||
|
- |
|
||
|
for ROLE_RELATIVE_PATH in roles/*/*; do
|
||
|
if [ -f "${ROLE_RELATIVE_PATH}/package.json" ]; then
|
||
|
ROLE_FOLDER="$(basename $ROLE_RELATIVE_PATH)"
|
||
|
ROLE_HTTPS_REPO="$(jq -r '.blueprint.repository.gitlab' $ROLE_RELATIVE_PATH/package.json)"
|
||
|
ROLE_SSH_REPO="$(echo $ROLE_HTTPS_REPO | sed 's/https:\/\/gitlab.com\//git@gitlab.com:/' | sed 's/$/.git/')"
|
||
|
if git config "remote.${ROLE_FOLDER}.url" > /dev/null; then
|
||
|
git remote set-url "$ROLE_FOLDER" "$ROLE_SSH_REPO"
|
||
|
else
|
||
|
git remote add "$ROLE_FOLDER" "$ROLE_SSH_REPO"
|
||
|
fi
|
||
|
if [ -d $ROLE_RELATIVE_PATH/.git ] && [ ! -f $ROLE_RELATIVE_PATH/.gitrepo ]; then
|
||
|
task ansible:playbook:subrepo:init -- $ROLE_RELATIVE_PATH
|
||
|
fi
|
||
|
else
|
||
|
.config/log warn "${ROLE_RELATIVE_PATH}/package.json is missing!"
|
||
|
fi
|
||
|
done
|
||
|
|
||
|
run:
|
||
|
cmds:
|
||
|
- task: run:{{if .CLI_ARGS}}cli{{else}}prompt{{end}}
|
||
|
|
||
|
run:cli:
|
||
|
deps:
|
||
|
- task: :install:python:requirements
|
||
|
env:
|
||
|
INSTALL_OPTIONS: --no-dev
|
||
|
- :symlink:playbook
|
||
|
vars:
|
||
|
PLAYBOOK_MAIN:
|
||
|
sh: |
|
||
|
if [ -n "$PLAYBOOK_MAIN" ]; then
|
||
|
echo "$PLAYBOOK_MAIN"
|
||
|
else
|
||
|
echo "main.yml"
|
||
|
fi
|
||
|
log:
|
||
|
error: Error encounted while running `ansible-playbook -i inventories/{{.CLI_ARGS}} --ask-vault-pass main.yml`
|
||
|
start: Running `ansible-playbook -i inventories/{{.CLI_ARGS}} --ask-vault-pass main.yml`
|
||
|
success: Successfully ran `ansible-playbook -i inventories/{{.CLI_ARGS}} --ask-vault-pass main.yml`
|
||
|
cmds:
|
||
|
- |
|
||
|
PATH="$PATH:$HOME/.local/bin"
|
||
|
if [ -z "$ANSIBLE_VAULT_PASSWORD" ]; then
|
||
|
.config/log info 'The `ANSIBLE_VAULT_PASSWORD` environment variable is not set so you will be prompted for the password'
|
||
|
ansible-playbook --skip-tags "mas" -i {{.CLI_ARGS}} --ask-vault-pass "{{.PLAYBOOK_MAIN}}"
|
||
|
else
|
||
|
echo "$ANSIBLE_VAULT_PASSWORD" > "$HOME/.VAULT_PASSWORD"
|
||
|
export ANSIBLE_VAULT_PASSWORD_FILE="$HOME/.VAULT_PASSWORD"
|
||
|
.config/log info 'Bypassing Ansible Vault password prompt since the `ANSIBLE_VAULT_PASSWORD` environment variable is set'
|
||
|
ansible-playbook --skip-tags "mas" -i {{.CLI_ARGS}} "{{.PLAYBOOK_MAIN}}"
|
||
|
fi
|
||
|
|
||
|
run:prompt:
|
||
|
summary: '{{.MARKDOWN}}'
|
||
|
vars:
|
||
|
MARKDOWN: |
|
||
|
# Run the Playbook
|
||
|
|
||
|
These set of prompts will run the `main.yml` playbook after you specify:
|
||
|
|
||
|
(1) The "environment"
|
||
|
|
||
|
The environment is a collection of folders that should, at the very minimum,
|
||
|
include "files", "group_vars", "host_vars", and "inventories". Each folder in
|
||
|
the "environments" folder constitutes a different environment. By using
|
||
|
environments, you can seperate different sets of variables/files or even seperate
|
||
|
your private variables out into a sub-module.
|
||
|
|
||
|
(2) An inventory file
|
||
|
|
||
|
The Ansible inventory stored in the "inventories" folder. This will generally be
|
||
|
a YML file with host connection information that also correlates the inventory with
|
||
|
the proper host_vars and group_vars. It is assumed that your sudo username and
|
||
|
password are encrypted inside the inventory (via "ansible-vault").
|
||
|
PLAYBOOK_DESCRIPTIONS: |
|
||
|
# Playbook Descriptions
|
||
|
|
||
|
Playbooks are where you store your main logic in Ansible. The `main.yml` file in the
|
||
|
root of the repository is a generic one-size-fits-all approach. You could theoretically
|
||
|
store all your logic in one playbook for multiple scenarios with conditional logic but
|
||
|
it might be easier to create seperate playbooks in some cases. The `main.yml` should work
|
||
|
in most scenarios and is a great starting point.
|
||
|
|
||
|
## Alternate Playbook Descriptions
|
||
|
|
||
|
Alternate playbooks are stored in the `playbooks/` directory. They are described below.
|
||
|
|
||
|
*If you want their description to show up in this message, you will have to edit the appropriate
|
||
|
field in `package.json`.*
|
||
|
|
||
|
env:
|
||
|
MARKDOWN: '{{.MARKDOWN}}'
|
||
|
cmds:
|
||
|
- |
|
||
|
MD_TMP="$(mktemp)"
|
||
|
echo "$MARKDOWN" > "$MD_TMP"
|
||
|
.config/log md "$MD_TMP"
|
||
|
- task: run:prompt:continue
|
||
|
|
||
|
run:prompt:continue:
|
||
|
interactive: true
|
||
|
deps:
|
||
|
- :install:software:jq
|
||
|
cmds:
|
||
|
- task: environment
|
||
|
- echo "\"inventories"$(find ./inventories/ -mindepth 1 -maxdepth 1 | sed 's/\.\/inventories\///' | jq -R '[.]' | jq -s -c -r 'add | join("\" \"inventories")')"\""
|
||
|
- |
|
||
|
INVENTORY_OPTIONS_LENGTH="$(find ./inventories/ -mindepth 1 -maxdepth 1 | sed 's/\.\/inventories\///' | jq -R '[.]' | jq -s -c -r 'add | length')"
|
||
|
if [[ "$INVENTORY_OPTIONS_LENGTH" == '0' ]]; then
|
||
|
.config/log error 'There are no inventory files present in the `inventories/` folder' && exit 1
|
||
|
else
|
||
|
INVENTORY_OPTIONS="$(echo "\""$(find ./inventories/ -mindepth 1 -maxdepth 1 | sed 's/\.\///' | jq -R '[.]' | jq -s -c -r 'add | join("\" \"")')"\"")"
|
||
|
.config/log prompt 'Which inventory would you like to use?'
|
||
|
CHOSEN_INVENTORY="$(.config/log choose $INVENTORY_OPTIONS)"
|
||
|
export PLAYBOOK_MAIN="main.yml"
|
||
|
if ! gum confirm "Would you like to use the main.yml playbook?"; then
|
||
|
PLAYBOOKS_OPTIONS="$(echo "\"playbooks"$(find ./playbooks/ -mindepth 1 -maxdepth 1 -name "*.yml" | sed 's/\.\/playbooks\///' | jq -R '[.]' | jq -s -c -r 'add | join("\" \"playbooks")')"\"")"
|
||
|
PLAYBOOK_DESCS_TMP="$(mktemp)" && echo "$PLAYBOOK_DESCRIPTIONS" > "$PLAYBOOK_DESCS_TMP"
|
||
|
TMP_LIST="$(mktemp)"
|
||
|
find ./playbooks/ -mindepth 1 -maxdepth 1 -name "*.yml" | sed 's/\.\/playbooks\///' | jq -R '[.]' | jq -s -c -r 'add' >> "$TMP_LIST"
|
||
|
echo "* **main.yml:** A generic playbook that attempts to install everything" >> "$PLAYBOOK_DESCS_TMP"
|
||
|
jq -c -r '.[]' "$TMP_LIST" | while read SLUG; do
|
||
|
PLAYBOOK_DESC="$(jq -r '.blueprint.fileDescriptions[$file]' package.json)"
|
||
|
if [ "$PLAYBOOK_DESC" != 'null' ]; then
|
||
|
echo "* **playbooks/${SLUG}.yml:** $PLAYBOOK_DESC" >> "$PLAYBOOK_DESCS_TMP"
|
||
|
fi
|
||
|
done
|
||
|
.config/log md "$PLAYBOOK_DESCS_TMP"
|
||
|
.config/log prompt 'Select the playbook you would like to provision with.'
|
||
|
export PLAYBOOK_MAIN="$(.config/log choose $PLAYBOOKS_OPTIONS)"
|
||
|
fi
|
||
|
task ansible:playbook:run:cli -- "$CHOSEN_INVENTORY"
|
||
|
fi
|
||
|
|
||
|
subrepo:init:
|
||
|
deps:
|
||
|
- :install:software:subrepo
|
||
|
summary: |
|
||
|
# Add Role as a Sub-Repository
|
||
|
|
||
|
Since roles should each have their own repository for Ansible Galaxy and to make it easier
|
||
|
for the community to download specific roles, they must be declared as sub-repositories.
|
||
|
Submodules could also be used but we use sub-repos instead because they are more flexible.
|
||
|
|
||
|
In the main playbook, if someone clones the playbook, the playbook and all the roles will download
|
||
|
without any requirement to initialize submodules. At the same time, each role can be in its own
|
||
|
repository. The playbook recognizes roles like this because they have a `.gitrepo` file that is only
|
||
|
saved in the playbook version of the role. Users can interact with the playbook and its role
|
||
|
repositories transparently without any need to understand what git subrepos are.
|
||
|
|
||
|
Managers of roles can update the role repositories without any need to understand what git subrepos
|
||
|
are. Managers of the playbook can use the tool [git-subrepo](https://github.com/ingydotnet/git-subrepo)
|
||
|
to perform various actions including pulling changes from individual role repositories and
|
||
|
other actions.
|
||
|
|
||
|
Usage:
|
||
|
`task ansible:playbook:subrepo:init -- path/to/folder/with.git/folder`
|
||
|
cmds:
|
||
|
- task: :git:commit:automated
|
||
|
- |
|
||
|
BASENAME="$(basename {{.CLI_ARGS}})"
|
||
|
REMOTE="$(git remote get-url $BASENAME)"
|
||
|
HUSKY=0 git subrepo init {{.CLI_ARGS}} -r "$REMOTE" -b master
|
||
|
|
||
|
types:
|
||
|
deps:
|
||
|
- :install:npm:quicktype
|
||
|
summary: |
|
||
|
# Generate Types from Vaulted Files
|
||
|
|
||
|
Automatically generate types from vaulted files.
|
||
|
|
||
|
**Example Usage:**
|
||
|
`task ansible:playbook:types -- ./environments/prod
|
||
|
vars:
|
||
|
TARGET_DIR: '{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}./environments/prod{{end}}'
|
||
|
cmds:
|
||
|
- task: vault:decrypt
|
||
|
vars:
|
||
|
TARGET_DIR: '{{.TARGET_DIR}}'
|
||
|
- |
|
||
|
qtype() {
|
||
|
local FILE_NO_EXT="$(echo "$1" | sed 's/.yml$//')"
|
||
|
yq e -o=json '.' $1 | quicktype -l schema -o ${FILE_NO_EXT}.schema.json
|
||
|
}
|
||
|
while read FILE; do
|
||
|
qtype "$FILE"
|
||
|
done < <(find {{.TARGET_DIR}} -type f -name "*vault.yml")
|
||
|
- task: vault:encrypt
|
||
|
vars:
|
||
|
TARGET_DIR: '{{.TARGET_DIR}}'
|
||
|
|
||
|
vault:decrypt:
|
||
|
vars:
|
||
|
TARGET_DIR: '{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}./environments/prod{{end}}'
|
||
|
cmds:
|
||
|
- find {{.TARGET_DIR}} -type f -name "*vault.yml" -printf "%h/\"%f\" " | xargs ansible-vault decrypt
|
||
|
|
||
|
vault:encrypt:
|
||
|
vars:
|
||
|
TARGET_DIR: '{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}./environments/prod{{end}}'
|
||
|
cmds:
|
||
|
- find {{.TARGET_DIR}} -type f -name "*vault.yml" -printf "%h/\"%f\" " | xargs ansible-vault encrypt
|