#!/bin/sh # Praxis — Create a Proxmox LXC container from a template via REST API. # # Uses the POST /nodes/{node}/lxc endpoint with ostemplate= # (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 }" 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"