Files
praxis/scripts/proxmox/lxc-clone.sh
T
Praxis CI 131545b70a feat(P01): SLICE-02 devops config + G-008 backup-restore drill
- TASK-02-01 .env.example: v0.4 operator vars (PRAXIS_PG_PASSWORD,
  PRAXIS_PG_DSN, PRAXIS_COOKIE_SECRET, PRAXIS_COOKIE_SECURE,
  PRAXIS_BOOTSTRAP_OPERATOR_USER/PASS, PRAXIS_VC_ISSUER_KEY,
  PRAXIS_ISSUER_URL) with documentation comments. PRAXIS_COOKIE_SECURE
  documents the G-031 reframe: k-anon defense-in-depth is the PRIMARY
  R-AUTH-01 mitigation (sniffed cookie leaks no PII); the secure flag is
  the SECONDARY mitigation. PROXMOX_MEMORY_MB default bumped 4096→6144.
- TASK-02-02 lxc-clone.sh: memory default 4096→6144 (REQ-NFR-MT-01 —
  Postgres ~400MB + praxis ~500MB + Docker ~200MB + build headroom ~1GB).
- TASK-02-03 scripts/backup-pg.sh: POSIX-sh nightly cron script,
  pg_dump -Fc to /backups/praxis-<dow>.dump (rolling 7-file, D-055),
  with restore-drill documentation in comments.
- G-008 tests/test_backup_restore.py: backup-restore drill — seeds all 5
  operator-tier tables, pg_dump, drop schema, pg_restore --clean --if-exists,
  verify 5 tables + row counts match. Skips if PRAXIS_PG_DSN unset.

---ci---
project: praxis
phase: 1
milestone: v0.4
status: execute
persona: devops-engineer
task: 02-01,02-02,02-03,G-008
requirements:
  covered: [REQ-NFR-MT-01]
  grill:
    - G-008 (backup-restore drill)
---/ci---
2026-08-04 00:48:14 +00:00

60 lines
2.0 KiB
Bash
Executable File

#!/bin/sh
# Praxis — Create a Proxmox LXC container from a template via REST API.
#
# Uses the POST /nodes/{node}/lxc endpoint with ostemplate=<volid>
# (create-from-template) instead of the storage clone endpoint. The
# clone endpoint rejects API tokens (`user != root@pam` guard), but
# the create endpoint accepts them — so this path works end-to-end
# with a PVEAPIToken. Pure REST, no SSH.
#
# Env: PROXMOX_API_URL, PROXMOX_API_TOKEN, PROXMOX_NODE,
# PROXMOX_STORAGE, PROXMOX_TEMPLATE_VOLID
# Args: $1 = target VMID (from pve_nextid)
# Stdout: the new VMID (integer)
# Exit: 0 on success, 1 on failure
set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck source=api.sh disable=SC1091
. "${SCRIPT_DIR}/api.sh"
pve_env PROXMOX_API_URL PROXMOX_API_TOKEN PROXMOX_NODE \
PROXMOX_STORAGE PROXMOX_TEMPLATE_VOLID
newid="${1:?usage: lxc-clone.sh <newid>}"
node="${PROXMOX_NODE}"
storage="${PROXMOX_STORAGE}"
template_volid="${PROXMOX_TEMPLATE_VOLID}"
# POST /nodes/{node}/lxc — create a CT from a template.
# Body (form-encoded): vmid, ostemplate, hostname, storage, rootfs, ...
# Returns: UPID (async task). Poll until done.
create_path="/nodes/${node}/lxc"
hostname="${PRAXIS_HOSTNAME:-praxis}"
echo "lxc-clone: creating VMID ${newid} from ${template_volid}" >&2
upid=$(pve_curl POST "$create_path" \
"vmid=${newid}" \
"ostemplate=${template_volid}" \
"hostname=${hostname}" \
"storage=${storage}" \
"rootfs=${storage}:16" \
# v0.4: 6144MB default (was 4096 in v0.2). Postgres ~400MB + praxis
# ~500MB + Docker daemon ~200MB + build headroom ~1GB + margin
# (REQ-NFR-MT-01). Override with PROXMOX_MEMORY_MB if needed.
"memory=${PROXMOX_MEMORY_MB:-6144}" \
"net0=name=eth0,bridge=vmbr0,ip=dhcp" \
"arch=amd64" \
"features=nesting=1")
if [ -z "$upid" ] || [ "$upid" = "null" ]; then
echo "lxc-clone: failed to start create (empty UPID)" >&2
exit 1
fi
echo "lxc-clone: polling create task ${upid}" >&2
pve_poll "$upid"
echo "lxc-clone: CT ${newid} created from ${template_volid}" >&2
printf '%s\n' "$newid"