- 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.
- Documented LXC setup, storage permissions, and the new Proxmox settings.
This commit is contained in:
Sven Steinert
2026-04-24 17:11:39 +02:00
parent 2c1949bf1e
commit 118809bfae
13 changed files with 672 additions and 126 deletions

View File

@@ -148,6 +148,8 @@
return '<span class="spp-badge OWNER">OWNER</span>';
};
const resourceTypeLabel = (type) => type === "lxc" ? "LXC" : "VM";
const actionButton = (permission, action, label, id, className = "", disabled = false) => {
if (!can(permission)) {
return "";
@@ -195,7 +197,7 @@
<div class="spp-header">
<div>
<h2 class="spp-title">Support Provisioning Portal</h2>
<p class="spp-subtitle">Template-based VM provisioning for support work.</p>
<p class="spp-subtitle">Template-based VM and LXC provisioning for support work.</p>
${quotaLine()}
</div>
<div class="spp-tabs">
@@ -215,7 +217,7 @@
<div class="spp-panel">
<table class="spp-table">
<thead>
<tr><th>Name</th><th>Status</th><th>Access</th><th>Template</th><th>IP addresses</th><th>Expires</th><th></th></tr>
<tr><th>Name</th><th>Status</th><th>Access</th><th>Type</th><th>Template</th><th>IP addresses</th><th>Expires</th><th></th></tr>
</thead>
<tbody>
${state.deployments.map((deployment) => `
@@ -223,6 +225,7 @@
<td><strong>${escapeHtml(deployment.name)}</strong></td>
<td>${statusBadge(deployment.status)}</td>
<td>${accessLabel(deployment)}</td>
<td>${resourceTypeLabel(deployment.provisioningType)}</td>
<td>${escapeHtml(deployment.templateName)}</td>
<td>${ipList(deployment.ipAddresses)}</td>
<td>${dateTime(deployment.expiresAt)}</td>
@@ -243,6 +246,7 @@
<p>${escapeHtml(template.description)}</p>
<div class="spp-meta">
<span>OS<strong>${template.osType}</strong></span>
<span>Type<strong>${resourceTypeLabel(template.provisioningType)}</strong></span>
<span>CPU<strong>${template.cpuCores} cores</strong></span>
<span>Memory<strong>${template.memoryMb} MB</strong></span>
<span>Disk<strong>${template.diskGb} GB</strong></span>
@@ -263,7 +267,7 @@
<form class="spp-form" id="spp-create-form">
<label>Template
<select class="spp-select" name="templateId" required>
${state.templates.map((template) => `<option value="${template.id}">${escapeHtml(template.name)}</option>`).join("")}
${state.templates.map((template) => `<option value="${template.id}">[${resourceTypeLabel(template.provisioningType)}] ${escapeHtml(template.name)}</option>`).join("")}
</select>
</label>
<label>Deployment name
@@ -313,9 +317,10 @@
</div>
<div class="spp-meta">
<span>Template<strong>${escapeHtml(deployment.templateName)}</strong></span>
<span>Type<strong>${resourceTypeLabel(deployment.provisioningType)}</strong></span>
<span>Requested by<strong>${escapeHtml(deployment.requestedByName)}</strong></span>
<span>Access<strong>${deployment.accessType ? escapeHtml(deployment.accessType) : "Owner"}</strong></span>
<span>Proxmox VM ID<strong>${deployment.proxmoxVmId || "Pending"}</strong></span>
<span>Proxmox ID<strong>${deployment.proxmoxResourceId || deployment.proxmoxVmId || "Pending"}</strong></span>
<span>IP addresses<strong>${ipList(deployment.ipAddresses)}</strong></span>
<span>CPU<strong>${deployment.cpuCores} cores</strong></span>
<span>Memory<strong>${deployment.memoryMb} MB</strong></span>