diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d3caba..ebeb6b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 0.7.0 - 2026-04-24 + +- Added template typing so approved templates can represent either QEMU VMs or LXC containers. +- Added LXC template discovery from Proxmox storage `vztmpl` content in the admin template manager. +- Added live LXC container provisioning through the Proxmox API with configurable rootfs storage and optional DHCP bridge. +- Routed start, stop, delete, expiration, status, and IP refresh operations through typed Proxmox VM/LXC API paths. +- Added Proxmox tags to newly created VMs and containers, including a sanitized per-user tag for easier PVE administration. +- Updated the admin and portal UI to show VM versus LXC template/deployment types and generic Proxmox resource IDs. +- Added schema upgrades for template provisioning type, LXC template references, and deployment resource type. +- Hardened admin template/settings saves against array-shaped POST values. +- Kept QEMU template management usable if the Proxmox token cannot list LXC-capable storages. +- Documented LXC setup, storage permissions, and the new Proxmox settings. + ## 0.6.0 - 2026-04-24 - Added deployment sharing with a dedicated `wp_spp_deployment_shares` table. diff --git a/README.md b/README.md index b6e3e73..ff6a2b5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Support Provisioning Portal -Internal WordPress plugin for support staff to provision standardized Proxmox VE VMs without direct Proxmox access. +Internal WordPress plugin for support staff to provision standardized Proxmox VE VMs and LXC containers without direct Proxmox access. The application runs as a WordPress plugin and exposes both: @@ -35,12 +35,12 @@ The application runs as a WordPress plugin and exposes both: - Audit log rows for every mutating action - Optional `Never expire` deployments - Per-user and global RAM contingents -- IP address display for deployments when available from the mock adapter or Proxmox guest agent +- IP address display for deployments when available from the mock adapter, Proxmox guest agent, or LXC interfaces - Manual IP refresh action for deployments -- Non-destructive expiration: expired VMs are stopped and locked, not deleted +- Non-destructive expiration: expired VMs and containers are stopped and locked, not deleted - Plugin-owned per-user rights for portal access, lifecycle actions, settings, and user-rights management - Admin-panel user rights management for WordPress and SSO-created users -- Admin-panel template management for importing QEMU templates from the configured Proxmox node +- Admin-panel template management for importing QEMU VM and LXC templates from the configured Proxmox node - Owner/private deployment visibility with explicit per-deployment sharing - Minimal admin/frontend UI for: - deployment dashboard @@ -108,9 +108,9 @@ Deployment creation supports either a TTL in hours or **Never expire**. When a deployment reaches its TTL: - WordPress cron and REST requests detect the expiration. -- The plugin attempts to stop the VM. +- The plugin attempts to stop the VM or container. - The deployment status becomes `EXPIRED`. -- The VM cannot be started again until the user prolongs its TTL. +- The deployment cannot be started again until the user prolongs its TTL. - The user can either prolong the TTL or delete the deployment. - Deleted deployments are hidden from the active deployment list, but audit rows remain. @@ -125,9 +125,9 @@ Per-user overrides are available in the **User Rights** section on the **Support ## IP Addresses -Deployments include an `ipAddresses` field in REST responses and show those addresses in the UI. In mock mode, deterministic documentation-range IPs are assigned. In HTTP mode, the plugin reads IPs from the Proxmox guest-agent `network-get-interfaces` endpoint when available. +Deployments include an `ipAddresses` field in REST responses and show those addresses in the UI. In mock mode, deterministic documentation-range IPs are assigned. In HTTP mode, the plugin reads VM IPs from the Proxmox guest-agent `network-get-interfaces` endpoint when available and reads LXC IPs from the container interfaces endpoint. -If the guest agent reports IPs only after boot, use **Refresh IPs** in the deployment detail view. +If IPs are reported only after boot, use **Refresh IPs** in the deployment detail view. ## Proxmox Settings @@ -138,6 +138,8 @@ The plugin defaults to mock mode. Configure live Proxmox access from the **Suppo - Token ID, for example `user@realm!token-name` - Token Secret. The saved secret is not rendered back into the settings form; leave the field blank to keep it unchanged. - Node, for example `pve-01` +- LXC rootfs storage, for example `local-lvm`. This is required before live LXC deployments can be created. +- LXC network bridge, for example `vmbr0`. Leave empty if containers should be created without an automatic DHCP `net0`. No Proxmox secrets are committed to the repository. @@ -147,16 +149,17 @@ Use this section when moving from mock mode to a real Proxmox VE node. ### 1. Prepare Proxmox Templates -The plugin only provisions from approved templates. Proxmox remains the source for actual VM templates, while the plugin stores an approved template policy row with display name, OS type, CPU, RAM, disk, default TTL, and Proxmox template VMID. +The plugin only provisions from approved templates. Proxmox remains the source for actual QEMU VM templates and LXC OS templates, while the plugin stores an approved template policy row with display name, OS type, CPU, RAM, disk, default TTL, template type, and either a Proxmox template VMID or an LXC `ostemplate` reference. Open the **Templates** section on the **Support Provisioning** admin page to: - see approved plugin templates -- import QEMU templates from the configured Proxmox node +- import QEMU VM templates from the configured Proxmox node +- import LXC templates from the configured node's storage `vztmpl` content - edit the policy values used during provisioning - remove templates from new provisioning without breaking historical deployment records -The plugin lists QEMU templates from the configured node via the Proxmox API. It does not provision from LXC templates. +The plugin lists QEMU templates from `/nodes/{node}/qemu` and LXC templates from storage content with `content=vztmpl`. Seeded example template IDs: @@ -166,9 +169,9 @@ Seeded example template IDs: | Windows Support Client | `9002` | | Linux Utility VM | `9003` | -The fastest first test is to create one real Proxmox QEMU template, then import it from **Support Provisioning > Templates**. +The fastest first test is to create one real Proxmox QEMU template or download one LXC OS template, then import it from **Support Provisioning > Templates**. -Template requirements: +QEMU template requirements: - The VM must be converted to a Proxmox template. - The template must exist on the Proxmox node configured in the plugin. @@ -176,6 +179,13 @@ Template requirements: - CPU and memory are set by the plugin after clone based on the approved template policy row. - For IP address display, install and enable `qemu-guest-agent` inside the guest and enable the guest agent option on the VM/template. +LXC template requirements: + +- The OS template must be visible as `vztmpl` storage content on the configured Proxmox node. +- Configure **LXC rootfs storage** in the plugin before deploying live containers. +- Configure **LXC network bridge** if containers should receive a DHCP `eth0` during creation. +- The rootfs storage must have enough free capacity for the approved template disk size. + ### 2. Create A Dedicated Proxmox API User In Proxmox, create a dedicated user instead of using `root@pam` for the plugin. @@ -214,12 +224,16 @@ The plugin needs permissions for: - getting the next VMID - listing QEMU templates on the configured node +- listing LXC template content on the node's storages - cloning a template VM +- creating LXC containers from an OS template - changing CPU and memory after clone -- starting and stopping VMs -- deleting VMs -- reading VM status +- setting Proxmox tags on created VMs and containers +- starting and stopping VMs and containers +- deleting VMs and containers +- reading VM and container status - reading guest-agent network interfaces for IP display +- reading LXC interfaces for IP display Practical first-test option: @@ -236,7 +250,7 @@ pveum aclmod /storage/local-lvm -user wp-support@pve -role PVEDatastoreAdmin For a tighter production setup, create a custom role with only the required privileges and assign it to the API token or user: ```bash -pveum role add SupportProvisioner -privs "VM.Allocate VM.Audit VM.Clone VM.Config.CPU VM.Config.Memory VM.PowerMgmt Datastore.AllocateSpace Datastore.Audit Sys.Audit" +pveum role add SupportProvisioner -privs "VM.Allocate VM.Audit VM.Clone VM.Config.CPU VM.Config.Disk VM.Config.Memory VM.Config.Network VM.Config.Options VM.PowerMgmt Datastore.AllocateSpace Datastore.Audit Sys.Audit" pveum aclmod / -user wp-support@pve -role SupportProvisioner ``` @@ -268,6 +282,8 @@ In WordPress admin, open **Support Provisioning** and use the **Proxmox Settings | Token ID | `wp-support@pve!support-portal` | | Token Secret | token secret from Proxmox | | Node | Proxmox node name, for example `pve-01` | +| LXC rootfs storage | target container rootfs storage, for example `local-lvm` | +| LXC network bridge | bridge for DHCP `net0`, for example `vmbr0` | The **Node** value must match the Proxmox node name exactly as shown in the Proxmox UI under **Datacenter**. @@ -278,9 +294,10 @@ Before creating a deployment: - Confirm WordPress can reach Proxmox on TCP `8006`. - Confirm the Proxmox base URL opens from the WordPress server. - Confirm the configured node name is exact. -- Confirm the selected plugin template points to a real Proxmox template VMID. -- Confirm the token has clone, VM config, power, delete, audit, and datastore permissions. -- Confirm target storage has enough capacity for a full clone. +- Confirm the selected plugin template points to a real Proxmox template VMID or visible LXC `vztmpl` item. +- For LXC tests, confirm **LXC rootfs storage** is configured. +- Confirm the token has clone/create, VM config, power, delete, audit, and datastore permissions. +- Confirm target storage has enough capacity for the VM clone or LXC rootfs. - Confirm RAM contingents in WordPress are not blocking the selected template. Then test in this order: @@ -302,16 +319,17 @@ Then test in this order: | `Missing Proxmox HTTP configuration` | One of Base URL, Token ID, Token Secret, or Node is empty. | | `Proxmox request failed with HTTP 401` | Token ID/secret is wrong, token was deleted, or the secret was copied incorrectly. | | `Proxmox request failed with HTTP 403` | Token exists but lacks permissions for clone/config/power/delete/storage. | -| `Proxmox request failed with HTTP 404` | Node name or template VMID is wrong, or the template is on a different node. | +| `Proxmox request failed with HTTP 404` | Node name, template VMID, or LXC template reference is wrong, or the template is on a different node/storage. | +| `Missing LXC rootfs storage configuration` | An LXC template was selected but no target rootfs storage is configured in plugin settings. | | SSL/cURL certificate error | WordPress/PHP does not trust the Proxmox certificate. | -| Deployment created but no IPs | Guest agent is missing, disabled, not running, or the VM has not finished booting. | +| Deployment created but no IPs | Guest agent is missing/disabled for a VM, the VM/container has not finished booting, or the LXC bridge/DHCP path is not configured. | | Start is blocked | Deployment is `EXPIRED`; prolong the TTL first. | ## Design Notes - Templates are the only provisioning path. - Resource limits come from approved templates, not user input. -- Deployment lifecycle operations are routed through a dedicated Proxmox client interface. +- Deployment lifecycle operations are routed through a dedicated Proxmox client interface and include the stored resource type so VM and LXC actions use the correct Proxmox API path. - Live Proxmox access can be replaced or expanded without changing REST or UI code. - WordPress users are used as actors for audit logging. Portal permissions are assigned per user inside the plugin so users created by SSO or external identity providers do not need WordPress author/editor roles. diff --git a/support-provisioning-portal/assets/portal.js b/support-provisioning-portal/assets/portal.js index 9b2725a..2c8129a 100644 --- a/support-provisioning-portal/assets/portal.js +++ b/support-provisioning-portal/assets/portal.js @@ -148,6 +148,8 @@ return 'OWNER'; }; + const resourceTypeLabel = (type) => type === "lxc" ? "LXC" : "VM"; + const actionButton = (permission, action, label, id, className = "", disabled = false) => { if (!can(permission)) { return ""; @@ -195,7 +197,7 @@
Template-based VM provisioning for support work.
+Template-based VM and LXC provisioning for support work.
${quotaLine()}| Name | Status | Access | Template | IP addresses | Expires | ||
|---|---|---|---|---|---|---|---|
| Name | Status | Access | Type | Template | IP addresses | Expires | ${escapeHtml(deployment.name)} | ${statusBadge(deployment.status)} | ${accessLabel(deployment)} | +${resourceTypeLabel(deployment.provisioningType)} | ${escapeHtml(deployment.templateName)} | ${ipList(deployment.ipAddresses)} | ${dateTime(deployment.expiresAt)} | @@ -243,6 +246,7 @@