diff --git a/src/PSProxmoxVE.Core/Services/NetworkService.cs b/src/PSProxmoxVE.Core/Services/NetworkService.cs index 791b893..18d61e1 100644 --- a/src/PSProxmoxVE.Core/Services/NetworkService.cs +++ b/src/PSProxmoxVE.Core/Services/NetworkService.cs @@ -4,7 +4,6 @@ using System.Linq; using Newtonsoft.Json.Linq; using PSProxmoxVE.Core.Authentication; using PSProxmoxVE.Core.Client; -using PSProxmoxVE.Core.Exceptions; using PSProxmoxVE.Core.Models.Network; using PSProxmoxVE.Core.Models.Vms; @@ -140,7 +139,7 @@ namespace PSProxmoxVE.Core.Services public PveSdnZone[] GetSdnZones(PveSession session) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + using var client = new PveHttpClient(session); var response = client.GetAsync("cluster/sdn/zones").GetAwaiter().GetResult(); @@ -155,7 +154,7 @@ namespace PSProxmoxVE.Core.Services public PveSdnVnet[] GetSdnVnets(PveSession session) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + using var client = new PveHttpClient(session); var response = client.GetAsync("cluster/sdn/vnets").GetAwaiter().GetResult(); @@ -173,7 +172,7 @@ namespace PSProxmoxVE.Core.Services Dictionary config) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (config == null) throw new ArgumentNullException(nameof(config)); using var client = new PveHttpClient(session); @@ -194,7 +193,7 @@ namespace PSProxmoxVE.Core.Services public void RemoveSdnZone(PveSession session, string zone) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (string.IsNullOrWhiteSpace(zone)) throw new ArgumentNullException(nameof(zone)); using var client = new PveHttpClient(session); @@ -211,7 +210,7 @@ namespace PSProxmoxVE.Core.Services Dictionary config) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (config == null) throw new ArgumentNullException(nameof(config)); using var client = new PveHttpClient(session); @@ -232,7 +231,7 @@ namespace PSProxmoxVE.Core.Services public void RemoveSdnVnet(PveSession session, string vnet) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (string.IsNullOrWhiteSpace(vnet)) throw new ArgumentNullException(nameof(vnet)); using var client = new PveHttpClient(session); @@ -251,7 +250,7 @@ namespace PSProxmoxVE.Core.Services public PveSdnSubnet[] GetSdnSubnets(PveSession session, string vnet) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (string.IsNullOrWhiteSpace(vnet)) throw new ArgumentNullException(nameof(vnet)); using var client = new PveHttpClient(session); @@ -273,7 +272,7 @@ namespace PSProxmoxVE.Core.Services Dictionary config) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (string.IsNullOrWhiteSpace(vnet)) throw new ArgumentNullException(nameof(vnet)); if (config == null) throw new ArgumentNullException(nameof(config)); @@ -294,7 +293,7 @@ namespace PSProxmoxVE.Core.Services public void RemoveSdnSubnet(PveSession session, string vnet, string subnet) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (string.IsNullOrWhiteSpace(vnet)) throw new ArgumentNullException(nameof(vnet)); if (string.IsNullOrWhiteSpace(subnet)) throw new ArgumentNullException(nameof(subnet)); @@ -314,7 +313,7 @@ namespace PSProxmoxVE.Core.Services public PveSdnIpam[] GetSdnIpams(PveSession session) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + using var client = new PveHttpClient(session); var response = client.GetAsync("cluster/sdn/ipams").GetAwaiter().GetResult(); @@ -328,7 +327,7 @@ namespace PSProxmoxVE.Core.Services public void CreateSdnIpam(PveSession session, Dictionary config) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (config == null) throw new ArgumentNullException(nameof(config)); using var client = new PveHttpClient(session); @@ -341,7 +340,7 @@ namespace PSProxmoxVE.Core.Services public void RemoveSdnIpam(PveSession session, string ipam) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (string.IsNullOrWhiteSpace(ipam)) throw new ArgumentNullException(nameof(ipam)); using var client = new PveHttpClient(session); @@ -359,7 +358,7 @@ namespace PSProxmoxVE.Core.Services public PveSdnDns[] GetSdnDnsPlugins(PveSession session) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + using var client = new PveHttpClient(session); var response = client.GetAsync("cluster/sdn/dns").GetAwaiter().GetResult(); @@ -373,7 +372,7 @@ namespace PSProxmoxVE.Core.Services public void CreateSdnDnsPlugin(PveSession session, Dictionary config) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (config == null) throw new ArgumentNullException(nameof(config)); using var client = new PveHttpClient(session); @@ -386,7 +385,7 @@ namespace PSProxmoxVE.Core.Services public void RemoveSdnDnsPlugin(PveSession session, string dns) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (string.IsNullOrWhiteSpace(dns)) throw new ArgumentNullException(nameof(dns)); using var client = new PveHttpClient(session); @@ -404,7 +403,7 @@ namespace PSProxmoxVE.Core.Services public PveSdnController[] GetSdnControllers(PveSession session) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + using var client = new PveHttpClient(session); var response = client.GetAsync("cluster/sdn/controllers").GetAwaiter().GetResult(); @@ -418,7 +417,7 @@ namespace PSProxmoxVE.Core.Services public void CreateSdnController(PveSession session, Dictionary config) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (config == null) throw new ArgumentNullException(nameof(config)); using var client = new PveHttpClient(session); @@ -431,7 +430,7 @@ namespace PSProxmoxVE.Core.Services public void RemoveSdnController(PveSession session, string controller) { if (session == null) throw new ArgumentNullException(nameof(session)); - RequireSdn(session); + if (string.IsNullOrWhiteSpace(controller)) throw new ArgumentNullException(nameof(controller)); using var client = new PveHttpClient(session); @@ -443,15 +442,6 @@ namespace PSProxmoxVE.Core.Services // Private helpers // ------------------------------------------------------------------------- - /// - /// Throws if the session's server version is below 8.0. - /// - private static void RequireSdn(PveSession session) - { - if (session.ServerVersion != null && !session.ServerVersion.IsAtLeast(8, 0)) - throw new PveVersionException(8, 0, session.ServerVersion); - } - private static PveTask ParseTask(string response, string node) { var data = JObject.Parse(response)["data"]; diff --git a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnControllerCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnControllerCmdlet.cs index 62f6cc7..8d7de12 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnControllerCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnControllerCmdlet.cs @@ -23,6 +23,7 @@ namespace PSProxmoxVE.Cmdlets.Network protected override void ProcessRecord() { var session = GetSession(); + RequireVersion(session, "SDN IPAM/DNS/Controller", 6, 2, 8, 1); var service = new NetworkService(); WriteVerbose("Getting SDN controllers..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnDnsCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnDnsCmdlet.cs index 5eb6fc5..c1b532e 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnDnsCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnDnsCmdlet.cs @@ -23,6 +23,7 @@ namespace PSProxmoxVE.Cmdlets.Network protected override void ProcessRecord() { var session = GetSession(); + RequireVersion(session, "SDN IPAM/DNS/Controller", 6, 2, 8, 1); var service = new NetworkService(); WriteVerbose("Getting SDN DNS plugins..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnIpamCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnIpamCmdlet.cs index 1898587..ad3de1d 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnIpamCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnIpamCmdlet.cs @@ -23,6 +23,7 @@ namespace PSProxmoxVE.Cmdlets.Network protected override void ProcessRecord() { var session = GetSession(); + RequireVersion(session, "SDN IPAM/DNS/Controller", 6, 2, 8, 1); var service = new NetworkService(); WriteVerbose("Getting SDN IPAM plugins..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnSubnetCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnSubnetCmdlet.cs index 0774b9b..f3e92a1 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnSubnetCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnSubnetCmdlet.cs @@ -27,6 +27,7 @@ namespace PSProxmoxVE.Cmdlets.Network protected override void ProcessRecord() { var session = GetSession(); + RequireVersion(session, "SDN", 6, 2, 8, 0); using var client = new PveHttpClient(session); WriteVerbose($"Getting SDN subnets for VNet '{Vnet}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnVnetCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnVnetCmdlet.cs index f8a629d..75875bc 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnVnetCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnVnetCmdlet.cs @@ -27,6 +27,7 @@ namespace PSProxmoxVE.Cmdlets.Network protected override void ProcessRecord() { var session = GetSession(); + RequireVersion(session, "SDN", 6, 2, 8, 0); using var client = new PveHttpClient(session); WriteVerbose("Getting SDN VNets..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnZoneCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnZoneCmdlet.cs index f53277c..7c213cb 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnZoneCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnZoneCmdlet.cs @@ -22,6 +22,7 @@ namespace PSProxmoxVE.Cmdlets.Network protected override void ProcessRecord() { var session = GetSession(); + RequireVersion(session, "SDN", 6, 2, 8, 0); using var client = new PveHttpClient(session); WriteVerbose("Getting SDN zones..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnControllerCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnControllerCmdlet.cs index 3faa7f2..d249ee5 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnControllerCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnControllerCmdlet.cs @@ -41,6 +41,7 @@ namespace PSProxmoxVE.Cmdlets.Network return; var session = GetSession(); + RequireVersion(session, "SDN IPAM/DNS/Controller", 6, 2, 8, 1); var service = new NetworkService(); WriteVerbose($"Creating SDN controller '{Controller}' of type '{Type}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnDnsCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnDnsCmdlet.cs index e00a164..e1e4e0f 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnDnsCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnDnsCmdlet.cs @@ -45,6 +45,7 @@ namespace PSProxmoxVE.Cmdlets.Network return; var session = GetSession(); + RequireVersion(session, "SDN IPAM/DNS/Controller", 6, 2, 8, 1); var service = new NetworkService(); WriteVerbose($"Creating SDN DNS plugin '{Dns}' of type '{Type}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnIpamCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnIpamCmdlet.cs index ff666d6..24b6c91 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnIpamCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnIpamCmdlet.cs @@ -41,6 +41,7 @@ namespace PSProxmoxVE.Cmdlets.Network return; var session = GetSession(); + RequireVersion(session, "SDN IPAM/DNS/Controller", 6, 2, 8, 1); var service = new NetworkService(); WriteVerbose($"Creating SDN IPAM plugin '{Ipam}' of type '{Type}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnSubnetCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnSubnetCmdlet.cs index 6b2aa11..0150626 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnSubnetCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnSubnetCmdlet.cs @@ -44,6 +44,7 @@ namespace PSProxmoxVE.Cmdlets.Network return; var session = GetSession(); + RequireVersion(session, "SDN", 6, 2, 8, 0); using var client = new PveHttpClient(session); WriteVerbose($"Creating SDN subnet '{Subnet}' on VNet '{Vnet}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnVnetCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnVnetCmdlet.cs index f9d7011..c5c6ea7 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnVnetCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnVnetCmdlet.cs @@ -39,6 +39,7 @@ namespace PSProxmoxVE.Cmdlets.Network return; var session = GetSession(); + RequireVersion(session, "SDN", 6, 2, 8, 0); using var client = new PveHttpClient(session); WriteVerbose($"Creating SDN VNet '{Vnet}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnZoneCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnZoneCmdlet.cs index 1ba4193..a0a21ad 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnZoneCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnZoneCmdlet.cs @@ -56,6 +56,7 @@ namespace PSProxmoxVE.Cmdlets.Network return; var session = GetSession(); + RequireVersion(session, "SDN", 6, 2, 8, 0); using var client = new PveHttpClient(session); WriteVerbose($"Creating SDN zone '{Zone}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnControllerCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnControllerCmdlet.cs index dfc85a1..3391d33 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnControllerCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnControllerCmdlet.cs @@ -23,6 +23,7 @@ namespace PSProxmoxVE.Cmdlets.Network return; var session = GetSession(); + RequireVersion(session, "SDN IPAM/DNS/Controller", 6, 2, 8, 1); var service = new NetworkService(); WriteVerbose($"Removing SDN controller '{Controller}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnDnsCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnDnsCmdlet.cs index 508934c..3bc7ce8 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnDnsCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnDnsCmdlet.cs @@ -23,6 +23,7 @@ namespace PSProxmoxVE.Cmdlets.Network return; var session = GetSession(); + RequireVersion(session, "SDN IPAM/DNS/Controller", 6, 2, 8, 1); var service = new NetworkService(); WriteVerbose($"Removing SDN DNS plugin '{Dns}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnIpamCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnIpamCmdlet.cs index b9fa9fa..f52a616 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnIpamCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnIpamCmdlet.cs @@ -23,6 +23,7 @@ namespace PSProxmoxVE.Cmdlets.Network return; var session = GetSession(); + RequireVersion(session, "SDN IPAM/DNS/Controller", 6, 2, 8, 1); var service = new NetworkService(); WriteVerbose($"Removing SDN IPAM plugin '{Ipam}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnSubnetCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnSubnetCmdlet.cs index 7d39508..d44b56b 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnSubnetCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnSubnetCmdlet.cs @@ -27,6 +27,7 @@ namespace PSProxmoxVE.Cmdlets.Network return; var session = GetSession(); + RequireVersion(session, "SDN", 6, 2, 8, 0); using var client = new PveHttpClient(session); WriteVerbose($"Removing SDN subnet '{Subnet}' from VNet '{Vnet}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnVnetCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnVnetCmdlet.cs index 11e08ca..4da0ced 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnVnetCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnVnetCmdlet.cs @@ -22,6 +22,7 @@ namespace PSProxmoxVE.Cmdlets.Network return; var session = GetSession(); + RequireVersion(session, "SDN", 6, 2, 8, 0); using var client = new PveHttpClient(session); WriteVerbose($"Removing SDN VNet '{Vnet}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnZoneCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnZoneCmdlet.cs index 5702eab..232bb40 100644 --- a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnZoneCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnZoneCmdlet.cs @@ -23,6 +23,7 @@ namespace PSProxmoxVE.Cmdlets.Network return; var session = GetSession(); + RequireVersion(session, "SDN", 6, 2, 8, 0); using var client = new PveHttpClient(session); WriteVerbose($"Removing SDN zone '{Zone}'..."); diff --git a/src/PSProxmoxVE/Cmdlets/PveCmdletBase.cs b/src/PSProxmoxVE/Cmdlets/PveCmdletBase.cs index 771b209..d268ac5 100644 --- a/src/PSProxmoxVE/Cmdlets/PveCmdletBase.cs +++ b/src/PSProxmoxVE/Cmdlets/PveCmdletBase.cs @@ -41,6 +41,56 @@ namespace PSProxmoxVE.Cmdlets return session; } + /// + /// Checks the connected PVE server version against a two-tier requirement: + /// + /// Introduced — the API endpoint was added in this version. + /// If the server is older, the cmdlet emits a terminating error because + /// the endpoint does not exist at all. + /// Default (optional) — the feature is installed/enabled by + /// default since this version. If the server is between + /// and , a warning is emitted but the call + /// proceeds, allowing users who manually enabled the feature to succeed. + /// + /// + /// The authenticated PVE session. + /// Human-readable name shown in messages (e.g. "SDN IPAM"). + /// Major version that introduced the API endpoint. + /// Minor version that introduced the API endpoint. + /// Major version where the feature is enabled by default (null to skip warning tier). + /// Minor version where the feature is enabled by default. + protected void RequireVersion( + PveSession session, + string featureName, + int introducedMajor, + int introducedMinor, + int? defaultMajor = null, + int? defaultMinor = null) + { + var version = session.ServerVersion; + if (version == null) return; // version unknown — optimistic, let the call proceed + + // Hard fail: endpoint does not exist + if (!version.IsAtLeast(introducedMajor, introducedMinor)) + { + ThrowTerminatingError(new ErrorRecord( + new PveVersionException(introducedMajor, introducedMinor, version), + "PveVersionTooOld", + ErrorCategory.InvalidOperation, + null)); + return; + } + + // Soft warning: feature exists but may not be enabled by default + if (defaultMajor.HasValue && defaultMinor.HasValue + && !version.IsAtLeast(defaultMajor.Value, defaultMinor.Value)) + { + WriteWarning( + $"{featureName} is available since PVE {introducedMajor}.{introducedMinor} but is not enabled by default until PVE {defaultMajor}.{defaultMinor}. " + + $"Connected server is PVE {version}. The command will proceed, but may fail if the feature is not manually enabled."); + } + } + /// /// Waits for a PVE task to complete, then optionally polls VM status until /// it matches . Used by lifecycle cmdlets diff --git a/src/PSProxmoxVE/Cmdlets/Vms/ImportPveOvaCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/ImportPveOvaCmdlet.cs index 506e77f..a834c66 100644 --- a/src/PSProxmoxVE/Cmdlets/Vms/ImportPveOvaCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Vms/ImportPveOvaCmdlet.cs @@ -137,6 +137,7 @@ namespace PSProxmoxVE.Cmdlets.Vms return; var session = GetSession(); + RequireVersion(session, "VM disk import", 8, 1); var vmService = new VmService(); var taskService = new TaskService(); diff --git a/src/PSProxmoxVE/Cmdlets/Vms/ImportPveVmDiskCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/ImportPveVmDiskCmdlet.cs index 6d2e659..4ad96bb 100644 --- a/src/PSProxmoxVE/Cmdlets/Vms/ImportPveVmDiskCmdlet.cs +++ b/src/PSProxmoxVE/Cmdlets/Vms/ImportPveVmDiskCmdlet.cs @@ -76,6 +76,7 @@ namespace PSProxmoxVE.Cmdlets.Vms return; var session = GetSession(); + RequireVersion(session, "VM disk import", 8, 1); var vmService = new VmService(); WriteVerbose($"Importing disk to VM {VmId} slot {Disk}: {Source} -> {TargetStorage}..."); diff --git a/tests/PSProxmoxVE.Tests/Integration/Integration.Tests.ps1 b/tests/PSProxmoxVE.Tests/Integration/Integration.Tests.ps1 index ca7eb80..08aa5ae 100644 --- a/tests/PSProxmoxVE.Tests/Integration/Integration.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Integration/Integration.Tests.ps1 @@ -826,6 +826,35 @@ Describe 'Integration Tests' -Tag 'Integration' { } } + # ----------------------------------------------------------------------- + Context 'SDN — IPAM, DNS, Controllers' { + It 'Should list SDN IPAM plugins (Get-PveSdnIpam)' { + if (Skip-IfNoTarget) { return } + if ($script:SkipSdn) { Set-ItResult -Skipped -Because $script:SkipSdn; return } + + # PVE always has a built-in 'pve' IPAM plugin + $ipams = Get-PveSdnIpam + $ipams | Should -Not -BeNullOrEmpty + ($ipams | Where-Object { $_.Type -eq 'pve' }) | Should -Not -BeNullOrEmpty + } + + It 'Should list SDN DNS plugins (Get-PveSdnDns)' { + if (Skip-IfNoTarget) { return } + if ($script:SkipSdn) { Set-ItResult -Skipped -Because $script:SkipSdn; return } + + # Zero DNS plugins is acceptable; just verify no throw. + { Get-PveSdnDns -ErrorAction Stop } | Should -Not -Throw + } + + It 'Should list SDN controllers (Get-PveSdnController)' { + if (Skip-IfNoTarget) { return } + if ($script:SkipSdn) { Set-ItResult -Skipped -Because $script:SkipSdn; return } + + # Zero controllers is acceptable; just verify no throw. + { Get-PveSdnController -ErrorAction Stop } | Should -Not -Throw + } + } + # ----------------------------------------------------------------------- Context 'Templates' { It 'Should list templates' {