diff --git a/elements/ansible/README.rst b/elements/ansible/README.rst new file mode 100644 index 0000000..1a57525 --- /dev/null +++ b/elements/ansible/README.rst @@ -0,0 +1,31 @@ +======= +ansible +======= +Runs ansible playbooks late in the cleanup.d phase so that the image has been mostly configured. Requires systemd-nspawn. + +* ``DIB_ANSIBLE__SRC``: Git repository pointing to your ansible code. +* ``DIB_ANSIBLE__BRANCH``: (Optional) Branch of repository to checkout. Defaults to ``master``. +* ``DIB_ANSIBLE__OPTS``: (Optional) Extra command line arguments to pass to ansible-pull. +* ``DIB_ANSIBLE__VAULT_PASSWORD``: (Optional) Vault password. +* ``DIB_ANSIBLE__SUBDIR``: (Optional) Subdirectory in the git checkout where the ansible code lives. +* | ``DIB_ANSIBLE__PLAYBOOKS``: (Optional) Playbooks to run, relative to ``DIB_ANSIBLE__SUBDIR`` + | if set. Defaults to ``main.yml``. Multiple values must be separated by a space. +* ``DIB_ANSIBLE_PKG``: (Optional) Globally controls the version of ansible to use. + +Where ```` can be an arbitrary string, the function of which is to tie the +variables together e.g ``DIB_ANSIBLE_EXAMPLE_SRC`` and ``DIB_ANSIBLE_EXAMPLE_OPTS`` both +affect the same ansible-pull invocation. You can use as many different references +as you like. + +Example +------- + +.. code-block:: + + export DIB_ANSIBLE_EXAMPLE_SRC=https://github.com/jovial/ansible-pull-hello-world.git + export DIB_ANSIBLE_EXAMPLE_BRANCH=test-branch + export DIB_ANSIBLE_EXAMPLE_OPTS="-i hosts -e buildgroup=computes" + export DIB_ANSIBLE_EXAMPLE_VAULT_PASSWORD="topsecret" + export DIB_ANSIBLE_EXAMPLE_SUBDIR=ansible + export DIB_ANSIBLE_EXAMPLE_PLAYBOOKS="main.yml build.yml" + export DIB_ANSIBLE_PKG='ansible<2.9.0' diff --git a/elements/ansible/cleanup.d/99-zz-ansible-run b/elements/ansible/cleanup.d/99-zz-ansible-run new file mode 100755 index 0000000..24f1e81 --- /dev/null +++ b/elements/ansible/cleanup.d/99-zz-ansible-run @@ -0,0 +1,79 @@ +#!/bin/bash + +if [ ${DIB_DEBUG_TRACE:-0} -gt 0 ]; then + set -x +fi +set -eu +set -o pipefail + +function cleanup () { + set +eu + sudo lsof $tmp_dir | tail -n +2 | awk '{print $2}' | xargs sudo kill || true + if ! timeout 120 sh -c "while ! sudo umount -R $tmp_dir; do sleep 1; done"; then + echo "ERROR: failed to umount the $tmp_dir tmpfs mount point" + exit 1 + fi + rmdir $tmp_dir +} + +function mount_proc_dev_sys () { + # supporting kernel file systems + sudo mount -t proc none $tmp_dir/proc + sudo mount --bind /dev $tmp_dir/dev + sudo mount -t devpts $(mount_dev_pts_options) devpts $tmp_dir/dev/pts + sudo mount -t sysfs none $tmp_dir/sys +} + +tmp_dir=$(mktemp -d) +sudo mount --bind "$TARGET_ROOT" "$tmp_dir" +mount_proc_dev_sys + +trap cleanup EXIT + +for value in $(compgen -v); do + if [[ "$value" =~ DIB_ANSIBLE_(.*)_SRC ]]; then + name="${BASH_REMATCH[1]}" + + repo_ref="DIB_ANSIBLE_""$name""_SRC" + repo=${!repo_ref:?"You must set DIB_ANSIBLE_$name""_SRC"} + + branch_ref="DIB_ANSIBLE_""$name""_BRANCH" + branch=${!branch_ref:-} + branch_option="" + if [ ! -z ${branch:+x} ]; then + branch_option="-b $branch" + fi + + opts_ref="DIB_ANSIBLE_""$name""_OPTS" + opts="${!opts_ref:-}" + + # Use vault password helper to avoid writing password to disk + vault_ref="DIB_ANSIBLE_""$name""_VAULT_PASSWORD" + export ANSIBLE_VAULT_PASSWORD="${!vault_ref:-}" + vault_password="" + if [ ! -z ${ANSIBLE_VAULT_PASSWORD:+x} ]; then + vault_password="--vault-password-file /opt/ansible-pull/bin/vault-password-helper.sh" + fi + + subdir_ref="DIB_ANSIBLE_""$name""_SUBDIR" + subdir="${!subdir_ref:-}" + + playbooks_ref="DIB_ANSIBLE_""$name""_PLAYBOOKS" + playbooks="${!playbooks_ref:-main.yml}" + + checkout=/"tmp/dib-ansible-$name" + + sudo chroot $tmp_dir /bin/bash << EOF + set -eux + git clone "$repo" "$checkout" $branch_option --depth 1 + if [ -f "$checkout/$subdir/requirements.yml" ]; then + "$DIB_ANSIBLE_VENV/bin/ansible-galaxy" install -r "$checkout/$subdir"/requirements.yml \ + -p "$checkout/$subdir"/roles/ + fi + pushd "$checkout/$subdir" + "$DIB_ANSIBLE_VENV/bin/ansible-playbook" $vault_password $opts $playbooks + popd +EOF + + fi +done diff --git a/elements/ansible/element-deps b/elements/ansible/element-deps new file mode 100644 index 0000000..fb35e97 --- /dev/null +++ b/elements/ansible/element-deps @@ -0,0 +1,2 @@ +package-installs +install-static diff --git a/elements/ansible/environment.d/ansible b/elements/ansible/environment.d/ansible new file mode 100755 index 0000000..ff16c49 --- /dev/null +++ b/elements/ansible/environment.d/ansible @@ -0,0 +1,4 @@ +#!/bin/bash + +export DIB_ANSIBLE_PKG=${DIB_ANSIBLE_PKG:-ansible} +export DIB_ANSIBLE_VENV=/opt/ansible-pull diff --git a/elements/ansible/package-installs.yaml b/elements/ansible/package-installs.yaml new file mode 100644 index 0000000..4e09197 --- /dev/null +++ b/elements/ansible/package-installs.yaml @@ -0,0 +1,5 @@ +# Needed to create the virtualenv +git: + phase: pre-install.d +python3: + phase: pre-install.d diff --git a/elements/ansible/pre-install.d/92-ansible-install b/elements/ansible/pre-install.d/92-ansible-install new file mode 100755 index 0000000..1294068 --- /dev/null +++ b/elements/ansible/pre-install.d/92-ansible-install @@ -0,0 +1,13 @@ +#!/bin/bash + +if [ ${DIB_DEBUG_TRACE:-0} -gt 0 ]; then + set -x +fi +set -eu +set -o pipefail + +mkdir -p "$DIB_ANSIBLE_VENV" + +/usr/bin/python3 -m venv "$DIB_ANSIBLE_VENV" +"$DIB_ANSIBLE_VENV/bin/pip" install -U pip +"$DIB_ANSIBLE_VENV/bin/pip" install "$DIB_ANSIBLE_PKG" diff --git a/elements/ansible/static/opt/ansible-pull/bin/vault-password-helper.sh b/elements/ansible/static/opt/ansible-pull/bin/vault-password-helper.sh new file mode 100755 index 0000000..ebc3b36 --- /dev/null +++ b/elements/ansible/static/opt/ansible-pull/bin/vault-password-helper.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo $ANSIBLE_VAULT_PASSWORD