.ansible_deploy: variables: ANSIBLE_DEPLOY_PLAYBOOK: playbook.yml ANSIBLE_DEPLOY_INVENTORY: "" ANSIBLE_DEPLOY_VALUES: "" ANSIBLE_DEPLOY_PACKAGES: "" ANSIBLE_DEPLOY_REQUIREMENTS: requirements.txt ANSIBLE_DEPLOY_GALAXY_REQUIREMENTS: roles/requirements.yml ANSIBLE_DEPLOY_DEBUG: 0 ANSIBLE_DEPLOY_PYTHON_INTERPRETER: "python" ANSIBLE_DEPLOY_PIP3_CMD: "pip" ANSIBLE_DEPLOY_VENV: "" ANSIBLE_DEPLOY_EXTRA_ARGS: "" ANSIBLE_DEPLOY_GALAXY_RETRIES: 3 script: - if [ "${ANSIBLE_DEPLOY_DEBUG}" -eq "1" ]; then set -x; ANSIBLE_DEPLOY_EXTRA_ARGS="${ANSIBLE_DEPLOY_EXTRA_ARGS} -vv"; fi - | if [ -x /usr/bin/yum ] && [ -n "${ANSIBLE_DEPLOY_PACKAGES}" ]; then retry=0 errors=1 while [ "${retry}" -lt 3 ] && [ "${errors}" -ne "0" ]; do if ! sudo yum -y install ${ANSIBLE_DEPLOY_PACKAGES}; then errors=1 fi retry=$(expr $retry + 1) done elif [ -x /usr/bin/apt-get ] && [ -n "${ANSIBLE_DEPLOY_PACKAGES}" ]; then sudo apt-get update && sudo apt-get -y install ${ANSIBLE_DEPLOY_PACKAGES} fi - if [ -z "${ANSIBLE_DEPLOY_PYTHON_INTERPRETER}" ]; then ANSIBLE_DEPLOY_PYTHON_INTERPRETER=$(which python3); fi - set -o pipefail - mkdir -p logs - playbook_dir=$(mktemp -d) - | if [ -n "${ANSIBLE_DEPLOY_ANSIBLE_CFG}" ]; then if [ -f "${ANSIBLE_DEPLOY_ANSIBLE_CFG}" ]; then cp -f "${ANSIBLE_DEPLOY_ANSIBLE_CFG}" .ansible.cfg fi fi - | if [ -z "${ANSIBLE_DEPLOY_INVENTORY}" ]; then if [ -d inventory ]; then ANSIBLE_DEPLOY_INVENTORY=inventory elif [ -f inventory.yml ]; then ANSIBLE_DEPLOY_INVENTORY=inventory.yml fi fi # Fetch the playbook from a git source - | if [ -n "${ANSIBLE_DEPLOY_PLAYBOOK_REPO}" ]; then git config --global url."${CI_SERVER_PROTOCOL}://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_HOST}/".insteadOf "${CI_SERVER_URL}/" git clone --branch "${ANSIBLE_DEPLOY_PLAYBOOK_RELEASE-master}" \ "${ANSIBLE_DEPLOY_PLAYBOOK_REPO}" "${playbook_dir}" rsync -rv --exclude=.git "${playbook_dir/}" ./ rm -rf "${playbook_dir}" fi # Set up the virtual environment - | if [ -n "${ANSIBLE_DEPLOY_VENV}" ]; then $ANSIBLE_DEPLOY_PIP3_CMD install --upgrade virtualenv $ANSIBLE_DEPLOY_PYTHON_INTERPRETER -m venv --copies $ANSIBLE_DEPLOY_VENV source $ANSIBLE_DEPLOY_VENV/bin/activate $ANSIBLE_DEPLOY_PIP3_CMD install --upgrade pip mkdir -p host_vars/localhost echo "ansible_python_interpreter: $(which python3)" > host_vars/localhost/$(echo $RANDOM)-__alt_python.yml else # Should be a random enough filename to avoid collisions... mkdir -p host_vars/localhost echo "ansible_python_interpreter: $ANSIBLE_DEPLOY_PYTHON_INTERPRETER" > host_vars/localhost/$(echo $RANDOM)-__alt_python.yml fi # Use the current python instance as the python interpreter to use # when connecting to localhost - | if [ ! -z "${ANSIBLE_DEPLOY_GIT_CREDENTIAL_STORE}" ]; then if [ -f "${ANSIBLE_DEPLOY_GIT_CREDENTIAL_STORE}" ]; then cp -f "${ANSIBLE_DEPLOY_GIT_CREDENTIAL_STORE}" $HOME/.git-credentials else echo -e "${ANSIBLE_DEPLOY_GIT_CREDENTIAL_STORE}" > $HOME/.git-credentials fi git config --global credential.helper store fi # If there are SSH keys, grab the ssh agent password providing expect script # from Gitlab snippets - _ssh_keys=$(env | grep -E '^ANSIBLE_DEPLOY_KEY_' | grep -v '^ANSIBLE_DEPLOY_KEY_PASSWORD_' || true) - | if [ ! -z "${ANSIBLE_DEPLOY_KEY}" ] || \ [ ! -z "${_ssh_keys}" ]; then cat <> ssh-agent-add-password.exp #!/usr/bin/env expect # Assign readable variable names to arguments set private_key_file [lindex $argv 0] set password_file [lindex $argv 1] # Read password in from file set f [open $password_file] set passphrase [read $f] close $f # Run ssh-add spawn ssh-add $private_key_file expect { "Enter passphrase for $private_key_file:" { # Send the read-in passphrase from the password file send "$passphrase\n"; expect "Identity added: $private_key_file ($private_key_file)" } "Identity added: $private_key_file ($private_key_file)" {} } EOF eval $(ssh-agent) fi # Install the per-host SSH keys - | mkdir -p .ssh for e in $(env | grep -E '^ANSIBLE_DEPLOY_KEY_' | grep -v -E '^ANSIBLE_DEPLOY_KEY_PASSWORD_'); do remote_hostname_underlined=$(echo $e | sed 's/^ANSIBLE_DEPLOY_KEY_\([^=]\+\).*/\1/') remote_hostname=$(echo $remote_hostname_underlined | sed 's/__/-/g' | sed 's/_/./g'); remote_key=$(echo $e | sed 's/^[^=]*=//') id_rsa=".ssh/id_rsa-${remote_hostname}" touch "${id_rsa}" chmod 600 "${id_rsa}" if [ -f "${remote_key}" ]; then cp -f "${remote_key}" "${id_rsa}" else echo "${remote_key}" | base64 -d > "${id_rsa}" fi password_varname="ANSIBLE_DEPLOY_KEY_PASSWORD_${remote_hostname_underlined}" if [ ! -z "${!password_varname}" ]; then pwfile=$(mktemp) echo "${!password_varname}" > $pwfile expect ./ssh-agent-add-password.exp "${id_rsa}" $pwfile rm -f "${pwfile}" fi done # Extra values to pass... - _generated_args="" - | if [ -n "${ANSIBLE_DEPLOY_VAULT_PASSWORD}" ]; then if [ -f "${ANSIBLE_DEPLOY_VAULT_PASSWORD}" ]; then export ANSIBLE_VAULT_PASSWORD_FILE="${ANSIBLE_DEPLOY_VAULT_PASSWORD}" else vault_pw=$(mktemp) chmod 600 "${vault_pw}" echo "${ANSIBLE_DEPLOY_VAULT_PASSWORD}" > "${vault_pw}" export ANSIBLE_VAULT_PASSWORD_FILE="${vault_pw}" fi fi - | for e in $(env | grep -E '^ANSIBLE_DEPLOY_VAULT_PASSWORD_'); do vault_id=$(echo $e | sed 's/^ANSIBLE_DEPLOY_VAULT_PASSWORD_\([^=]\+\).*/\1/') vault_pass=$(echo $e | sed 's/^\([^=]\+\)=\(.*\)/\2/') echo "${vault_pass}" > "${vault_id}" _generated_args="${_generated_args} --vault-id ${vault_id}" done # Extra environment variables to include... - | for e in $(env | grep -E '^ANSIBLE_DEPLOY_ENV_'); do new_env=$(echo $e | sed 's/^ANSIBLE_DEPLOY_ENV_//') eval "export ${new_env}" done - | for f in ${ANSIBLE_DEPLOY_VALUES}; do _generated_args="${_generated_args} --extra-vars @${f}" done - | for v in $(env | grep ^ANSIBLE_DEPLOY_VALUE_); do full_var=$(echo $v | sed 's/^ANSIBLE_DEPLOY_VALUE_\([^=]\+\).*/\1/') var_name=$(echo $full_var| sed 's/___/-/g' | sed 's/__/./g') var_val=$(echo $full_var | sed 's/^[^=]*=//') _generated_args="${_generated_args} --extra-vars \"${var_name}=${var_val}\"" done - | if [ ! -z "${ANSIBLE_DEPLOY_REQUIREMENTS}" ] && \ [ -f "${ANSIBLE_DEPLOY_REQUIREMENTS}" ]; then $ANSIBLE_DEPLOY_PIP3_CMD install --requirement "${ANSIBLE_DEPLOY_REQUIREMENTS}" --force fi - | if [ ! -z "${ANSIBLE_DEPLOY_GALAXY_REQUIREMENTS}" ] && \ [ -f "${ANSIBLE_DEPLOY_GALAXY_REQUIREMENTS}" ]; then i=0 while [ "$i" -lt "$ANSIBLE_DEPLOY_GALAXY_RETRIES" ] && \ [ "$(yq -r .roles $ANSIBLE_DEPLOY_GALAXY_REQUIREMENTS)" != "null" ] && \ ! ansible-galaxy role install -r "${ANSIBLE_DEPLOY_GALAXY_REQUIREMENTS}"; do i=$(expr $i + 1) done i=0 while [ "$i" -lt "$ANSIBLE_DEPLOY_GALAXY_RETRIES" ] && \ [ "$(yq -r .collections $ANSIBLE_DEPLOY_GALAXY_REQUIREMENTS)" != "null" ] && \ ! ansible-galaxy collection install -r "${ANSIBLE_DEPLOY_GALAXY_REQUIREMENTS}"; do i=$(expr $i + 1) done fi - | if [ ! -z "${_requirements}" ] && [ -f "${_requirements}" ]; then $ANSIBLE_DEPLOY_PIP3_CMD install --requirement "${_requirements}" --force fi - | if [ -n "${ANSIBLE_DEPLOY_HOSTKEYS}" ]; then if [ -f "${ANSIBLE_DEPLOY_HOSTKEYS}" ]; then mkdir -p "${HOME}/.ssh" cat "${ANSIBLE_DEPLOY_HOSTKEYS}" >> "${HOME}/.ssh/known_hosts" else echo "${ANSIBLE_DEPLOY_HOSTKEYS}" | base64 -d >> "${HOME}/.ssh/known_hosts" fi fi - | if [ -n "${ANSIBLE_DEPLOY_FETCH_HOSTKEYS}" ] && [ "${ANSIBLE_DEPLOY_FETCH_HOSTKEYS}" -eq "1" ]; then for h in $(ansible all -i "${ANSIBLE_DEPLOY_INVENTORY}" --list-hosts 2>/dev/null | grep -v -E 'localhost|127.0.0.1|::1'| tail -n +2); do hostkey_env="$(echo "ANSIBLE_DEPLOY_HOSTKEY_${h}" | sed 's/\./_/g' | sed 's/-/__/g')" hostkey_val="" if [ ! -z "${env_hostname}" ]; then hostkey_val="${!env_hostname}" fi if [ -z "${hostkey_val}" ]; then ssh-keyscan "${h}" >> "${HOME}/.ssh/known_hosts" fi done fi - if [ ! -z "${ANSIBLE_DEPLOY_SSH_CONFIG}" ] && [ -f "${ANSIBLE_DEPLOY_SSH_CONFIG}" ]; then mkdir -p "${HOME}/.ssh" cp -f $ANSIBLE_DEPLOY_SSH_CONFIG "${HOME}/.ssh/config"; fi - | if [ ! -z "${ANSIBLE_DEPLOY_SSH_ARGS}" ]; then export ANSIBLE_SSH_ARGS="${ANSIBLE_DEPLOY_SSH_ARGS}"; elif [ ! -f "${HOME}/.ssh/config" ]; then export ANSIBLE_SSH_ARGS="-C -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=$HOME/.ssh/known_hosts"; fi - > env