Author SHA1 Message Date
christianmanivong 841881018c Merge feature/nic-mac-address: optional explicit MAC on NICConfigDict 2026-07-08 09:09:18 +02:00
christianmanivong f5c286a713 feat(hypervisor): add optional explicit mac to NICConfigDict
Lets a caller pin a NIC's MAC address ahead of VM creation, needed to
create a matching DHCP static reservation before the VM even exists.
2026-07-08 09:09:14 +02:00
christianmanivong 6c4ff65710 Merge feature/node-scoped-image-storage: get_image_storages() + storage param 2026-07-07 22:35:35 +02:00
christianmanivong f9b8a54673 feat(hypervisor): add StorageTargetDict and get_image_storages(), storage param on create_vm_from_cloud_init
Lets callers select which node-available storage pool a new VM's root
disk lands on, instead of always trusting the driver's auto-detected
default.
2026-07-07 22:35:33 +02:00
christianmanivong d9a23e08f2 Merge feature/create-vm-from-image: create_vm_from_cloud_init downloads images directly 2026-07-07 10:38:03 +02:00
christianmanivong 5059df6b25 feat(hypervisor): create_vm_from_cloud_init downloads a cloud image directly
Replaces template-clone semantics (template: str, existing Proxmox template
VMID) with image_url: str — the driver now downloads the cloud image itself
and imports it as the VM's root disk, rather than requiring an admin to have
pre-built a template. Adds image_checksum for optional verification and a
separate download_timeout since image downloads can take much longer than
the rest of provisioning.
2026-07-07 10:25:45 +02:00
christianmanivong a37dc8d632 Merge feature/network-target-vlan-tag: expose fixed VLAN tag for SDN vnets 2026-07-07 10:20:42 +02:00
christianmanivong cb274156a4 feat(models): add fixed_vlan_tag to NetworkTargetDict for SDN vnets 2026-07-07 10:20:36 +02:00
christianmanivong a16ca77156 Merge feature/network-targets: add get_network_targets() interface 2026-07-07 09:09:57 +02:00
christianmanivong fcf72b6dad feat(hypervisor): add get_network_targets() interface for VM NIC provisioning
Returns selectable bridge/vnet targets for a new VM's NIC, distinguishing
real bridges (Linux, OVS) from SDN vnets, and exposing whether a NIC on that
target may additionally carry a vlan_tag (Linux bridge vlan_aware flag, OVS
always, SDN vnet never — the VLAN is already fixed by the vnet's zone/tag).
2026-07-07 09:03:44 +02:00
christianmanivong 2cc93885b4 Reapply "Merge feature/generic-vm-provisioning: generalize create_vm_from_cloud_init interface"
This reverts commit 97cab9754b.
2026-07-07 08:20:55 +02:00
christianmanivong 97cab9754b Revert "Merge feature/generic-vm-provisioning: generalize create_vm_from_cloud_init interface"
This reverts commit 7d18c12579, reversing
changes made to 7f0dd789b0.
2026-07-07 00:53:06 +02:00
christianmanivong 7d18c12579 Merge feature/generic-vm-provisioning: generalize create_vm_from_cloud_init interface 2026-07-07 00:46:30 +02:00
2 changed files with 103 additions and 12 deletions
+71 -12
View File
@@ -16,8 +16,10 @@ from napalm_device_types._ucd_metrics import IF_SKIP_DEFAULT, collect_ucd_metric
from napalm_device_types.models import (
HealthMetricsDict,
NICConfigDict,
NetworkTargetDict,
PackageDict,
SnapshotDict,
StorageTargetDict,
StorageVolumeDict,
VMConfigDict,
VMDict,
@@ -547,47 +549,68 @@ class HypervisorDriver(DeviceTypeDriver):
self,
name: str,
*,
template: str,
image_url: str,
cpu: int,
memory: int,
nics: List[NICConfigDict],
cloud_init_config: Dict[str, Any],
image_checksum: str | None = None,
ssh_public_keys: List[str] | None = None,
disk_resize_gb: int | None = None,
storage: str | None = None,
download_timeout: int = 300,
timeout: int = 180,
) -> VMProvisionResultDict:
"""
Create a new virtual machine from a Cloud-Init template.
Create a new virtual machine from a cloud image via Cloud-Init.
Clones a pre-existing VM template, configures virtual network interfaces,
and injects Cloud-Init configuration via a storage snippet or similar
mechanism. The resulting VM is left in a running state.
Downloads the cloud image (qcow2/raw) directly on the hypervisor if not
already cached there, creates a new VM shell, imports the image as its
root disk, configures virtual network interfaces, and injects Cloud-Init
configuration via a storage snippet or similar mechanism. The resulting
VM is left in a running state.
Implementations should cache downloaded images by URL/filename on the
hypervisor so repeated provisioning from the same image does not
re-download it every time.
Args:
name (string) - new VM display name
template (string) - hypervisor-internal ID/name of the template VM to clone
image_url (string) - URL of the cloud image to download and use as
the VM's root disk (e.g. an official Debian/Ubuntu cloud image).
cpu (int) - number of virtual CPUs to assign
memory (int) - RAM to assign in megabytes
nics (list[NICConfigDict]) - list of network interface configurations.
First NIC is primary (DHCP by default); subsequent NICs are optional.
Each entry specifies bridge, optional vlan_tag (access) or trunk_vlan_tags,
and dhcp flag.
dhcp flag, and an optional explicit mac address (omit to let the
hypervisor auto-generate one; needed when a caller must know the
MAC ahead of time, e.g. to create a matching DHCP reservation).
cloud_init_config (dict) - user-data dict (will be rendered to YAML).
Should include hostname, bootstrap_token, runcmd, and any custom config.
image_checksum (string | None) - expected checksum of the downloaded
image (e.g. "sha256:<hex>"). If given, verified after download;
mismatch raises RuntimeError. If None, no verification is performed.
ssh_public_keys (list[str] | None) - SSH public keys to inject into guest.
If None or empty, no SSH key injection is performed.
disk_resize_gb (int | None) - resize root disk to this size in GB.
If None, disk remains template size. Default None.
timeout (int) - maximum seconds to wait for provisioning completion
(clone, config, start). Default 180.
If None, disk remains the downloaded image's native size. Default None.
storage (string | None) - name of the storage pool to place the root
disk on (a name returned by ``get_image_storages()``). If None,
the driver auto-detects the first enabled, node-available storage
whose content includes "images".
download_timeout (int) - maximum seconds to wait for the image download
(skipped entirely if already cached on the hypervisor). Default 300.
timeout (int) - maximum seconds to wait for the remaining provisioning
steps (VM creation, disk import, config, start). Default 180.
Returns:
VMProvisionResultDict - ``{"vmid": str, "name": str, "node": str}``
vmid is the hypervisor-internal VM ID as a string (numeric for Proxmox).
Raises:
RuntimeError - if provisioning fails (storage unavailable, invalid
config, timeout, etc.)
RuntimeError - if provisioning fails (download failure, checksum
mismatch, storage unavailable, invalid config, timeout, etc.)
"""
raise NotImplementedError
@@ -655,3 +678,39 @@ class HypervisorDriver(DeviceTypeDriver):
timeout is exceeded.
"""
raise NotImplementedError
def get_network_targets(self) -> List[NetworkTargetDict]:
"""
List the network targets a new VM's NIC may attach to.
Returns only targets that are actually valid ``NICConfigDict.bridge``
values — real bridges (Linux or OVS) and SDN network segments (vnets).
Physical NICs, bonds, and other non-bridge interface types are excluded,
since VMs cannot attach directly to them on any hypervisor this interface
supports.
Returns:
List[NetworkTargetDict] - each entry's ``vlan_aware`` flag tells the
caller whether a ``NICConfigDict.vlan_tag`` may additionally be set
for a NIC using that target (see ``NetworkTargetDict`` for the
per-kind rules).
"""
raise NotImplementedError
def get_image_storages(self) -> List[StorageTargetDict]:
"""
List the storage pools a new VM's root disk may be placed on, scoped to
the specific node the VM will be created on.
Returns only storages that are actually usable for this purpose right
now: content includes "images", administratively enabled, and — for
hypervisors where storage can be restricted to a subset of cluster
nodes — available on this node specifically. A storage configured
cluster-wide but restricted to other nodes must not appear here, since
passing its name to ``create_vm_from_cloud_init(storage=...)`` would fail.
Returns:
List[StorageTargetDict] - each entry's ``name`` is directly usable
as ``create_vm_from_cloud_init``'s ``storage`` argument.
"""
raise NotImplementedError
+32
View File
@@ -713,6 +713,7 @@ class NICConfigDict(TypedDict):
vlan_tag: NotRequired[int | None] # Access VLAN (None = untagged)
trunk_vlan_tags: NotRequired[list[int]] # Trunk VLAN list (alternative to vlan_tag)
dhcp: NotRequired[bool] # Enable DHCP (default True for first NIC, False for others)
mac: NotRequired[str] # Explicit MAC address (omit to let the hypervisor auto-generate one)
class VMProvisionResultDict(TypedDict):
@@ -730,3 +731,34 @@ class VMStatusDict(TypedDict):
ip_address: NotRequired[str] # Management NIC IP (absent if VM has no IP or is stopped)
hostname: NotRequired[str] # Hostname resolved from IP (if available)
mac_address: NotRequired[str] # MAC of management NIC
class NetworkTargetDict(TypedDict):
"""A selectable network target for a new VM's NIC (``NICConfigDict.bridge``).
Distinguishes real bridges (Linux or OVS) from SDN network segments (vnets),
and tells the caller whether a separate ``vlan_tag`` may be applied on top:
- Linux bridge: vlan_aware reflects the bridge's own ``bridge_vlan_aware`` flag.
- OVS bridge: always vlan_aware (OVS bridges tag per-port regardless of a
dedicated "VLAN aware" setting).
- SDN vnet: never vlan_aware — the VLAN is already fixed by the vnet's zone/tag,
so a NIC attached to it must not also carry a ``vlan_tag``. That fixed VLAN
is surfaced via ``fixed_vlan_tag`` instead, for display purposes.
"""
name: str # Bridge or vnet name, usable directly as NICConfigDict.bridge
kind: str # "bridge" or "vnet"
vlan_aware: bool # True if a NICConfigDict.vlan_tag may be set on top of this target
fixed_vlan_tag: NotRequired[int | None] # vnet only: the VLAN ID already baked into it
class StorageTargetDict(TypedDict):
"""A selectable storage pool for a new VM's root disk (``create_vm_from_cloud_init``'s
``storage`` argument), scoped to the specific node the VM will be created on —
a storage restricted to other cluster nodes must not appear here.
"""
name: str # Storage pool name, usable directly as create_vm_from_cloud_init(storage=...)
type: str # Backend type: "dir", "lvmthin", "zfspool", "nfs", etc.
total_gb: float # Total capacity in gigabytes
available_gb: float # Free capacity in gigabytes