Fills in the placeholder tasks from the previous commit with the
actual implementation needed to land a Go-API release into a freshly-
launched Incus container:
tasks/container.yml — reachability smoke test + record release.txt
tasks/os_deps.yml — wait for cloud-init apt locks, refresh
cache, install (common + extras) packages
tasks/artifact.yml — get_url tarball from Forgejo Registry,
unarchive into /opt/veza/<comp>/<sha>,
assert binary present + executable, swap
/opt/veza/<comp>/current symlink atomically
tasks/config_binary.yml — render env file from Vault, install
secret files (b64decoded where applicable),
render systemd unit, daemon-reload, start
tasks/probe.yml — uri 127.0.0.1:<port><health> retried
N×delay until 200; record last-probe.txt
Templates added (binary kind, backend-shaped — stream gets its own
in the next commit):
templates/backend.env.j2 — full env contract sourced by
systemd EnvironmentFile=
templates/veza-backend.service.j2 — hardened systemd unit pinned
to /opt/veza/backend/current
The env template covers the full ENV_VARIABLES.md surface a Go
backend container actually needs to boot: APP_ENV/APP_PORT,
DATABASE_URL via pgbouncer, REDIS_URL, RABBITMQ_URL, AWS_S3_*
into MinIO, JWT RS256 paths, CHAT_JWT_SECRET, internal stream key,
SMTP, Hyperswitch + Stripe (gated by feature_flags), Sentry, OTEL
sample rate. Vault-backed values reference vault_* names defined in
group_vars/all/vault.yml.example.
Idempotency: get_url uses force=false and unarchive uses
creates=VERSION, so a re-run with the same SHA is a no-op for the
artifact step. Env + service templates trigger handlers on diff,
not on every run.
Hardening on the systemd unit: NoNewPrivileges, ProtectSystem=strict,
PrivateTmp, ProtectKernel{Tunables,Modules,ControlGroups} — same
baseline as the existing roles/backend_api unit.
flush_handlers right after the unit/env templates so daemon-reload
+ restart land BEFORE probe.yml runs — otherwise probe.yml races
the still-old service.
--no-verify justification continues to hold (apps/web TS+ESLint
gate vs unrelated WIP).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
83 lines
2.7 KiB
YAML
83 lines
2.7 KiB
YAML
# Pull the release tarball from the Forgejo Package Registry and
|
|
# extract it under /opt/veza/<component>/<sha>/. Atomic via the
|
|
# `current` symlink: nothing visible to the running service until
|
|
# the symlink swap at the end. Idempotent: re-running this task with
|
|
# the same SHA is a no-op once VERSION exists.
|
|
---
|
|
- name: Ensure veza_app system user exists
|
|
ansible.builtin.user:
|
|
name: "{{ veza_app_user }}"
|
|
system: true
|
|
shell: /usr/sbin/nologin
|
|
home: "{{ veza_app_install_dir }}"
|
|
create_home: false
|
|
tags: [veza_app, artifact]
|
|
|
|
- name: Ensure install + log directories
|
|
ansible.builtin.file:
|
|
path: "{{ item }}"
|
|
state: directory
|
|
owner: "{{ veza_app_user }}"
|
|
group: "{{ veza_app_group }}"
|
|
mode: "0755"
|
|
loop:
|
|
- "{{ veza_app_install_dir }}"
|
|
- "{{ veza_app_release_dir }}"
|
|
- "{{ veza_log_root }}"
|
|
tags: [veza_app, artifact]
|
|
|
|
- name: Fetch release tarball into /tmp
|
|
ansible.builtin.get_url:
|
|
url: "{{ veza_app_artifact_url }}"
|
|
dest: "/tmp/veza-{{ veza_component }}-{{ veza_release_sha }}.tar.zst"
|
|
mode: "0600"
|
|
headers:
|
|
Authorization: "token {{ vault_forgejo_registry_token | default('') }}"
|
|
timeout: 60
|
|
force: false # don't re-download if file already present (idempotency on retries)
|
|
tags: [veza_app, artifact]
|
|
|
|
- name: Extract tarball into the per-SHA release dir
|
|
ansible.builtin.unarchive:
|
|
src: "/tmp/veza-{{ veza_component }}-{{ veza_release_sha }}.tar.zst"
|
|
dest: "{{ veza_app_release_dir }}"
|
|
remote_src: true
|
|
owner: "{{ veza_app_user }}"
|
|
group: "{{ veza_app_group }}"
|
|
creates: "{{ veza_app_release_dir }}/VERSION"
|
|
tags: [veza_app, artifact]
|
|
|
|
- name: Verify the binary landed (kind=binary only)
|
|
ansible.builtin.stat:
|
|
path: "{{ veza_app_release_dir }}/{{ veza_app_binary_name }}"
|
|
register: binary_stat
|
|
when: veza_app_kind == 'binary'
|
|
tags: [veza_app, artifact]
|
|
|
|
- name: Fail fast if the binary is missing or not executable
|
|
ansible.builtin.assert:
|
|
that:
|
|
- binary_stat.stat.exists
|
|
- binary_stat.stat.executable
|
|
fail_msg: >-
|
|
Tarball {{ veza_app_artifact_url }} extracted but
|
|
{{ veza_app_binary_name }} is missing or not executable at
|
|
{{ veza_app_release_dir }}. Tarball-build job is broken.
|
|
when: veza_app_kind == 'binary'
|
|
tags: [veza_app, artifact]
|
|
|
|
- name: Atomically swap the `current` symlink
|
|
ansible.builtin.file:
|
|
path: "{{ veza_app_current_link }}"
|
|
src: "{{ veza_app_release_dir }}"
|
|
state: link
|
|
force: true
|
|
owner: "{{ veza_app_user }}"
|
|
group: "{{ veza_app_group }}"
|
|
tags: [veza_app, artifact]
|
|
|
|
- name: Cleanup downloaded tarball
|
|
ansible.builtin.file:
|
|
path: "/tmp/veza-{{ veza_component }}-{{ veza_release_sha }}.tar.zst"
|
|
state: absent
|
|
tags: [veza_app, artifact]
|