Files
PSProxmoxVE/CHANGELOG.md
T
goodolclint-claude[bot] 2dff02f2bd feat: VLAN-aware bridges via New-PveNetwork and Set-PveNetwork
PveNetwork already deserialised bridge_vlan_aware as BridgeVlanAware, so a
VLAN-aware bridge could be read back but never created or changed. Both write
paths now take a -BridgeVlanAware switch.

Clearing the flag does not use bridge_vlan_aware=0. PVE merges the supplied
keys onto the stored stanza and accepts that 0 without acting on it, so the
obvious form is a silent no-op: an integration run against PVE 9 issued it and
Get-PveNetwork still reported 1. The endpoint's delete list is what actually
removes the key. The API schema advertises a plain boolean and gives no hint of
this, which is why the behaviour is pinned by an integration test rather than
inferred.

Set-PveNetwork guards the switch on BoundParameters so an update that omits it
leaves the flag alone; the create path follows the existing -Autostart form.
Only bridge_vlan_aware is added. bridge_vids is an independent parameter that
PVE defaults to 2-4094, and the issue asks only for the flag.

Coverage: the integration suite pins create, disable, re-enable, and that an
unrelated Set leaves the flag alone -- that last one kills a mutant that drops
the BoundParameters guard, which every other test survives. A model test pins
the read path the assertions depend on. The Pester unit tests assert only
parameter metadata; the defect is server-side, so nothing offline can catch it.

Closes #92
2026-09-01 22:53:26 -05:00

10 KiB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Conventional Commits.

[Unreleased]

Added

  • New-PveNetwork and Set-PveNetwork gained -BridgeVlanAware, so a VLAN-aware Linux bridge can be created and toggled from the module instead of only being read back. The model already surfaced bridge_vlan_aware as BridgeVlanAware, so this closed a write-path gap. On Set-PveNetwork the switch is only sent when explicitly bound, so an update that omits it leaves the flag alone. Clearing it goes through the endpoint's delete list rather than bridge_vlan_aware=0: PVE merges supplied keys onto the stored stanza and accepts the 0 without acting on it, so the obvious form is a silent no-op — confirmed against a live PVE 9 cluster, where the bridge stayed VLAN-aware. bridge_vids is not covered; it is an independent parameter and PVE defaults to 2-4094. (#92)

Fixed

  • Restart-PveVm now uses PVE's native reboot endpoint (POST {vmid}/status/reboot) instead of composing a shutdown followed by a start. The two-call form raced Proxmox's own post-stop cleanup: the start won the guest's config lock, qm cleanup then held that lock for 30 seconds waiting on the newly started process, and the caller's next operation failed with can't lock file '/var/lock/qemu-server/lock-<vmid>.conf' - got timeout. Reproduced in integration runs 183, 185 and 186 as a cascade of 4 failures. Restart-PveContainer is unchanged — LXC has no reboot endpoint. See DECISIONS.md D016.
  • Guest operations that Proxmox rejects with can't lock file '/var/lock/qemu-server/lock-<vmid>.conf' - got timeout are now reissued for up to 45 seconds instead of surfacing as an error. That flock is taken by qm cleanup for up to 30 seconds after a guest stops and is not exposed through the API in any form, so it can only be retried past, never waited on. Covers both the synchronous form (Set-PveVmConfig, Resize-PveVmDisk, and every other call through the HTTP client) and the asynchronous form, where the request succeeds and the PVE task then fails (Reset-PveVm, Copy-PveVm). Reproduced on a client ~40% slower than CI, which failed three VM tests on a commit CI passed. (#113) See DECISIONS.md D020.
  • Lifecycle cmdlets with -Wait (Start/Stop/Restart/Reset/Resume for VMs and containers) also wait for the guest's config lock (the lock: property, e.g. backup or migrate) to clear before returning, and the post-timeout fallback tests the most recent poll rather than whether a match was ever seen. See DECISIONS.md D015 — that guard covers the config lock only; the separate flock race is D020.
  • New-PveCluster -Wait now blocks until the cluster reports quorum, not merely until the creation task finishes. PVE's create task returns before corosync converges (~6s earlier in testing), so the natural New-PveCluster -WaitAdd-PveClusterMember sequence failed with cluster not ready - no quorum?. Adds -Timeout (seconds, default 60, range 1-3600) following the -Wait timeout convention used by Stop-PveContainer and Reset-PveVm. See DECISIONS.md D014.

[0.2.0] - 2026-05-22

Added

  • New-PveVm disk controller / IO options: -DiskBus (virtio/scsi/sata/ide), -ScsiHardware (scsihw), -DiskIoThread, -DiskAio, -DiskSsd, -DiskDiscard, -DiskCache. Invalid combinations (e.g. ssd on virtio, iothread on sata/ide or scsi without virtio-scsi-single) are rejected up front with a clear error. (#65)
  • Get-PveVmConfig now surfaces scsihw, efidisk0, and tpmstate0 as typed properties, plus an AdditionalProperties dictionary capturing any other config key (e.g. hostpci0) as native .NET values instead of silently dropping it. (#65)

Fixed

  • Form values containing ; were split into bogus fields by PVE's parser, so a multi-device boot order set via Set-PveVmConfig -AdditionalConfig @{ boot = 'order=scsi0;ide2' } failed with unable to parse drive options. Semicolons are now percent-encoded. (#64)
  • Invoke-PveVmGuestExec -Args were delivered to the guest as JSON on STDIN instead of as argv, so commands ran with no/garbage arguments. Arguments are now sent as the PVE command array (repeated keys), reaching the process as real argv. (#68)

[0.1.3] - 2026-05-20

Added

  • Connect-PveServer -TimeoutSeconds to set the session-default HttpClient timeout (default 100s; 0 = infinite). (#59)
  • Send-PveFile -TimeoutSeconds and Invoke-PveStorageDownload -TimeoutSeconds for per-call override with a 30-minute implicit default so large uploads/downloads no longer trip the 100s default. (#59)

Fixed

  • New-PveVm -DiskSize and New-PveContainer -RootFsSize now normalize unit suffixes (32G, 1T, 32GB, etc.) to bare GiB before constructing the disk spec. Previously the suffix was passed verbatim, which LVM/LVM-thin storages rejected with unable to parse lvm volume name '32G'. Sub-GB units (M, MB, K, KB) are now rejected client-side with a clear error. (#58)
  • PveHttpClient.SendAsync surfaces HttpClient.Timeout firings as PveApiException(RequestTimeout) with the resource path and configured timeout, instead of leaking a raw TaskCanceledException. Works across net48, net10.0, and netstandard2.0. (#59)
  • Disk-size validation runs before ShouldProcess so typos like 512M are caught with -WhatIf, regardless of whether -DiskStorage/-RootFsStorage is also supplied. (#58)

[0.1.2] - 2026-03-27

Fixed

  • Get-PveApiToken: FullTokenId is now computed from UserId!TokenId (was always empty). (#44)
  • Set-PvePermission: added token ACL type with auto-detection from ! in -UgId, enabling permission assignment for API tokens. (#43)
  • Connect-PveServer: always emits the session to the pipeline. Use -Quiet to suppress; -PassThru is kept hidden for backwards compatibility. (#45)

[0.1.1] - 2026-03-26

Added

  • Firewall management cmdlets (21): rules, security groups, aliases, IP sets, options at cluster/node/VM/container levels
  • Backup/vzdump cmdlets (5): ad-hoc backup creation and scheduled backup job CRUD
  • SDN IPAM cmdlets (3): Get/New/Remove-PveSdnIpam for IPAM plugin management
  • SDN DNS cmdlets (3): Get/New/Remove-PveSdnDns for DNS plugin management
  • SDN Controller cmdlets (3): Get/New/Remove-PveSdnController for controller management
  • SDN Update cmdlets (7): Set-PveSdnZone/Vnet/Subnet/Controller/Ipam/Dns + Invoke-PveSdnApply
  • Set-PveRole, Set-PveStorage, Set-PveApiToken for missing update operations
  • Get-PveClusterResource: single-call cluster-wide inventory of all VMs, containers, nodes, storage
  • Task management: Get-PveTaskList (list tasks on node), Stop-PveTask (cancel running tasks)
  • Pool management cmdlets (4): Get/New/Set/Remove-PvePool
  • Get-PveBackupInfo: find VMs/containers not covered by backup jobs
  • VM disk operations: Move-PveVmDisk (storage migration), Remove-PveVmDisk (detach/delete)
  • Guest agent extensions (6): Get-PveVmGuestOsInfo, Get-PveVmGuestFsInfo, Read/Write-PveVmGuestFile, Set-PveVmGuestPassword, Invoke-PveVmGuestFsTrim
  • Container gaps (6): Suspend/Resume-PveContainer, Resize-PveContainerDisk, New-PveContainerTemplate, Move-PveContainerVolume, Get-PveContainerInterface
  • Storage content management (4): Get-PveStorageStatus, Remove/Set-PveStorageContent, New-PveStorageDisk
  • Node operations (6): Get/Set-PveNodeConfig, Get/Set-PveNodeDns, Start/Stop-PveNodeVms
  • Access management (9): Get/New/Set/Remove-PveGroup, Get/New/Set/Remove-PveDomain, Set-PvePassword
  • Two-tier version gating: introduced vs default version with clear user messaging
  • 70 xUnit tests validating every ValidateSet against the PVE OpenAPI spec, with pve-api-enums.json fixture extracted from the full spec
  • Integration tests for firewall rules, aliases, IP sets, backup jobs, and OVA import
  • PSGallery version badge in README

Changed

  • All cmdlet classes sealed for design clarity and JIT optimization
  • [OutputType] attribute added to all 169 cmdlets for IntelliSense and pipeline support
  • Publishable projects retargeted to netstandard2.0 for PS 5.1 + PS 7.x compatibility
  • System.Text.Json attributes removed — module uses Newtonsoft.Json exclusively
  • Inline task-polling loops replaced with TaskService.WaitForTask (timeout + progress support)
  • Password parameters changed from string to SecureString with secure memory handling
  • ValidateRange(100, 999999999) added to all VmId parameters
  • Uri.EscapeDataString() applied to all dynamic URL path segments
  • Hardcoded verb strings replaced with verb class constants (VerbsCommon.Get, etc.)
  • Auth header magic strings extracted to named constants in PveHttpClient
  • Bare catch blocks replaced with specific or filtered exception handling
  • MAML help (dll-Help.xml) and 170 markdown cmdlet docs generated
  • PSGallery publish workflow with PS 5.1 smoke testing

Fixed

  • ConfirmImpact.High added to all destructive cmdlets (Stop, Reset, Restart, Suspend, Remove, Restore, New-PveTemplate)
  • Storage ValidateSet: removed glusterfs (dropped in PVE 9), added btrfs and esxi
  • Backup compression: none0 (PVE expects the string "0", not "none")
  • Cluster resource filter: removed lxc (PVE uses vm for both QEMU and LXC)
  • Hardcoded test password moved from CI workflow to GitHub Actions secret
  • Terraform variable default password removed (requires env var)

[0.1.0-preview] - 2026-03-19

Added

  • Initial project structure and solution setup
  • Ticket and API token authentication with session management
  • HTTP client with manual multipart ISO upload (bugzilla 7389 workaround)
  • Typed response models for PVE 8.x and 9.x API resources
  • Service layer for all resource domains
  • 66 PowerShell cmdlets for VMs, containers, storage, networking, SDN, users, roles, permissions, API tokens, templates, cloud-init, snapshots, and tasks
  • QEMU guest agent cmdlets (Test-PveVmGuestAgent, Get-PveVmGuestNetwork, Invoke-PveVmGuestExec)
  • xUnit unit tests for core library
  • Pester 5 cmdlet tests across OS/PS version matrix (Windows PS 5.1, PS 7.5 on Windows/Linux/macOS)
  • Integration tests against live PVE 8 and PVE 9 instances via Terraform-provisioned nested VMs
  • GitHub Actions CI/CD workflows (build, unit tests, integration tests)
  • Format definitions for default table output on all PS versions