{% include "shared/header.py.j2" %}
{% include "shared/create-tasks.py.j2" %}
{%- if vade.internal.app.paths.systemd_units %}
###
# Sanity checks
###
{%- for unit in vade.internal.app.paths.systemd_units %}
# This unit must not collide with a pre-existing, unmanaged unit file
# (an existing unit is considered unmanaged if it has no copy in the app's active deployment)
if host.get_fact(File, path="{{ unit.installed_path }}") and not host.get_fact(File, path="{{ unit.active_path }}"):
raise DeployError(
"Your application wants to install the systemd unit `{{ unit.name }}`, but "
"`{{ unit.installed_path }}` already exists and is not managed by vade. "
"If removing the existing unit is not possible, try using a different app name."
)
{%- endfor %}
{%- endif %}
###
# Initialize deployment candidate
###
files.directory(
name="Delete stale candidate deployment if it exists",
path="{{ vade.internal.app.paths.deployment_candidate }}",
present=False,
)
files.directory(
name="Create candidate deployment directory",
path="{{ vade.internal.app.paths.deployment_candidate }}",
user="{{ vade.app.username }}",
group="{{ vade.app.username }}",
mode="755",
)
{% if vade.internal.app.paths.artifacts_local is defined %}
files.rsync(
name="Sync local artifacts to candidate deployment",
src="{{ vade.internal.app.paths.artifacts_local }}/",
dest="{{ vade.internal.app.paths.artifacts_candidate }}",
flags=["-a", "--delete", "--link-dest={{ vade.app.paths.artifacts }}"],
_sudo=True,
_sudo_user="{{ vade.app.username }}",
)
{% endif %}
{% for unit in vade.internal.app.paths.systemd_units %}
files.put(
name="Upload systemd unit to candidate deployment",
src="{{ unit.local_path }}",
dest="{{ unit.candidate_path }}",
user="{{ vade.app.username }}",
group="{{ vade.app.username }}",
mode="644",
)
{% endfor %}
{% if vade.internal.app.paths.caddyfile_local is defined %}
files.put(
name="Upload Caddyfile to candidate deployment",
src="{{ vade.internal.app.paths.caddyfile_local }}",
dest="{{ vade.internal.app.paths.caddyfile_candidate }}",
user="{{ vade.app.username }}",
group="{{ vade.app.username }}",
mode="644",
)
{% endif %}
###
# Assign ports and bake them into the candidate's files (if necessary)
###
if not host.get_fact(Which, command="python3"):
raise DeployError(
"vade needs `python3` on the target host to assign ports for `{{ vade.app.name }}`, "
"but it was not found. Please install python3 and try again."
)
server.shell(
name="Assign ports and substitute them into the candidate's templated files",
commands=[
"python3 {{ vade.internal.assign_ports_script.remote }}"
" {{ vade.internal.app.paths.deployment_active }}/assigned-ports"
" {{ vade.internal.app.paths.deployment_candidate }}"
" {{ vade.app.username }}"
{%- if vade.internal.app.paths.caddyfile_candidate is defined %}
" {{ vade.internal.app.paths.caddyfile_candidate }}"
{%- endif %}
{%- for unit in vade.internal.app.paths.systemd_units %}
" {{ unit.candidate_path }}"
{%- endfor %}
],
)
files.directory(
name="Delete previous deployment",
path="{{ vade.internal.app.paths.deployment_previous }}",
present=False,
)
###
# Promote deployment candidate to active deployment
###
server.shell(
name="Promote deployment candidate (rolling back on failure)",
commands=r"""
# The weird structure of the script is actually a poor man's try/catch in bash
set -uo pipefail
bash <<'__VADE_PROMOTE__'
set -euo pipefail
{% with src_dir=vade.internal.app.paths.deployment_candidate, downgraded_dir=vade.internal.app.paths.deployment_previous %}{% include "deploy-promote.sh.j2" %}{% endwith %}
__VADE_PROMOTE__
promote_status=$?
if [ "$promote_status" -eq 0 ]; then
exit 0
fi
echo "Promotion failed (exit $promote_status), rolling back to the previous deployment..." >&2
bash <<'__VADE_ROLLBACK__'
set -euo pipefail
{% with src_dir=vade.internal.app.paths.deployment_previous %}{% include "deploy-promote.sh.j2" %}{% endwith %}
__VADE_ROLLBACK__
rollback_status=$?
if [ "$rollback_status" -ne 0 ]; then
echo "FATAL: rollback failed (exit $rollback_status). The host may be in an inconsistent state and needs manual recovery." >&2
exit 2
fi
echo "Deploying failed and was rolled back" >&2
exit 1
""",
)