You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Offer VDS products alongside the existing VPS line: VMs with dedicated, non-oversubscribed CPU cores and RAM (host CPU passthrough, optionally pinned cores), sold at a premium. Everything below is based on a deep dive of the current code.
available_cpu() = cpu * load_cpu - consumed, summed over all VMs uniformly
No way to account shared and dedicated consumption differently on one host
Proxmox client (lnvps_api/src/host/proxmox.rs)
VMs created with cpu: "kvm64" (from QemuConfig.cpu), supports cpulimit
No cputype=host, no affinity (PVE 7.3+ core pinning), no numa, no cpuunits, no hugepages
Libvirt client (lnvps_api/src/host/libvirt.rs)
Plain <vcpu>/<memory> XML
No <cputune>/<vcpupin>, no host-passthrough CPU mode, no <numatune>
Provisioner / placement
Picks host by region + arch/mfg/features + capacity
Needs host-class awareness
Pricing
Per-template via cost_plan_id; custom pricing per region
Dedicated templates can simply carry their own (pricier) cost plans — little work needed
Design
1. Data model (migration)
vm_template.dedicated BOOLEAN NOT NULL DEFAULT 0 (or a template_class enum if more classes are expected later).
vm_host.host_class SMALLINT NOT NULL DEFAULT 0 — 0 = Shared, 1 = Dedicated. Phase 1 keeps the classes exclusive per host: dedicated templates only place on dedicated hosts, whose load_cpu/load_memory are forced to 1.0.
(Phase 3, only if mixing classes on one host) vm_core_assignment (vm_id, host_id, core_idx) table recording pinned cores, so the allocator can hand out disjoint core sets and reclaim them on delete.
2. Capacity engine
Phase 1 (host-class separation) keeps capacity.rs almost unchanged:
list_available_vm_templates / placement filter hosts by host.host_class == template.class.
Dedicated hosts run with load factors 1.0, so the existing arithmetic already yields no-overcommit accounting.
Guard: reject load_cpu/load_memory != 1.0 on dedicated hosts in admin API validation (or clamp).
Mixing shared + dedicated on one host is much harder (shared VMs still steal cycles unless every dedicated VM is pinned and shared VMs are confined to the complementary core set via affinity/cgroup cpusets). Defer.
3. Proxmox host client
For VMs from dedicated templates:
cpu: host (CPU passthrough) instead of the configured kvm64 — expose as QemuConfig.dedicated_cpu or derive from the template flag.
cpuunits: 10000 so dedicated VMs win scheduling against any co-located workload.
Optional core pinning via the PVE affinity: <core-list> config key (PVE >= 7.3), driven by the core allocator (phase 5).
Optional: numa: 1 + hugepages for large-memory templates.
Note: cputype=host breaks live-migration between heterogeneous hosts — acceptable for VDS (document it), and cpu_mfg/cpu_features matching already exists to keep templates on homogeneous hardware.
4. Libvirt host client (parity, later)
<cpu mode="host-passthrough"/>, <cputune><vcpupin vcpu="N" cpuset="M"/></cputune>, <numatune> as needed.
5. API surface
User API: dedicated: bool on template/VM responses so the frontend can badge VDS plans; capacity-aware template listing already flows through list_available_vm_templates.
Admin API: CRUD for the template flag + host class; validation as above.
ApiVmTemplate, admin models, and E2E fixtures updated.
6. Explicitly out of scope (follow-ups)
Mixed shared/dedicated hosts with core-set partitioning (needs vm_core_assignment + confining shared VMs to the complement).
Converting an existing shared VM to VDS in place (would be a migration/upgrade flow like Transfer VM #178/VM addons #187).
Dedicated disk spindles/NVMe namespaces — current VmHostDisk + IOPS caps are considered sufficient.
Suggested phasing (one PR each)
DB + admin API: migration, dedicated template flag, host_class, validation. (S)
Capacity/placement: class-aware host filtering + template availability. (S)
Proxmox: cpu: host + cpuunits for dedicated VMs, config plumbed through FullVmInfo. (M)
User API exposure + E2E test covering provision-on-dedicated-host. (S)
Goal
Offer VDS products alongside the existing VPS line: VMs with dedicated, non-oversubscribed CPU cores and RAM (host CPU passthrough, optionally pinned cores), sold at a premium. Everything below is based on a deep dive of the current code.
Where the codebase stands today
VmTemplate(lnvps_db/src/model.rs)cpu,memory,cpu_mfg/arch/features,cpu_limit(fractional cap), IOPS/net caps,cost_plan_id,region_iddedicatedclass flag;cpu_limitis the opposite lever (throttling shared VMs)VmHostload_cpu/load_memory/load_diskare host-wide overcommit factorslnvps_api_common/src/capacity.rs)available_cpu()=cpu * load_cpu - consumed, summed over all VMs uniformlylnvps_api/src/host/proxmox.rs)cpu: "kvm64"(fromQemuConfig.cpu), supportscpulimitcputype=host, noaffinity(PVE 7.3+ core pinning), nonuma, nocpuunits, no hugepageslnvps_api/src/host/libvirt.rs)<vcpu>/<memory>XML<cputune>/<vcpupin>, no host-passthrough CPU mode, no<numatune>cost_plan_id; custom pricing per regionDesign
1. Data model (migration)
vm_template.dedicated BOOLEAN NOT NULL DEFAULT 0(or atemplate_classenum if more classes are expected later).vm_host.host_class SMALLINT NOT NULL DEFAULT 0—0 = Shared,1 = Dedicated. Phase 1 keeps the classes exclusive per host: dedicated templates only place on dedicated hosts, whoseload_cpu/load_memoryare forced to1.0.vm_core_assignment (vm_id, host_id, core_idx)table recording pinned cores, so the allocator can hand out disjoint core sets and reclaim them on delete.2. Capacity engine
Phase 1 (host-class separation) keeps
capacity.rsalmost unchanged:list_available_vm_templates/ placement filter hosts byhost.host_class == template.class.load_cpu/load_memory != 1.0on dedicated hosts in admin API validation (or clamp).Mixing shared + dedicated on one host is much harder (shared VMs still steal cycles unless every dedicated VM is pinned and shared VMs are confined to the complementary core set via
affinity/cgroup cpusets). Defer.3. Proxmox host client
For VMs from dedicated templates:
cpu: host(CPU passthrough) instead of the configuredkvm64— expose asQemuConfig.dedicated_cpuor derive from the template flag.cpuunits: 10000so dedicated VMs win scheduling against any co-located workload.affinity: <core-list>config key (PVE >= 7.3), driven by the core allocator (phase 5).numa: 1+ hugepages for large-memory templates.cputype=hostbreaks live-migration between heterogeneous hosts — acceptable for VDS (document it), andcpu_mfg/cpu_featuresmatching already exists to keep templates on homogeneous hardware.4. Libvirt host client (parity, later)
<cpu mode="host-passthrough"/>,<cputune><vcpupin vcpu="N" cpuset="M"/></cputune>,<numatune>as needed.5. API surface
dedicated: boolon template/VM responses so the frontend can badge VDS plans; capacity-aware template listing already flows throughlist_available_vm_templates.ApiVmTemplate, admin models, and E2E fixtures updated.6. Explicitly out of scope (follow-ups)
vm_core_assignment+ confining shared VMs to the complement).VmHostDisk+ IOPS caps are considered sufficient.Suggested phasing (one PR each)
dedicatedtemplate flag,host_class, validation. (S)cpu: host+cpuunitsfor dedicated VMs, config plumbed throughFullVmInfo. (M)affinity) — optional hardening. (M)Acceptance criteria (phases 1-4)
dedicatedonly ever places on aDedicated-class host, with 1:1 CPU/RAM accounting (no overcommit).cpuunits.