vor: stack + playbook + workflow template for ana-docker deploy
Same shape as task-board: build-on-host from vh/vor, bind-mounted
persistence for sessions/ and responses/ (the user-published markdown
files), exposed at port 7879 (adjacent to task-board's 7878 since both
are claude-tooling sidecars).
Workflow template assumes the same DEPLOY_SSH_KEY + MGMT_REPO_TOKEN
secrets at user scope; nothing new to provision. Playbook accepts SHA
or branch refs (same fix as deploy-task-board.yaml) so manual runs
and CI runs share the same code path.
Centralized vs upstream-local: README documents the trade. Claude
fetches response markdown via /api/sessions/{id} JSON instead of a
local file read — the only API-flow change from the upstream README.
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
# Deploy vor (Inquisitor UI, https://gitea.phasefinal.com/vh/vor) to a
|
||||
# Docker host following the PFI /opt/docker/ convention. Default
|
||||
# target is ana-docker; the playbook is host-agnostic.
|
||||
#
|
||||
# Idempotent: rerunning is safe. Creates-gates + conditional when:
|
||||
# checks skip work that's already done; `docker compose up -d` is
|
||||
# itself idempotent (no restart unless compose content or env changed).
|
||||
#
|
||||
# Usage:
|
||||
# scripts/elway ana-docker --playbook playbooks/deploy-vor.yaml
|
||||
# scripts/elway ana-docker --playbook playbooks/deploy-vor.yaml --var ref=v0.2.0
|
||||
#
|
||||
# Prereqs on the target host:
|
||||
# - Docker + docker compose plugin
|
||||
# - `traefik-net` docker network (external)
|
||||
# - Target user (lkraven) has git SSH access to gitea.phasefinal.com
|
||||
# - Target user is in the `docker` group.
|
||||
|
||||
vars:
|
||||
repo_url: git@gitea.phasefinal.com:vh/vor.git
|
||||
ref: main
|
||||
build_dir: /opt/docker/build/vor
|
||||
image_tag: vor:local
|
||||
compose_dir: /opt/docker/compose/vor
|
||||
conf_dir: /opt/docker/conf/vor
|
||||
host_port: "7879"
|
||||
|
||||
steps:
|
||||
# ── host-side directory prep ─────────────────────────────────────────
|
||||
- name: Ensure /opt/docker/build parent exists
|
||||
shell: mkdir -p /opt/docker/build
|
||||
sudo: true
|
||||
creates: /opt/docker/build
|
||||
|
||||
- name: Chown /opt/docker/build to lkraven (only if mkdir'd by root above)
|
||||
shell: chown lkraven:lkraven /opt/docker/build
|
||||
sudo: true
|
||||
when: '[ "$(stat -c %U /opt/docker/build)" != lkraven ]'
|
||||
|
||||
# ── fetch / sync source ─────────────────────────────────────────────
|
||||
- name: Clone vor repo if absent
|
||||
shell: GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new" git clone {{ repo_url }} {{ build_dir }}
|
||||
creates: "{{ build_dir }}/.git"
|
||||
|
||||
- name: Fetch from origin
|
||||
shell: cd {{ build_dir }} && git fetch --quiet origin
|
||||
|
||||
- name: Reset working tree to {{ ref }}
|
||||
# Accept either a branch name (resolves via origin/<ref>) or a
|
||||
# full/short SHA (resolves directly). CI passes the triggering
|
||||
# commit SHA via --var ref=${{ github.sha }}; manual runs pass
|
||||
# branch names like main / v0.2.0.
|
||||
shell: |
|
||||
cd {{ build_dir }}
|
||||
if sha=$(git rev-parse --verify --quiet "origin/{{ ref }}^{commit}"); then :;
|
||||
elif sha=$(git rev-parse --verify --quiet "{{ ref }}^{commit}"); then :;
|
||||
else echo "elway: ref not found: {{ ref }}" >&2; exit 1; fi
|
||||
git reset --hard "$sha"
|
||||
changed_when: '[ "$(cd {{ build_dir }} && git rev-parse HEAD)" != "$(cd {{ build_dir }} && (git rev-parse --verify --quiet "origin/{{ ref }}^{commit}" || git rev-parse --verify --quiet "{{ ref }}^{commit}"))" ]'
|
||||
|
||||
# ── image build ─────────────────────────────────────────────────────
|
||||
- name: Build image {{ image_tag }}
|
||||
shell: cd {{ build_dir }} && docker build -t {{ image_tag }} .
|
||||
|
||||
# ── compose + persistence dirs ──────────────────────────────────────
|
||||
- name: Ensure compose dir exists
|
||||
shell: mkdir -p {{ compose_dir }}
|
||||
creates: "{{ compose_dir }}"
|
||||
|
||||
- name: Ensure sessions dir exists
|
||||
shell: mkdir -p {{ conf_dir }}/sessions
|
||||
creates: "{{ conf_dir }}/sessions"
|
||||
|
||||
- name: Ensure responses dir exists
|
||||
shell: mkdir -p {{ conf_dir }}/responses
|
||||
creates: "{{ conf_dir }}/responses"
|
||||
|
||||
# ── deploy compose files ────────────────────────────────────────────
|
||||
- name: Upload compose.yaml
|
||||
upload:
|
||||
src: stacks/vor/compose.yaml
|
||||
dest: "{{ compose_dir }}/compose.yaml"
|
||||
mode: "0644"
|
||||
|
||||
- name: Seed .env from template (only if absent)
|
||||
upload:
|
||||
src: stacks/vor/.env.example
|
||||
dest: "{{ compose_dir }}/.env"
|
||||
mode: "0644"
|
||||
when: "[ ! -f {{ compose_dir }}/.env ]"
|
||||
|
||||
# ── bring up + wait for ready ───────────────────────────────────────
|
||||
- name: docker compose up -d
|
||||
shell: cd {{ compose_dir }} && docker compose up -d
|
||||
|
||||
- name: Wait for /api/sessions to respond
|
||||
shell: |
|
||||
for i in $(seq 1 30); do
|
||||
curl -sf -o /dev/null http://localhost:{{ host_port }}/api/sessions && exit 0
|
||||
sleep 1
|
||||
done
|
||||
exit 1
|
||||
changed_when: "false"
|
||||
|
||||
verify:
|
||||
- name: /api/sessions returns 200
|
||||
shell: curl -sf -o /dev/null http://localhost:{{ host_port }}/api/sessions
|
||||
changed_when: "false"
|
||||
|
||||
- name: / returns the UI shell
|
||||
shell: curl -sf http://localhost:{{ host_port }}/ | grep -q -i 'inquisitor\|vor'
|
||||
changed_when: "false"
|
||||
|
||||
- name: Container is in the traefik-net network
|
||||
shell: docker inspect vor --format '{{json .NetworkSettings.Networks}}' | grep -q traefik-net
|
||||
changed_when: "false"
|
||||
Reference in New Issue
Block a user