--- name: provision-proxmox-instance version: 1.0.0 description: Outer provisioning layer — resolves feature flags to VM or CT, selects image, runs quota pre-flight, dispatches to create. Caller describes what they need; this skill picks the implementation. tags: [proxmox, provision, vm, lxc, api, shell] --- # Provision Proxmox Instance Assumes `my_auth`, `my_base_url`, `my_curl` are set (see `auth-proxmox-api` skill). Feature reference: see `docs/instance-features.md`. Image selection: see `list-proxmox-images` skill. ## Feature Flag → Type Resolution These flags force VM regardless of other options: | Flag | Reason | |------|--------| | `--live-migrate` | LXC has no live migration | | `--docker` | nesting=1 does not resolve core Docker issues | | `--windows` | LXC is Linux-only | | `--custom-kernel` | LXC shares host kernel | | `--ha-live` | Zero-downtime HA requires live migration | | `--iso ` | ISO install only applies to VMs | If none of the above are set → CT (LXC). Additional CT modifiers: - `--nesting` → adds `features=nesting=1` (required for systemd distros) - Any systemd-based OS template → always set `features=nesting=1` automatically VM modifier: - `--live-migrate` → set `cpu=kvm64` (or lowest cluster CPU type) instead of `cpu=host` ## Type Resolution Function ```sh fn_resolve_type() { ( my_live_migrate="${1:-}" my_docker="${2:-}" my_windows="${3:-}" my_custom_kernel="${4:-}" my_iso="${5:-}" if test -n "${my_live_migrate}" || test -n "${my_docker}" || test -n "${my_windows}" || test -n "${my_custom_kernel}" || test -n "${my_iso}"; then echo "vm" else echo "ct" fi ); } ``` ## Readiness → Image Selection ```sh fn_resolve_image() { ( my_instance_type="${1}" # ct or vm my_os_hint="${2:-}" # e.g. "ubuntu24", "alpine20", or a full volid my_iso="${3:-}" # explicit ISO volid overrides everything # Explicit ISO if test -n "${my_iso}"; then echo "${my_iso}" return fi # Explicit volid passthrough case "${my_os_hint}" in *:*) echo "${my_os_hint}"; return ;; esac if test "${my_instance_type}" = "ct"; then # Look up alias in docs/ct-os-templates.md or fall back to env default echo "${PROXMOX_TEMPLATE_DEFAULT}" else # For VMs, caller must supply a cloud-image volid or ISO # No alias resolution built in — use fn_images_list to discover echo "${PROXMOX_TEMPLATE_DEFAULT:-}" fi ); } ``` ## Full Provision Flow ```sh fn_provision() { ( my_hostname="${1}" my_pubkeys="${2:-${PROXMOX_AUTHORIZED_KEYS:-}}" my_os="${3:-}" my_cores="${4:-2}" my_ram="${5:-512}" my_storage="${6:-1}" my_cpulimit="${7:-${my_cores}}" # Feature flags (non-empty string = enabled) my_live_migrate="${PROVISION_LIVE_MIGRATE:-}" my_docker="${PROVISION_DOCKER:-}" my_windows="${PROVISION_WINDOWS:-}" my_custom_kernel="${PROVISION_CUSTOM_KERNEL:-}" my_iso="${PROVISION_ISO:-}" my_nesting="${PROVISION_NESTING:-}" my_instance_type="$( fn_resolve_type "${my_live_migrate}" "${my_docker}" \ "${my_windows}" "${my_custom_kernel}" "${my_iso}" )" my_image="$(fn_resolve_image "${my_instance_type}" "${my_os}" "${my_iso}")" # Quota pre-flight fn_pool_preflight "${PROXMOX_RESOURCE_POOL}" "${my_cores}" "${my_storage}" || return 1 if test "${my_instance_type}" = "ct"; then # Systemd distros need nesting — set it unless explicitly OpenRC/musl my_features="nesting=1" if test -z "${my_nesting}" && echo "${my_image}" | grep -qi 'alpine'; then my_features="" fi my_next_unit="$(fn_resources_next_index "${PROXMOX_ID_PREFIX}")" my_3digit="$((my_next_unit + 1000))" my_3digit="$(echo "${my_3digit}" | cut -c2-4)" my_vmid="${PROXMOX_ID_PREFIX}${my_3digit}" my_task_id="$( fn_create_lxc "${PROXMOX_TARGET_NODE}" "${PROXMOX_VLAN:-}" \ "${my_next_unit}" "${my_hostname}" "${my_pubkeys}" \ "${my_image}" "${my_ram}" "${my_storage}" \ "${my_cores}" "${my_cpulimit}" "${my_vmid}" "${my_features}" )" else # VM: use kvm64 for live-migrate, host otherwise my_cpu_type="host" if test -n "${my_live_migrate}"; then my_cpu_type="kvm64" fi my_next_unit="$(fn_resources_next_index "${PROXMOX_ID_PREFIX}")" my_3digit="$((my_next_unit + 1000))" my_3digit="$(echo "${my_3digit}" | cut -c2-4)" my_vmid="${PROXMOX_ID_PREFIX}${my_3digit}" my_task_id="$( fn_create_qemu "${PROXMOX_TARGET_NODE}" "${my_vmid}" \ "${my_hostname}" "${my_cores}" "${my_ram}" \ "${my_storage}" "${PROXMOX_DATA_POOL}" "${my_iso:-}" )" fi fn_wait_status "${PROXMOX_TARGET_NODE}" "${my_task_id}" ); } ``` ## Usage via ENV Flags ```sh # Plain Linux CT (systemd — nesting=1 set automatically) fn_provision "myhost" "" "ubuntu24" 2 512 10 # Docker host (forces VM) PROVISION_DOCKER=1 fn_provision "docker1" "" "" 4 2048 50 # Live-migratable VM (forces cpu=kvm64) PROVISION_LIVE_MIGRATE=1 fn_provision "web1" "" "" 2 1024 20 # ISO install VM PROVISION_ISO="local:iso/debian-12.iso" fn_provision "bare1" "" "" 2 1024 20 # Alpine CT (OpenRC — nesting=1 skipped) fn_provision "cache1" "" "alpine20" 1 256 5 ``` ## Dependency Map ``` provision-proxmox-instance ├── fn_resolve_type (inline) ├── fn_resolve_image (inline) ├── fn_pool_preflight (manage-proxmox-pool skill) ├── fn_resources_next_index (manage-proxmox-ct skill) ├── fn_create_lxc (manage-proxmox-ct skill) ├── fn_create_qemu (manage-proxmox-vm skill) └── fn_wait_status (auth-proxmox-api skill) ``` ## Notes - `--docker` forces VM unconditionally. `nesting=1` in LXC does not resolve cgroup namespace, seccomp, and device access issues Docker requires. - `--live-migrate` forces `cpu=kvm64`. Using `cpu=host` breaks live migration across nodes with different CPU microcode versions. - nesting=1 is set by default for all non-Alpine CTs. It is required for any systemd-based distro since ~2023 (cgroup v2 namespace support). - This skill does not handle HA group assignment after creation. See `manage-proxmox-ct` for `fn_ha_resources_add`.