985 lines
38 KiB
YAML
985 lines
38 KiB
YAML
---
|
|
version: '3'
|
|
|
|
vars:
|
|
MOLECULE_LOGS_PATH: molecule/.results/logs
|
|
MOLECULE_TEST_OPTIONS: ANSIBLE_STDOUT_CALLBACK=community.general.yaml
|
|
ANSIBLE_CALLBACKS_ENABLED="junit, ansible.posix.profile_tasks, ansible.posix.timer"
|
|
JUNIT_OUTPUT_DIR="molecule/.results/junit" JUNIT_FAIL_ON_CHANGE=true JUNIT_HIDE_TASK_ARGUMENTS=true
|
|
PYTHON_MOLECULE_HANDLE:
|
|
sh: |
|
|
if [ -n "$CI" ]; then
|
|
echo ''
|
|
else
|
|
if command -v unbuffer > /dev/null; then
|
|
echo 'unbuffer {{.PYTHON_HANDLE}}'
|
|
else
|
|
echo '{{.PYTHON_HANDLE}}'
|
|
fi
|
|
fi
|
|
|
|
tasks:
|
|
allure:report:
|
|
deps:
|
|
- :install:software:allure
|
|
log:
|
|
error: Failed to generate and/or open the unit test report
|
|
start: Generating and opening unit test report
|
|
success: Successfully generated and opened unit test report
|
|
cmds:
|
|
- allure generate molecule/.results/junit --output allure-reports --clean
|
|
- mkdir -p molecule/.results/junit
|
|
- cp -rf allure-reports/history/ molecule/.results/junit/
|
|
- .config/log info 'Opening JUnit results with Allure in the default browser'
|
|
- allure open allure-reports
|
|
|
|
ansifilter:
|
|
deps:
|
|
- :install:software:ansifilter
|
|
cmds:
|
|
- TMP="$(mktemp)" && cat {{.RESULTS_FILE}} | ansifilter > "$TMP" && mv "$TMP" {{.RESULTS_FILE}}
|
|
status:
|
|
- '[ -n "$CI" ]'
|
|
|
|
default:
|
|
log:
|
|
start: Running default Ansible test
|
|
cmds:
|
|
- task: molecule:docker:matrix
|
|
|
|
local:
|
|
desc: Run the Ansible play on the local machine (or via WSL - see task summary)
|
|
hide: '{{ne (print .REPOSITORY_TYPE "-" .REPOSITORY_SUBTYPE) "ansible-playbook"}}'
|
|
summary: |
|
|
# Run the Ansible play on the local machine
|
|
|
|
This task will use the inventory stored in `test/<OS>/inventory`, the playbook
|
|
file stored in `test/<OS>/test.yml`, and the Ansible configuration file stored in
|
|
`test/<OS>/ansible.cfg` to run the play. At the beginning of the play, you will
|
|
be prompted for the sudo password.
|
|
cmds:
|
|
- task: local:test
|
|
|
|
local:test:
|
|
cmds:
|
|
- |
|
|
if [ -n "$CI" ]; then
|
|
.config/log info '`$CI` environment variable is present'
|
|
task ansible:test:local:test:ci
|
|
else
|
|
task ansible:test:local:test:local
|
|
fi
|
|
|
|
local:test:ci:
|
|
deps:
|
|
- :symlink:{{.REPOSITORY_SUBTYPE}}
|
|
cmds:
|
|
- |
|
|
if [ -n "$WINDOWS_ANSIBLE_TEST" ]; then
|
|
pip3 install ansible 'pywinrm[credssp]'
|
|
else
|
|
pip3 install ansible
|
|
fi
|
|
- |
|
|
PATH="$PATH:$HOME/.local/bin"
|
|
ansible-galaxy install -r requirements.yml
|
|
- task: local:test:logic
|
|
|
|
local:test:local:
|
|
deps:
|
|
- :symlink:{{.REPOSITORY_SUBTYPE}}
|
|
- task: :install:python:requirements
|
|
env:
|
|
INSTALL_OPTIONS: --no-dev
|
|
cmds:
|
|
- task: local:test:logic
|
|
|
|
local:test:logic:
|
|
vars:
|
|
ANSIBLE_CFG: |-
|
|
[winrm_connection]
|
|
scheme = https
|
|
server_cert_validation = ignore
|
|
transport = credssp,ssl
|
|
ROLE_NAME: '{{.GALAXY_NAMESPACE}}.{{.GALAXY_ROLE_NAME}}'
|
|
SUDO_PASS_PARAM:
|
|
sh: if [ -z "$CI" ]; then echo ' --ask-sudo-pass'; else echo ''; fi
|
|
WINDOWS_INVENTORY: windows-ci ansible_host=localhost ansible_user=runneradmin
|
|
ansible_password=AnsibleTest999 ansible_connection=winrm ansible_winrm_server_cert_validation=ignore
|
|
ansible_winrm_transport=credssp
|
|
log:
|
|
error: Encountered error while testing the Ansible playbook locally
|
|
start: Testing the Ansible playbook locally
|
|
success: Successfully tested the Ansible playbook locally
|
|
cmds:
|
|
- |
|
|
if [ -n "$WINDOWS_ANSIBLE_TEST" ]; then
|
|
echo '{{.WINDOWS_INVENTORY}}' > inventory
|
|
echo '{{.ANSIBLE_CFG}}' > ansible.cfg
|
|
else
|
|
echo 'localhost ansible_connection=local' > inventory
|
|
fi
|
|
- task: local:test:playbook
|
|
vars:
|
|
PLAY_HOSTS:
|
|
sh: if [ -z "$WINDOWS_ANSIBLE_TEST" ]; then echo 'localhost'; else echo 'windows-ci'; fi
|
|
PLAY_ROLE_NAME: '{{.ROLE_NAME}}'
|
|
- |
|
|
if [ -z "$CI" ]; then
|
|
.config/log info 'Prompting for sudo password (required for non-CI environments)'
|
|
fi
|
|
if [ -n "$WINDOWS_ANSIBLE_TEST" ]; then
|
|
export ANSIBLE_CONFIG="$PWD/ansible.cfg"
|
|
fi
|
|
PATH="$PATH:$HOME/.local/bin"
|
|
{{.PYTHON_MOLECULE_HANDLE}} ansible-playbook --skip-tags "mas" -i inventory{{.SUDO_PASS_PARAM}} test/{{OS}}/test.yml 2>&1 | tee debug.log || EXIT_CODE=$?
|
|
- task: post:molecule:log
|
|
vars:
|
|
RESULTS_FILE: debug.log
|
|
|
|
local:test:playbook:
|
|
vars:
|
|
TEST_PLAY: |
|
|
---
|
|
- hosts: {{.PLAY_HOSTS}}
|
|
roles:
|
|
- role: '{{.PLAY_ROLE_NAME}}'
|
|
cmds:
|
|
- echo '{{.TEST_PLAY}}' > test.yml
|
|
|
|
molecule:ci:requirements:
|
|
cmds:
|
|
- |
|
|
if [ -n "$WINDOWS_ANSIBLE_TEST" ]; then
|
|
.config/log info 'Running `pip3 install ansible ansibler molecule pywinrm[credssp]`'
|
|
pip3 install ansible ansibler molecule 'pywinrm[credssp]'
|
|
else
|
|
.config/log info 'Running `pip3 install ansible ansibler molecule`'
|
|
pip3 install ansible ansibler molecule
|
|
fi
|
|
- |
|
|
.config/log info 'Running `ansible-galaxy install --ignore-errors -r requirements.yml`'
|
|
PATH="$PATH:$HOME/.local/bin"
|
|
ansible-galaxy install --ignore-errors -r requirements.yml
|
|
|
|
molecule:dependencies:
|
|
run: once
|
|
cmds:
|
|
- |
|
|
if [ -n "$CI" ]; then
|
|
.config/log info '`$CI` environment is present'
|
|
task ansible:test:molecule:dependencies:ci
|
|
else
|
|
task ansible:test:molecule:dependencies:local
|
|
fi
|
|
|
|
molecule:dependencies:ci:
|
|
cmds:
|
|
- task: molecule:ci:requirements
|
|
status:
|
|
- '[ -z "$CI" ]'
|
|
|
|
molecule:dependencies:local:
|
|
deps:
|
|
- :install:python:requirements
|
|
- :install:software:expect
|
|
- :install:software:sshpass
|
|
log:
|
|
error: Encountered error while installing Ansible Galaxy requirements defined in `requirements.yml`
|
|
start: Installing Ansible Galaxy requirements defined in `requirements.yml`
|
|
success: Installed Ansible Galaxy requirements defined in `requirements.yml`
|
|
cmds:
|
|
- |
|
|
PATH="$PATH:$HOME/.local/bin"
|
|
if poetry &> /dev/null; then
|
|
{{.PYTHON_HANDLE}} ansible-galaxy install --ignore-errors -r requirements.yml
|
|
else
|
|
.config/log info 'Current shell is already a Poetry virtual environment'
|
|
ansible-galaxy install --ignore-errors -r requirements.yml
|
|
fi
|
|
- task: :symlink:{{.REPOSITORY_SUBTYPE}}
|
|
status:
|
|
- '[ -n "$CI" ]'
|
|
|
|
molecule:docker:
|
|
desc: Runs a Docker Molecule test
|
|
hide: '{{ne .REPOSITORY_TYPE "ansible"}}'
|
|
summary: |
|
|
# Runs a Docker Molecule test
|
|
|
|
This task runs the project's Molecule tests using Docker. It only tests against
|
|
Linux systems.
|
|
|
|
**Opens a prompt:**
|
|
`task ansible:test:molecule:docker`
|
|
|
|
**Runs the test against the "CentOS-8" group directly:**
|
|
`task ansible:test:molecule:docker -- CentOS-8`
|
|
|
|
**Save test results for use with auto-generating compatibility chart:**
|
|
`task ansible:test:molecule:docker:matrix`
|
|
cmds:
|
|
- |
|
|
if ! docker run --rm hello-world; then
|
|
.config/log warn 'The command `docker run --rm hello-world` failed'
|
|
if [ -f '/Applications/Docker.app' ]; then
|
|
.config/log info 'Attempting to open `Applications/Docker.app` (Docker Desktop for macOS)'
|
|
open /Applications/Docker.app
|
|
sleep 30
|
|
fi
|
|
fi
|
|
- task: molecule:docker:{{if .CLI_ARGS}}cli{{else}}prompt{{end}}
|
|
|
|
molecule:docker:cli:
|
|
deps:
|
|
- molecule:dependencies
|
|
- :install:software:docker
|
|
log:
|
|
error: The `{{.CLI_ARGS}}` Docker Molecule test finished with errors
|
|
start: Running Docker Molecule test on containers in the `{{.CLI_ARGS}}` group
|
|
success: Successfully ran the `{{.CLI_ARGS}}` Docker Molecule test
|
|
cmds:
|
|
- |
|
|
set -o pipefail
|
|
{{.MOLECULE_TEST_OPTIONS}} MOLECULE_GROUP="{{.CLI_ARGS}}" {{.PYTHON_MOLECULE_HANDLE}}molecule test -s docker \
|
|
-- --skip-tags skipdockertest 2>&1 | tee debug.log || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
fi
|
|
- task: post:molecule:log
|
|
vars:
|
|
RESULTS_FILE: debug.log
|
|
|
|
molecule:docker:matrix:
|
|
deps:
|
|
- molecule:dependencies
|
|
- :install:software:docker
|
|
vars:
|
|
MOLECULE_DATE:
|
|
sh: date '+%Y-%m-%d'
|
|
log:
|
|
error: There were errors while running the test (results were logged to `{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-$SCENARIO.txt`)
|
|
start: Running Docker Molecule test with results teed to `{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-$SCENARIO.txt`
|
|
success: Finished running the test (results were logged to `{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-$SCENARIO.txt`)
|
|
cmds:
|
|
- mkdir -p {{.MOLECULE_LOGS_PATH}}
|
|
- |
|
|
SCENARIO="Linux"
|
|
if grep -Ril 'community.general.snap:' ./tasks; then
|
|
SCENARIO="Snap"
|
|
.config/log warn 'Running Docker Molecule tests on the Docker containers that are compatible with `snap` since the role has references to `snap`'
|
|
fi
|
|
set -o pipefail
|
|
{{.MOLECULE_TEST_OPTIONS}} MOLECULE_GROUP="$SCENARIO" {{.PYTHON_MOLECULE_HANDLE}}molecule test -s docker -- --skip-tags skipdockertest 2>&1 | \
|
|
tee '{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-$SCENARIO.txt' || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
fi
|
|
- task: post:molecule:log
|
|
vars:
|
|
RESULTS_FILE: '{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-$SCENARIO.txt'
|
|
|
|
molecule:docker:prompt:
|
|
env:
|
|
MARKDOWN: |
|
|
# Ansible Molecule Test via Docker
|
|
|
|
Choose a container group from the options below to begin the Molecule test.
|
|
The choices should be mostly self-explanatory. The `Snap` group is a special group
|
|
that should be used to test roles that contain `snap` logic. Only recent versions of
|
|
Debian and Ubuntu support snap installations inside a Docker container. Docker tests
|
|
are a quick way to test Ansible plays without consuming a large amount of system
|
|
resources. Granted, to fully test an Ansible play, a VirtualBox method should be used
|
|
instead.
|
|
cmds:
|
|
- TMP="$(mktemp)" && echo "$MARKDOWN" > "$TMP" && .config/log md "$TMP"
|
|
- task: molecule:docker:prompt:continue
|
|
|
|
molecule:docker:prompt:continue:
|
|
interactive: true
|
|
deps:
|
|
- :install:software:gum
|
|
- :install:software:jq
|
|
- :install:software:yq
|
|
cmds:
|
|
- |
|
|
DOCKER_OPTIONS="$(yq eval -o=j '.groups' molecule/docker/molecule.yml | jq -r 'keys | join(" ")')"
|
|
DOCKER_OPTIONS_LENGTH="$(yq eval -o=j '.groups' molecule/docker/molecule.yml | jq -r 'keys | length')"
|
|
if [[ "$DOCKER_OPTIONS_LENGTH" == '0' ]]; then
|
|
.config/log error 'There are no Molecule groups defined in `molecule/desktop/molecule.yml`' && exit 1
|
|
else
|
|
.config/log info 'Press SPACE to select an item and ENTER when you are done selecting test environments'
|
|
.config/log prompt 'Which environment(s) would you like to run the test on?'
|
|
CHOSEN_OPTIONS="$(gum choose --no-limit $(echo "$DOCKER_OPTIONS"))"
|
|
COMBINED_OPTIONS=""
|
|
CHOSEN_COUNT="$(echo "$CHOSEN_OPTIONS" | wc -l)"
|
|
if [[ "$CHOSEN_COUNT" == '0' ]]; then
|
|
.config/log error 'No items were selected!' && exit 1
|
|
else
|
|
while read CURRENT_OPTION; do
|
|
COMBINED_OPTIONS="${COMBINED_OPTIONS}:${CURRENT_OPTION}"
|
|
done< <(echo "$CHOSEN_OPTIONS")
|
|
CHOSEN_OPTION="${COMBINED_OPTIONS:1}"
|
|
export ANSIBLE_ENABLE_TASK_DEBUGGER=true
|
|
.config/log info 'Running `task ansible:test:molecule:docker:cli -- '"$CHOSEN_OPTION"'`'
|
|
task ansible:test:molecule:docker:cli -- "$CHOSEN_OPTION"
|
|
fi
|
|
fi
|
|
- task: allure:report
|
|
preconditions:
|
|
- sh: test -f molecule/docker/molecule.yml
|
|
msg: The `molecule/docker/molecule.yml` file must be present and in the proper format
|
|
|
|
molecule:gcp:
|
|
deps:
|
|
- molecule:dependencies
|
|
- :install:software:gcloud
|
|
log:
|
|
error: Encountered error(s) while running the Google Cloud Platform Molecule test
|
|
start: Running Google Cloud Platform Molecule test
|
|
success: Finished running Google Cloud Platform Molecule test
|
|
cmds:
|
|
- task: molecule:gcp:preconditions
|
|
- |
|
|
set -o pipefail
|
|
.config/log 'Results will be available in the `debug.log` file'
|
|
{{.PYTHON_MOLECULE_HANDLE}}molecule test -s gcp 2>&1 | tee debug.log || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
fi
|
|
- task: post:molecule:log
|
|
vars:
|
|
RESULTS_FILE: debug.log
|
|
|
|
molecule:gcp:matrix:
|
|
deps:
|
|
- molecule:dependencies
|
|
- :install:software:gcloud
|
|
- :install:software:yq
|
|
vars:
|
|
MOLECULE_DATE:
|
|
sh: date '+%Y-%m-%d'
|
|
log:
|
|
error: An error occurred while running the Google Cloud Platform Molecule test sequence
|
|
start: Running Docker Molecule test with results teed to `{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-$SCENARIO.txt`
|
|
success: Finished running and formatting the results of the Google Cloud Platform molecule test
|
|
cmds:
|
|
- task: molecule:gcp:preconditions
|
|
- mkdir -p {{.MOLECULE_LOGS_PATH}}
|
|
- |
|
|
set -o pipefail
|
|
{{.PYTHON_MOLECULE_HANDLE}}molecule test -s gcp 2>&1 | tee "{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-gcp.txt" || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
else
|
|
.config/log success 'Finished running the test (results were logged to `{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-gcp.txt`)'
|
|
fi
|
|
- task: post:molecule:log
|
|
vars:
|
|
RESULTS_FILE: '{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-gcp.txt'
|
|
- |
|
|
RESULTS="{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-gcp.txt"
|
|
PLATFORM_LENGTH="$(yq e '.platforms | length' molecule/gcp/molecule.yml)"
|
|
INDEX=0
|
|
while [ $INDEX -lt $PLATFORM_LENGTH ]; do
|
|
NAME="$(yq e '.platforms['$INDEX'].name' molecule/gcp/molecule.yml)"
|
|
ALIAS="$(yq e '.platforms['$INDEX'].alias' molecule/gcp/molecule.yml)"
|
|
sed -i -- 's/'"$NAME"'/'"$ALIAS"'/g' "$RESULTS"
|
|
INDEX=$((INDEX+1))
|
|
done
|
|
|
|
molecule:gcp:preconditions:
|
|
preconditions:
|
|
- sh: '[ -n "$GCE_SERVICE_ACCOUNT_EMAIL" ]'
|
|
msg: The GCE_SERVICE_ACCOUNT_EMAIL environment variable must be set (e.g. export
|
|
GCE_SERVICE_ACCOUNT_EMAIL=molecule@megabyte-labs.iam.gserviceaccount.com).
|
|
- sh: '[ -n "$GCE_CREDENTIALS_FILE" ]'
|
|
msg: The GCE_CREDENTIALS_FILE environment variable must be set and pointing to the GCP
|
|
service account JSON key (e.g. export GCE_CREDENTIALS_FILE=~/.config/gcp.json).
|
|
- sh: test -f "$GCE_CREDENTIALS_FILE"
|
|
msg: The GCE_CREDENTIALS_FILE environment variable is defined but is not pointing to a file that exists.
|
|
- sh: '[ -n "$GCE_PROJECT_ID" ]'
|
|
msg: The GCE_PROJECT_ID environment variable must be set (e.g. export GCE_PROJECT_ID=megabyte-labs)
|
|
|
|
molecule:local:
|
|
desc: Runs a Molecule test on the localhost
|
|
hide: '{{ne .REPOSITORY_TYPE "ansible"}}'
|
|
summary: |
|
|
# Run a local Molecule test
|
|
|
|
This option is the same as running the play on the localhost with the added
|
|
benefit of incorporating Molecule's test for idempotency and other tests.
|
|
|
|
**Opens a prompt:**
|
|
`task ansible:test:local`
|
|
cmds:
|
|
- task: molecule:local:{{if .CLI_ARGS}}test{{else}}prompt{{end}}
|
|
|
|
molecule:local:prompt:
|
|
env:
|
|
MARKDOWN: |
|
|
# Run Molecule Locally
|
|
|
|
This testing option is provided for cases where you would like to locally test the
|
|
Ansible play with Molecule. This option assumes that the current user has sudo
|
|
privileges.
|
|
|
|
## Sudo Password
|
|
|
|
A sudo password is required for all roles because Molecule has a step where it
|
|
ensures Python is installed with `become: true`. The sudo password could potentially
|
|
be logged in clear text if logging is in verbose mode so be careful when using this
|
|
method.
|
|
|
|
## Running Locally Without Molecule
|
|
|
|
If you only want to install the play (without leveraging Molecule's features
|
|
like testing for idempotency and running test cases), then a more secure method would
|
|
be to run "ansible localhost --ask-sudo-pass -m include_role -a name=<role_name>" after
|
|
installing the role and its dependencies with ansible-galaxy.
|
|
cmds:
|
|
- TMP="$(mktemp)" && echo "$MARKDOWN" > "$TMP" && .config/log md "$TMP"
|
|
- task: molecule:local:prompt:continue
|
|
|
|
molecule:local:prompt:continue:
|
|
deps:
|
|
- :install:software:gum
|
|
interactive: true
|
|
cmds:
|
|
- .config/log prompt 'What is the sudo password for the current user?'
|
|
- |
|
|
SUDO_PASS="$(.config/log password 'Enter sudo password for local machine..')"
|
|
export ANSIBLE_ENABLE_TASK_DEBUGGER=true
|
|
export TEST_PASSWORD="$SUDO_PASS"
|
|
task ansible:test:molecule:local:test
|
|
- task: allure:report
|
|
|
|
molecule:local:test:
|
|
deps:
|
|
- molecule:dependencies
|
|
vars:
|
|
MOLECULE_DATE:
|
|
sh: date '+%Y-%m-%d'
|
|
log:
|
|
error: There was an error while running the Molecule test locally
|
|
start: Running the Molecule test locally
|
|
success: The local Molecule test was successfully run
|
|
cmds:
|
|
- |
|
|
set -o pipefail
|
|
if [ -z "$CI" ]; then
|
|
export PATH="$(poetry env info | grep 'Python: /' | sed 's/Python: //' | sed 's/$/\/bin/'):$PATH"
|
|
fi
|
|
{{.MOLECULE_TEST_OPTIONS}} {{.PYTHON_MOLECULE_HANDLE}}molecule test -s local 2>&1 | \
|
|
tee '{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-default.txt' || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
fi
|
|
- task: post:molecule:log
|
|
vars:
|
|
RESULTS_FILE: '{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-default.txt'
|
|
|
|
molecule:ssh:
|
|
desc: Runs a Molecule test over SSH
|
|
hide: '{{ne .REPOSITORY_TYPE "ansible"}}'
|
|
summary: |
|
|
# Run an SSH Molecule test
|
|
|
|
This option allows you to run the Molecule test against a single
|
|
SSH host.
|
|
|
|
**Opens a prompt:**
|
|
`task ansible:test:molecule:ssh`
|
|
cmds:
|
|
- task: molecule:ssh:{{if .CLI_ARGS}}cli{{else}}prompt{{end}}
|
|
|
|
molecule:ssh:cli:
|
|
deps:
|
|
- molecule:dependencies
|
|
log:
|
|
error: Errors encountered while running the SSH Molecule test
|
|
start: Running the Molecule test over SSH
|
|
success: Successfully ran the Molecule test over SSH
|
|
cmds:
|
|
- |
|
|
set -o pipefail
|
|
{{.MOLECULE_TEST_OPTIONS}} {{.PYTHON_MOLECULE_HANDLE}}molecule test -s remote 2>&1 | tee debug.log || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
fi
|
|
- task: post:molecule:log
|
|
vars:
|
|
RESULTS_FILE: debug.log
|
|
|
|
molecule:ssh:prompt:
|
|
env:
|
|
MARKDOWN: |
|
|
# Remote Ansible Molecule Test via SSH
|
|
|
|
This testing option is provided for cases where you would like to remotely test
|
|
the Ansible play on remote machines via SSH. The prompts will ask you for the
|
|
host IP address or FQDN, user, and password. Before running this test, you should
|
|
ensure that you can already connect to the machine via SSH (i.e. the ~/.ssh keys
|
|
should already be set up). This test assumes that SSH does not require any passwords
|
|
to establish the connection.
|
|
cmds:
|
|
- TMP="$(mktemp)" && echo "$MARKDOWN" > "$TMP" && .config/log md "$TMP"
|
|
- task: molecule:ssh:prompt:continue
|
|
|
|
molecule:ssh:prompt:continue:
|
|
deps:
|
|
- :install:software:gum
|
|
interactive: true
|
|
cmds:
|
|
- |
|
|
.config/log prompt 'What is the IP address or the FQDN of the target host?'
|
|
IP_ANSWER="$(.config/log input 'Enter IP address or FQDN..')"
|
|
if [[ "$IP_ANSWER" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]] || \
|
|
[[ "$IP_ANSWER" =~ ^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$ ]]; then
|
|
.config/log prompt 'What port should the SSH connection use?'
|
|
PORT_ANSWER="$(gum input --placeholder='Enter SSH port..' --value='22')"
|
|
if [[ "$PORT_ANSWER" =~ ^[0-9]*$ ]]; then
|
|
.config/log prompt 'What is the username of a user that has both sudo and SSH privileges?'
|
|
USER_ANSWER="$(.config/log input 'SSH username..')"
|
|
if [[ "$USER_ANSWER" ^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$ ]]; then
|
|
export ANSIBLE_ENABLE_TASK_DEBUGGER=true
|
|
export TEST_HOST="$IP_ANSWER"
|
|
export TEST_PORT="$PORT_ANSWER"
|
|
export TEST_SSH_USER="$USER_ANSWER"
|
|
export TEST_USER="$USER_ANSWER"
|
|
if [[ "$USER_ANSWER" != 'root' ]]; then
|
|
.config/log prompt 'What is the user's sudo password?'
|
|
SUDO_PASS_ANSWER="$(.config/log password 'Enter sudo password..')"
|
|
export TEST_PASSWORD="$SUDO_PASS_ANSWER"
|
|
export TEST_BECOME_PASSWORD="$SUDO_PASS_ANSWER"
|
|
fi
|
|
task ansible:test:molecule:ssh:cli
|
|
else
|
|
.config/log error 'Username is invalid!' && exit 1
|
|
else
|
|
.config/log error 'That SSH port is not valid!' && exit 1
|
|
else
|
|
.config/log error 'An invalid IP address / FQDN was entered.' && exit 1
|
|
fi
|
|
|
|
molecule:virtualbox:
|
|
desc: Runs a full E2E Molecule test for all supported operating systems
|
|
hide: '{{ne .REPOSITORY_TYPE "ansible"}}'
|
|
summary: |
|
|
# Run a full E2E Molecule test for all supported operating systems
|
|
|
|
This task uses VirtualBox to run tests for all of our supported operating
|
|
systems in parallel. It is very RAM intensive so, if you want to run this,
|
|
your computer should have _at least 32GB of RAM_.
|
|
|
|
**Opens a prompt:**
|
|
`task ansible:test:molecule:virtualbox`
|
|
|
|
**Generate the compatibility matrix used in the README.md:**
|
|
`task ansible:test:molecule:virtualbox:matrix`
|
|
cmds:
|
|
- task: molecule:virtualbox:{{if .CLI_ARGS}}cli{{else}}prompt{{end}}
|
|
|
|
# yamllint disable rule:truthy
|
|
molecule:virtualbox:cli:
|
|
deps:
|
|
- molecule:dependencies
|
|
- :install:software:vagrant
|
|
- :install:software:virtualbox
|
|
env:
|
|
OBJC_DISABLE_INITIALIZE_FORK_SAFETY: YES
|
|
log:
|
|
error: Errors encountered while running the `{{.CLI_ARGS}}` VirtualBox Molecule test
|
|
start: Running a VirtualBox Molecule test on platforms in the `{{.CLI_ARGS}}` group
|
|
success: Finished running the `{{.CLI_ARGS}}` VirtualBox Molecule test
|
|
cmds:
|
|
- |
|
|
set -o pipefail
|
|
{{.MOLECULE_TEST_OPTIONS}} MOLECULE_GROUP="{{.CLI_ARGS}}" {{.PYTHON_MOLECULE_HANDLE}}molecule test 2>&1 | tee debug.log || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
fi
|
|
- task: post:molecule:log
|
|
vars:
|
|
RESULTS_FILE: debug.log
|
|
|
|
molecule:virtualbox:converge:
|
|
desc: Provisions a desktop VirtualBox VM and then runs a Molecule test
|
|
hide: '{{ne .REPOSITORY_TYPE "ansible"}}'
|
|
summary: |
|
|
# Provision a desktop VirtualBox VM and then run a Molecule test
|
|
|
|
This task opens a VM with an operating system of your choosing and then tests
|
|
the project's play against it. It then leaves the VM open for inspection.
|
|
|
|
**Example with interactive prompt for VM type:**
|
|
`task test:molecule`
|
|
|
|
**Example usage bypassing prompt:**
|
|
`task test:molecule -- ArchLinux`
|
|
|
|
## Available scenarios:
|
|
|
|
* ArchLinux
|
|
* CentOS
|
|
* Debian
|
|
* Fedora
|
|
* macOS
|
|
* Ubuntu
|
|
* Windows
|
|
cmds:
|
|
- task: molecule:virtualbox:converge:{{if .CLI_ARGS}}cli{{else}}prompt{{end}}
|
|
|
|
molecule:virtualbox:converge:cli:
|
|
deps:
|
|
- molecule:dependencies
|
|
- :install:software:vagrant
|
|
- :install:software:virtualbox
|
|
env:
|
|
OBJC_DISABLE_INITIALIZE_FORK_SAFETY: YES
|
|
log:
|
|
error: Errors were encountered while running the `{{.CLI_ARGS}}` VirtualBox Molecule converge play
|
|
start: Running the `{{.CLI_ARGS}}` VirtualBox Molecule converge play (this will leave the VirtualBox instance open for inspection)
|
|
success: Finished running the `{{.CLI_ARGS}}` VirtualBox Molecule converge play (you are encouraged to inspect the VM)
|
|
cmds:
|
|
- |
|
|
set -o pipefail
|
|
{{.MOLECULE_TEST_OPTIONS}} MOLECULE_GROUP={{.CLI_ARGS}} {{.PYTHON_MOLECULE_HANDLE}}molecule converge -s desktop 2>&1 | tee debug.log || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
fi
|
|
- task: post:molecule:log
|
|
vars:
|
|
RESULTS_FILE: debug.log
|
|
|
|
molecule:virtualbox:converge:prompt:
|
|
env:
|
|
MARKDOWN: |
|
|
# Desktop Ansible Molecule Test via VirtualBox
|
|
|
|
Choose a desktop environment below to run the Ansible play on.
|
|
After choosing, a VirtualBox VM will be created. Then, the Ansible play will run on the VM.
|
|
After it is done, the VM will be left open for inspection. Please do get carried away
|
|
ensuring everything is working as expected and looking for configuration optimizations that
|
|
can be made. The operating systems should all be the latest stable release but might
|
|
not always be the latest version.
|
|
cmds:
|
|
- TMP="$(mktemp)" && echo "$MARKDOWN" > "$TMP" && .config/log md "$TMP"
|
|
- task: molecule:virtualbox:converge:prompt:continue
|
|
|
|
molecule:virtualbox:converge:prompt:continue:
|
|
interactive: true
|
|
deps:
|
|
- :install:software:gum
|
|
- :install:software:jq
|
|
- :install:software:yq
|
|
vars:
|
|
VIRTUALBOX_OPTIONS:
|
|
sh: echo "\"$(yq eval -o=j '.groups' molecule/desktop/molecule.yml | jq -r 'keys | join("\" \"")')\""
|
|
VIRTUALBOX_OPTIONS_LENGTH:
|
|
sh: yq eval -o=j '.groups' molecule/desktop/molecule.yml | jq -r 'keys | length'
|
|
cmds:
|
|
- |
|
|
if [[ '{{.VIRTUALBOX_OPTIONS_LENGTH}}' == '0' ]]; then
|
|
.config/log error 'There are no Molecule groups defined in `molecule/desktop/molecule.yml`' && exit 1
|
|
else
|
|
.config/log prompt 'Which desktop operating system would you like to test the Ansible play against?'
|
|
CHOSEN_OPTION="$(.config/log choose {{.VIRTUALBOX_OPTIONS}})"
|
|
export ANSIBLE_ENABLE_TASK_DEBUGGER=true
|
|
task ansible:test:molecule:virtualbox:converge:cli -- "$CHOSEN_OPTION"
|
|
fi
|
|
- task: allure:report
|
|
preconditions:
|
|
- sh: test -f molecule/desktop/molecule.yml
|
|
msg: The `molecule/desktop/molecule.yml` file must be present and in the proper format
|
|
|
|
molecule:virtualbox:matrix:
|
|
deps:
|
|
- molecule:dependencies
|
|
- :install:software:vagrant
|
|
- :install:software:virtualbox
|
|
vars:
|
|
MOLECULE_DATE:
|
|
sh: date '+%Y-%m-%d'
|
|
log:
|
|
error: Errors were encountered while running the full E2E test (see `{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-default.txt` for details)
|
|
start: Running a full E2E test with VirtualBox (results will be saved to `{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-default.txt`)
|
|
success: Finished running the full E2E test (results are in `{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-default.txt`)
|
|
cmds:
|
|
- mkdir -p {{.MOLECULE_LOGS_PATH}}
|
|
- |
|
|
set -o pipefail
|
|
{{.MOLECULE_TEST_OPTIONS}} {{.PYTHON_MOLECULE_HANDLE}}molecule test 2>&1 | \
|
|
tee '{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-default.txt' || EXIT_CODE=$?
|
|
if [ "$EXIT_CODE" ]; then
|
|
fi
|
|
- task: post:molecule:log
|
|
vars:
|
|
RESULTS_FILE: '{{.MOLECULE_LOGS_PATH}}/{{.MOLECULE_DATE}}-default.txt'
|
|
|
|
# yamllint enable rule:truthy
|
|
molecule:virtualbox:prompt:
|
|
env:
|
|
MARKDOWN: |
|
|
# Ansible Molecule Test via Headless VirtualBox Instances
|
|
|
|
This particular type of test is the best method for testing Ansible plays. It
|
|
uses VirtualBox and utilizes headless images. Despite that, running the test across
|
|
all the supported operating systems is RAM intensive. Ideally, you should have at
|
|
least 16GB of RAM to run all the tests at once. This type of test is used to generate
|
|
the compatibility chart so the results of this type of test have the final say.
|
|
|
|
You do not need to run the tests on all instances at once. Use the prompt below to
|
|
narrow your test scope.
|
|
cmds:
|
|
- TMP="$(mktemp)" && echo "$MARKDOWN" > "$TMP" && .config/log md "$TMP"
|
|
- task: molecule:virtualbox:prompt:continue
|
|
|
|
molecule:virtualbox:prompt:continue:
|
|
interactive: true
|
|
deps:
|
|
- :install:software:gum
|
|
- :install:software:jq
|
|
- :install:software:yq
|
|
vars:
|
|
VIRTUALBOX_OPTIONS:
|
|
sh: echo "\"$(yq eval -o=j '.groups' molecule/desktop/molecule.yml | jq -r 'keys | join("\" \"")')\""
|
|
VIRTUALBOX_OPTIONS_LENGTH:
|
|
sh: yq eval -o=j '.groups' molecule/desktop/molecule.yml | jq -r 'keys | length'
|
|
cmds:
|
|
- |
|
|
if [[ '{{.VIRTUALBOX_OPTIONS_LENGTH}}' == '0' ]]; then
|
|
.config/log error 'There are no Molecule groups defined in `molecule/desktop/molecule.yml`' && exit 1
|
|
else
|
|
.config/log prompt 'What environment(s) would you like to target with this test?'
|
|
CHOSEN_OPTIONS="$(gum choose --no-limit {{.VIRTUALBOX_OPTIONS}})"
|
|
COMBINED_OPTIONS=""
|
|
CHOSEN_COUNT="$(echo "$CHOSEN_OPTIONS" | wc -l)"
|
|
if [[ "$CHOSEN_COUNT" == '0' ]]; then
|
|
.config/log error 'No items were selected!' && exit 1
|
|
else
|
|
while read CURRENT_OPTION; do
|
|
COMBINED_OPTIONS="${COMBINED_OPTIONS}:${CURRENT_OPTION}"
|
|
done< <(echo "$CHOSEN_OPTIONS")
|
|
CHOSEN_OPTION="${COMBINED_OPTIONS:1}"
|
|
export ANSIBLE_ENABLE_TASK_DEBUGGER=true
|
|
task ansible:test:molecule:virtualbox:cli -- "$CHOSEN_OPTION"
|
|
fi
|
|
fi
|
|
- task: allure:report
|
|
preconditions:
|
|
- sh: test -f molecule/default/molecule.yml
|
|
msg: The `molecule/default/molecule.yml` file must be present and in the proper format
|
|
|
|
post:molecule:log:
|
|
deps:
|
|
- :ci:commit:config
|
|
cmds:
|
|
- task: ansifilter
|
|
vars:
|
|
RESULTS_FILE: '{{.RESULTS_FILE}}'
|
|
- task: post:molecule:log:commit:ci
|
|
- cmd: |
|
|
git pull --ff-only origin master
|
|
task --list > /dev/null || (echo "ERROR: Invalid Taskfiles!" && exit 1)
|
|
git add '{{.RESULTS_FILE}}'
|
|
HUSKY=0 git commit -o ci.skip -m "📝 docs(molecule): New Molecule test results added." -n
|
|
git push origin master
|
|
ignore_error: true
|
|
status:
|
|
- '[ "{{.RESULTS_FILE}}" == "debug.log" ] || [ ! -d .git ]'
|
|
|
|
post:molecule:log:commit:ci:
|
|
cmds:
|
|
- task: :ci:commit:config
|
|
status:
|
|
- '[ -z "$GITLAB_CI" ]'
|
|
|
|
prompt:
|
|
env:
|
|
MARKDOWN: |
|
|
# Molecule Test
|
|
|
|
There are currently six different options for running Molecule tests.
|
|
|
|
## 1. VirtualBox Headless
|
|
|
|
Runs tests using VirtualBox headless VMs. It is the test type used to generate
|
|
the compatibility chart.
|
|
|
|
## 2. VirtualBox Desktop
|
|
|
|
Runs tests using a VirtualBox desktop version VM. Use this type of test to run
|
|
the Ansible play and then open the VirtualBox VM to smoke test the software.
|
|
|
|
## 3. Docker
|
|
|
|
Utilizes Docker to test the Ansible play. It has some limitations such as not being
|
|
able to test snap installations on all operating systems. It also can only run tests
|
|
on Linux environments. This is, however, the fastest way to test roles and requires
|
|
the least amount of RAM.
|
|
|
|
## 4. Local
|
|
|
|
Runs the Ansible play on the local machine. Use this to run the Ansible play on your
|
|
local machine. You might use this if you want to inspect the software after running
|
|
the play.
|
|
|
|
## 5. SSH
|
|
|
|
Runs the Ansible play on a remote machine after connecting via SSH. This requires
|
|
that you already have the SSH credentials configured (i.e. ~/.ssh is setup).
|
|
|
|
## 6. Google Cloud Platform
|
|
|
|
Provisions Google Cloud Platform instances and tests the Ansible play on them. This
|
|
test requires that you have access to a GCP account and that the proper credentials
|
|
are in place. For help, see
|
|
[this guide](https://github.com/ProfessorManhattan/molecule-ansible-google-cloud/blob/master/README.md).
|
|
Without the environment variables mentioned in the guide set, this task will fail.
|
|
|
|
## Note on Debugging
|
|
|
|
All of the tests below (except GCP) enable the built-in Ansible debugger. If a task
|
|
fails, the STDOUT will freeze and you will be able to enter a few different commands.
|
|
For example, if you enter "r", then Ansible will run the task again. For more
|
|
information on the Ansible debugger (including available commands), see
|
|
https://docs.ansible.com/ansible/latest/user_guide/playbooks_debugger.html#available-debug-commands.
|
|
cmds:
|
|
- TMP="$(mktemp)" && echo "$MARKDOWN" > "$TMP" && .config/log md "$TMP"
|
|
- task: prompt:continue
|
|
|
|
prompt:continue:
|
|
interactive: true
|
|
cmds:
|
|
- .config/log prompt 'What type of test would you like to perform?'
|
|
- |
|
|
CHOSEN_TEST="$(.config/log choose 'VirtualBox Headless' 'VirtualBox Desktop' 'Docker' 'Local' 'SSH' 'Google Cloud Platform')"
|
|
if [[ "$CHOSEN_TEST" == 'VirtualBox Headless' ]]; then
|
|
TEST_SLUG='virtualbox:prompt'
|
|
elif [[ "$CHOSEN_TEST" == 'VirtualBox Desktop' ]]; then
|
|
TEST_SLUG='virtualbox:converge:prompt'
|
|
elif [[ "$CHOSEN_TEST" == 'Docker' ]]; then
|
|
TEST_SLUG='docker:prompt'
|
|
elif [ '{{.ANSWER}}' == 'Local' ]; then
|
|
TEST_SLUG='local'
|
|
elif [ '{{.ANSWER}}' == 'SSH' ]; then
|
|
TEST_SLUG='ssh:prompt'
|
|
elif [ '{{.ANSWER}}' == 'Google Cloud Platform' ]; then
|
|
TEST_SLUG='gcp'
|
|
fi
|
|
export ANSIBLE_ENABLE_TASK_DEBUGGER=true
|
|
task ansible:test:molecule:${TEST_SLUG}
|
|
- task: allure:report
|
|
|
|
vagrant:
|
|
desc: Runs the playbook using Vagrant
|
|
hide: '{{ne (print .REPOSITORY_TYPE "-" .REPOSITORY_SUBTYPE) "ansible-role"}}'
|
|
summary: |
|
|
# Run the playbook using Vagrant
|
|
|
|
Using Vagrant, you can pick and choose which operating system and
|
|
virtualization provider you want to use to test the playbook.
|
|
|
|
## Possible virtualization providers:
|
|
|
|
* hyperv
|
|
* libvirt
|
|
* parallels
|
|
* virtualbox
|
|
* vmware_fusion
|
|
* vmware_workstation
|
|
|
|
## Possible operating systems:
|
|
|
|
* archlinux
|
|
* centos
|
|
* debian
|
|
* fedora
|
|
* macos
|
|
* ubuntu
|
|
* windows
|
|
|
|
**Example opening interactive prompt:**
|
|
`task test:vagrant`
|
|
|
|
**Example bypassing interactive prompt:**
|
|
`task test:vagrant -- --provider=vmware_workstation windows`
|
|
cmds:
|
|
- task: vagrant:{{if .CLI_ARGS}}cli{{else}}prompt{{end}}
|
|
|
|
vagrant:cli:
|
|
deps:
|
|
- task: :install:python:requirements
|
|
vars:
|
|
INSTALL_OPTIONS: --no-dev
|
|
- :install:software:vagrant
|
|
- :install:software:virtualbox
|
|
log:
|
|
error: Encountered error when running `vagrant up {{.CLI_ARGS}}`
|
|
start: Running `vagrant up {{.CLI_ARGS}}`
|
|
success: Successfully ran `vagrant up {{.CLI_ARGS}}`
|
|
cmds:
|
|
- |
|
|
set -o pipefail
|
|
vagrant up {{.CLI_ARGS}} 2>&1 | tee debug.log || EXIT_CODE=$?
|
|
if [ -n "$EXIT_CODE" ]; then
|
|
fi
|
|
- task: post:molecule:log
|
|
vars:
|
|
RESULTS_FILE: debug.log
|
|
|
|
vagrant:prompt:
|
|
env:
|
|
MARKDOWN: |
|
|
# Launch VM via Vagrant and Run Playbook
|
|
|
|
Use the following prompts to select the type of operating system and
|
|
the virtualization platform you wish to use with Vagrant. After you make your choice
|
|
the corresponding environment will be provisioned with Vagrant.
|
|
|
|
The options are generated by inspecting your system for which virtualization
|
|
platforms are installed. The supported virtualization platforms are:
|
|
|
|
* **KVM** - Shows if `qemu-system-x86_64` command is available
|
|
* **Parallels** (macOS only) - Shows if `Parallels Desktop.app` is installed
|
|
* **VirtualBox** - Shows if `vboxmanage` command is available
|
|
* **VMWare Fusion** (macOS only) - Shows if `vmrun` command is available
|
|
* **VMWare Workstation** (Linux only) - Shows if `vmware` command is available
|
|
cmds:
|
|
- TMP="$(mktemp)" && echo "$MARKDOWN" > "$TMP" && .config/log md "$TMP"
|
|
- task: vagrant:prompt:continue
|
|
|
|
vagrant:prompt:continue:
|
|
deps:
|
|
- :install:software:gum
|
|
- :install:software:jq
|
|
interactive: true
|
|
vars:
|
|
PROMPT_OPTIONS:
|
|
sh: |
|
|
TMP="$(mktemp)"
|
|
if type qemu-system-x86_64 &> /dev/null; then
|
|
echo 'KVM' > "$TMP"
|
|
fi
|
|
if [[ '{{OS}}' == 'darwin' ]] && mdfind -name 'Parallels Desktop.app' &> /dev/null; then
|
|
echo 'Parallels' > "$TMP"
|
|
fi
|
|
if type vboxmanage &> /dev/null; then
|
|
echo 'VirtualBox' > "$TMP"
|
|
fi
|
|
if [[ '{{OS}}' == 'linux' ]] && type vmware &> /dev/null; then
|
|
echo 'VMWare Workstation' > "$TMP"
|
|
fi
|
|
if [[ '{{OS}}' == 'darwin' ]] && type vmrun &> /dev/null; then
|
|
echo 'VMWare Fusion' > "$TMP"
|
|
fi
|
|
LIST_LENGTH="$(jq -R -s -c -r 'split("\n") | length' < "$TMP")"
|
|
if [ "$LIST_LENGTH" != '0' ]; then
|
|
echo "\""$(jq -R -s -c -r 'split("\n") | join("\" \"")' < "$TMP")"\""
|
|
else
|
|
echo "None"
|
|
fi
|
|
cmds:
|
|
- |
|
|
if [[ '{{.PROMPT_OPTIONS' == 'None' ]]; then
|
|
.config/log error 'No virtualization platforms installed. Install a platform (e.g. VirtualBox, VMWare, QEMU) to continue.' && exit 1
|
|
else
|
|
.config/log prompt 'Which virtualization platform would you like to use?'
|
|
PLATFORM_CHOICE="$(.config/log choose '{{.PROMPT_OPTIONS}}')"
|
|
.config/log prompt 'Which desktop OS would you like to launch / provision?'
|
|
OS_CHOICE="$(.config/log choose 'ArchLinux' 'CentOS' 'Debian' 'Fedora' 'macOS' 'Ubuntu' 'Windows')"
|
|
task ansible:test:vagrant:cli -- --provider=\""$PLATFORM_CHOICE"\" "$OS_CHOICE"
|
|
fi
|