mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-08-10 14:26:52 +00:00
fix: remediate findings F045, F047, F048, F064, F070, F071, F076-F079
Phase 1 — Trivial fixes: - F071: Add Uri.EscapeDataString to GetPveTemplateCmdlet node path - F077: Add ValidateRange(100, 999999999) to GetPveTaskListCmdlet.VmId - F076: Create .github/dependabot.yml (nuget + github-actions, weekly) - F079: Fix unit-tests.yml dotnet SDK from 9.0.x to 10.0.x - F048: Mark wont_fix — sync-over-async accepted for PS 5.1 compat Phase 2 — Framework targeting (D009 compliance): - F047: Reduce publishable csproj to netstandard2.0 only, remove all #if NET48/NETSTANDARD2_0 conditionals from PveHttpClient.cs, restructure build.yml for netstandard2.0 publish + net10.0/net48 tests - F064: Resolved by F047 — SMA 7.5.0 ItemGroup removed with net10.0 TFM - F070: Add PS 5.1 smoke-test job to publish.yml (windows-latest) Phase 3 — IPveHttpClient interface extraction (F045): - Extract IPveHttpClient interface from PveHttpClient - Add constructor injection to all 14 service classes - Services use injected client when available, create+dispose when not Phase 4 — Service unit tests (F078): - 196 new xUnit tests across 10 service test files - All services tested via Moq-mocked IPveHttpClient - Total test count: 382 (was 186) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PSProxmoxVE.Core.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstraction over the PVE HTTP client for testability and dependency injection.
|
||||
/// Services accept this interface via constructor injection; tests can mock it.
|
||||
/// </summary>
|
||||
public interface IPveHttpClient : IDisposable
|
||||
{
|
||||
/// <summary>Performs a GET request against the specified API resource path.</summary>
|
||||
Task<string> GetAsync(string resource);
|
||||
|
||||
/// <summary>Performs a POST request against the specified API resource path.</summary>
|
||||
Task<string> PostAsync(string resource, Dictionary<string, string>? data = null);
|
||||
|
||||
/// <summary>Performs a PUT request against the specified API resource path.</summary>
|
||||
Task<string> PutAsync(string resource, Dictionary<string, string>? data = null);
|
||||
|
||||
/// <summary>Performs a DELETE request against the specified API resource path.</summary>
|
||||
Task<string> DeleteAsync(string resource);
|
||||
|
||||
/// <summary>Synchronous wrapper for <see cref="GetAsync"/>.</summary>
|
||||
string Get(string resource);
|
||||
|
||||
/// <summary>Synchronous wrapper for <see cref="PostAsync"/>.</summary>
|
||||
string Post(string resource, Dictionary<string, string>? data = null);
|
||||
|
||||
/// <summary>Synchronous wrapper for <see cref="PutAsync"/>.</summary>
|
||||
string Put(string resource, Dictionary<string, string>? data = null);
|
||||
|
||||
/// <summary>Synchronous wrapper for <see cref="DeleteAsync"/>.</summary>
|
||||
string Delete(string resource);
|
||||
|
||||
/// <summary>
|
||||
/// Uploads a file to a Proxmox VE storage endpoint using MultipartFormDataContent.
|
||||
/// </summary>
|
||||
Task<string> UploadFileAsync(
|
||||
string resource,
|
||||
string filePath,
|
||||
Dictionary<string, string>? formFields = null,
|
||||
string? checksum = null,
|
||||
string? checksumAlgorithm = null,
|
||||
Action<long, long>? progressCallback = null);
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,8 @@ using Newtonsoft.Json.Linq;
|
||||
using PSProxmoxVE.Core.Authentication;
|
||||
using PSProxmoxVE.Core.Exceptions;
|
||||
|
||||
#if NET48 || NETSTANDARD2_0
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
#endif
|
||||
|
||||
namespace PSProxmoxVE.Core.Client
|
||||
{
|
||||
@@ -22,7 +20,7 @@ namespace PSProxmoxVE.Core.Client
|
||||
/// Low-level HTTP client for communicating with the Proxmox VE API.
|
||||
/// Handles authentication headers, error parsing, and the ISO upload workaround.
|
||||
/// </summary>
|
||||
public class PveHttpClient : IDisposable
|
||||
public class PveHttpClient : IPveHttpClient
|
||||
{
|
||||
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type
|
||||
private readonly PveSession? _session;
|
||||
@@ -44,7 +42,6 @@ namespace PSProxmoxVE.Core.Client
|
||||
_session = session ?? throw new ArgumentNullException(nameof(session));
|
||||
_baseUrl = session.BaseUrl;
|
||||
|
||||
#if NET48 || NETSTANDARD2_0
|
||||
var handler = new HttpClientHandler();
|
||||
if (session.SkipCertificateCheck)
|
||||
{
|
||||
@@ -52,21 +49,6 @@ namespace PSProxmoxVE.Core.Client
|
||||
(HttpRequestMessage _, X509Certificate2 _, X509Chain _, SslPolicyErrors _) => true;
|
||||
}
|
||||
_httpClient = new HttpClient(handler);
|
||||
#else
|
||||
if (session.SkipCertificateCheck)
|
||||
{
|
||||
var handler = new HttpClientHandler
|
||||
{
|
||||
ServerCertificateCustomValidationCallback =
|
||||
(_, _, _, _) => true
|
||||
};
|
||||
_httpClient = new HttpClient(handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpClient = new HttpClient();
|
||||
}
|
||||
#endif
|
||||
|
||||
_httpClient.DefaultRequestHeaders.Accept.Add(
|
||||
new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
@@ -84,7 +66,6 @@ namespace PSProxmoxVE.Core.Client
|
||||
_session = null;
|
||||
_baseUrl = $"https://{hostname}:{port}";
|
||||
|
||||
#if NET48 || NETSTANDARD2_0
|
||||
var handler = new HttpClientHandler();
|
||||
if (skipCertificateCheck)
|
||||
{
|
||||
@@ -92,21 +73,6 @@ namespace PSProxmoxVE.Core.Client
|
||||
(HttpRequestMessage _, X509Certificate2 _, X509Chain _, SslPolicyErrors _) => true;
|
||||
}
|
||||
_httpClient = new HttpClient(handler);
|
||||
#else
|
||||
if (skipCertificateCheck)
|
||||
{
|
||||
var handler = new HttpClientHandler
|
||||
{
|
||||
ServerCertificateCustomValidationCallback =
|
||||
(_, _, _, _) => true
|
||||
};
|
||||
_httpClient = new HttpClient(handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpClient = new HttpClient();
|
||||
}
|
||||
#endif
|
||||
|
||||
_httpClient.DefaultRequestHeaders.Accept.Add(
|
||||
new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
@@ -295,11 +261,7 @@ namespace PSProxmoxVE.Core.Client
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if NET48 || NETSTANDARD2_0
|
||||
fileStream.Dispose();
|
||||
#else
|
||||
await fileStream.DisposeAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,12 +359,8 @@ namespace PSProxmoxVE.Core.Client
|
||||
{
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
var bytes = new byte[32];
|
||||
#if NET48 || NETSTANDARD2_0
|
||||
using (var rng = RandomNumberGenerator.Create())
|
||||
rng.GetBytes(bytes);
|
||||
#else
|
||||
RandomNumberGenerator.Fill(bytes);
|
||||
#endif
|
||||
var sb = new StringBuilder(32);
|
||||
for (int i = 0; i < 32; i++)
|
||||
sb.Append(chars[bytes[i] % chars.Length]);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;net10.0;net48</TargetFrameworks>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>10.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>PSProxmoxVE.Core</RootNamespace>
|
||||
@@ -16,18 +16,7 @@
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="SharpCompress" Version="0.38.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net48'">
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="SharpCompress" Version="0.38.0" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net10.0'">
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="SharpCompress" Version="0.38.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -13,6 +13,24 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class BackupService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="BackupService"/> with no injected client.
|
||||
/// Each method will create and dispose its own <see cref="PveHttpClient"/>.
|
||||
/// </summary>
|
||||
public BackupService() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="BackupService"/> with an injected HTTP client.
|
||||
/// The caller owns the client's lifetime; this service will not dispose it.
|
||||
/// </summary>
|
||||
/// <param name="client">The HTTP client to use for all requests.</param>
|
||||
public BackupService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Ad-hoc backup (vzdump)
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -29,10 +47,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/vzdump", config)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/vzdump", config)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -46,10 +71,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("cluster/backup").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveBackupJob[]>() ?? Array.Empty<PveBackupJob>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("cluster/backup").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveBackupJob[]>() ?? Array.Empty<PveBackupJob>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -60,11 +92,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(id)) throw new ArgumentNullException(nameof(id));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"cluster/backup/{Uri.EscapeDataString(id)}")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveBackupJob>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"cluster/backup/{Uri.EscapeDataString(id)}")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveBackupJob>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -75,8 +114,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync("cluster/backup", config).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync("cluster/backup", config).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -88,9 +134,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(id)) throw new ArgumentNullException(nameof(id));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"cluster/backup/{Uri.EscapeDataString(id)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"cluster/backup/{Uri.EscapeDataString(id)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,9 +154,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(id)) throw new ArgumentNullException(nameof(id));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"cluster/backup/{Uri.EscapeDataString(id)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"cluster/backup/{Uri.EscapeDataString(id)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -117,11 +177,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("cluster/backup-info/not-backed-up")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data as JArray ?? new JArray();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("cluster/backup-info/not-backed-up")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data as JArray ?? new JArray();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class CloudInitService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
|
||||
// Cloud-Init field names as used in the PVE API
|
||||
private static readonly string[] CloudInitFields =
|
||||
{
|
||||
@@ -22,6 +24,20 @@ namespace PSProxmoxVE.Core.Services
|
||||
"nameserver", "searchdomain", "cicustom"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CloudInitService"/> class.
|
||||
/// </summary>
|
||||
public CloudInitService() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CloudInitService"/> class with an injected HTTP client.
|
||||
/// </summary>
|
||||
/// <param name="client">The HTTP client to use for API calls. The caller owns its lifetime.</param>
|
||||
public CloudInitService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the Cloud-Init specific configuration fields for a VM.
|
||||
/// Internally fetches the full VM config and extracts the CI fields.
|
||||
@@ -31,21 +47,28 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{node}/qemu/{vmid}/config")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
if (data == null) return new PveCloudInitConfig();
|
||||
|
||||
// Extract only the Cloud-Init fields into a reduced JObject for deserialization
|
||||
var ciObj = new JObject();
|
||||
foreach (var field in CloudInitFields)
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
if (data[field] != null)
|
||||
ciObj[field] = data[field];
|
||||
}
|
||||
var response = client.GetAsync($"nodes/{node}/qemu/{vmid}/config")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
if (data == null) return new PveCloudInitConfig();
|
||||
|
||||
return ciObj.ToObject<PveCloudInitConfig>() ?? new PveCloudInitConfig();
|
||||
// Extract only the Cloud-Init fields into a reduced JObject for deserialization
|
||||
var ciObj = new JObject();
|
||||
foreach (var field in CloudInitFields)
|
||||
{
|
||||
if (data[field] != null)
|
||||
ciObj[field] = data[field];
|
||||
}
|
||||
|
||||
return ciObj.ToObject<PveCloudInitConfig>() ?? new PveCloudInitConfig();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -66,12 +89,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
client.PutAsync($"nodes/{node}/qemu/{vmid}/config", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
client.PutAsync($"nodes/{node}/qemu/{vmid}/config", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -87,13 +117,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
|
||||
// Request a Cloud-Init dump (user-data section) — this causes PVE to rebuild the image
|
||||
var dumpResponse = client.GetAsync($"nodes/{node}/qemu/{vmid}/cloudinit/dump?type=user")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(dumpResponse)["data"];
|
||||
return data?.ToString() ?? string.Empty;
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
// Request a Cloud-Init dump (user-data section) — this causes PVE to rebuild the image
|
||||
var dumpResponse = client.GetAsync($"nodes/{node}/qemu/{vmid}/cloudinit/dump?type=user")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(dumpResponse)["data"];
|
||||
return data?.ToString() ?? string.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,22 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class ClusterService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClusterService"/> class.
|
||||
/// </summary>
|
||||
public ClusterService() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClusterService"/> class with an injected HTTP client.
|
||||
/// </summary>
|
||||
/// <param name="client">The HTTP client to use for API calls. The caller owns its lifetime.</param>
|
||||
public ClusterService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current cluster status. The response is a mixed array of
|
||||
/// "cluster" and "node" type entries.
|
||||
@@ -19,10 +35,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("cluster/status").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveClusterStatus[]>() ?? Array.Empty<PveClusterStatus>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("cluster/status").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveClusterStatus[]>() ?? Array.Empty<PveClusterStatus>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -34,14 +57,21 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var resource = "cluster/resources";
|
||||
if (!string.IsNullOrEmpty(type))
|
||||
resource += $"?type={Uri.EscapeDataString(type!)}";
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var resource = "cluster/resources";
|
||||
if (!string.IsNullOrEmpty(type))
|
||||
resource += $"?type={Uri.EscapeDataString(type!)}";
|
||||
|
||||
var response = client.GetAsync(resource).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveClusterResource[]>() ?? Array.Empty<PveClusterResource>();
|
||||
var response = client.GetAsync(resource).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveClusterResource[]>() ?? Array.Empty<PveClusterResource>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class ContainerService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
private readonly NodeService _nodeService = new NodeService();
|
||||
|
||||
/// <summary>Initializes a new instance that creates its own HTTP clients.</summary>
|
||||
public ContainerService() { }
|
||||
|
||||
/// <summary>Initializes a new instance that uses the supplied HTTP client for all requests.</summary>
|
||||
/// <param name="client">The HTTP client to use. The caller owns its lifetime.</param>
|
||||
public ContainerService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Read operations
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -51,10 +62,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
|
||||
private PveContainer[] GetContainersOnNode(PveSession session, string node)
|
||||
{
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/lxc").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveContainer[]>() ?? Array.Empty<PveContainer>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/lxc").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveContainer[]>() ?? Array.Empty<PveContainer>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -81,11 +99,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/config")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveContainerConfig>() ?? new PveContainerConfig();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/config")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveContainerConfig>() ?? new PveContainerConfig();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -105,12 +130,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
client.PutAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/config", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
client.PutAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/config", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -125,11 +157,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/snapshot")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSnapshot[]>() ?? Array.Empty<PveSnapshot>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/snapshot")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSnapshot[]>() ?? Array.Empty<PveSnapshot>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -153,10 +192,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(description))
|
||||
formData["description"] = description!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/snapshot", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/snapshot", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -172,10 +218,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (string.IsNullOrWhiteSpace(snapname)) throw new ArgumentNullException(nameof(snapname));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.DeleteAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/snapshot/{Uri.EscapeDataString(snapname)}")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.DeleteAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/snapshot/{Uri.EscapeDataString(snapname)}")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -191,10 +244,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (string.IsNullOrWhiteSpace(snapname)) throw new ArgumentNullException(nameof(snapname));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/snapshot/{Uri.EscapeDataString(snapname)}/rollback")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/snapshot/{Uri.EscapeDataString(snapname)}/rollback")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -213,13 +273,20 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Starts a container. Returns the task UPID.</summary>
|
||||
@@ -244,10 +311,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (timeoutSeconds.HasValue)
|
||||
formData["timeout"] = timeoutSeconds.Value.ToString();
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/status/shutdown", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/status/shutdown", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Removes a container. Returns the task UPID.</summary>
|
||||
@@ -261,10 +335,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
var purgeParam = purge ? "?purge=1" : "?purge=0";
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.DeleteAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}{purgeParam}")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.DeleteAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}{purgeParam}")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Clones a container. Returns the task UPID.</summary>
|
||||
@@ -288,10 +369,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(hostname)) formData["hostname"] = hostname!;
|
||||
if (!string.IsNullOrEmpty(targetNode)) formData["target"] = targetNode!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/clone", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/clone", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Migrates a container to another node. Returns the task UPID.</summary>
|
||||
@@ -312,10 +400,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
["online"] = online ? "1" : "0"
|
||||
};
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/migrate", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/migrate", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -350,10 +445,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
["size"] = size
|
||||
};
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PutAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/resize", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PutAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/resize", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -373,10 +475,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
["delete"] = delete ? "1" : "0"
|
||||
};
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/move_volume", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/move_volume", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -391,10 +500,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/template")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/template")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -409,11 +525,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/interfaces")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveContainerInterface[]>() ?? Array.Empty<PveContainerInterface>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/interfaces")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveContainerInterface[]>() ?? Array.Empty<PveContainerInterface>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -425,10 +548,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/status/{action}")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/lxc/{vmid}/status/{action}")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static PveTask ParseTask(string response, string node)
|
||||
|
||||
@@ -13,6 +13,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class FirewallService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
|
||||
/// <summary>Initializes a new instance that creates its own HTTP clients.</summary>
|
||||
public FirewallService() { }
|
||||
|
||||
/// <summary>Initializes a new instance that uses the supplied HTTP client for all requests.</summary>
|
||||
/// <param name="client">The HTTP client to use. The caller owns its lifetime.</param>
|
||||
public FirewallService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Rules
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -25,10 +37,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
var basePath = BuildBasePath(level, node, vmid);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"{basePath}/rules").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallRule[]>() ?? Array.Empty<PveFirewallRule>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"{basePath}/rules").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallRule[]>() ?? Array.Empty<PveFirewallRule>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -41,8 +60,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
var basePath = BuildBasePath(level, node, vmid);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync($"{basePath}/rules", config).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync($"{basePath}/rules", config).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -55,8 +81,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
var basePath = BuildBasePath(level, node, vmid);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"{basePath}/rules/{pos}", config).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"{basePath}/rules/{pos}", config).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,8 +101,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
var basePath = BuildBasePath(level, node, vmid);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"{basePath}/rules/{pos}").GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"{basePath}/rules/{pos}").GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -83,10 +123,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("cluster/firewall/groups").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallGroup[]>() ?? Array.Empty<PveFirewallGroup>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("cluster/firewall/groups").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallGroup[]>() ?? Array.Empty<PveFirewallGroup>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,8 +148,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(comment))
|
||||
formData["comment"] = comment!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync("cluster/firewall/groups", formData).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync("cluster/firewall/groups", formData).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -113,9 +167,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"cluster/firewall/groups/{Uri.EscapeDataString(name)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"cluster/firewall/groups/{Uri.EscapeDataString(name)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -126,11 +187,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(group)) throw new ArgumentNullException(nameof(group));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"cluster/firewall/groups/{Uri.EscapeDataString(group)}")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallRule[]>() ?? Array.Empty<PveFirewallRule>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"cluster/firewall/groups/{Uri.EscapeDataString(group)}")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallRule[]>() ?? Array.Empty<PveFirewallRule>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -142,9 +210,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(group)) throw new ArgumentNullException(nameof(group));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync($"cluster/firewall/groups/{Uri.EscapeDataString(group)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync($"cluster/firewall/groups/{Uri.EscapeDataString(group)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -156,9 +231,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(group)) throw new ArgumentNullException(nameof(group));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"cluster/firewall/groups/{Uri.EscapeDataString(group)}/{pos}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"cluster/firewall/groups/{Uri.EscapeDataString(group)}/{pos}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -169,9 +251,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(group)) throw new ArgumentNullException(nameof(group));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"cluster/firewall/groups/{Uri.EscapeDataString(group)}/{pos}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"cluster/firewall/groups/{Uri.EscapeDataString(group)}/{pos}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -186,10 +275,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
var basePath = BuildBasePath(level, node, vmid);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"{basePath}/aliases").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallAlias[]>() ?? Array.Empty<PveFirewallAlias>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"{basePath}/aliases").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallAlias[]>() ?? Array.Empty<PveFirewallAlias>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -211,8 +307,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(comment))
|
||||
formData["comment"] = comment!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync($"{basePath}/aliases", formData).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync($"{basePath}/aliases", formData).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -231,9 +334,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(comment))
|
||||
formData["comment"] = comment!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"{basePath}/aliases/{Uri.EscapeDataString(name)}", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"{basePath}/aliases/{Uri.EscapeDataString(name)}", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -246,9 +356,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name));
|
||||
var basePath = BuildBasePath(level, node, vmid);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"{basePath}/aliases/{Uri.EscapeDataString(name)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"{basePath}/aliases/{Uri.EscapeDataString(name)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -263,10 +380,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
var basePath = BuildBasePath(level, node, vmid);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"{basePath}/ipset").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallIpSet[]>() ?? Array.Empty<PveFirewallIpSet>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"{basePath}/ipset").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallIpSet[]>() ?? Array.Empty<PveFirewallIpSet>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -283,8 +407,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(comment))
|
||||
formData["comment"] = comment!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync($"{basePath}/ipset", formData).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync($"{basePath}/ipset", formData).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -297,9 +428,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name));
|
||||
var basePath = BuildBasePath(level, node, vmid);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"{basePath}/ipset/{Uri.EscapeDataString(name)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"{basePath}/ipset/{Uri.EscapeDataString(name)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -316,11 +454,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name));
|
||||
var basePath = BuildBasePath(level, node, vmid);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"{basePath}/ipset/{Uri.EscapeDataString(name)}")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallIpSetEntry[]>() ?? Array.Empty<PveFirewallIpSetEntry>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"{basePath}/ipset/{Uri.EscapeDataString(name)}")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallIpSetEntry[]>() ?? Array.Empty<PveFirewallIpSetEntry>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -340,9 +485,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(comment))
|
||||
formData["comment"] = comment!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync($"{basePath}/ipset/{Uri.EscapeDataString(name)}", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync($"{basePath}/ipset/{Uri.EscapeDataString(name)}", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -362,10 +514,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(comment))
|
||||
formData["comment"] = comment!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync(
|
||||
$"{basePath}/ipset/{Uri.EscapeDataString(name)}/{Uri.EscapeDataString(cidr)}",
|
||||
formData).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync(
|
||||
$"{basePath}/ipset/{Uri.EscapeDataString(name)}/{Uri.EscapeDataString(cidr)}",
|
||||
formData).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -379,10 +538,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(cidr)) throw new ArgumentNullException(nameof(cidr));
|
||||
var basePath = BuildBasePath(level, node, vmid);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync(
|
||||
$"{basePath}/ipset/{Uri.EscapeDataString(name)}/{Uri.EscapeDataString(cidr)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync(
|
||||
$"{basePath}/ipset/{Uri.EscapeDataString(name)}/{Uri.EscapeDataString(cidr)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -398,10 +564,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
var basePath = BuildBasePath(level, node, vmid);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"{basePath}/options").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallOptions>() ?? new PveFirewallOptions();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"{basePath}/options").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallOptions>() ?? new PveFirewallOptions();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -414,8 +587,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
var basePath = BuildBasePath(level, node, vmid);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"{basePath}/options", config).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"{basePath}/options", config).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -435,10 +615,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(type))
|
||||
resource += $"?type={Uri.EscapeDataString(type!)}";
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync(resource).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallRef[]>() ?? Array.Empty<PveFirewallRef>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync(resource).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveFirewallRef[]>() ?? Array.Empty<PveFirewallRef>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -15,6 +15,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class NetworkService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
|
||||
/// <summary>Initializes a new instance that creates its own HTTP clients.</summary>
|
||||
public NetworkService() { }
|
||||
|
||||
/// <summary>Initializes a new instance that uses the supplied HTTP client for all requests.</summary>
|
||||
/// <param name="client">The HTTP client to use. The caller owns its lifetime.</param>
|
||||
public NetworkService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Node network interfaces
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -36,10 +48,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(type))
|
||||
resource += $"?type={Uri.EscapeDataString(type!)}";
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync(resource).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveNetwork[]>() ?? Array.Empty<PveNetwork>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync(resource).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveNetwork[]>() ?? Array.Empty<PveNetwork>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -58,14 +77,21 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
var response = client.PostAsync($"nodes/{node}/network", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveNetwork>() ?? new PveNetwork();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
var response = client.PostAsync($"nodes/{node}/network", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveNetwork>() ?? new PveNetwork();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -87,12 +113,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(iface)) throw new ArgumentNullException(nameof(iface));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
client.PutAsync($"nodes/{node}/network/{iface}", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
client.PutAsync($"nodes/{node}/network/{iface}", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -108,8 +141,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (string.IsNullOrWhiteSpace(iface)) throw new ArgumentNullException(nameof(iface));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"nodes/{node}/network/{iface}").GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"nodes/{node}/network/{iface}").GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -122,10 +162,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PutAsync($"nodes/{node}/network")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PutAsync($"nodes/{node}/network")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -140,11 +187,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("cluster/sdn/zones").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnZone[]>() ?? Array.Empty<PveSdnZone>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("cluster/sdn/zones").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnZone[]>() ?? Array.Empty<PveSdnZone>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -155,11 +208,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("cluster/sdn/vnets").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnVnet[]>() ?? Array.Empty<PveSdnVnet>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("cluster/sdn/vnets").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnVnet[]>() ?? Array.Empty<PveSdnVnet>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -172,17 +231,23 @@ namespace PSProxmoxVE.Core.Services
|
||||
Dictionary<string, object> config)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
var response = client.PostAsync("cluster/sdn/zones", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnZone>() ?? new PveSdnZone();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
var response = client.PostAsync("cluster/sdn/zones", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnZone>() ?? new PveSdnZone();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -193,11 +258,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
public void RemoveSdnZone(PveSession session, string zone)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(zone)) throw new ArgumentNullException(nameof(zone));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"cluster/sdn/zones/{zone}").GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"cluster/sdn/zones/{zone}").GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -210,17 +281,23 @@ namespace PSProxmoxVE.Core.Services
|
||||
Dictionary<string, object> config)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
var response = client.PostAsync("cluster/sdn/vnets", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnVnet>() ?? new PveSdnVnet();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
var response = client.PostAsync("cluster/sdn/vnets", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnVnet>() ?? new PveSdnVnet();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -231,11 +308,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
public void RemoveSdnVnet(PveSession session, string vnet)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(vnet)) throw new ArgumentNullException(nameof(vnet));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"cluster/sdn/vnets/{vnet}").GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"cluster/sdn/vnets/{vnet}").GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -250,14 +333,20 @@ namespace PSProxmoxVE.Core.Services
|
||||
public PveSdnSubnet[] GetSdnSubnets(PveSession session, string vnet)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(vnet)) throw new ArgumentNullException(nameof(vnet));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"cluster/sdn/vnets/{Uri.EscapeDataString(vnet)}/subnets")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnSubnet[]>() ?? Array.Empty<PveSdnSubnet>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"cluster/sdn/vnets/{Uri.EscapeDataString(vnet)}/subnets")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnSubnet[]>() ?? Array.Empty<PveSdnSubnet>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -272,16 +361,22 @@ namespace PSProxmoxVE.Core.Services
|
||||
Dictionary<string, object> config)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(vnet)) throw new ArgumentNullException(nameof(vnet));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
client.PostAsync($"cluster/sdn/vnets/{Uri.EscapeDataString(vnet)}/subnets", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
client.PostAsync($"cluster/sdn/vnets/{Uri.EscapeDataString(vnet)}/subnets", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -293,14 +388,20 @@ namespace PSProxmoxVE.Core.Services
|
||||
public void RemoveSdnSubnet(PveSession session, string vnet, string subnet)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(vnet)) throw new ArgumentNullException(nameof(vnet));
|
||||
if (string.IsNullOrWhiteSpace(subnet)) throw new ArgumentNullException(nameof(subnet));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync(
|
||||
$"cluster/sdn/vnets/{Uri.EscapeDataString(vnet)}/subnets/{Uri.EscapeDataString(subnet)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync(
|
||||
$"cluster/sdn/vnets/{Uri.EscapeDataString(vnet)}/subnets/{Uri.EscapeDataString(subnet)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -314,11 +415,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("cluster/sdn/ipams").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnIpam[]>() ?? Array.Empty<PveSdnIpam>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("cluster/sdn/ipams").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnIpam[]>() ?? Array.Empty<PveSdnIpam>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -327,11 +434,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
public void CreateSdnIpam(PveSession session, Dictionary<string, string> config)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync("cluster/sdn/ipams", config).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync("cluster/sdn/ipams", config).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -340,12 +453,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
public void RemoveSdnIpam(PveSession session, string ipam)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ipam)) throw new ArgumentNullException(nameof(ipam));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"cluster/sdn/ipams/{Uri.EscapeDataString(ipam)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"cluster/sdn/ipams/{Uri.EscapeDataString(ipam)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -359,11 +478,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("cluster/sdn/dns").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnDns[]>() ?? Array.Empty<PveSdnDns>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("cluster/sdn/dns").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnDns[]>() ?? Array.Empty<PveSdnDns>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -372,11 +497,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
public void CreateSdnDnsPlugin(PveSession session, Dictionary<string, string> config)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync("cluster/sdn/dns", config).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync("cluster/sdn/dns", config).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -385,12 +516,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
public void RemoveSdnDnsPlugin(PveSession session, string dns)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(dns)) throw new ArgumentNullException(nameof(dns));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"cluster/sdn/dns/{Uri.EscapeDataString(dns)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"cluster/sdn/dns/{Uri.EscapeDataString(dns)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -404,11 +541,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("cluster/sdn/controllers").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnController[]>() ?? Array.Empty<PveSdnController>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("cluster/sdn/controllers").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSdnController[]>() ?? Array.Empty<PveSdnController>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -417,11 +560,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
public void CreateSdnController(PveSession session, Dictionary<string, string> config)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync("cluster/sdn/controllers", config).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync("cluster/sdn/controllers", config).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -430,12 +579,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
public void RemoveSdnController(PveSession session, string controller)
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(controller)) throw new ArgumentNullException(nameof(controller));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"cluster/sdn/controllers/{Uri.EscapeDataString(controller)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"cluster/sdn/controllers/{Uri.EscapeDataString(controller)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -449,9 +604,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync("cluster/sdn", new Dictionary<string, string>())
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync("cluster/sdn", new Dictionary<string, string>())
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -463,9 +625,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(zone)) throw new ArgumentNullException(nameof(zone));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"cluster/sdn/zones/{Uri.EscapeDataString(zone)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"cluster/sdn/zones/{Uri.EscapeDataString(zone)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -477,9 +646,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(vnet)) throw new ArgumentNullException(nameof(vnet));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"cluster/sdn/vnets/{Uri.EscapeDataString(vnet)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"cluster/sdn/vnets/{Uri.EscapeDataString(vnet)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -492,10 +668,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(subnet)) throw new ArgumentNullException(nameof(subnet));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync(
|
||||
$"cluster/sdn/vnets/{Uri.EscapeDataString(vnet)}/subnets/{Uri.EscapeDataString(subnet)}",
|
||||
config).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync(
|
||||
$"cluster/sdn/vnets/{Uri.EscapeDataString(vnet)}/subnets/{Uri.EscapeDataString(subnet)}",
|
||||
config).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -507,9 +690,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(controller)) throw new ArgumentNullException(nameof(controller));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"cluster/sdn/controllers/{Uri.EscapeDataString(controller)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"cluster/sdn/controllers/{Uri.EscapeDataString(controller)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -521,9 +711,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(ipam)) throw new ArgumentNullException(nameof(ipam));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"cluster/sdn/ipams/{Uri.EscapeDataString(ipam)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"cluster/sdn/ipams/{Uri.EscapeDataString(ipam)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -535,9 +732,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(dns)) throw new ArgumentNullException(nameof(dns));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"cluster/sdn/dns/{Uri.EscapeDataString(dns)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"cluster/sdn/dns/{Uri.EscapeDataString(dns)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -14,6 +14,24 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class NodeService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="NodeService"/> with no injected client.
|
||||
/// Each method will create and dispose its own <see cref="PveHttpClient"/>.
|
||||
/// </summary>
|
||||
public NodeService() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="NodeService"/> with an injected HTTP client.
|
||||
/// The caller owns the client's lifetime; this service will not dispose it.
|
||||
/// </summary>
|
||||
/// <param name="client">The HTTP client to use for all requests.</param>
|
||||
public NodeService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all cluster nodes.
|
||||
/// </summary>
|
||||
@@ -21,10 +39,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("nodes").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveNode[]>() ?? Array.Empty<PveNode>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("nodes").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveNode[]>() ?? Array.Empty<PveNode>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -35,10 +60,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{node}/status").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveNodeStatus>() ?? new PveNodeStatus();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{node}/status").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveNodeStatus>() ?? new PveNodeStatus();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -51,10 +83,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{node}/config").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data as JObject ?? new JObject();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{node}/config").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data as JObject ?? new JObject();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -69,8 +108,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"nodes/{node}/config", config).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"nodes/{node}/config", config).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -83,10 +129,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{node}/dns").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data as JObject ?? new JObject();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{node}/dns").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data as JObject ?? new JObject();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,8 +154,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"nodes/{node}/dns", config).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"nodes/{node}/dns", config).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -117,9 +177,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
var formData = config ?? new Dictionary<string, string>();
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{node}/startall", formData).GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{node}/startall", formData).GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -134,9 +201,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
var formData = config ?? new Dictionary<string, string>();
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{node}/stopall", formData).GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{node}/stopall", formData).GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -146,13 +220,20 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("version").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var versionStr = data?["version"]?.ToString();
|
||||
if (string.IsNullOrEmpty(versionStr))
|
||||
throw new InvalidOperationException("Failed to retrieve PVE version from API response.");
|
||||
return PveVersion.Parse(versionStr!);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("version").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var versionStr = data?["version"]?.ToString();
|
||||
if (string.IsNullOrEmpty(versionStr))
|
||||
throw new InvalidOperationException("Failed to retrieve PVE version from API response.");
|
||||
return PveVersion.Parse(versionStr!);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -12,6 +12,24 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class PoolService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="PoolService"/> with no injected client.
|
||||
/// Each method will create and dispose its own <see cref="PveHttpClient"/>.
|
||||
/// </summary>
|
||||
public PoolService() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="PoolService"/> with an injected HTTP client.
|
||||
/// The caller owns the client's lifetime; this service will not dispose it.
|
||||
/// </summary>
|
||||
/// <param name="client">The HTTP client to use for all requests.</param>
|
||||
public PoolService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all resource pools.
|
||||
/// </summary>
|
||||
@@ -19,10 +37,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("pools").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PvePool[]>() ?? Array.Empty<PvePool>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("pools").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PvePool[]>() ?? Array.Empty<PvePool>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -33,11 +58,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(poolId)) throw new ArgumentNullException(nameof(poolId));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"pools/{Uri.EscapeDataString(poolId)}")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PvePool>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"pools/{Uri.EscapeDataString(poolId)}")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PvePool>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -48,12 +80,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(poolId)) throw new ArgumentNullException(nameof(poolId));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var config = new Dictionary<string, string> { { "poolid", poolId } };
|
||||
if (!string.IsNullOrEmpty(comment))
|
||||
config["comment"] = comment!;
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var config = new Dictionary<string, string> { { "poolid", poolId } };
|
||||
if (!string.IsNullOrEmpty(comment))
|
||||
config["comment"] = comment!;
|
||||
|
||||
client.PostAsync("pools", config).GetAwaiter().GetResult();
|
||||
client.PostAsync("pools", config).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -65,9 +104,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(poolId)) throw new ArgumentNullException(nameof(poolId));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"pools/{Uri.EscapeDataString(poolId)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"pools/{Uri.EscapeDataString(poolId)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,9 +124,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(poolId)) throw new ArgumentNullException(nameof(poolId));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"pools/{Uri.EscapeDataString(poolId)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"pools/{Uri.EscapeDataString(poolId)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,22 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class SnapshotService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SnapshotService"/> class.
|
||||
/// </summary>
|
||||
public SnapshotService() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SnapshotService"/> class with an injected HTTP client.
|
||||
/// </summary>
|
||||
/// <param name="client">The HTTP client to use for API calls. The caller owns its lifetime.</param>
|
||||
public SnapshotService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all snapshots for a VM.
|
||||
/// </summary>
|
||||
@@ -24,11 +40,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/snapshot")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSnapshot[]>() ?? Array.Empty<PveSnapshot>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/snapshot")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveSnapshot[]>() ?? Array.Empty<PveSnapshot>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -60,10 +83,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(description))
|
||||
formData["description"] = description!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/snapshot", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/snapshot", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -83,10 +113,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (string.IsNullOrWhiteSpace(snapname)) throw new ArgumentNullException(nameof(snapname));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.DeleteAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/snapshot/{Uri.EscapeDataString(snapname)}")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.DeleteAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/snapshot/{Uri.EscapeDataString(snapname)}")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -106,10 +143,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (string.IsNullOrWhiteSpace(snapname)) throw new ArgumentNullException(nameof(snapname));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/snapshot/{Uri.EscapeDataString(snapname)}/rollback")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/snapshot/{Uri.EscapeDataString(snapname)}/rollback")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -14,6 +14,24 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class StorageService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="StorageService"/> with no injected client.
|
||||
/// Each method will create and dispose its own <see cref="PveHttpClient"/>.
|
||||
/// </summary>
|
||||
public StorageService() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="StorageService"/> with an injected HTTP client.
|
||||
/// The caller owns the client's lifetime; this service will not dispose it.
|
||||
/// </summary>
|
||||
/// <param name="client">The HTTP client to use for all requests.</param>
|
||||
public StorageService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Read operations
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -32,10 +50,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
? $"nodes/{Uri.EscapeDataString(node)}/storage"
|
||||
: "storage";
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync(resource).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveStorage[]>() ?? Array.Empty<PveStorage>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync(resource).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveStorage[]>() ?? Array.Empty<PveStorage>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -61,10 +86,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(contentType))
|
||||
resource += $"?content={Uri.EscapeDataString(contentType!)}";
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync(resource).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveStorageContent[]>() ?? Array.Empty<PveStorageContent>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync(resource).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveStorageContent[]>() ?? Array.Empty<PveStorageContent>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -100,16 +132,23 @@ namespace PSProxmoxVE.Core.Services
|
||||
["content"] = "iso"
|
||||
};
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.UploadFileAsync(
|
||||
$"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/upload",
|
||||
filePath,
|
||||
formFields,
|
||||
checksum,
|
||||
checksumAlgorithm,
|
||||
progressCallback)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.UploadFileAsync(
|
||||
$"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/upload",
|
||||
filePath,
|
||||
formFields,
|
||||
checksum,
|
||||
checksumAlgorithm,
|
||||
progressCallback)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -143,10 +182,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
["content"] = contentType
|
||||
};
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/download-url", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/download-url", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -164,13 +210,20 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
var response = client.PostAsync("storage", formData).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveStorage>() ?? new PveStorage();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
var response = client.PostAsync("storage", formData).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveStorage>() ?? new PveStorage();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -183,8 +236,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(storage)) throw new ArgumentNullException(nameof(storage));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"storage/{Uri.EscapeDataString(storage)}").GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"storage/{Uri.EscapeDataString(storage)}").GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -199,9 +259,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(storage)) throw new ArgumentNullException(nameof(storage));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"storage/{Uri.EscapeDataString(storage)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"storage/{Uri.EscapeDataString(storage)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -220,10 +287,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (string.IsNullOrWhiteSpace(storage)) throw new ArgumentNullException(nameof(storage));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/status").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveStorageStatus>() ?? new PveStorageStatus();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/status").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveStorageStatus>() ?? new PveStorageStatus();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -240,9 +314,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(storage)) throw new ArgumentNullException(nameof(storage));
|
||||
if (string.IsNullOrWhiteSpace(volume)) throw new ArgumentNullException(nameof(volume));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/content/{Uri.EscapeDataString(volume)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/content/{Uri.EscapeDataString(volume)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -261,9 +342,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(volume)) throw new ArgumentNullException(nameof(volume));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/content/{Uri.EscapeDataString(volume)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/content/{Uri.EscapeDataString(volume)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -280,10 +368,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(storage)) throw new ArgumentNullException(nameof(storage));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/content", config)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/content", config)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -14,10 +14,22 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class TaskService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
|
||||
private static readonly TimeSpan DefaultTimeout = TimeSpan.FromMinutes(10);
|
||||
private static readonly TimeSpan DefaultPollInterval = TimeSpan.FromSeconds(2);
|
||||
private static readonly TimeSpan MinPollInterval = TimeSpan.FromSeconds(1);
|
||||
|
||||
/// <summary>Initializes a new instance that creates its own HTTP clients.</summary>
|
||||
public TaskService() { }
|
||||
|
||||
/// <summary>Initializes a new instance that uses the supplied HTTP client for all requests.</summary>
|
||||
/// <param name="client">The HTTP client to use. The caller owns its lifetime.</param>
|
||||
public TaskService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current status of a task identified by its UPID.
|
||||
/// </summary>
|
||||
@@ -27,14 +39,21 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (string.IsNullOrWhiteSpace(upid)) throw new ArgumentNullException(nameof(upid));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var encodedUpid = Uri.EscapeDataString(upid);
|
||||
var response = client.GetAsync($"nodes/{node}/tasks/{encodedUpid}/status")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var task = data?.ToObject<PveTask>() ?? new PveTask { Upid = upid };
|
||||
task.Node = node;
|
||||
return task;
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var encodedUpid = Uri.EscapeDataString(upid);
|
||||
var response = client.GetAsync($"nodes/{node}/tasks/{encodedUpid}/status")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var task = data?.ToObject<PveTask>() ?? new PveTask { Upid = upid };
|
||||
task.Node = node;
|
||||
return task;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -46,12 +65,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (string.IsNullOrWhiteSpace(upid)) throw new ArgumentNullException(nameof(upid));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var encodedUpid = Uri.EscapeDataString(upid);
|
||||
var response = client.GetAsync($"nodes/{node}/tasks/{encodedUpid}/log")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveTaskLog[]>() ?? Array.Empty<PveTaskLog>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var encodedUpid = Uri.EscapeDataString(upid);
|
||||
var response = client.GetAsync($"nodes/{node}/tasks/{encodedUpid}/log")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveTaskLog[]>() ?? Array.Empty<PveTaskLog>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -119,23 +145,30 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var queryParts = new List<string> { $"limit={limit}" };
|
||||
if (vmid.HasValue)
|
||||
queryParts.Add($"vmid={vmid.Value}");
|
||||
if (!string.IsNullOrEmpty(source))
|
||||
queryParts.Add($"source={Uri.EscapeDataString(source!)}");
|
||||
if (!string.IsNullOrEmpty(typeFilter))
|
||||
queryParts.Add($"typefilter={Uri.EscapeDataString(typeFilter!)}");
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var queryParts = new List<string> { $"limit={limit}" };
|
||||
if (vmid.HasValue)
|
||||
queryParts.Add($"vmid={vmid.Value}");
|
||||
if (!string.IsNullOrEmpty(source))
|
||||
queryParts.Add($"source={Uri.EscapeDataString(source!)}");
|
||||
if (!string.IsNullOrEmpty(typeFilter))
|
||||
queryParts.Add($"typefilter={Uri.EscapeDataString(typeFilter!)}");
|
||||
|
||||
var query = string.Join("&", queryParts);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/tasks?{query}")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var tasks = data?.ToObject<PveTask[]>() ?? Array.Empty<PveTask>();
|
||||
foreach (var t in tasks)
|
||||
t.Node ??= node;
|
||||
return tasks;
|
||||
var query = string.Join("&", queryParts);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/tasks?{query}")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var tasks = data?.ToObject<PveTask[]>() ?? Array.Empty<PveTask>();
|
||||
foreach (var t in tasks)
|
||||
t.Node ??= node;
|
||||
return tasks;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -150,10 +183,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (string.IsNullOrWhiteSpace(upid)) throw new ArgumentNullException(nameof(upid));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var encodedUpid = Uri.EscapeDataString(upid);
|
||||
client.DeleteAsync($"nodes/{Uri.EscapeDataString(node)}/tasks/{encodedUpid}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var encodedUpid = Uri.EscapeDataString(upid);
|
||||
client.DeleteAsync($"nodes/{Uri.EscapeDataString(node)}/tasks/{encodedUpid}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,23 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class TemplateService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
private readonly VmService _vmService = new VmService();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TemplateService"/> class.
|
||||
/// </summary>
|
||||
public TemplateService() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TemplateService"/> class with an injected HTTP client.
|
||||
/// </summary>
|
||||
/// <param name="client">The HTTP client to use for API calls. The caller owns its lifetime.</param>
|
||||
public TemplateService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all VM templates. If <paramref name="node"/> is null, searches all cluster nodes.
|
||||
/// </summary>
|
||||
@@ -43,10 +58,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{node}/qemu/{vmid}/template")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{node}/qemu/{vmid}/template")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -13,6 +13,24 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class UserService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="UserService"/> with no injected client.
|
||||
/// Each method will create and dispose its own <see cref="PveHttpClient"/>.
|
||||
/// </summary>
|
||||
public UserService() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="UserService"/> with an injected HTTP client.
|
||||
/// The caller owns the client's lifetime; this service will not dispose it.
|
||||
/// </summary>
|
||||
/// <param name="client">The HTTP client to use for all requests.</param>
|
||||
public UserService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Users
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -23,10 +41,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("access/users").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveUser[]>() ?? Array.Empty<PveUser>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("access/users").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveUser[]>() ?? Array.Empty<PveUser>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Returns a single user by their user ID (e.g. "admin@pam").</summary>
|
||||
@@ -37,15 +62,22 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(userId)) throw new ArgumentNullException(nameof(userId));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var encodedId = Uri.EscapeDataString(userId);
|
||||
var response = client.GetAsync($"access/users/{encodedId}").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var user = data?.ToObject<PveUser>() ?? new PveUser();
|
||||
// The single-user endpoint may not echo back the userid
|
||||
if (string.IsNullOrEmpty(user.UserId))
|
||||
user.UserId = userId;
|
||||
return user;
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var encodedId = Uri.EscapeDataString(userId);
|
||||
var response = client.GetAsync($"access/users/{encodedId}").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var user = data?.ToObject<PveUser>() ?? new PveUser();
|
||||
// The single-user endpoint may not echo back the userid
|
||||
if (string.IsNullOrEmpty(user.UserId))
|
||||
user.UserId = userId;
|
||||
return user;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -69,8 +101,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
formData[kvp.Key] = kvp.Value?.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync("access/users", formData).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync("access/users", formData).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Removes a user account.</summary>
|
||||
@@ -81,9 +120,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(userId)) throw new ArgumentNullException(nameof(userId));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var encodedId = Uri.EscapeDataString(userId);
|
||||
client.DeleteAsync($"access/users/{encodedId}").GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var encodedId = Uri.EscapeDataString(userId);
|
||||
client.DeleteAsync($"access/users/{encodedId}").GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Updates one or more properties of an existing user.</summary>
|
||||
@@ -99,12 +145,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(userId)) throw new ArgumentNullException(nameof(userId));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var encodedId = Uri.EscapeDataString(userId);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
client.PutAsync($"access/users/{encodedId}", formData).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var encodedId = Uri.EscapeDataString(userId);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
client.PutAsync($"access/users/{encodedId}", formData).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -119,14 +172,21 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(userId)) throw new ArgumentNullException(nameof(userId));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var encodedId = Uri.EscapeDataString(userId);
|
||||
var response = client.GetAsync($"access/users/{encodedId}/token").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var tokens = data?.ToObject<PveApiToken[]>() ?? Array.Empty<PveApiToken>();
|
||||
foreach (var t in tokens)
|
||||
t.UserId = userId;
|
||||
return tokens;
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var encodedId = Uri.EscapeDataString(userId);
|
||||
var response = client.GetAsync($"access/users/{encodedId}/token").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var tokens = data?.ToObject<PveApiToken[]>() ?? Array.Empty<PveApiToken>();
|
||||
foreach (var t in tokens)
|
||||
t.UserId = userId;
|
||||
return tokens;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -158,18 +218,25 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (expire.HasValue) formData["expire"] = expire.Value.ToString();
|
||||
if (privilegeSeparation.HasValue) formData["privsep"] = privilegeSeparation.Value ? "1" : "0";
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var encodedUser = Uri.EscapeDataString(userId);
|
||||
var encodedToken = Uri.EscapeDataString(tokenId);
|
||||
var response = client.PostAsync(
|
||||
$"access/users/{encodedUser}/token/{encodedToken}", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var encodedUser = Uri.EscapeDataString(userId);
|
||||
var encodedToken = Uri.EscapeDataString(tokenId);
|
||||
var response = client.PostAsync(
|
||||
$"access/users/{encodedUser}/token/{encodedToken}", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var token = data?.ToObject<PveApiToken>() ?? new PveApiToken();
|
||||
token.UserId = userId;
|
||||
token.TokenId = tokenId;
|
||||
return token;
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var token = data?.ToObject<PveApiToken>() ?? new PveApiToken();
|
||||
token.UserId = userId;
|
||||
token.TokenId = tokenId;
|
||||
return token;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Removes an API token.</summary>
|
||||
@@ -182,11 +249,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(userId)) throw new ArgumentNullException(nameof(userId));
|
||||
if (string.IsNullOrWhiteSpace(tokenId)) throw new ArgumentNullException(nameof(tokenId));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var encodedUser = Uri.EscapeDataString(userId);
|
||||
var encodedToken = Uri.EscapeDataString(tokenId);
|
||||
client.DeleteAsync($"access/users/{encodedUser}/token/{encodedToken}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var encodedUser = Uri.EscapeDataString(userId);
|
||||
var encodedToken = Uri.EscapeDataString(tokenId);
|
||||
client.DeleteAsync($"access/users/{encodedUser}/token/{encodedToken}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -199,11 +273,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(tokenId)) throw new ArgumentNullException(nameof(tokenId));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var encodedUser = Uri.EscapeDataString(userId);
|
||||
var encodedToken = Uri.EscapeDataString(tokenId);
|
||||
client.PutAsync($"access/users/{encodedUser}/token/{encodedToken}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var encodedUser = Uri.EscapeDataString(userId);
|
||||
var encodedToken = Uri.EscapeDataString(tokenId);
|
||||
client.PutAsync($"access/users/{encodedUser}/token/{encodedToken}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -216,10 +297,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("access/roles").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveRole[]>() ?? Array.Empty<PveRole>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("access/roles").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveRole[]>() ?? Array.Empty<PveRole>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates a new role.</summary>
|
||||
@@ -235,8 +323,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(privileges))
|
||||
formData["privs"] = privileges!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync("access/roles", formData).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync("access/roles", formData).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Removes a role.</summary>
|
||||
@@ -247,9 +342,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(roleId)) throw new ArgumentNullException(nameof(roleId));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"access/roles/{Uri.EscapeDataString(roleId)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"access/roles/{Uri.EscapeDataString(roleId)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -265,9 +367,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(privileges)) throw new ArgumentNullException(nameof(privileges));
|
||||
|
||||
var formData = new Dictionary<string, string> { ["privs"] = privileges };
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"access/roles/{Uri.EscapeDataString(roleId)}", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"access/roles/{Uri.EscapeDataString(roleId)}", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -280,10 +389,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("access/groups").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveGroup[]>() ?? Array.Empty<PveGroup>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("access/groups").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveGroup[]>() ?? Array.Empty<PveGroup>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates a new group.</summary>
|
||||
@@ -299,8 +415,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(comment))
|
||||
formData["comment"] = comment!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync("access/groups", formData).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync("access/groups", formData).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Updates a group's properties.</summary>
|
||||
@@ -313,9 +436,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(groupId)) throw new ArgumentNullException(nameof(groupId));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"access/groups/{Uri.EscapeDataString(groupId)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"access/groups/{Uri.EscapeDataString(groupId)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Removes a group.</summary>
|
||||
@@ -326,9 +456,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(groupId)) throw new ArgumentNullException(nameof(groupId));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"access/groups/{Uri.EscapeDataString(groupId)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"access/groups/{Uri.EscapeDataString(groupId)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -341,10 +478,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync("access/domains").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveDomain[]>() ?? Array.Empty<PveDomain>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync("access/domains").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveDomain[]>() ?? Array.Empty<PveDomain>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates a new authentication domain/realm.</summary>
|
||||
@@ -355,8 +499,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync("access/domains", config).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync("access/domains", config).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Updates an authentication domain/realm.</summary>
|
||||
@@ -369,9 +520,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(realm)) throw new ArgumentNullException(nameof(realm));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"access/domains/{Uri.EscapeDataString(realm)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"access/domains/{Uri.EscapeDataString(realm)}", config)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Removes an authentication domain/realm.</summary>
|
||||
@@ -382,9 +540,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(realm)) throw new ArgumentNullException(nameof(realm));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.DeleteAsync($"access/domains/{Uri.EscapeDataString(realm)}")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.DeleteAsync($"access/domains/{Uri.EscapeDataString(realm)}")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -407,8 +572,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
["password"] = password
|
||||
};
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync("access/password", formData).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync("access/password", formData).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -437,22 +609,29 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (queryParts.Count > 0)
|
||||
resource += "?" + string.Join("&", queryParts);
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync(resource).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
// /access/permissions returns an object keyed by path, not an array
|
||||
if (data == null) return Array.Empty<PvePermission>();
|
||||
if (data.Type == JTokenType.Array)
|
||||
return data.ToObject<PvePermission[]>() ?? Array.Empty<PvePermission>();
|
||||
|
||||
// Unwrap path-keyed object into flat list
|
||||
var result = new List<PvePermission>();
|
||||
foreach (var prop in ((JObject)data).Properties())
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var perm = new PvePermission { Path = prop.Name };
|
||||
result.Add(perm);
|
||||
var response = client.GetAsync(resource).GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
// /access/permissions returns an object keyed by path, not an array
|
||||
if (data == null) return Array.Empty<PvePermission>();
|
||||
if (data.Type == JTokenType.Array)
|
||||
return data.ToObject<PvePermission[]>() ?? Array.Empty<PvePermission>();
|
||||
|
||||
// Unwrap path-keyed object into flat list
|
||||
var result = new List<PvePermission>();
|
||||
foreach (var prop in ((JObject)data).Properties())
|
||||
{
|
||||
var perm = new PvePermission { Path = prop.Name };
|
||||
result.Add(perm);
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -488,8 +667,15 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(users)) formData["users"] = users!;
|
||||
if (!string.IsNullOrEmpty(groups)) formData["groups"] = groups!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync("access/acl", formData).GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync("access/acl", formData).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
/// </summary>
|
||||
public class VmService
|
||||
{
|
||||
private readonly IPveHttpClient? _injectedClient;
|
||||
private readonly NodeService _nodeService = new NodeService();
|
||||
|
||||
/// <summary>Initializes a new instance that creates its own HTTP clients.</summary>
|
||||
public VmService() { }
|
||||
|
||||
/// <summary>Initializes a new instance that uses the supplied HTTP client for all requests.</summary>
|
||||
/// <param name="client">The HTTP client to use. The caller owns its lifetime.</param>
|
||||
public VmService(IPveHttpClient client)
|
||||
{
|
||||
_injectedClient = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Read operations
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -55,10 +66,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
|
||||
private PveVm[] GetVmsOnNode(PveSession session, string node)
|
||||
{
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveVm[]>() ?? Array.Empty<PveVm>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu").GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveVm[]>() ?? Array.Empty<PveVm>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -93,19 +111,26 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (vm == null) throw new ArgumentNullException(nameof(vm));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vm.VmId}/status/current")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
if (data == null) return;
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vm.VmId}/status/current")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
if (data == null) return;
|
||||
|
||||
vm.QmpStatus = data["qmpstatus"]?.ToString();
|
||||
vm.Status = data["status"]?.ToString() ?? vm.Status;
|
||||
vm.Pid = data["pid"]?.ToObject<int?>();
|
||||
vm.Uptime = data["uptime"]?.ToObject<long?>();
|
||||
vm.CpuCount = data["cpus"]?.ToObject<int?>() ?? vm.CpuCount;
|
||||
vm.MaxMem = data["maxmem"]?.ToObject<long?>() ?? vm.MaxMem;
|
||||
vm.MaxDisk = data["maxdisk"]?.ToObject<long?>() ?? vm.MaxDisk;
|
||||
vm.QmpStatus = data["qmpstatus"]?.ToString();
|
||||
vm.Status = data["status"]?.ToString() ?? vm.Status;
|
||||
vm.Pid = data["pid"]?.ToObject<int?>();
|
||||
vm.Uptime = data["uptime"]?.ToObject<long?>();
|
||||
vm.CpuCount = data["cpus"]?.ToObject<int?>() ?? vm.CpuCount;
|
||||
vm.MaxMem = data["maxmem"]?.ToObject<long?>() ?? vm.MaxMem;
|
||||
vm.MaxDisk = data["maxdisk"]?.ToObject<long?>() ?? vm.MaxDisk;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -119,11 +144,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/config")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveVmConfig>() ?? new PveVmConfig();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/config")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?.ToObject<PveVmConfig>() ?? new PveVmConfig();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -143,12 +175,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
client.PutAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/config", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
client.PutAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/config", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -199,11 +238,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
[disk] = diskValue
|
||||
};
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
// POST (not PUT) because import-from triggers a background task
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/config", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
// POST (not PUT) because import-from triggers a background task
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/config", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -222,13 +268,20 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var formData = config.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Starts a VM. Returns the task UPID.</summary>
|
||||
@@ -259,10 +312,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (timeoutSeconds.HasValue)
|
||||
formData["timeout"] = timeoutSeconds.Value.ToString();
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/status/shutdown", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/status/shutdown", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Resets a VM (hard reset). Returns the task UPID.</summary>
|
||||
@@ -303,10 +363,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
var purgeParam = purge ? "?purge=1" : "?purge=0";
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.DeleteAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}{purgeParam}")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.DeleteAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}{purgeParam}")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -339,10 +406,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(name)) formData["name"] = name!;
|
||||
if (!string.IsNullOrEmpty(targetNode)) formData["target"] = targetNode!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/clone", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/clone", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -370,10 +444,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
["online"] = online ? "1" : "0"
|
||||
};
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/migrate", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/migrate", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -404,10 +485,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
["size"] = size
|
||||
};
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PutAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/resize", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PutAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/resize", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -419,10 +507,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/status/{action}")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/status/{action}")
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static PveTask ParseTask(string response, string node)
|
||||
@@ -449,7 +544,7 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/ping").GetAwaiter().GetResult();
|
||||
@@ -459,6 +554,10 @@ namespace PSProxmoxVE.Core.Services
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -469,12 +568,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/network-get-interfaces")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var result = data?["result"];
|
||||
return result?.ToObject<PveGuestNetworkInterface[]>() ?? Array.Empty<PveGuestNetworkInterface>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/network-get-interfaces")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var result = data?["result"];
|
||||
return result?.ToObject<PveGuestNetworkInterface[]>() ?? Array.Empty<PveGuestNetworkInterface>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -488,23 +594,30 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (string.IsNullOrWhiteSpace(command)) throw new ArgumentNullException(nameof(command));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var data = new Dictionary<string, string>
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
["command"] = command
|
||||
};
|
||||
var data = new Dictionary<string, string>
|
||||
{
|
||||
["command"] = command
|
||||
};
|
||||
|
||||
if (args != null && args.Length > 0)
|
||||
{
|
||||
// PVE expects input-data for arguments passed as a JSON-encoded string array
|
||||
var argsJson = Newtonsoft.Json.JsonConvert.SerializeObject(args);
|
||||
data["input-data"] = argsJson;
|
||||
if (args != null && args.Length > 0)
|
||||
{
|
||||
// PVE expects input-data for arguments passed as a JSON-encoded string array
|
||||
var argsJson = Newtonsoft.Json.JsonConvert.SerializeObject(args);
|
||||
data["input-data"] = argsJson;
|
||||
}
|
||||
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/exec", data)
|
||||
.GetAwaiter().GetResult();
|
||||
var pid = JObject.Parse(response)["data"]?["pid"]?.ToObject<int>() ?? 0;
|
||||
return pid;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/exec", data)
|
||||
.GetAwaiter().GetResult();
|
||||
var pid = JObject.Parse(response)["data"]?["pid"]?.ToObject<int>() ?? 0;
|
||||
return pid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -515,10 +628,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/exec-status?pid={pid}")
|
||||
.GetAwaiter().GetResult();
|
||||
return JObject.Parse(response)["data"] as JObject ?? new JObject();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/exec-status?pid={pid}")
|
||||
.GetAwaiter().GetResult();
|
||||
return JObject.Parse(response)["data"] as JObject ?? new JObject();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -544,10 +664,17 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (!string.IsNullOrEmpty(format))
|
||||
formData["format"] = format!;
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/move_disk", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/move_disk", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
return ParseTask(response, node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -566,9 +693,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (force)
|
||||
formData["force"] = "1";
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PutAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/unlink", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PutAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/unlink", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -583,12 +717,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/get-osinfo")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var result = data?["result"];
|
||||
return result?.ToObject<PveGuestOsInfo>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/get-osinfo")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var result = data?["result"];
|
||||
return result?.ToObject<PveGuestOsInfo>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -599,12 +740,19 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/get-fsinfo")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var result = data?["result"];
|
||||
return result?.ToObject<PveGuestFsInfo[]>() ?? Array.Empty<PveGuestFsInfo>();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/get-fsinfo")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
var result = data?["result"];
|
||||
return result?.ToObject<PveGuestFsInfo[]>() ?? Array.Empty<PveGuestFsInfo>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -616,11 +764,18 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
if (string.IsNullOrWhiteSpace(file)) throw new ArgumentNullException(nameof(file));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/file-read?file={Uri.EscapeDataString(file)}")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?["content"]?.ToString() ?? string.Empty;
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/file-read?file={Uri.EscapeDataString(file)}")
|
||||
.GetAwaiter().GetResult();
|
||||
var data = JObject.Parse(response)["data"];
|
||||
return data?["content"]?.ToString() ?? string.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -638,9 +793,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
["content"] = content
|
||||
};
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/file-write", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/file-write", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -660,9 +822,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (crypted)
|
||||
formData["crypted"] = "1";
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/set-user-password", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/set-user-password", formData)
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -673,9 +842,16 @@ namespace PSProxmoxVE.Core.Services
|
||||
if (session == null) throw new ArgumentNullException(nameof(session));
|
||||
if (string.IsNullOrWhiteSpace(node)) throw new ArgumentNullException(nameof(node));
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/fstrim")
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
client.PostAsync($"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/agent/fstrim")
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -710,17 +886,24 @@ namespace PSProxmoxVE.Core.Services
|
||||
["content"] = "import"
|
||||
};
|
||||
|
||||
using var client = new PveHttpClient(session);
|
||||
var response = client.UploadFileAsync(
|
||||
$"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/upload",
|
||||
ovaPath,
|
||||
formFields,
|
||||
progressCallback: progressCallback)
|
||||
.GetAwaiter().GetResult();
|
||||
IPveHttpClient client = _injectedClient ?? new PveHttpClient(session);
|
||||
try
|
||||
{
|
||||
var response = client.UploadFileAsync(
|
||||
$"nodes/{Uri.EscapeDataString(node)}/storage/{Uri.EscapeDataString(storage)}/upload",
|
||||
ovaPath,
|
||||
formFields,
|
||||
progressCallback: progressCallback)
|
||||
.GetAwaiter().GetResult();
|
||||
|
||||
var root = JObject.Parse(response);
|
||||
var upid = root["data"]?.ToString() ?? string.Empty;
|
||||
return new PveTask { Upid = upid, Node = node, Status = "running" };
|
||||
var root = JObject.Parse(response);
|
||||
var upid = root["data"]?.ToString() ?? string.Empty;
|
||||
return new PveTask { Upid = upid, Node = node, Status = "running" };
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_injectedClient == null) client.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace PSProxmoxVE.Cmdlets.Tasks
|
||||
/// <para type="description">Filter tasks by VM ID.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false, HelpMessage = "Filter tasks by VM ID.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int? VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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.Templates
|
||||
{
|
||||
if (string.IsNullOrEmpty(node)) continue;
|
||||
|
||||
var json = client.GetAsync($"nodes/{node}/qemu").GetAwaiter().GetResult();
|
||||
var json = client.GetAsync($"nodes/{Uri.EscapeDataString(node)}/qemu").GetAwaiter().GetResult();
|
||||
var root = JObject.Parse(json);
|
||||
var data = root["data"] as JArray ?? new JArray();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;net10.0;net48</TargetFrameworks>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>10.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>PSProxmoxVE</RootNamespace>
|
||||
@@ -12,16 +12,9 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PSProxmoxVE.Core\PSProxmoxVE.Core.csproj" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0' Or '$(TargetFramework)' == 'net48'">
|
||||
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net10.0'">
|
||||
<PackageReference Include="System.Management.Automation" Version="7.5.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="PSProxmoxVE.psd1" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Include="PSProxmoxVE.format.ps1xml" CopyToOutputDirectory="PreserveNewest" />
|
||||
|
||||
Reference in New Issue
Block a user