mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-08-13 07:36:52 +00:00
fix: remediate scan-4 findings F058, F062, F063, F071, F072, F073, F074, F075
F058 (critical): Replace while(true) infinite-loop task polling with TaskService.WaitForTask in 5 container snapshot and storage cmdlets. F073+F047 (high): Migrate net9.0 → net10.0 across both source .csproj files, build.yml, publish.yml, and test helper. F071 (medium): Add Uri.EscapeDataString() to all inline URL path segments in ~16 cmdlets that bypass service classes (D003). F062+F063 (medium): Add ConfirmImpact.High to Restart-PveContainer and Suspend-PveContainer (D006). F075 (medium): Generate markdown help docs for 89 cmdlets that were missing documentation (170 total, up from 81). F072 (low): Remove unused System.Text.Json dependency from Core.csproj. F074 (low): Raise publish smoke-test threshold from 60 to 150. F065 (low): Add .github/ISSUE_TEMPLATE/config.yml. F066 (low): Add CODEOWNERS. Also fix _TestHelper.ps1 net9.0 → net10.0 framework reference. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;net9.0;net48</TargetFrameworks>
|
||||
<TargetFrameworks>netstandard2.0;net10.0;net48</TargetFrameworks>
|
||||
<LangVersion>10.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>PSProxmoxVE.Core</RootNamespace>
|
||||
@@ -18,18 +18,16 @@
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.5" />
|
||||
<PackageReference Include="SharpCompress" Version="0.38.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net48'">
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.5" />
|
||||
<PackageReference Include="SharpCompress" Version="0.38.0" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net10.0'">
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="SharpCompress" Version="0.38.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PSProxmoxVE.Core.Client;
|
||||
@@ -33,7 +34,7 @@ namespace PSProxmoxVE.Cmdlets.CloudInit
|
||||
using var client = new PveHttpClient(session);
|
||||
|
||||
WriteVerbose($"Getting cloud-init config for VM {VmId}...");
|
||||
var json = client.GetAsync($"nodes/{Node}/qemu/{VmId}/config").GetAwaiter().GetResult();
|
||||
var json = client.GetAsync($"nodes/{Uri.EscapeDataString(Node)}/qemu/{VmId}/config").GetAwaiter().GetResult();
|
||||
var root = JObject.Parse(json);
|
||||
var data = root["data"];
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Management.Automation;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PSProxmoxVE.Core.Client;
|
||||
using PSProxmoxVE.Core.Models.Vms;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
@@ -54,7 +55,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
};
|
||||
if (!string.IsNullOrEmpty(Description)) data["description"] = Description!;
|
||||
|
||||
var json = client.PostAsync($"nodes/{Node}/lxc/{VmId}/snapshot", data).GetAwaiter().GetResult();
|
||||
var json = client.PostAsync($"nodes/{Uri.EscapeDataString(Node)}/lxc/{VmId}/snapshot", data).GetAwaiter().GetResult();
|
||||
var root = JObject.Parse(json);
|
||||
var upid = root["data"]?.ToString() ?? string.Empty;
|
||||
|
||||
@@ -62,25 +63,11 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
|
||||
if (Wait.IsPresent && !string.IsNullOrEmpty(upid))
|
||||
{
|
||||
task = WaitForTask(client, Node, upid);
|
||||
var taskService = new TaskService();
|
||||
task = taskService.WaitForTask(session, Node, upid);
|
||||
}
|
||||
|
||||
WriteObject(task);
|
||||
}
|
||||
|
||||
private static PveTask WaitForTask(PveHttpClient client, string node, string upid)
|
||||
{
|
||||
var encodedUpid = Uri.EscapeDataString(upid);
|
||||
var statusResource = $"nodes/{node}/tasks/{encodedUpid}/status";
|
||||
while (true)
|
||||
{
|
||||
System.Threading.Thread.Sleep(2000);
|
||||
var statusJson = client.GetAsync(statusResource).GetAwaiter().GetResult();
|
||||
var statusRoot = JObject.Parse(statusJson);
|
||||
var d = statusRoot["data"];
|
||||
if (d?["status"]?.ToString() == "stopped")
|
||||
return new PveTask { Upid = upid, Node = node, Status = "stopped", ExitStatus = d["exitstatus"]?.ToString() };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Management.Automation;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PSProxmoxVE.Core.Client;
|
||||
using PSProxmoxVE.Core.Models.Vms;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
@@ -46,7 +47,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
WriteVerbose($"Removing snapshot '{Name}' from container {VmId}...");
|
||||
using var client = new PveHttpClient(session);
|
||||
|
||||
var json = client.DeleteAsync($"nodes/{Node}/lxc/{VmId}/snapshot/{Name}").GetAwaiter().GetResult();
|
||||
var json = client.DeleteAsync($"nodes/{Uri.EscapeDataString(Node)}/lxc/{VmId}/snapshot/{Uri.EscapeDataString(Name)}").GetAwaiter().GetResult();
|
||||
var root = JObject.Parse(json);
|
||||
var upid = root["data"]?.ToString() ?? string.Empty;
|
||||
|
||||
@@ -54,25 +55,11 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
|
||||
if (Wait.IsPresent && !string.IsNullOrEmpty(upid))
|
||||
{
|
||||
task = WaitForTask(client, Node, upid);
|
||||
var taskService = new TaskService();
|
||||
task = taskService.WaitForTask(session, Node, upid);
|
||||
}
|
||||
|
||||
WriteObject(task);
|
||||
}
|
||||
|
||||
private static PveTask WaitForTask(PveHttpClient client, string node, string upid)
|
||||
{
|
||||
var encodedUpid = Uri.EscapeDataString(upid);
|
||||
var statusResource = $"nodes/{node}/tasks/{encodedUpid}/status";
|
||||
while (true)
|
||||
{
|
||||
System.Threading.Thread.Sleep(2000);
|
||||
var statusJson = client.GetAsync(statusResource).GetAwaiter().GetResult();
|
||||
var statusRoot = JObject.Parse(statusJson);
|
||||
var d = statusRoot["data"];
|
||||
if (d?["status"]?.ToString() == "stopped")
|
||||
return new PveTask { Upid = upid, Node = node, Status = "stopped", ExitStatus = d["exitstatus"]?.ToString() };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// Use -Wait to block until both tasks complete.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsLifecycle.Restart, "PveContainer", SupportsShouldProcess = true)]
|
||||
[Cmdlet(VerbsLifecycle.Restart, "PveContainer", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
|
||||
[OutputType(typeof(PveTask))]
|
||||
public sealed class RestartPveContainerCmdlet : PveCmdletBase
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Management.Automation;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PSProxmoxVE.Core.Client;
|
||||
using PSProxmoxVE.Core.Models.Vms;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
@@ -49,7 +50,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
WriteVerbose($"Restoring snapshot '{Name}' on container {VmId}...");
|
||||
using var client = new PveHttpClient(session);
|
||||
|
||||
var json = client.PostAsync($"nodes/{Node}/lxc/{VmId}/snapshot/{Name}/rollback").GetAwaiter().GetResult();
|
||||
var json = client.PostAsync($"nodes/{Uri.EscapeDataString(Node)}/lxc/{VmId}/snapshot/{Uri.EscapeDataString(Name)}/rollback").GetAwaiter().GetResult();
|
||||
var root = JObject.Parse(json);
|
||||
var upid = root["data"]?.ToString() ?? string.Empty;
|
||||
|
||||
@@ -57,25 +58,11 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
|
||||
if (Wait.IsPresent && !string.IsNullOrEmpty(upid))
|
||||
{
|
||||
task = WaitForTask(client, Node, upid);
|
||||
var taskService = new TaskService();
|
||||
task = taskService.WaitForTask(session, Node, upid);
|
||||
}
|
||||
|
||||
WriteObject(task);
|
||||
}
|
||||
|
||||
private static PveTask WaitForTask(PveHttpClient client, string node, string upid)
|
||||
{
|
||||
var encodedUpid = Uri.EscapeDataString(upid);
|
||||
var statusResource = $"nodes/{node}/tasks/{encodedUpid}/status";
|
||||
while (true)
|
||||
{
|
||||
System.Threading.Thread.Sleep(2000);
|
||||
var statusJson = client.GetAsync(statusResource).GetAwaiter().GetResult();
|
||||
var statusRoot = JObject.Parse(statusJson);
|
||||
var d = statusRoot["data"];
|
||||
if (d?["status"]?.ToString() == "stopped")
|
||||
return new PveTask { Upid = upid, Node = node, Status = "stopped", ExitStatus = d["exitstatus"]?.ToString() };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// Use -Wait to block until the suspend task completes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsLifecycle.Suspend, "PveContainer", SupportsShouldProcess = true)]
|
||||
[Cmdlet(VerbsLifecycle.Suspend, "PveContainer", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
|
||||
[OutputType(typeof(PveTask))]
|
||||
public sealed class SuspendPveContainerCmdlet : PveCmdletBase
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
using var client = new PveHttpClient(session);
|
||||
|
||||
WriteVerbose($"Getting network interfaces on node '{Node}'...");
|
||||
var resource = $"nodes/{Node}/network";
|
||||
var resource = $"nodes/{Uri.EscapeDataString(Node)}/network";
|
||||
if (!string.IsNullOrEmpty(Type))
|
||||
resource += $"?type={Uri.EscapeDataString(Type)}";
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PSProxmoxVE.Core.Client;
|
||||
@@ -35,7 +36,7 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
using var client = new PveHttpClient(session);
|
||||
|
||||
WriteVerbose($"Applying network configuration on node '{Node}'...");
|
||||
var json = client.PutAsync($"nodes/{Node}/network").GetAwaiter().GetResult();
|
||||
var json = client.PutAsync($"nodes/{Uri.EscapeDataString(Node)}/network").GetAwaiter().GetResult();
|
||||
var root = JObject.Parse(json);
|
||||
var upid = root["data"]?.ToString() ?? string.Empty;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PSProxmoxVE.Core.Client;
|
||||
@@ -90,7 +91,7 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
if (Autostart.IsPresent) data["autostart"] = "1";
|
||||
if (!string.IsNullOrEmpty(Comments)) data["comments"] = Comments!;
|
||||
|
||||
client.PostAsync($"nodes/{Node}/network", data).GetAwaiter().GetResult();
|
||||
client.PostAsync($"nodes/{Uri.EscapeDataString(Node)}/network", data).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using PSProxmoxVE.Core.Client;
|
||||
|
||||
@@ -31,7 +32,7 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
using var client = new PveHttpClient(session);
|
||||
|
||||
WriteVerbose($"Removing network interface '{Iface}' on node '{Node}'...");
|
||||
client.DeleteAsync($"nodes/{Node}/network/{Iface}").GetAwaiter().GetResult();
|
||||
client.DeleteAsync($"nodes/{Uri.EscapeDataString(Node)}/network/{Uri.EscapeDataString(Iface)}").GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PSProxmoxVE.Core.Client;
|
||||
@@ -97,7 +98,7 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
if (Autostart.IsPresent) data["autostart"] = "1";
|
||||
if (!string.IsNullOrEmpty(Comments)) data["comments"] = Comments!;
|
||||
|
||||
client.PutAsync($"nodes/{Node}/network/{Iface}", data).GetAwaiter().GetResult();
|
||||
client.PutAsync($"nodes/{Uri.EscapeDataString(Node)}/network/{Uri.EscapeDataString(Iface)}", data).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,8 +126,8 @@ namespace PSProxmoxVE.Cmdlets
|
||||
// because it returns qmpstatus (needed for paused state detection — PVE reports
|
||||
// status=running but qmpstatus=paused for suspended VMs).
|
||||
var statusResource = isContainer
|
||||
? $"nodes/{node}/lxc/{vmid}/status/current"
|
||||
: $"nodes/{node}/qemu/{vmid}/status/current";
|
||||
? $"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/status/current"
|
||||
: $"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/status/current";
|
||||
|
||||
var deadline = DateTime.UtcNow.AddSeconds(timeoutSeconds);
|
||||
using var pollClient = new PveHttpClient(session);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -59,7 +60,7 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
|
||||
if (!string.IsNullOrEmpty(Description)) data["description"] = Description!;
|
||||
if (IncludeVmState.IsPresent) data["vmstate"] = "1";
|
||||
|
||||
var json = client.PostAsync($"nodes/{Node}/qemu/{VmId}/snapshot", data).GetAwaiter().GetResult();
|
||||
var json = client.PostAsync($"nodes/{Uri.EscapeDataString(Node)}/qemu/{VmId}/snapshot", data).GetAwaiter().GetResult();
|
||||
var root = JObject.Parse(json);
|
||||
var upid = root["data"]?.ToString() ?? string.Empty;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PSProxmoxVE.Core.Client;
|
||||
@@ -46,7 +47,7 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
|
||||
WriteVerbose($"Removing snapshot '{Name}' from VM {VmId}...");
|
||||
using var client = new PveHttpClient(session);
|
||||
|
||||
var json = client.DeleteAsync($"nodes/{Node}/qemu/{VmId}/snapshot/{Name}").GetAwaiter().GetResult();
|
||||
var json = client.DeleteAsync($"nodes/{Uri.EscapeDataString(Node)}/qemu/{VmId}/snapshot/{Uri.EscapeDataString(Name)}").GetAwaiter().GetResult();
|
||||
var root = JObject.Parse(json);
|
||||
var upid = root["data"]?.ToString() ?? string.Empty;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PSProxmoxVE.Core.Client;
|
||||
@@ -49,7 +50,7 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
|
||||
WriteVerbose($"Restoring snapshot '{Name}' on VM {VmId}...");
|
||||
using var client = new PveHttpClient(session);
|
||||
|
||||
var json = client.PostAsync($"nodes/{Node}/qemu/{VmId}/snapshot/{Name}/rollback").GetAwaiter().GetResult();
|
||||
var json = client.PostAsync($"nodes/{Uri.EscapeDataString(Node)}/qemu/{VmId}/snapshot/{Uri.EscapeDataString(Name)}/rollback").GetAwaiter().GetResult();
|
||||
var root = JObject.Parse(json);
|
||||
var upid = root["data"]?.ToString() ?? string.Empty;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Management.Automation;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PSProxmoxVE.Core.Client;
|
||||
using PSProxmoxVE.Core.Models.Vms;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Storage
|
||||
{
|
||||
@@ -53,7 +54,7 @@ namespace PSProxmoxVE.Cmdlets.Storage
|
||||
using var client = new PveHttpClient(session);
|
||||
|
||||
WriteVerbose($"Downloading '{Url}' to {Node}/{Storage}...");
|
||||
var resource = $"nodes/{Node}/storage/{Storage}/download-url";
|
||||
var resource = $"nodes/{Uri.EscapeDataString(Node)}/storage/{Uri.EscapeDataString(Storage)}/download-url";
|
||||
var data = new Dictionary<string, string>
|
||||
{
|
||||
["url"] = Url,
|
||||
@@ -69,37 +70,11 @@ namespace PSProxmoxVE.Cmdlets.Storage
|
||||
|
||||
if (Wait.IsPresent && !string.IsNullOrEmpty(upid))
|
||||
{
|
||||
task = WaitForTask(client, Node, upid);
|
||||
var taskService = new TaskService();
|
||||
task = taskService.WaitForTask(session, Node, upid);
|
||||
}
|
||||
|
||||
WriteObject(task);
|
||||
}
|
||||
|
||||
private static PveTask WaitForTask(PveHttpClient client, string node, string upid)
|
||||
{
|
||||
var encodedUpid = Uri.EscapeDataString(upid);
|
||||
var statusResource = $"nodes/{node}/tasks/{encodedUpid}/status";
|
||||
|
||||
while (true)
|
||||
{
|
||||
System.Threading.Thread.Sleep(2000);
|
||||
var statusJson = client.GetAsync(statusResource).GetAwaiter().GetResult();
|
||||
var statusRoot = JObject.Parse(statusJson);
|
||||
var data = statusRoot["data"];
|
||||
var status = data?["status"]?.ToString();
|
||||
var exitStatus = data?["exitstatus"]?.ToString();
|
||||
|
||||
if (status == "stopped")
|
||||
{
|
||||
return new PveTask
|
||||
{
|
||||
Upid = upid,
|
||||
Node = node,
|
||||
Status = status,
|
||||
ExitStatus = exitStatus
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Management.Automation;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PSProxmoxVE.Core.Client;
|
||||
using PSProxmoxVE.Core.Models.Vms;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Storage
|
||||
{
|
||||
@@ -77,7 +78,7 @@ namespace PSProxmoxVE.Cmdlets.Storage
|
||||
using var client = new PveHttpClient(session);
|
||||
|
||||
WriteVerbose($"Uploading {fileName} to {Node}/{Storage} (content={ContentType})...");
|
||||
var resource = $"nodes/{Node}/storage/{Storage}/upload";
|
||||
var resource = $"nodes/{Uri.EscapeDataString(Node)}/storage/{Uri.EscapeDataString(Storage)}/upload";
|
||||
var totalBytes = new System.IO.FileInfo(Path).Length;
|
||||
|
||||
var activityId = 1;
|
||||
@@ -129,38 +130,12 @@ namespace PSProxmoxVE.Cmdlets.Storage
|
||||
|
||||
if (Wait.IsPresent && !string.IsNullOrEmpty(upid))
|
||||
{
|
||||
task = WaitForTask(client, Node, upid);
|
||||
var taskService = new TaskService();
|
||||
task = taskService.WaitForTask(session, Node, upid);
|
||||
}
|
||||
|
||||
WriteObject(task);
|
||||
}
|
||||
|
||||
private static PveTask WaitForTask(PveHttpClient client, string node, string upid)
|
||||
{
|
||||
var encodedUpid = Uri.EscapeDataString(upid);
|
||||
var statusResource = $"nodes/{node}/tasks/{encodedUpid}/status";
|
||||
|
||||
while (true)
|
||||
{
|
||||
System.Threading.Thread.Sleep(2000);
|
||||
var statusJson = client.GetAsync(statusResource).GetAwaiter().GetResult();
|
||||
var statusRoot = JObject.Parse(statusJson);
|
||||
var data = statusRoot["data"];
|
||||
var status = data?["status"]?.ToString();
|
||||
var exitStatus = data?["exitstatus"]?.ToString();
|
||||
|
||||
if (status == "stopped")
|
||||
{
|
||||
return new PveTask
|
||||
{
|
||||
Upid = upid,
|
||||
Node = node,
|
||||
Status = status,
|
||||
ExitStatus = exitStatus
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Validates that a file path exists on disk.</summary>
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace PSProxmoxVE.Cmdlets.Tasks
|
||||
var deadline = Timeout.HasValue ? DateTime.UtcNow + Timeout.Value : DateTime.MaxValue;
|
||||
|
||||
var encodedUpid = Uri.EscapeDataString(Upid);
|
||||
var statusResource = $"nodes/{Node}/tasks/{encodedUpid}/status";
|
||||
var statusResource = $"nodes/{Uri.EscapeDataString(Node)}/tasks/{encodedUpid}/status";
|
||||
|
||||
// Derive a short human-readable description from the UPID for progress display
|
||||
var taskDesc = Upid.Length > 50 ? Upid.Substring(0, 47) + "..." : Upid;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;net9.0;net48</TargetFrameworks>
|
||||
<TargetFrameworks>netstandard2.0;net10.0;net48</TargetFrameworks>
|
||||
<LangVersion>10.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>PSProxmoxVE</RootNamespace>
|
||||
@@ -18,8 +18,8 @@
|
||||
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
|
||||
<PackageReference Include="System.Management.Automation" Version="7.4.0" PrivateAssets="all" />
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net10.0'">
|
||||
<PackageReference Include="System.Management.Automation" Version="7.5.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user