feat(models): implement typed response models for PVE 8.x and 9.x

Add C# model classes for all PVE API resources: nodes, VMs, VM config,
containers, storage, network interfaces, SDN zones/vnets, users, roles,
permissions, snapshots, tasks, and cluster status. All models use dual
JSON attributes (System.Text.Json + Newtonsoft.Json), nullable optional
fields, and human-readable ToString() overrides.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Clint Branham
2026-03-17 15:45:06 -05:00
parent 2c7e90d185
commit 4ac38f7714
20 changed files with 2085 additions and 0 deletions
@@ -0,0 +1,89 @@
using System.Text.Json.Serialization;
using Newtonsoft.Json;
namespace PSProxmoxVE.Core.Models.Storage;
/// <summary>
/// Represents a Proxmox VE storage entry as returned by the /storage or /nodes/{node}/storage endpoints.
/// </summary>
public class PveStorage
{
/// <summary>
/// The unique identifier / name of the storage pool.
/// </summary>
[JsonPropertyName("storage")]
[JsonProperty("storage")]
public string Storage { get; set; } = string.Empty;
/// <summary>
/// The storage backend type (e.g., "dir", "lvm", "zfspool", "nfs", "cifs", "rbd").
/// </summary>
[JsonPropertyName("type")]
[JsonProperty("type")]
public string? Type { get; set; }
/// <summary>
/// Comma-separated list of content types this storage supports
/// (e.g., "images,rootdir,backup,snippets,iso,vztmpl").
/// </summary>
[JsonPropertyName("content")]
[JsonProperty("content")]
public string? Content { get; set; }
/// <summary>
/// Total capacity of the storage pool, in bytes.
/// </summary>
[JsonPropertyName("total")]
[JsonProperty("total")]
public long? Total { get; set; }
/// <summary>
/// Used capacity of the storage pool, in bytes.
/// </summary>
[JsonPropertyName("used")]
[JsonProperty("used")]
public long? Used { get; set; }
/// <summary>
/// Available (free) capacity of the storage pool, in bytes.
/// </summary>
[JsonPropertyName("avail")]
[JsonProperty("avail")]
public long? Available { get; set; }
/// <summary>
/// Indicates whether the storage is enabled (1) or disabled (0) in the configuration.
/// </summary>
[JsonPropertyName("enabled")]
[JsonProperty("enabled")]
public int? Enabled { get; set; }
/// <summary>
/// Indicates whether the storage is shared across all cluster nodes (1) or node-local (0).
/// </summary>
[JsonPropertyName("shared")]
[JsonProperty("shared")]
public int? Shared { get; set; }
/// <summary>
/// Indicates whether the storage is currently active and reachable (1) or not (0).
/// </summary>
[JsonPropertyName("active")]
[JsonProperty("active")]
public int? Active { get; set; }
/// <summary>The node this storage entry is associated with. Populated by cmdlets after retrieval.</summary>
public string? Node { get; set; }
/// <inheritdoc />
public override string ToString()
{
var usedGb = Used.HasValue ? $"{Used.Value / 1024.0 / 1024 / 1024:F1} GB" : "N/A";
var totalGb = Total.HasValue ? $"{Total.Value / 1024.0 / 1024 / 1024:F1} GB" : "N/A";
var availGb = Available.HasValue ? $"{Available.Value / 1024.0 / 1024 / 1024:F1} GB" : "N/A";
var activeStr = Active is 1 ? "active" : "inactive";
var sharedStr = Shared is 1 ? "shared" : "local";
return $"Storage: {Storage} | Type: {Type ?? "N/A"} | {activeStr} | {sharedStr} | "
+ $"Used: {usedGb}/{totalGb} | Free: {availGb} | Content: {Content ?? "N/A"}";
}
}
@@ -0,0 +1,87 @@
using System;
using System.Text.Json.Serialization;
using Newtonsoft.Json;
namespace PSProxmoxVE.Core.Models.Storage;
/// <summary>
/// Represents a single content item (disk image, backup, ISO, template, etc.)
/// stored within a Proxmox VE storage pool, as returned by
/// the /nodes/{node}/storage/{storage}/content endpoint.
/// </summary>
public class PveStorageContent
{
/// <summary>
/// The full volume identifier in the form "storage:volumename"
/// (e.g., "local-lvm:vm-100-disk-0").
/// </summary>
[JsonPropertyName("volid")]
[JsonProperty("volid")]
public string VolId { get; set; } = string.Empty;
/// <summary>
/// The content type of this volume (e.g., "images", "backup", "iso", "vztmpl", "rootdir").
/// </summary>
[JsonPropertyName("content")]
[JsonProperty("content")]
public string? Content { get; set; }
/// <summary>
/// The disk image format (e.g., "raw", "qcow2", "vmdk", "subvol").
/// </summary>
[JsonPropertyName("format")]
[JsonProperty("format")]
public string? Format { get; set; }
/// <summary>
/// The size of the volume in bytes.
/// </summary>
[JsonPropertyName("size")]
[JsonProperty("size")]
public long? Size { get; set; }
/// <summary>
/// Unix timestamp of when the volume was created.
/// </summary>
[JsonPropertyName("ctime")]
[JsonProperty("ctime")]
public long? CreationTime { get; set; }
/// <summary>
/// The VM or container ID that owns this volume, if applicable (e.g., for disk images and backups).
/// </summary>
[JsonPropertyName("vmid")]
[JsonProperty("vmid")]
public int? VmId { get; set; }
/// <summary>
/// Optional notes or description attached to the volume (commonly used on backup files).
/// </summary>
[JsonPropertyName("notes")]
[JsonProperty("notes")]
public string? Notes { get; set; }
/// <summary>
/// Verification status of the volume, if applicable (e.g., for backups verified with vzdump).
/// </summary>
[JsonPropertyName("verification")]
[JsonProperty("verification")]
public string? Verification { get; set; }
/// <summary>The storage identifier this content resides on. Populated by cmdlets after retrieval.</summary>
public string? Storage { get; set; }
/// <summary>The node this content was retrieved from. Populated by cmdlets after retrieval.</summary>
public string? Node { get; set; }
/// <inheritdoc />
public override string ToString()
{
var sizeGb = Size.HasValue ? $"{Size.Value / 1024.0 / 1024 / 1024:F2} GB" : "N/A";
var created = CreationTime.HasValue
? DateTimeOffset.FromUnixTimeSeconds(CreationTime.Value).ToString("yyyy-MM-dd HH:mm:ss")
: "N/A";
return $"Volume: {VolId} | Content: {Content ?? "N/A"} | Format: {Format ?? "N/A"} | "
+ $"Size: {sizeGb} | Created: {created}";
}
}