mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-07-26 07:58:14 +00:00
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:
@@ -0,0 +1,69 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Cluster;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a node entry within the cluster status response,
|
||||
/// as returned by the /cluster/status endpoint when the item type is "node".
|
||||
/// </summary>
|
||||
public class PveClusterNode
|
||||
{
|
||||
/// <summary>
|
||||
/// The node name (e.g., "pve", "pve2").
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this node is currently online (1) or offline (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("online")]
|
||||
[JsonProperty("online")]
|
||||
public int? Online { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this is the local node making the request (1) or a remote node (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("local")]
|
||||
[JsonProperty("local")]
|
||||
public int? Local { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The numeric node ID within the cluster Corosync configuration.
|
||||
/// </summary>
|
||||
[JsonPropertyName("nodeid")]
|
||||
[JsonProperty("nodeid")]
|
||||
public int? NodeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IP address used for cluster communication on this node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ip")]
|
||||
[JsonProperty("ip")]
|
||||
public string? Ip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The cluster membership level of this node (e.g., "c" for configured member).
|
||||
/// </summary>
|
||||
[JsonPropertyName("level")]
|
||||
[JsonProperty("level")]
|
||||
public string? Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The item type as returned by the cluster status endpoint (always "node" for this model).
|
||||
/// </summary>
|
||||
[JsonPropertyName("type")]
|
||||
[JsonProperty("type")]
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var onlineStr = Online is 1 ? "online" : "offline";
|
||||
var localStr = Local is 1 ? " [local]" : string.Empty;
|
||||
return $"Node: {Name}{localStr} | ID: {NodeId?.ToString() ?? "N/A"} | "
|
||||
+ $"IP: {Ip ?? "N/A"} | {onlineStr}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Cluster;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an entry in the mixed array returned by the /cluster/status endpoint.
|
||||
/// Each entry has a Type of either "cluster" (cluster-wide info) or "node" (per-node info).
|
||||
/// Filter by <see cref="Type"/> to distinguish cluster vs. node entries.
|
||||
/// </summary>
|
||||
public class PveClusterStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry type: "cluster" for the cluster-wide record, or "node" for a node record.
|
||||
/// </summary>
|
||||
[JsonPropertyName("type")]
|
||||
[JsonProperty("type")]
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the cluster (present when Type == "cluster") or the node name (when Type == "node").
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
[JsonProperty("name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The total number of nodes in the cluster. Only present when Type == "cluster".
|
||||
/// </summary>
|
||||
[JsonPropertyName("nodes")]
|
||||
[JsonProperty("nodes")]
|
||||
public int? Nodes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the cluster currently has quorum (1) or not (0).
|
||||
/// Without quorum, most write operations are blocked to maintain data consistency.
|
||||
/// Only present when Type == "cluster".
|
||||
/// </summary>
|
||||
[JsonPropertyName("quorate")]
|
||||
[JsonProperty("quorate")]
|
||||
public int? Quorate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The cluster configuration version number. Only present when Type == "cluster".
|
||||
/// </summary>
|
||||
[JsonPropertyName("version")]
|
||||
[JsonProperty("version")]
|
||||
public int? Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IP address used for cluster communication on this node.
|
||||
/// Only present when Type == "node".
|
||||
/// </summary>
|
||||
[JsonPropertyName("ip")]
|
||||
[JsonProperty("ip")]
|
||||
public string? Ip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this node is currently online (1) or offline (0).
|
||||
/// Only present when Type == "node".
|
||||
/// </summary>
|
||||
[JsonPropertyName("online")]
|
||||
[JsonProperty("online")]
|
||||
public int? Online { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this is the local node making the request (1) or a remote node (0).
|
||||
/// Only present when Type == "node".
|
||||
/// </summary>
|
||||
[JsonPropertyName("local")]
|
||||
[JsonProperty("local")]
|
||||
public int? Local { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The numeric node ID within the cluster Corosync configuration.
|
||||
/// Only present when Type == "node".
|
||||
/// </summary>
|
||||
[JsonPropertyName("nodeid")]
|
||||
[JsonProperty("nodeid")]
|
||||
public int? NodeId { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
if (Type == "node")
|
||||
{
|
||||
var onlineStr = Online is 1 ? "online" : "offline";
|
||||
var localStr = Local is 1 ? " [local]" : string.Empty;
|
||||
return $"Node: {Name ?? "N/A"}{localStr} | IP: {Ip ?? "N/A"} | {onlineStr}";
|
||||
}
|
||||
var quorateStr = Quorate is 1 ? "quorate" : "NO QUORUM";
|
||||
return $"Cluster: {Name ?? "N/A"} | Nodes: {Nodes?.ToString() ?? "N/A"} | "
|
||||
+ $"{quorateStr} | Config Version: {Version?.ToString() ?? "N/A"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Containers;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Linux Container (LXC) as returned by the cluster or node container list endpoints.
|
||||
/// </summary>
|
||||
public class PveContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique container identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("vmid")]
|
||||
[JsonProperty("vmid")]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The hostname / display name of the container.
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
[JsonProperty("name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current runtime status of the container (e.g., "running", "stopped").
|
||||
/// </summary>
|
||||
[JsonPropertyName("status")]
|
||||
[JsonProperty("status")]
|
||||
public string? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The node on which the container resides.
|
||||
/// </summary>
|
||||
[JsonPropertyName("node")]
|
||||
[JsonProperty("node")]
|
||||
public string? Node { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of CPU cores assigned to the container.
|
||||
/// </summary>
|
||||
[JsonPropertyName("cpus")]
|
||||
[JsonProperty("cpus")]
|
||||
public int? CpuCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum memory allocated to the container, in bytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("maxmem")]
|
||||
[JsonProperty("maxmem")]
|
||||
public long? MaxMem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum swap space allocated to the container, in bytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("maxswap")]
|
||||
[JsonProperty("maxswap")]
|
||||
public long? MaxSwap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Root filesystem disk size allocated to the container, in bytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("maxdisk")]
|
||||
[JsonProperty("maxdisk")]
|
||||
public long? RootFsSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The OS template type used for this container (e.g., "debian", "ubuntu").
|
||||
/// </summary>
|
||||
[JsonPropertyName("ostype")]
|
||||
[JsonProperty("ostype")]
|
||||
public string? OsType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the container runs in unprivileged mode (1) or privileged mode (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("unprivileged")]
|
||||
[JsonProperty("unprivileged")]
|
||||
public int? Unprivileged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current lock type applied to the container, if any (e.g., "migrate", "backup").
|
||||
/// </summary>
|
||||
[JsonPropertyName("lock")]
|
||||
[JsonProperty("lock")]
|
||||
public string? Lock { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Container uptime in seconds.
|
||||
/// </summary>
|
||||
[JsonPropertyName("uptime")]
|
||||
[JsonProperty("uptime")]
|
||||
public long? Uptime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Semicolon-separated list of tags assigned to the container.
|
||||
/// </summary>
|
||||
[JsonPropertyName("tags")]
|
||||
[JsonProperty("tags")]
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var maxMemMb = MaxMem.HasValue ? $"{MaxMem.Value / 1024 / 1024} MB" : "N/A";
|
||||
var rootFsGb = RootFsSize.HasValue ? $"{RootFsSize.Value / 1024 / 1024 / 1024} GB" : "N/A";
|
||||
var uptimeStr = Uptime.HasValue ? TimeSpan.FromSeconds(Uptime.Value).ToString(@"d\.hh\:mm\:ss") : "N/A";
|
||||
var privStr = Unprivileged is 1 ? "unprivileged" : "privileged";
|
||||
return $"CT {VmId}: {Name ?? "(unnamed)"} | Node: {Node ?? "N/A"} | "
|
||||
+ $"Status: {Status ?? "N/A"} | CPUs: {CpuCount?.ToString() ?? "N/A"} | "
|
||||
+ $"Mem: {maxMemMb} | Disk: {rootFsGb} | {privStr} | Uptime: {uptimeStr}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Containers;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the configuration of a Linux Container (LXC),
|
||||
/// as returned by the /nodes/{node}/lxc/{vmid}/config endpoint.
|
||||
/// </summary>
|
||||
public class PveContainerConfig
|
||||
{
|
||||
// -------------------------------------------------------------------------
|
||||
// Identity / OS
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// The container hostname.
|
||||
/// </summary>
|
||||
[JsonPropertyName("hostname")]
|
||||
[JsonProperty("hostname")]
|
||||
public string? Hostname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The OS type used for the container (e.g., "debian", "ubuntu", "alpine").
|
||||
/// </summary>
|
||||
[JsonPropertyName("ostype")]
|
||||
[JsonProperty("ostype")]
|
||||
public string? OsType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Container architecture (e.g., "amd64", "arm64").
|
||||
/// </summary>
|
||||
[JsonPropertyName("arch")]
|
||||
[JsonProperty("arch")]
|
||||
public string? Arch { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the container runs unprivileged (1) or privileged (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("unprivileged")]
|
||||
[JsonProperty("unprivileged")]
|
||||
public int? Unprivileged { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Resources
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Memory limit in megabytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("memory")]
|
||||
[JsonProperty("memory")]
|
||||
public int? Memory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Swap space limit in megabytes. 0 disables swap.
|
||||
/// </summary>
|
||||
[JsonPropertyName("swap")]
|
||||
[JsonProperty("swap")]
|
||||
public int? Swap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of CPU cores allocated to the container.
|
||||
/// </summary>
|
||||
[JsonPropertyName("cores")]
|
||||
[JsonProperty("cores")]
|
||||
public int? Cores { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Root filesystem configuration string (e.g., "local-lvm:8").
|
||||
/// </summary>
|
||||
[JsonPropertyName("rootfs")]
|
||||
[JsonProperty("rootfs")]
|
||||
public string? RootFs { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Metadata
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable description or notes for the container.
|
||||
/// </summary>
|
||||
[JsonPropertyName("description")]
|
||||
[JsonProperty("description")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Semicolon-separated list of tags assigned to the container.
|
||||
/// </summary>
|
||||
[JsonPropertyName("tags")]
|
||||
[JsonProperty("tags")]
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When set to 1, prevents the container from being deleted or modified accidentally.
|
||||
/// </summary>
|
||||
[JsonPropertyName("protection")]
|
||||
[JsonProperty("protection")]
|
||||
public int? Protection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Startup / shutdown order and delay configuration string.
|
||||
/// </summary>
|
||||
[JsonPropertyName("startup")]
|
||||
[JsonProperty("startup")]
|
||||
public string? Startup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Feature flags for the container (e.g., "nesting=1,keyctl=1").
|
||||
/// </summary>
|
||||
[JsonPropertyName("features")]
|
||||
[JsonProperty("features")]
|
||||
public string? Features { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Network interfaces (0-7)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>Network interface 0 configuration string.</summary>
|
||||
[JsonPropertyName("net0")]
|
||||
[JsonProperty("net0")]
|
||||
public string? Net0 { get; set; }
|
||||
|
||||
/// <summary>Network interface 1 configuration string.</summary>
|
||||
[JsonPropertyName("net1")]
|
||||
[JsonProperty("net1")]
|
||||
public string? Net1 { get; set; }
|
||||
|
||||
/// <summary>Network interface 2 configuration string.</summary>
|
||||
[JsonPropertyName("net2")]
|
||||
[JsonProperty("net2")]
|
||||
public string? Net2 { get; set; }
|
||||
|
||||
/// <summary>Network interface 3 configuration string.</summary>
|
||||
[JsonPropertyName("net3")]
|
||||
[JsonProperty("net3")]
|
||||
public string? Net3 { get; set; }
|
||||
|
||||
/// <summary>Network interface 4 configuration string.</summary>
|
||||
[JsonPropertyName("net4")]
|
||||
[JsonProperty("net4")]
|
||||
public string? Net4 { get; set; }
|
||||
|
||||
/// <summary>Network interface 5 configuration string.</summary>
|
||||
[JsonPropertyName("net5")]
|
||||
[JsonProperty("net5")]
|
||||
public string? Net5 { get; set; }
|
||||
|
||||
/// <summary>Network interface 6 configuration string.</summary>
|
||||
[JsonPropertyName("net6")]
|
||||
[JsonProperty("net6")]
|
||||
public string? Net6 { get; set; }
|
||||
|
||||
/// <summary>Network interface 7 configuration string.</summary>
|
||||
[JsonPropertyName("net7")]
|
||||
[JsonProperty("net7")]
|
||||
public string? Net7 { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Mount points (0-7)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>Mount point 0 configuration string (e.g., "local-lvm:10,mp=/data").</summary>
|
||||
[JsonPropertyName("mp0")]
|
||||
[JsonProperty("mp0")]
|
||||
public string? Mp0 { get; set; }
|
||||
|
||||
/// <summary>Mount point 1 configuration string.</summary>
|
||||
[JsonPropertyName("mp1")]
|
||||
[JsonProperty("mp1")]
|
||||
public string? Mp1 { get; set; }
|
||||
|
||||
/// <summary>Mount point 2 configuration string.</summary>
|
||||
[JsonPropertyName("mp2")]
|
||||
[JsonProperty("mp2")]
|
||||
public string? Mp2 { get; set; }
|
||||
|
||||
/// <summary>Mount point 3 configuration string.</summary>
|
||||
[JsonPropertyName("mp3")]
|
||||
[JsonProperty("mp3")]
|
||||
public string? Mp3 { get; set; }
|
||||
|
||||
/// <summary>Mount point 4 configuration string.</summary>
|
||||
[JsonPropertyName("mp4")]
|
||||
[JsonProperty("mp4")]
|
||||
public string? Mp4 { get; set; }
|
||||
|
||||
/// <summary>Mount point 5 configuration string.</summary>
|
||||
[JsonPropertyName("mp5")]
|
||||
[JsonProperty("mp5")]
|
||||
public string? Mp5 { get; set; }
|
||||
|
||||
/// <summary>Mount point 6 configuration string.</summary>
|
||||
[JsonPropertyName("mp6")]
|
||||
[JsonProperty("mp6")]
|
||||
public string? Mp6 { get; set; }
|
||||
|
||||
/// <summary>Mount point 7 configuration string.</summary>
|
||||
[JsonPropertyName("mp7")]
|
||||
[JsonProperty("mp7")]
|
||||
public string? Mp7 { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// DNS / SSH
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// DNS nameserver(s) for the container.
|
||||
/// </summary>
|
||||
[JsonPropertyName("nameserver")]
|
||||
[JsonProperty("nameserver")]
|
||||
public string? Nameserver { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DNS search domain for the container.
|
||||
/// </summary>
|
||||
[JsonPropertyName("searchdomain")]
|
||||
[JsonProperty("searchdomain")]
|
||||
public string? Searchdomain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SSH public keys injected into the container's root account.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ssh-public-keys")]
|
||||
[JsonProperty("ssh-public-keys")]
|
||||
public string? SshPublicKeys { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Config | Hostname: {Hostname ?? "N/A"} | OS: {OsType ?? "N/A"} | "
|
||||
+ $"Cores: {Cores?.ToString() ?? "N/A"} | Memory: {Memory?.ToString() ?? "N/A"} MB | "
|
||||
+ $"Swap: {Swap?.ToString() ?? "N/A"} MB | Arch: {Arch ?? "N/A"} | "
|
||||
+ $"Unprivileged: {(Unprivileged is 1 ? "yes" : "no")}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Network;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a network interface configuration on a Proxmox VE node,
|
||||
/// as returned by the /nodes/{node}/network endpoint.
|
||||
/// </summary>
|
||||
public class PveNetwork
|
||||
{
|
||||
/// <summary>
|
||||
/// The interface name (e.g., "vmbr0", "eth0", "bond0").
|
||||
/// </summary>
|
||||
[JsonPropertyName("iface")]
|
||||
[JsonProperty("iface")]
|
||||
public string Iface { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The interface type (e.g., "bridge", "bond", "eth", "vlan", "OVSBridge").
|
||||
/// </summary>
|
||||
[JsonPropertyName("type")]
|
||||
[JsonProperty("type")]
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IPv4 address assigned to this interface.
|
||||
/// </summary>
|
||||
[JsonPropertyName("address")]
|
||||
[JsonProperty("address")]
|
||||
public string? Address { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IPv4 netmask for this interface.
|
||||
/// </summary>
|
||||
[JsonPropertyName("netmask")]
|
||||
[JsonProperty("netmask")]
|
||||
public string? Netmask { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IPv4 default gateway associated with this interface.
|
||||
/// </summary>
|
||||
[JsonPropertyName("gateway")]
|
||||
[JsonProperty("gateway")]
|
||||
public string? Gateway { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Space-separated list of physical ports attached to this bridge.
|
||||
/// </summary>
|
||||
[JsonPropertyName("bridge_ports")]
|
||||
[JsonProperty("bridge_ports")]
|
||||
public string? BridgePorts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Space-separated list of slave interfaces for bond/team interfaces.
|
||||
/// </summary>
|
||||
[JsonPropertyName("slaves")]
|
||||
[JsonProperty("slaves")]
|
||||
public string? BondSlaves { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// VLAN ID for VLAN sub-interfaces.
|
||||
/// </summary>
|
||||
[JsonPropertyName("vlan-id")]
|
||||
[JsonProperty("vlan-id")]
|
||||
public int? VlanId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Maximum Transmission Unit in bytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("mtu")]
|
||||
[JsonProperty("mtu")]
|
||||
public int? Mtu { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the interface is brought up automatically at boot (1) or not (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("autostart")]
|
||||
[JsonProperty("autostart")]
|
||||
public int? Autostart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the interface is currently active/up (1) or down (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("active")]
|
||||
[JsonProperty("active")]
|
||||
public int? Active { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional comment or description for this interface.
|
||||
/// </summary>
|
||||
[JsonPropertyName("comments")]
|
||||
[JsonProperty("comments")]
|
||||
public string? Comments { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// IPv4 address in CIDR notation (e.g., "192.168.1.1/24").
|
||||
/// </summary>
|
||||
[JsonPropertyName("cidr")]
|
||||
[JsonProperty("cidr")]
|
||||
public string? Cidr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether VLAN-aware bridging is enabled on this bridge (1) or not (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("bridge_vlan_aware")]
|
||||
[JsonProperty("bridge_vlan_aware")]
|
||||
public int? BridgeVlanAware { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The bonding mode for bond interfaces (e.g., "active-backup", "802.3ad", "balance-rr").
|
||||
/// </summary>
|
||||
[JsonPropertyName("bond_mode")]
|
||||
[JsonProperty("bond_mode")]
|
||||
public string? BondMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The node this network interface belongs to. Populated by cmdlets after retrieval.
|
||||
/// </summary>
|
||||
public string? Node { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var addr = Cidr ?? Address ?? "N/A";
|
||||
var activeStr = Active is 1 ? "up" : "down";
|
||||
return $"Network: {Iface} | Type: {Type ?? "N/A"} | Address: {addr} | "
|
||||
+ $"GW: {Gateway ?? "N/A"} | MTU: {Mtu?.ToString() ?? "N/A"} | {activeStr}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Network;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Software-Defined Networking (SDN) virtual network (VNet) as returned by
|
||||
/// the /cluster/sdn/vnets endpoint.
|
||||
/// Available in Proxmox VE 8.0+.
|
||||
/// </summary>
|
||||
public class PveSdnVnet
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique VNet identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("vnet")]
|
||||
[JsonProperty("vnet")]
|
||||
public string Vnet { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The SDN zone this VNet belongs to.
|
||||
/// </summary>
|
||||
[JsonPropertyName("zone")]
|
||||
[JsonProperty("zone")]
|
||||
public string? Zone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The VLAN or VXLAN tag associated with this VNet.
|
||||
/// </summary>
|
||||
[JsonPropertyName("tag")]
|
||||
[JsonProperty("tag")]
|
||||
public int? Tag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An optional human-readable alias for this VNet.
|
||||
/// </summary>
|
||||
[JsonPropertyName("alias")]
|
||||
[JsonProperty("alias")]
|
||||
public string? Alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether VLAN-aware mode is enabled on this VNet (1) or not (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("vlanaware")]
|
||||
[JsonProperty("vlanaware")]
|
||||
public int? VlanAware { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional comment or description for this SDN VNet.
|
||||
/// </summary>
|
||||
[JsonPropertyName("comments")]
|
||||
[JsonProperty("comments")]
|
||||
public string? Comments { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var vlanAwareStr = VlanAware is 1 ? " [vlan-aware]" : string.Empty;
|
||||
return $"SDN VNet: {Vnet}{vlanAwareStr} | Zone: {Zone ?? "N/A"} | "
|
||||
+ $"Tag: {Tag?.ToString() ?? "N/A"} | Alias: {Alias ?? "N/A"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Network;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Software-Defined Networking (SDN) zone as returned by
|
||||
/// the /cluster/sdn/zones endpoint.
|
||||
/// Available in Proxmox VE 8.0+.
|
||||
/// </summary>
|
||||
public class PveSdnZone
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique zone identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("zone")]
|
||||
[JsonProperty("zone")]
|
||||
public string Zone { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The zone type (e.g., "simple", "vlan", "qinq", "vxlan", "evpn").
|
||||
/// </summary>
|
||||
[JsonPropertyName("type")]
|
||||
[JsonProperty("type")]
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The DNS server address associated with this zone.
|
||||
/// </summary>
|
||||
[JsonPropertyName("dns")]
|
||||
[JsonProperty("dns")]
|
||||
public string? Dns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The reverse DNS zone name for this SDN zone.
|
||||
/// </summary>
|
||||
[JsonPropertyName("reversedns")]
|
||||
[JsonProperty("reversedns")]
|
||||
public string? Reversedns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The DNS zone name used for forward lookups.
|
||||
/// </summary>
|
||||
[JsonPropertyName("dnszone")]
|
||||
[JsonProperty("dnszone")]
|
||||
public string? DnsZone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IPAM plugin to use for IP address management in this zone.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ipam")]
|
||||
[JsonProperty("ipam")]
|
||||
public string? Ipam { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Maximum Transmission Unit in bytes for this zone.
|
||||
/// </summary>
|
||||
[JsonPropertyName("mtu")]
|
||||
[JsonProperty("mtu")]
|
||||
public int? Mtu { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Comma-separated list of nodes that participate in this SDN zone.
|
||||
/// </summary>
|
||||
[JsonPropertyName("nodes")]
|
||||
[JsonProperty("nodes")]
|
||||
public string? Nodes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the zone has pending (unapplied) configuration changes (1) or not (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("pending")]
|
||||
[JsonProperty("pending")]
|
||||
public int? Pending { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional comment or description for this SDN zone.
|
||||
/// </summary>
|
||||
[JsonPropertyName("comments")]
|
||||
[JsonProperty("comments")]
|
||||
public string? Comments { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var pendingStr = Pending is 1 ? " [pending]" : string.Empty;
|
||||
return $"SDN Zone: {Zone}{pendingStr} | Type: {Type ?? "N/A"} | DNS: {Dns ?? "N/A"} | "
|
||||
+ $"IPAM: {Ipam ?? "N/A"} | Nodes: {Nodes ?? "all"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Nodes;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Proxmox VE cluster node as returned by the /nodes endpoint.
|
||||
/// </summary>
|
||||
public class PveNode
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("node")]
|
||||
[JsonProperty("node")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The current status of the node (e.g., "online" or "offline").
|
||||
/// </summary>
|
||||
[JsonPropertyName("status")]
|
||||
[JsonProperty("status")]
|
||||
public string Status { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The total number of CPU cores available on the node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("maxcpu")]
|
||||
[JsonProperty("maxcpu")]
|
||||
public int? CpuCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total memory in bytes available on the node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("maxmem")]
|
||||
[JsonProperty("maxmem")]
|
||||
public long? MemoryTotal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Memory currently in use on the node, in bytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("mem")]
|
||||
[JsonProperty("mem")]
|
||||
public long? MemoryUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Node uptime in seconds.
|
||||
/// </summary>
|
||||
[JsonPropertyName("uptime")]
|
||||
[JsonProperty("uptime")]
|
||||
public long? Uptime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The version of Proxmox VE running on the node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("pveversion")]
|
||||
[JsonProperty("pveversion")]
|
||||
public string? PveVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Linux kernel version running on the node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("kversion")]
|
||||
[JsonProperty("kversion")]
|
||||
public string? KernelVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The 1-minute, 5-minute, and 15-minute load averages for the node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("loadavg")]
|
||||
[JsonProperty("loadavg")]
|
||||
public double[]? LoadAverage { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var memUsedMb = MemoryUsed.HasValue ? $"{MemoryUsed.Value / 1024 / 1024} MB" : "N/A";
|
||||
var memTotalMb = MemoryTotal.HasValue ? $"{MemoryTotal.Value / 1024 / 1024} MB" : "N/A";
|
||||
var uptimeStr = Uptime.HasValue ? TimeSpan.FromSeconds(Uptime.Value).ToString(@"d\.hh\:mm\:ss") : "N/A";
|
||||
return $"Node: {Name} | Status: {Status} | CPUs: {CpuCount?.ToString() ?? "N/A"} | "
|
||||
+ $"Mem: {memUsedMb}/{memTotalMb} | Uptime: {uptimeStr} | PVE: {PveVersion ?? "N/A"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Nodes;
|
||||
|
||||
/// <summary>
|
||||
/// Represents detailed status information for a single Proxmox VE node,
|
||||
/// as returned by the /nodes/{node}/status endpoint.
|
||||
/// </summary>
|
||||
public class PveNodeStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("node")]
|
||||
[JsonProperty("node")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The current status of the node (e.g., "online" or "offline").
|
||||
/// </summary>
|
||||
[JsonPropertyName("status")]
|
||||
[JsonProperty("status")]
|
||||
public string Status { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The total number of CPU cores available on the node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("maxcpu")]
|
||||
[JsonProperty("maxcpu")]
|
||||
public int? CpuCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total memory in bytes available on the node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("maxmem")]
|
||||
[JsonProperty("maxmem")]
|
||||
public long? MemoryTotal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Memory currently in use on the node, in bytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("mem")]
|
||||
[JsonProperty("mem")]
|
||||
public long? MemoryUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Node uptime in seconds.
|
||||
/// </summary>
|
||||
[JsonPropertyName("uptime")]
|
||||
[JsonProperty("uptime")]
|
||||
public long? Uptime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The version of Proxmox VE running on the node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("pveversion")]
|
||||
[JsonProperty("pveversion")]
|
||||
public string? PveVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Linux kernel version running on the node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("kversion")]
|
||||
[JsonProperty("kversion")]
|
||||
public string? KernelVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The 1-minute, 5-minute, and 15-minute load averages for the node.
|
||||
/// </summary>
|
||||
[JsonPropertyName("loadavg")]
|
||||
[JsonProperty("loadavg")]
|
||||
public double[]? LoadAverage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total root filesystem size in bytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("rootfs.total")]
|
||||
[JsonProperty("rootfs.total")]
|
||||
public long? DiskTotal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used root filesystem space in bytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("rootfs.used")]
|
||||
[JsonProperty("rootfs.used")]
|
||||
public long? DiskUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current CPU utilization as a fraction between 0.0 and 1.0.
|
||||
/// </summary>
|
||||
[JsonPropertyName("cpu")]
|
||||
[JsonProperty("cpu")]
|
||||
public double? CpuUsage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Memory utilization as a percentage (0–100), computed from MemoryUsed / MemoryTotal.
|
||||
/// </summary>
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public double? MemoryUsage =>
|
||||
MemoryTotal.HasValue && MemoryTotal.Value > 0 && MemoryUsed.HasValue
|
||||
? (double)MemoryUsed.Value / MemoryTotal.Value * 100.0
|
||||
: null;
|
||||
|
||||
/// <summary>
|
||||
/// Total swap space in bytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("swap.total")]
|
||||
[JsonProperty("swap.total")]
|
||||
public long? SwapTotal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used swap space in bytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("swap.used")]
|
||||
[JsonProperty("swap.used")]
|
||||
public long? SwapUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total bytes received over the network since boot.
|
||||
/// </summary>
|
||||
[JsonPropertyName("netin")]
|
||||
[JsonProperty("netin")]
|
||||
public long? NetworkIn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total bytes transmitted over the network since boot.
|
||||
/// </summary>
|
||||
[JsonPropertyName("netout")]
|
||||
[JsonProperty("netout")]
|
||||
public long? NetworkOut { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var memUsedMb = MemoryUsed.HasValue ? $"{MemoryUsed.Value / 1024 / 1024} MB" : "N/A";
|
||||
var memTotalMb = MemoryTotal.HasValue ? $"{MemoryTotal.Value / 1024 / 1024} MB" : "N/A";
|
||||
var cpuPct = CpuUsage.HasValue ? $"{CpuUsage.Value * 100:F1}%" : "N/A";
|
||||
var diskUsedGb = DiskUsed.HasValue ? $"{DiskUsed.Value / 1024 / 1024 / 1024} GB" : "N/A";
|
||||
var diskTotalGb = DiskTotal.HasValue ? $"{DiskTotal.Value / 1024 / 1024 / 1024} GB" : "N/A";
|
||||
var uptimeStr = Uptime.HasValue ? TimeSpan.FromSeconds(Uptime.Value).ToString(@"d\.hh\:mm\:ss") : "N/A";
|
||||
return $"Node: {Name} | Status: {Status} | CPU: {cpuPct} | "
|
||||
+ $"Mem: {memUsedMb}/{memTotalMb} ({MemoryUsage:F1}%) | "
|
||||
+ $"Disk: {diskUsedGb}/{diskTotalGb} | Uptime: {uptimeStr}";
|
||||
}
|
||||
}
|
||||
@@ -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}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Users;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single Access Control List (ACL) entry as returned by the /access/acl endpoint.
|
||||
/// An ACL entry grants a specific role to a user or group on a particular resource path.
|
||||
/// </summary>
|
||||
public class PvePermission
|
||||
{
|
||||
/// <summary>
|
||||
/// The resource path this ACL entry applies to (e.g., "/", "/nodes/pve", "/vms/100").
|
||||
/// </summary>
|
||||
[JsonPropertyName("path")]
|
||||
[JsonProperty("path")]
|
||||
public string? Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The role ID granted by this ACL entry (e.g., "Administrator", "PVEVMAdmin").
|
||||
/// </summary>
|
||||
[JsonPropertyName("roleid")]
|
||||
[JsonProperty("roleid")]
|
||||
public string? RoleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the permission propagates to sub-paths (1) or is restricted to the exact path (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("propagate")]
|
||||
[JsonProperty("propagate")]
|
||||
public int? Propagate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user ID or group ID (with "@" prefix for groups) that this ACL entry applies to.
|
||||
/// Maps to the "ugid" JSON field.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ugid")]
|
||||
[JsonProperty("ugid")]
|
||||
public string? UserId { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var propagateStr = Propagate is 1 ? " [propagate]" : string.Empty;
|
||||
return $"ACL: {UserId ?? "N/A"} | Path: {Path ?? "/"} | Role: {RoleId ?? "N/A"}{propagateStr}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Users;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Proxmox VE role as returned by the /access/roles endpoint.
|
||||
/// Roles are named collections of privileges that can be assigned to users or groups via ACLs.
|
||||
/// </summary>
|
||||
public class PveRole
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique role identifier (e.g., "Administrator", "PVEVMAdmin", "PVEDatastoreUser").
|
||||
/// </summary>
|
||||
[JsonPropertyName("roleid")]
|
||||
[JsonProperty("roleid")]
|
||||
public string RoleId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Comma-separated list of privilege strings assigned to this role
|
||||
/// (e.g., "VM.Allocate,VM.Config.Disk,Datastore.AllocateSpace").
|
||||
/// </summary>
|
||||
[JsonPropertyName("privs")]
|
||||
[JsonProperty("privs")]
|
||||
public string? Privileges { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this is a built-in / special role (1) that cannot be deleted,
|
||||
/// or a custom role (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("special")]
|
||||
[JsonProperty("special")]
|
||||
public int? Special { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var specialStr = Special is 1 ? " [built-in]" : string.Empty;
|
||||
return $"Role: {RoleId}{specialStr} | Privs: {Privileges ?? "none"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Users;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Proxmox VE user account as returned by the /access/users endpoint.
|
||||
/// </summary>
|
||||
public class PveUser
|
||||
{
|
||||
/// <summary>
|
||||
/// The full user ID in the format "username@realm" (e.g., "admin@pam", "user@pve").
|
||||
/// </summary>
|
||||
[JsonPropertyName("userid")]
|
||||
[JsonProperty("userid")]
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The user's first name.
|
||||
/// </summary>
|
||||
[JsonPropertyName("firstname")]
|
||||
[JsonProperty("firstname")]
|
||||
public string? FirstName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's last name.
|
||||
/// </summary>
|
||||
[JsonPropertyName("lastname")]
|
||||
[JsonProperty("lastname")]
|
||||
public string? LastName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's email address.
|
||||
/// </summary>
|
||||
[JsonPropertyName("email")]
|
||||
[JsonProperty("email")]
|
||||
public string? Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the user account is enabled (1) or disabled (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("enable")]
|
||||
[JsonProperty("enable")]
|
||||
public int? Enabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The authentication realm for this user (e.g., "pam", "pve", "ldap").
|
||||
/// </summary>
|
||||
[JsonPropertyName("realm")]
|
||||
[JsonProperty("realm")]
|
||||
public string? Realm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Comma-separated list of groups this user is a member of.
|
||||
/// </summary>
|
||||
[JsonPropertyName("groups")]
|
||||
[JsonProperty("groups")]
|
||||
public string? Groups { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional comment or description for this user account.
|
||||
/// </summary>
|
||||
[JsonPropertyName("comment")]
|
||||
[JsonProperty("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Account expiry as a Unix timestamp. 0 or null means the account never expires.
|
||||
/// </summary>
|
||||
[JsonPropertyName("expire")]
|
||||
[JsonProperty("expire")]
|
||||
public long? Expire { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var fullName = string.Join(" ", new[] { FirstName, LastName }.Where(s => !string.IsNullOrWhiteSpace(s)));
|
||||
var enabledStr = Enabled is 1 ? "enabled" : "disabled";
|
||||
var expireStr = Expire is > 0 ? DateTimeOffset.FromUnixTimeSeconds(Expire.Value).ToString("yyyy-MM-dd") : "never";
|
||||
return $"User: {UserId} | Name: {(string.IsNullOrEmpty(fullName) ? "N/A" : fullName)} | "
|
||||
+ $"{enabledStr} | Groups: {Groups ?? "none"} | Expires: {expireStr}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Vms
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the Cloud-Init specific configuration fields for a VM.
|
||||
/// Fields are extracted from the full VM config.
|
||||
/// </summary>
|
||||
public class PveCloudInitConfig
|
||||
{
|
||||
/// <summary>Default user name injected by Cloud-Init.</summary>
|
||||
[JsonProperty("ciuser")]
|
||||
public string? CiUser { get; set; }
|
||||
|
||||
/// <summary>Default user password (may be hashed).</summary>
|
||||
[JsonProperty("cipassword")]
|
||||
public string? CiPassword { get; set; }
|
||||
|
||||
/// <summary>URL-encoded SSH public keys.</summary>
|
||||
[JsonProperty("sshkeys")]
|
||||
public string? SshKeys { get; set; }
|
||||
|
||||
/// <summary>IP configuration for interface 0 (e.g. "ip=dhcp" or "ip=192.168.1.10/24,gw=192.168.1.1").</summary>
|
||||
[JsonProperty("ipconfig0")]
|
||||
public string? IpConfig0 { get; set; }
|
||||
|
||||
/// <summary>IP configuration for interface 1.</summary>
|
||||
[JsonProperty("ipconfig1")]
|
||||
public string? IpConfig1 { get; set; }
|
||||
|
||||
/// <summary>IP configuration for interface 2.</summary>
|
||||
[JsonProperty("ipconfig2")]
|
||||
public string? IpConfig2 { get; set; }
|
||||
|
||||
/// <summary>IP configuration for interface 3.</summary>
|
||||
[JsonProperty("ipconfig3")]
|
||||
public string? IpConfig3 { get; set; }
|
||||
|
||||
/// <summary>DNS nameserver(s) space-separated.</summary>
|
||||
[JsonProperty("nameserver")]
|
||||
public string? Nameserver { get; set; }
|
||||
|
||||
/// <summary>DNS search domain.</summary>
|
||||
[JsonProperty("searchdomain")]
|
||||
public string? Searchdomain { get; set; }
|
||||
|
||||
/// <summary>Custom Cloud-Init config files (cicustom field).</summary>
|
||||
[JsonProperty("cicustom")]
|
||||
public string? CiCustom { get; set; }
|
||||
|
||||
public override string ToString() =>
|
||||
$"CloudInit: User={CiUser ?? "N/A"} | IP0={IpConfig0 ?? "N/A"} | NS={Nameserver ?? "N/A"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Vms;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a VM snapshot as returned by the /nodes/{node}/qemu/{vmid}/snapshot endpoint.
|
||||
/// </summary>
|
||||
public class PveSnapshot
|
||||
{
|
||||
/// <summary>
|
||||
/// The snapshot name / identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Optional human-readable description of what this snapshot captures.
|
||||
/// </summary>
|
||||
[JsonPropertyName("description")]
|
||||
[JsonProperty("description")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unix timestamp when the snapshot was created.
|
||||
/// </summary>
|
||||
[JsonPropertyName("snaptime")]
|
||||
[JsonProperty("snaptime")]
|
||||
public long? SnapTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the VM RAM state was saved with this snapshot (1) or not (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("vmstate")]
|
||||
[JsonProperty("vmstate")]
|
||||
public int? VmState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the parent snapshot, or null if this is the root snapshot.
|
||||
/// </summary>
|
||||
[JsonPropertyName("parent")]
|
||||
[JsonProperty("parent")]
|
||||
public string? Parent { get; set; }
|
||||
|
||||
/// <summary>The VM ID this snapshot belongs to. Populated by cmdlets after retrieval.</summary>
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>The node the VM resides on. Populated by cmdlets after retrieval.</summary>
|
||||
public string? Node { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var timeStr = SnapTime.HasValue
|
||||
? DateTimeOffset.FromUnixTimeSeconds(SnapTime.Value).ToString("yyyy-MM-dd HH:mm:ss")
|
||||
: "N/A";
|
||||
var stateStr = VmState is 1 ? " [+vmstate]" : string.Empty;
|
||||
var parentStr = Parent is not null ? $" | Parent: {Parent}" : string.Empty;
|
||||
return $"Snapshot: {Name}{stateStr} | Created: {timeStr} | "
|
||||
+ $"Description: {Description ?? "(none)"}{parentStr}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Vms;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Proxmox VE asynchronous task as returned by the task-related endpoints
|
||||
/// (e.g., /nodes/{node}/tasks, /nodes/{node}/tasks/{upid}/status).
|
||||
/// Most mutating API calls return a UPID string that identifies the created task.
|
||||
/// </summary>
|
||||
public class PveTask
|
||||
{
|
||||
/// <summary>
|
||||
/// The Unique Process Identifier for this task
|
||||
/// (e.g., "UPID:pve:000ABC:00000001:5F1234AB:qmstart:100:root@pam:").
|
||||
/// </summary>
|
||||
[JsonPropertyName("upid")]
|
||||
[JsonProperty("upid")]
|
||||
public string Upid { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The task type string (e.g., "qmstart", "qmstop", "qmmigrate", "vzrestore").
|
||||
/// </summary>
|
||||
[JsonPropertyName("type")]
|
||||
[JsonProperty("type")]
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current task status: "running" while in progress, "stopped" when complete.
|
||||
/// </summary>
|
||||
[JsonPropertyName("status")]
|
||||
[JsonProperty("status")]
|
||||
public string? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The exit status when the task has stopped (e.g., "OK" on success, or an error message).
|
||||
/// </summary>
|
||||
[JsonPropertyName("exitstatus")]
|
||||
[JsonProperty("exitstatus")]
|
||||
public string? ExitStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The node on which this task is executing.
|
||||
/// </summary>
|
||||
[JsonPropertyName("node")]
|
||||
[JsonProperty("node")]
|
||||
public string? Node { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unix timestamp of when the task started.
|
||||
/// </summary>
|
||||
[JsonPropertyName("starttime")]
|
||||
[JsonProperty("starttime")]
|
||||
public long? StartTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unix timestamp of when the task ended. Null if still running.
|
||||
/// </summary>
|
||||
[JsonPropertyName("endtime")]
|
||||
[JsonProperty("endtime")]
|
||||
public long? EndTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user that initiated the task (e.g., "root@pam").
|
||||
/// </summary>
|
||||
[JsonPropertyName("user")]
|
||||
[JsonProperty("user")]
|
||||
public string? User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The object ID the task is operating on (e.g., a VM ID or storage name).
|
||||
/// </summary>
|
||||
[JsonPropertyName("id")]
|
||||
[JsonProperty("id")]
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true when the task completed successfully (stopped with exit status "OK").
|
||||
/// </summary>
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public bool IsSuccessful => Status == "stopped" && ExitStatus == "OK";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var startStr = StartTime.HasValue
|
||||
? DateTimeOffset.FromUnixTimeSeconds(StartTime.Value).ToString("yyyy-MM-dd HH:mm:ss")
|
||||
: "N/A";
|
||||
return $"Task [{Type ?? "unknown"}] UPID: {Upid} | Node: {Node ?? "N/A"} | "
|
||||
+ $"Status: {Status ?? "unknown"} | ExitStatus: {ExitStatus ?? "-"} | "
|
||||
+ $"User: {User ?? "N/A"} | Started: {startStr}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Vms
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single log line from a Proxmox VE task log,
|
||||
/// as returned by the /nodes/{node}/tasks/{upid}/log endpoint.
|
||||
/// </summary>
|
||||
public class PveTaskLog
|
||||
{
|
||||
/// <summary>Line number (1-based).</summary>
|
||||
[JsonProperty("n")]
|
||||
public int LineNumber { get; set; }
|
||||
|
||||
/// <summary>Log line text.</summary>
|
||||
[JsonProperty("t")]
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
public override string ToString() => $"{LineNumber,4}: {Text}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Vms;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a QEMU/KVM virtual machine as returned by the cluster or node VM list endpoints.
|
||||
/// </summary>
|
||||
public class PveVm
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique VM identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("vmid")]
|
||||
[JsonProperty("vmid")]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the virtual machine.
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
[JsonProperty("name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current runtime status of the VM (e.g., "running", "stopped").
|
||||
/// </summary>
|
||||
[JsonPropertyName("status")]
|
||||
[JsonProperty("status")]
|
||||
public string? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The node on which the VM resides.
|
||||
/// </summary>
|
||||
[JsonPropertyName("node")]
|
||||
[JsonProperty("node")]
|
||||
public string? Node { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of virtual CPU cores assigned to the VM.
|
||||
/// </summary>
|
||||
[JsonPropertyName("cpus")]
|
||||
[JsonProperty("cpus")]
|
||||
public int? CpuCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum memory allocated to the VM, in bytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("maxmem")]
|
||||
[JsonProperty("maxmem")]
|
||||
public long? MaxMem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum disk size allocated to the VM, in bytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("maxdisk")]
|
||||
[JsonProperty("maxdisk")]
|
||||
public long? MaxDisk { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// VM uptime in seconds.
|
||||
/// </summary>
|
||||
[JsonPropertyName("uptime")]
|
||||
[JsonProperty("uptime")]
|
||||
public long? Uptime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Semicolon-separated list of tags assigned to the VM.
|
||||
/// </summary>
|
||||
[JsonPropertyName("tags")]
|
||||
[JsonProperty("tags")]
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the VM is a template (1) or a regular VM (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("template")]
|
||||
[JsonProperty("template")]
|
||||
public int? Template { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current lock type applied to the VM, if any (e.g., "migrate", "backup").
|
||||
/// </summary>
|
||||
[JsonPropertyName("lock")]
|
||||
[JsonProperty("lock")]
|
||||
public string? Lock { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The process ID of the running QEMU process, if applicable.
|
||||
/// </summary>
|
||||
[JsonPropertyName("pid")]
|
||||
[JsonProperty("pid")]
|
||||
public int? Pid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The QMP (QEMU Machine Protocol) status string.
|
||||
/// </summary>
|
||||
[JsonPropertyName("qmpstatus")]
|
||||
[JsonProperty("qmpstatus")]
|
||||
public string? QmpStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the QEMU guest agent is running (non-zero) inside the VM.
|
||||
/// </summary>
|
||||
[JsonPropertyName("agent")]
|
||||
[JsonProperty("agent")]
|
||||
public int? AgentStatus { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var maxMemMb = MaxMem.HasValue ? $"{MaxMem.Value / 1024 / 1024} MB" : "N/A";
|
||||
var maxDiskGb = MaxDisk.HasValue ? $"{MaxDisk.Value / 1024 / 1024 / 1024} GB" : "N/A";
|
||||
var uptimeStr = Uptime.HasValue ? TimeSpan.FromSeconds(Uptime.Value).ToString(@"d\.hh\:mm\:ss") : "N/A";
|
||||
var templateStr = Template is 1 ? " [template]" : string.Empty;
|
||||
return $"VM {VmId}{templateStr}: {Name ?? "(unnamed)"} | Node: {Node ?? "N/A"} | "
|
||||
+ $"Status: {Status ?? "N/A"} | CPUs: {CpuCount?.ToString() ?? "N/A"} | "
|
||||
+ $"Mem: {maxMemMb} | Disk: {maxDiskGb} | Uptime: {uptimeStr}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSProxmoxVE.Core.Models.Vms;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the configuration of a QEMU/KVM virtual machine,
|
||||
/// as returned by the /nodes/{node}/qemu/{vmid}/config endpoint.
|
||||
/// </summary>
|
||||
public class PveVmConfig
|
||||
{
|
||||
// -------------------------------------------------------------------------
|
||||
// CPU / Memory
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Number of CPU cores per socket.
|
||||
/// </summary>
|
||||
[JsonPropertyName("cores")]
|
||||
[JsonProperty("cores")]
|
||||
public int? Cores { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of CPU sockets.
|
||||
/// </summary>
|
||||
[JsonPropertyName("sockets")]
|
||||
[JsonProperty("sockets")]
|
||||
public int? Sockets { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Memory size in megabytes.
|
||||
/// </summary>
|
||||
[JsonPropertyName("memory")]
|
||||
[JsonProperty("memory")]
|
||||
public int? Memory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Emulated CPU type (e.g., "host", "x86-64-v2-AES").
|
||||
/// </summary>
|
||||
[JsonPropertyName("cpu")]
|
||||
[JsonProperty("cpu")]
|
||||
public string? CpuType { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Firmware / Machine
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// BIOS implementation to use: "seabios" (default) or "ovmf" (UEFI).
|
||||
/// </summary>
|
||||
[JsonPropertyName("bios")]
|
||||
[JsonProperty("bios")]
|
||||
public string? Bios { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Emulated machine type (e.g., "q35", "i440fx").
|
||||
/// </summary>
|
||||
[JsonPropertyName("machine")]
|
||||
[JsonProperty("machine")]
|
||||
public string? Machine { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Boot / Args
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Boot order specification string.
|
||||
/// </summary>
|
||||
[JsonPropertyName("boot")]
|
||||
[JsonProperty("boot")]
|
||||
public string? Boot { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Arbitrary QEMU command-line arguments appended to the QEMU launch command.
|
||||
/// </summary>
|
||||
[JsonPropertyName("args")]
|
||||
[JsonProperty("args")]
|
||||
public string? Args { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Metadata
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable description or notes for the VM.
|
||||
/// </summary>
|
||||
[JsonPropertyName("description")]
|
||||
[JsonProperty("description")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Semicolon-separated list of tags assigned to the VM.
|
||||
/// </summary>
|
||||
[JsonPropertyName("tags")]
|
||||
[JsonProperty("tags")]
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When set to 1, prevents the VM from being deleted or modified accidentally.
|
||||
/// </summary>
|
||||
[JsonPropertyName("protection")]
|
||||
[JsonProperty("protection")]
|
||||
public int? Protection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// NUMA topology enabled (1) or disabled (0).
|
||||
/// </summary>
|
||||
[JsonPropertyName("numa")]
|
||||
[JsonProperty("numa")]
|
||||
public int? Numa { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// VirtIO balloon device target memory in MB. 0 disables ballooning.
|
||||
/// </summary>
|
||||
[JsonPropertyName("balloon")]
|
||||
[JsonProperty("balloon")]
|
||||
public int? Balloon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Guest OS type hint (e.g., "l26" for Linux 2.6+, "win10").
|
||||
/// </summary>
|
||||
[JsonPropertyName("ostype")]
|
||||
[JsonProperty("ostype")]
|
||||
public string? OsType { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// VirtIO disk slots (0–3, most commonly used)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>VirtIO disk slot 0 configuration string.</summary>
|
||||
[JsonPropertyName("virtio0")]
|
||||
[JsonProperty("virtio0")]
|
||||
public string? Virtio0 { get; set; }
|
||||
|
||||
/// <summary>VirtIO disk slot 1 configuration string.</summary>
|
||||
[JsonPropertyName("virtio1")]
|
||||
[JsonProperty("virtio1")]
|
||||
public string? Virtio1 { get; set; }
|
||||
|
||||
/// <summary>VirtIO disk slot 2 configuration string.</summary>
|
||||
[JsonPropertyName("virtio2")]
|
||||
[JsonProperty("virtio2")]
|
||||
public string? Virtio2 { get; set; }
|
||||
|
||||
/// <summary>VirtIO disk slot 3 configuration string.</summary>
|
||||
[JsonPropertyName("virtio3")]
|
||||
[JsonProperty("virtio3")]
|
||||
public string? Virtio3 { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// SCSI disk slots (0–7)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>SCSI disk slot 0 configuration string.</summary>
|
||||
[JsonPropertyName("scsi0")]
|
||||
[JsonProperty("scsi0")]
|
||||
public string? Scsi0 { get; set; }
|
||||
|
||||
/// <summary>SCSI disk slot 1 configuration string.</summary>
|
||||
[JsonPropertyName("scsi1")]
|
||||
[JsonProperty("scsi1")]
|
||||
public string? Scsi1 { get; set; }
|
||||
|
||||
/// <summary>SCSI disk slot 2 configuration string.</summary>
|
||||
[JsonPropertyName("scsi2")]
|
||||
[JsonProperty("scsi2")]
|
||||
public string? Scsi2 { get; set; }
|
||||
|
||||
/// <summary>SCSI disk slot 3 configuration string.</summary>
|
||||
[JsonPropertyName("scsi3")]
|
||||
[JsonProperty("scsi3")]
|
||||
public string? Scsi3 { get; set; }
|
||||
|
||||
/// <summary>SCSI disk slot 4 configuration string.</summary>
|
||||
[JsonPropertyName("scsi4")]
|
||||
[JsonProperty("scsi4")]
|
||||
public string? Scsi4 { get; set; }
|
||||
|
||||
/// <summary>SCSI disk slot 5 configuration string.</summary>
|
||||
[JsonPropertyName("scsi5")]
|
||||
[JsonProperty("scsi5")]
|
||||
public string? Scsi5 { get; set; }
|
||||
|
||||
/// <summary>SCSI disk slot 6 configuration string.</summary>
|
||||
[JsonPropertyName("scsi6")]
|
||||
[JsonProperty("scsi6")]
|
||||
public string? Scsi6 { get; set; }
|
||||
|
||||
/// <summary>SCSI disk slot 7 configuration string.</summary>
|
||||
[JsonPropertyName("scsi7")]
|
||||
[JsonProperty("scsi7")]
|
||||
public string? Scsi7 { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// IDE disk slots (0–3)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>IDE disk/CDROM slot 0 configuration string.</summary>
|
||||
[JsonPropertyName("ide0")]
|
||||
[JsonProperty("ide0")]
|
||||
public string? Ide0 { get; set; }
|
||||
|
||||
/// <summary>IDE disk/CDROM slot 1 configuration string.</summary>
|
||||
[JsonPropertyName("ide1")]
|
||||
[JsonProperty("ide1")]
|
||||
public string? Ide1 { get; set; }
|
||||
|
||||
/// <summary>IDE disk/CDROM slot 2 configuration string.</summary>
|
||||
[JsonPropertyName("ide2")]
|
||||
[JsonProperty("ide2")]
|
||||
public string? Ide2 { get; set; }
|
||||
|
||||
/// <summary>IDE disk/CDROM slot 3 configuration string.</summary>
|
||||
[JsonPropertyName("ide3")]
|
||||
[JsonProperty("ide3")]
|
||||
public string? Ide3 { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// SATA disk slots (0–5)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>SATA disk slot 0 configuration string.</summary>
|
||||
[JsonPropertyName("sata0")]
|
||||
[JsonProperty("sata0")]
|
||||
public string? Sata0 { get; set; }
|
||||
|
||||
/// <summary>SATA disk slot 1 configuration string.</summary>
|
||||
[JsonPropertyName("sata1")]
|
||||
[JsonProperty("sata1")]
|
||||
public string? Sata1 { get; set; }
|
||||
|
||||
/// <summary>SATA disk slot 2 configuration string.</summary>
|
||||
[JsonPropertyName("sata2")]
|
||||
[JsonProperty("sata2")]
|
||||
public string? Sata2 { get; set; }
|
||||
|
||||
/// <summary>SATA disk slot 3 configuration string.</summary>
|
||||
[JsonPropertyName("sata3")]
|
||||
[JsonProperty("sata3")]
|
||||
public string? Sata3 { get; set; }
|
||||
|
||||
/// <summary>SATA disk slot 4 configuration string.</summary>
|
||||
[JsonPropertyName("sata4")]
|
||||
[JsonProperty("sata4")]
|
||||
public string? Sata4 { get; set; }
|
||||
|
||||
/// <summary>SATA disk slot 5 configuration string.</summary>
|
||||
[JsonPropertyName("sata5")]
|
||||
[JsonProperty("sata5")]
|
||||
public string? Sata5 { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Network interface slots (0–7)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>Network interface 0 configuration string (e.g., "virtio=XX:XX:XX:XX:XX:XX,bridge=vmbr0").</summary>
|
||||
[JsonPropertyName("net0")]
|
||||
[JsonProperty("net0")]
|
||||
public string? Net0 { get; set; }
|
||||
|
||||
/// <summary>Network interface 1 configuration string.</summary>
|
||||
[JsonPropertyName("net1")]
|
||||
[JsonProperty("net1")]
|
||||
public string? Net1 { get; set; }
|
||||
|
||||
/// <summary>Network interface 2 configuration string.</summary>
|
||||
[JsonPropertyName("net2")]
|
||||
[JsonProperty("net2")]
|
||||
public string? Net2 { get; set; }
|
||||
|
||||
/// <summary>Network interface 3 configuration string.</summary>
|
||||
[JsonPropertyName("net3")]
|
||||
[JsonProperty("net3")]
|
||||
public string? Net3 { get; set; }
|
||||
|
||||
/// <summary>Network interface 4 configuration string.</summary>
|
||||
[JsonPropertyName("net4")]
|
||||
[JsonProperty("net4")]
|
||||
public string? Net4 { get; set; }
|
||||
|
||||
/// <summary>Network interface 5 configuration string.</summary>
|
||||
[JsonPropertyName("net5")]
|
||||
[JsonProperty("net5")]
|
||||
public string? Net5 { get; set; }
|
||||
|
||||
/// <summary>Network interface 6 configuration string.</summary>
|
||||
[JsonPropertyName("net6")]
|
||||
[JsonProperty("net6")]
|
||||
public string? Net6 { get; set; }
|
||||
|
||||
/// <summary>Network interface 7 configuration string.</summary>
|
||||
[JsonPropertyName("net7")]
|
||||
[JsonProperty("net7")]
|
||||
public string? Net7 { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Cloud-Init
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>Cloud-Init default user name.</summary>
|
||||
[JsonPropertyName("ciuser")]
|
||||
[JsonProperty("ciuser")]
|
||||
public string? CiUser { get; set; }
|
||||
|
||||
/// <summary>Cloud-Init default user password (hashed or plaintext depending on PVE version).</summary>
|
||||
[JsonPropertyName("cipassword")]
|
||||
[JsonProperty("cipassword")]
|
||||
public string? CiPassword { get; set; }
|
||||
|
||||
/// <summary>URL-encoded SSH public keys injected by Cloud-Init.</summary>
|
||||
[JsonPropertyName("sshkeys")]
|
||||
[JsonProperty("sshkeys")]
|
||||
public string? SshKeys { get; set; }
|
||||
|
||||
/// <summary>Cloud-Init IP configuration for interface 0.</summary>
|
||||
[JsonPropertyName("ipconfig0")]
|
||||
[JsonProperty("ipconfig0")]
|
||||
public string? IpConfig0 { get; set; }
|
||||
|
||||
/// <summary>Cloud-Init IP configuration for interface 1.</summary>
|
||||
[JsonPropertyName("ipconfig1")]
|
||||
[JsonProperty("ipconfig1")]
|
||||
public string? IpConfig1 { get; set; }
|
||||
|
||||
/// <summary>Cloud-Init IP configuration for interface 2.</summary>
|
||||
[JsonPropertyName("ipconfig2")]
|
||||
[JsonProperty("ipconfig2")]
|
||||
public string? IpConfig2 { get; set; }
|
||||
|
||||
/// <summary>Cloud-Init IP configuration for interface 3.</summary>
|
||||
[JsonPropertyName("ipconfig3")]
|
||||
[JsonProperty("ipconfig3")]
|
||||
public string? IpConfig3 { get; set; }
|
||||
|
||||
/// <summary>DNS nameserver(s) injected via Cloud-Init.</summary>
|
||||
[JsonPropertyName("nameserver")]
|
||||
[JsonProperty("nameserver")]
|
||||
public string? Nameserver { get; set; }
|
||||
|
||||
/// <summary>DNS search domain injected via Cloud-Init.</summary>
|
||||
[JsonPropertyName("searchdomain")]
|
||||
[JsonProperty("searchdomain")]
|
||||
public string? Searchdomain { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
var totalCores = (Cores ?? 1) * (Sockets ?? 1);
|
||||
return $"Config | CPUs: {totalCores} ({Sockets ?? 1}S x {Cores ?? 1}C) | "
|
||||
+ $"Memory: {Memory?.ToString() ?? "N/A"} MB | BIOS: {Bios ?? "seabios"} | "
|
||||
+ $"Machine: {Machine ?? "default"} | OS: {OsType ?? "N/A"}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user