mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-08-13 15:46:52 +00:00
feat(cmdlets): implement container cmdlets
Add Get-PveContainer, New-PveContainer, Remove-PveContainer, Start/Stop/Restart-PveContainer, Copy-PveContainer, Get-PveContainerConfig, and Set-PveContainerConfig. Mirrors VM cmdlet patterns with LXC-appropriate parameters. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
using System.Management.Automation;
|
||||
using PSProxmoxVE.Core.Models.Vms;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Clones (copies) an LXC container on a Proxmox VE node.</para>
|
||||
/// <para type="description">
|
||||
/// Creates a clone of an existing LXC container. By default, a linked clone is created
|
||||
/// when the source is a template. Use -Full to create a full independent copy. Optionally
|
||||
/// specify a target node to create the clone on a different cluster node.
|
||||
/// Use -Wait to block until the clone task completes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Copy, "PveContainer", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(PveTask))]
|
||||
public sealed class CopyPveContainerCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="description">The node on which the source container resides.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true)]
|
||||
public string SourceNode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the source container to clone. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The container ID to assign to the new clone. When omitted, the next available ID is used.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public int? NewVmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The hostname for the new clone.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? NewName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The target node for the clone. Defaults to the source node.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? TargetNode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// When specified, creates a full independent clone instead of a linked clone.
|
||||
/// A full clone is required when the source container is not a template.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public SwitchParameter Full { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Target storage pool for the full clone root filesystem.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? Storage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the clone task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public SwitchParameter Wait { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
var target = TargetNode ?? SourceNode;
|
||||
if (!ShouldProcess($"Container {VmId} on node '{SourceNode}' to new container on node '{target}'", "Copy-PveContainer"))
|
||||
return;
|
||||
|
||||
var session = GetSession();
|
||||
var containerService = new ContainerService();
|
||||
|
||||
var task = containerService.CloneContainer(
|
||||
session,
|
||||
SourceNode,
|
||||
VmId,
|
||||
NewVmId ?? 0,
|
||||
NewName,
|
||||
TargetNode,
|
||||
Full.IsPresent);
|
||||
|
||||
if (Wait.IsPresent)
|
||||
{
|
||||
var taskService = new TaskService();
|
||||
task = taskService.WaitForTask(session, task.Node ?? SourceNode, task.Upid!, null, null, null);
|
||||
}
|
||||
|
||||
WriteObject(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using PSProxmoxVE.Core.Models.Containers;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Gets one or more LXC containers from a Proxmox VE server.</para>
|
||||
/// <para type="description">
|
||||
/// Retrieves container objects from the Proxmox VE API. Results can be filtered by
|
||||
/// node, container ID, name, status, or tag.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "PveContainer")]
|
||||
[OutputType(typeof(PveContainer))]
|
||||
public sealed class GetPveContainerCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// The name of the node to query. Accepts pipeline input from a PveNode object's Name property.
|
||||
/// When omitted, containers from all nodes are returned.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
|
||||
public string? Node { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Filter results to the container with this ID.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public int? VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Filter results to containers whose name matches this value (case-insensitive, contains match).</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Filter results to containers in the specified status (e.g., "running", "stopped").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Filter results to containers that have the specified tag (substring match against the semicolon-separated tags field).</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? Tag { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
var session = GetSession();
|
||||
var service = new ContainerService();
|
||||
|
||||
IEnumerable<PveContainer> containers = service.GetContainers(session, Node);
|
||||
|
||||
if (VmId.HasValue)
|
||||
containers = containers.Where(c => c.VmId == VmId.Value);
|
||||
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
containers = containers.Where(c => c.Name != null &&
|
||||
c.Name.IndexOf(Name, System.StringComparison.OrdinalIgnoreCase) >= 0);
|
||||
|
||||
if (!string.IsNullOrEmpty(Status))
|
||||
containers = containers.Where(c => string.Equals(c.Status, Status, System.StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!string.IsNullOrEmpty(Tag))
|
||||
containers = containers.Where(c => c.Tags != null &&
|
||||
c.Tags.IndexOf(Tag, System.StringComparison.OrdinalIgnoreCase) >= 0);
|
||||
|
||||
foreach (var container in containers)
|
||||
WriteObject(container);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Management.Automation;
|
||||
using PSProxmoxVE.Core.Models.Containers;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Gets the configuration of an LXC container.</para>
|
||||
/// <para type="description">
|
||||
/// Retrieves the full configuration of the specified LXC container from the Proxmox VE API,
|
||||
/// including CPU, memory, storage, network, and metadata settings.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "PveContainerConfig")]
|
||||
[OutputType(typeof(PveContainerConfig))]
|
||||
public sealed class GetPveContainerConfigCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// The node on which the container resides. Accepts pipeline input from a PveNode object's Name property.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the container whose configuration to retrieve. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
var session = GetSession();
|
||||
var containerService = new ContainerService();
|
||||
|
||||
var config = containerService.GetContainerConfig(session, Node, VmId);
|
||||
WriteObject(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using PSProxmoxVE.Core.Models.Vms;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Creates a new LXC container on a Proxmox VE node.</para>
|
||||
/// <para type="description">
|
||||
/// Creates a new Linux container using the Proxmox VE API. An OS template is required.
|
||||
/// The container runs in unprivileged mode by default. Use -Wait to block until the
|
||||
/// creation task completes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.New, "PveContainer", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(PveTask))]
|
||||
public sealed class NewPveContainerCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="description">The node on which to create the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The container ID to assign. When omitted, the next available ID is used.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public int? VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The hostname to assign to the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? Hostname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Memory limit in MiB.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public int? Memory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Swap size in MiB.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public int? Swap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Number of CPU cores to allocate to the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public int? Cores { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Size of the root filesystem (e.g., "8G").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? RootFsSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Storage pool for the root filesystem (e.g., "local-lvm").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? RootFsStorage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// The OS template to use (e.g., "local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst").
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? OsTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Root password for the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public System.Security.SecureString? Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">SSH public keys to inject for the root user (newline-separated).</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? SshPublicKeys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// When specified (the default), the container runs in unprivileged mode.
|
||||
/// To create a privileged container, explicitly set this to $false.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public SwitchParameter Unprivileged { get; set; } = new SwitchParameter(true);
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Network interface model (e.g., "eth0").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? Network { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Network bridge to attach to (e.g., "vmbr0").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? Bridge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, starts the container after creation.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public SwitchParameter Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the creation task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public SwitchParameter Wait { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!ShouldProcess($"Container on node '{Node}'", "New-PveContainer"))
|
||||
return;
|
||||
|
||||
var session = GetSession();
|
||||
var containerService = new ContainerService();
|
||||
|
||||
var config = new Dictionary<string, object>();
|
||||
|
||||
if (VmId.HasValue)
|
||||
config["vmid"] = VmId.Value.ToString();
|
||||
if (!string.IsNullOrEmpty(Hostname))
|
||||
config["hostname"] = Hostname!;
|
||||
if (Memory.HasValue)
|
||||
config["memory"] = Memory.Value.ToString();
|
||||
if (Swap.HasValue)
|
||||
config["swap"] = Swap.Value.ToString();
|
||||
if (Cores.HasValue)
|
||||
config["cores"] = Cores.Value.ToString();
|
||||
if (!string.IsNullOrEmpty(OsTemplate))
|
||||
config["ostemplate"] = OsTemplate!;
|
||||
|
||||
if (!string.IsNullOrEmpty(RootFsStorage))
|
||||
{
|
||||
var rootFsValue = RootFsStorage!;
|
||||
if (!string.IsNullOrEmpty(RootFsSize))
|
||||
rootFsValue += $":{RootFsSize}";
|
||||
config["rootfs"] = rootFsValue;
|
||||
}
|
||||
|
||||
if (Password != null)
|
||||
{
|
||||
var ptr = Marshal.SecureStringToGlobalAllocUnicode(Password);
|
||||
try
|
||||
{
|
||||
config["password"] = Marshal.PtrToStringUni(ptr) ?? string.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.ZeroFreeGlobalAllocUnicode(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(SshPublicKeys))
|
||||
config["ssh-public-keys"] = SshPublicKeys!;
|
||||
|
||||
config["unprivileged"] = Unprivileged.IsPresent ? "1" : "0";
|
||||
|
||||
if (!string.IsNullOrEmpty(Bridge))
|
||||
{
|
||||
var ifName = string.IsNullOrEmpty(Network) ? "eth0" : Network!;
|
||||
config["net0"] = $"name={ifName},bridge={Bridge}";
|
||||
}
|
||||
|
||||
if (Start.IsPresent)
|
||||
config["start"] = "1";
|
||||
|
||||
var task = containerService.CreateContainer(session, Node, config);
|
||||
|
||||
if (Wait.IsPresent)
|
||||
{
|
||||
var taskService = new TaskService();
|
||||
task = taskService.WaitForTask(session, task.Node ?? Node, task.Upid!, null, null, null);
|
||||
}
|
||||
|
||||
WriteObject(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using System.Management.Automation;
|
||||
using PSProxmoxVE.Core.Models.Vms;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Removes an LXC container from a Proxmox VE node.</para>
|
||||
/// <para type="description">
|
||||
/// Deletes an LXC container and, optionally, all associated storage.
|
||||
/// This operation is destructive and requires confirmation unless -Force is specified.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Remove, "PveContainer",
|
||||
SupportsShouldProcess = true,
|
||||
ConfirmImpact = ConfirmImpact.High)]
|
||||
[OutputType(typeof(PveTask))]
|
||||
public sealed class RemovePveContainerCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// The node on which the container resides. Accepts pipeline input from a PveNode object's Name property.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the container to remove. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// When specified, also removes the container from HA resource configuration and replication jobs.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public SwitchParameter Purge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// When specified, bypasses locks and forces removal even if a lock is set on the container.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public SwitchParameter Force { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the removal task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public SwitchParameter Wait { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!ShouldProcess($"Container {VmId} on node '{Node}'", "Remove-PveContainer"))
|
||||
return;
|
||||
|
||||
var session = GetSession();
|
||||
var containerService = new ContainerService();
|
||||
|
||||
var task = containerService.RemoveContainer(session, Node, VmId, Purge.IsPresent);
|
||||
|
||||
if (Wait.IsPresent)
|
||||
{
|
||||
var taskService = new TaskService();
|
||||
task = taskService.WaitForTask(session, task.Node ?? Node, task.Upid!, null, null, null);
|
||||
}
|
||||
|
||||
WriteObject(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.Management.Automation;
|
||||
using PSProxmoxVE.Core.Models.Vms;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Gracefully restarts an LXC container on a Proxmox VE node.</para>
|
||||
/// <para type="description">
|
||||
/// Performs a graceful shutdown of the container followed by a start via the Proxmox VE API.
|
||||
/// A configurable timeout controls how long to wait for the container to shut down cleanly.
|
||||
/// Use -Wait to block until both tasks complete.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsLifecycle.Restart, "PveContainer", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(PveTask))]
|
||||
public sealed class RestartPveContainerCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// The node on which the container resides. Accepts pipeline input from a PveNode object's Name property.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the container to restart. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// Timeout in seconds for the graceful shutdown phase. Defaults to 60 seconds.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public int Timeout { get; set; } = 60;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for both shutdown and start tasks to complete before returning.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public SwitchParameter Wait { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!ShouldProcess($"Container {VmId} on node '{Node}'", "Restart-PveContainer"))
|
||||
return;
|
||||
|
||||
var session = GetSession();
|
||||
var containerService = new ContainerService();
|
||||
var taskService = new TaskService();
|
||||
|
||||
// Graceful shutdown
|
||||
var shutdownTask = containerService.ShutdownContainer(session, Node, VmId, Timeout);
|
||||
|
||||
if (Wait.IsPresent)
|
||||
taskService.WaitForTask(session, shutdownTask.Node ?? Node, shutdownTask.Upid!, null, null, null);
|
||||
|
||||
// Start
|
||||
var startTask = containerService.StartContainer(session, Node, VmId);
|
||||
|
||||
if (Wait.IsPresent)
|
||||
startTask = taskService.WaitForTask(session, startTask.Node ?? Node, startTask.Upid!, null, null, null);
|
||||
|
||||
WriteObject(startTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Updates the configuration of an LXC container.</para>
|
||||
/// <para type="description">
|
||||
/// Modifies one or more configuration settings of the specified LXC container via the
|
||||
/// Proxmox VE API. Only the parameters explicitly provided are changed; all other settings
|
||||
/// are left untouched.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Set, "PveContainerConfig", SupportsShouldProcess = true)]
|
||||
public sealed class SetPveContainerConfigCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// The node on which the container resides. Accepts pipeline input from a PveNode object's Name property.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the container to configure. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The hostname to assign to the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? Hostname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Number of CPU cores to allocate to the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public int? Cores { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Memory limit in MiB.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public int? Memory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Swap size in MiB.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public int? Swap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Human-readable description / notes for the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Semicolon-separated list of tags to assign to the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">DNS nameservers (space-separated).</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? Nameserver { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">DNS search domain.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public string? SearchDomain { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!ShouldProcess($"Container {VmId} on node '{Node}'", "Set-PveContainerConfig"))
|
||||
return;
|
||||
|
||||
var session = GetSession();
|
||||
var containerService = new ContainerService();
|
||||
|
||||
var config = new Dictionary<string, object>();
|
||||
|
||||
if (!string.IsNullOrEmpty(Hostname))
|
||||
config["hostname"] = Hostname!;
|
||||
if (Cores.HasValue)
|
||||
config["cores"] = Cores.Value.ToString();
|
||||
if (Memory.HasValue)
|
||||
config["memory"] = Memory.Value.ToString();
|
||||
if (Swap.HasValue)
|
||||
config["swap"] = Swap.Value.ToString();
|
||||
if (!string.IsNullOrEmpty(Description))
|
||||
config["description"] = Description!;
|
||||
if (!string.IsNullOrEmpty(Tags))
|
||||
config["tags"] = Tags!;
|
||||
if (!string.IsNullOrEmpty(Nameserver))
|
||||
config["nameserver"] = Nameserver!;
|
||||
if (!string.IsNullOrEmpty(SearchDomain))
|
||||
config["searchdomain"] = SearchDomain!;
|
||||
|
||||
containerService.SetContainerConfig(session, Node, VmId, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System.Management.Automation;
|
||||
using PSProxmoxVE.Core.Models.Vms;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Starts an LXC container on a Proxmox VE node.</para>
|
||||
/// <para type="description">
|
||||
/// Sends a start command to the specified LXC container via the Proxmox VE API.
|
||||
/// Use -Wait to block until the start task completes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsLifecycle.Start, "PveContainer", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(PveTask))]
|
||||
public sealed class StartPveContainerCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// The node on which the container resides. Accepts pipeline input from a PveNode object's Name property.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the container to start. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the start task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public SwitchParameter Wait { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!ShouldProcess($"Container {VmId} on node '{Node}'", "Start-PveContainer"))
|
||||
return;
|
||||
|
||||
var session = GetSession();
|
||||
var containerService = new ContainerService();
|
||||
|
||||
var task = containerService.StartContainer(session, Node, VmId);
|
||||
|
||||
if (Wait.IsPresent)
|
||||
{
|
||||
var taskService = new TaskService();
|
||||
task = taskService.WaitForTask(session, task.Node ?? Node, task.Upid!, null, null, null);
|
||||
}
|
||||
|
||||
WriteObject(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System.Management.Automation;
|
||||
using PSProxmoxVE.Core.Models.Vms;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Stops (powers off) an LXC container on a Proxmox VE node.</para>
|
||||
/// <para type="description">
|
||||
/// Sends a stop command to the specified LXC container via the Proxmox VE API.
|
||||
/// This immediately terminates the container without a graceful shutdown.
|
||||
/// Use Restart-PveContainer or a guest-initiated shutdown for graceful stops.
|
||||
/// Use -Wait to block until the stop task completes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsLifecycle.Stop, "PveContainer", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(PveTask))]
|
||||
public sealed class StopPveContainerCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="description">
|
||||
/// The node on which the container resides. Accepts pipeline input from a PveNode object's Name property.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the container to stop. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the stop task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
public SwitchParameter Wait { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!ShouldProcess($"Container {VmId} on node '{Node}'", "Stop-PveContainer"))
|
||||
return;
|
||||
|
||||
var session = GetSession();
|
||||
var containerService = new ContainerService();
|
||||
|
||||
var task = containerService.StopContainer(session, Node, VmId);
|
||||
|
||||
if (Wait.IsPresent)
|
||||
{
|
||||
var taskService = new TaskService();
|
||||
task = taskService.WaitForTask(session, task.Node ?? Node, task.Upid!, null, null, null);
|
||||
}
|
||||
|
||||
WriteObject(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user