Add LXC container and TurnKey template support

This commit is contained in:
Alphaeus Mote
2025-05-11 09:27:20 -04:00
parent 64c49b462d
commit 8f84140337
20 changed files with 3178 additions and 4 deletions
@@ -0,0 +1,118 @@
# Get-ProxmoxContainer
## SYNOPSIS
Gets Proxmox LXC containers.
## SYNTAX
```powershell
Get-ProxmoxContainer [[-CTID] <Int32>] [[-Node] <String>] [[-Name] <String>] [<CommonParameters>]
```
## DESCRIPTION
Gets Proxmox LXC containers from a Proxmox server.
If no parameters are specified, all containers are returned.
If a CTID is specified, only that container is returned.
If a node is specified, only containers on that node are returned.
If a name is specified, only containers with that name are returned (supports wildcards and regex).
## EXAMPLES
### Example 1: Get all containers
```powershell
Get-ProxmoxContainer
```
Gets all containers from the Proxmox server.
### Example 2: Get a specific container
```powershell
Get-ProxmoxContainer -CTID 100
```
Gets the container with CTID 100.
### Example 3: Get all containers on a specific node
```powershell
Get-ProxmoxContainer -Node "pve1"
```
Gets all containers on node pve1.
### Example 4: Get containers by name using wildcards
```powershell
Get-ProxmoxContainer -Name "web*"
```
Gets all containers with names starting with "web" (wildcard).
### Example 5: Get containers by name using regex
```powershell
Get-ProxmoxContainer -Name "^web\d+$"
```
Gets all containers with names matching the regex pattern "^web\d+$".
## PARAMETERS
### -CTID
The container ID.
```yaml
Type: Int32
Parameter Sets: (All)
Aliases:
Required: False
Position: 0
Default value: None
Accept pipeline input: True (ByValue, ByPropertyName)
Accept wildcard characters: False
```
### -Node
The node name.
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 1
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -Name
The container name (supports wildcards and regex).
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 2
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: True
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
### System.Int32
### System.String
## OUTPUTS
### PSProxmox.Models.ProxmoxContainer
## NOTES
## RELATED LINKS
@@ -0,0 +1,116 @@
# Get-ProxmoxTurnKeyTemplate
## SYNOPSIS
Gets TurnKey Linux templates for Proxmox LXC containers.
## SYNTAX
```powershell
Get-ProxmoxTurnKeyTemplate [[-Node] <String>] [[-Name] <String>] [-IncludeDownloaded] [<CommonParameters>]
```
## DESCRIPTION
Gets TurnKey Linux templates for Proxmox LXC containers from a Proxmox server.
If no parameters are specified, all templates are returned.
If a node is specified, only templates available on that node are returned.
If a name is specified, only templates with that name are returned (supports wildcards and regex).
## EXAMPLES
### Example 1: Get all TurnKey templates
```powershell
Get-ProxmoxTurnKeyTemplate
```
Gets all TurnKey Linux templates from the Proxmox server.
### Example 2: Get all TurnKey templates on a specific node
```powershell
Get-ProxmoxTurnKeyTemplate -Node "pve1"
```
Gets all TurnKey Linux templates available on node pve1.
### Example 3: Get TurnKey templates by name using wildcards
```powershell
Get-ProxmoxTurnKeyTemplate -Name "wordpress*"
```
Gets all TurnKey Linux templates with names starting with "wordpress" (wildcard).
### Example 4: Get TurnKey templates by name using regex
```powershell
Get-ProxmoxTurnKeyTemplate -Name "^wordpress\d+$"
```
Gets all TurnKey Linux templates with names matching the regex pattern "^wordpress\d+$".
### Example 5: Include downloaded templates
```powershell
Get-ProxmoxTurnKeyTemplate -IncludeDownloaded
```
Gets all TurnKey Linux templates, including those that have already been downloaded.
## PARAMETERS
### -Node
The node name.
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 0
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -Name
The template name (supports wildcards and regex).
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: 1
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: True
```
### -IncludeDownloaded
Whether to include downloaded templates.
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
### System.String
## OUTPUTS
### PSProxmox.Models.ProxmoxTurnKeyTemplate
## NOTES
## RELATED LINKS
@@ -0,0 +1,303 @@
# New-ProxmoxContainer
## SYNOPSIS
Creates a new Proxmox LXC container.
## SYNTAX
```powershell
New-ProxmoxContainer -Node <String> [-Builder <ProxmoxContainerBuilder>] [-CTID <Int32>] [-Name <String>]
[-OSTemplate <String>] [-Storage <String>] [-Memory <Int32>] [-Swap <Int32>] [-Cores <Int32>]
[-DiskSize <Int32>] [-Unprivileged] [-Password <SecureString>] [-SSHKey <String>] [-Description <String>]
[-StartOnBoot] [-Start] [<CommonParameters>]
```
## DESCRIPTION
Creates a new Proxmox LXC container on a Proxmox server.
## EXAMPLES
### Example 1: Create a new container
```powershell
New-ProxmoxContainer -Node "pve1" -Name "web-container" -OSTemplate "local:vztmpl/ubuntu-20.04-standard_20.04-1_amd64.tar.gz" -Storage "local-lvm" -Memory 512 -Swap 512 -Cores 1 -DiskSize 8
```
Creates a new LXC container on node pve1.
### Example 2: Create a new container using a builder
```powershell
$builder = New-ProxmoxContainerBuilder -Name "web-container"
$builder.WithOSTemplate("local:vztmpl/ubuntu-20.04-standard_20.04-1_amd64.tar.gz")
.WithStorage("local-lvm")
.WithMemory(512)
.WithSwap(512)
.WithCores(1)
.WithDiskSize(8)
.WithUnprivileged($true)
.WithStartOnBoot($true)
.WithStart($true)
New-ProxmoxContainer -Node "pve1" -Builder $builder
```
Creates a new LXC container on node pve1 using a builder.
## PARAMETERS
### -Node
The node name.
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: True
Position: 0
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -Builder
The container builder.
```yaml
Type: ProxmoxContainerBuilder
Parameter Sets: (All)
Aliases:
Required: False
Position: 1
Default value: None
Accept pipeline input: True (ByValue)
Accept wildcard characters: False
```
### -CTID
The container ID.
```yaml
Type: Int32
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -Name
The container name.
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -OSTemplate
The container OS template.
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -Storage
The container storage.
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -Memory
The container memory limit in MB.
```yaml
Type: Int32
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -Swap
The container swap limit in MB.
```yaml
Type: Int32
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -Cores
The container CPU cores.
```yaml
Type: Int32
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -DiskSize
The container disk size in GB.
```yaml
Type: Int32
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -Unprivileged
Whether the container is unprivileged.
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -Password
The container password.
```yaml
Type: SecureString
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -SSHKey
The container SSH public key.
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -Description
The container description.
```yaml
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -StartOnBoot
Whether to start the container on boot.
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### -Start
Whether to start the container after creation.
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
### System.String
### PSProxmox.Models.ProxmoxContainerBuilder
### System.Int32
### System.Security.SecureString
### System.Management.Automation.SwitchParameter
## OUTPUTS
### PSProxmox.Models.ProxmoxContainer
## NOTES
## RELATED LINKS
@@ -0,0 +1,79 @@
# LXC Container Management Examples
# Connect to the Proxmox server
$securePassword = ConvertTo-SecureString "password" -AsPlainText -Force
Connect-ProxmoxServer -Server "proxmox.example.com" -Username "root" -Password $securePassword -Realm "pam"
# Get all LXC containers
$containers = Get-ProxmoxContainer
$containers | Format-Table -Property CTID, Name, Status, Node
# Get a specific LXC container
$container = Get-ProxmoxContainer -CTID 100
$container
# Get all LXC containers on a specific node
$nodeContainers = Get-ProxmoxContainer -Node "pve1"
$nodeContainers | Format-Table -Property CTID, Name, Status
# Get LXC containers by name pattern (wildcard)
$webContainers = Get-ProxmoxContainer -Name "web*"
$webContainers | Format-Table -Property CTID, Name, Status, Node
# Get LXC containers by name pattern (regex)
$dbContainers = Get-ProxmoxContainer -Name "^db\d+$"
$dbContainers | Format-Table -Property CTID, Name, Status, Node
# Create a new LXC container using parameters
$container = New-ProxmoxContainer -Node "pve1" -Name "web-container" -OSTemplate "local:vztmpl/ubuntu-20.04-standard_20.04-1_amd64.tar.gz" -Storage "local-lvm" -Memory 512 -Swap 512 -Cores 1 -DiskSize 8 -Unprivileged -StartOnBoot -Start
$container
# Create a new LXC container using a builder
$builder = New-ProxmoxContainerBuilder -Name "db-container"
$builder.WithOSTemplate("local:vztmpl/ubuntu-20.04-standard_20.04-1_amd64.tar.gz")
.WithStorage("local-lvm")
.WithMemory(1024)
.WithSwap(1024)
.WithCores(2)
.WithDiskSize(16)
.WithUnprivileged($true)
.WithStartOnBoot($true)
.WithStart($true)
.WithDescription("Database container")
$container = New-ProxmoxContainer -Node "pve1" -Builder $builder
$container
# Start an LXC container
Start-ProxmoxContainer -Node "pve1" -CTID 100 -Wait
Get-ProxmoxContainer -CTID 100
# Stop an LXC container
Stop-ProxmoxContainer -Node "pve1" -CTID 100 -Wait
Get-ProxmoxContainer -CTID 100
# Restart an LXC container
Restart-ProxmoxContainer -Node "pve1" -CTID 100 -Wait
Get-ProxmoxContainer -CTID 100
# Remove an LXC container
Remove-ProxmoxContainer -Node "pve1" -CTID 100 -Confirm:$false
# Get all TurnKey Linux templates
$templates = Get-ProxmoxTurnKeyTemplate
$templates | Format-Table -Property Name, Title, OS, Version, HumanSize
# Get TurnKey Linux templates by name pattern (wildcard)
$wordpressTemplates = Get-ProxmoxTurnKeyTemplate -Name "wordpress*"
$wordpressTemplates | Format-Table -Property Name, Title, OS, Version, HumanSize
# Download a TurnKey Linux template
$templatePath = Save-ProxmoxTurnKeyTemplate -Node "pve1" -Name "wordpress" -Storage "local"
$templatePath
# Create a new LXC container from a TurnKey Linux template
$container = New-ProxmoxContainerFromTurnKey -Node "pve1" -Name "wordpress" -Template "wordpress" -Storage "local-lvm" -Memory 512 -Cores 1 -DiskSize 8 -Start
$container
# Disconnect from the Proxmox server
Disconnect-ProxmoxServer
+172
View File
@@ -0,0 +1,172 @@
# LXC Container Management Guide
This guide covers how to use PSProxmox to manage LXC containers on a Proxmox VE server.
## Overview
Proxmox VE supports Linux Containers (LXC) as a lightweight alternative to full virtual machines. LXC containers provide an isolated environment for applications with minimal overhead compared to VMs.
PSProxmox provides cmdlets for creating, managing, and removing LXC containers, as well as working with TurnKey Linux templates.
## Container Management Cmdlets
PSProxmox includes the following cmdlets for managing LXC containers:
- `Get-ProxmoxContainer`: List all LXC containers or get details for a specific container
- `New-ProxmoxContainer`: Create a new LXC container
- `New-ProxmoxContainerBuilder`: Create a builder for configuring container parameters
- `Remove-ProxmoxContainer`: Delete an LXC container
- `Start-ProxmoxContainer`: Start an LXC container
- `Stop-ProxmoxContainer`: Stop an LXC container
- `Restart-ProxmoxContainer`: Restart an LXC container
## TurnKey Template Management Cmdlets
PSProxmox also includes cmdlets for working with TurnKey Linux templates:
- `Get-ProxmoxTurnKeyTemplate`: List available TurnKey templates
- `Save-ProxmoxTurnKeyTemplate`: Download a TurnKey template to a Proxmox storage
- `New-ProxmoxContainerFromTurnKey`: Create a new LXC container from a TurnKey template
## Basic Container Operations
### Listing Containers
To list all containers on a Proxmox server:
```powershell
Get-ProxmoxContainer
```
To get a specific container by ID:
```powershell
Get-ProxmoxContainer -CTID 100
```
To get containers on a specific node:
```powershell
Get-ProxmoxContainer -Node "pve1"
```
To get containers by name pattern (supports wildcards and regex):
```powershell
# Using wildcards
Get-ProxmoxContainer -Name "web*"
# Using regex
Get-ProxmoxContainer -Name "^web\d+$"
```
### Creating Containers
To create a new container using parameters:
```powershell
New-ProxmoxContainer -Node "pve1" -Name "web-container" -OSTemplate "local:vztmpl/ubuntu-20.04-standard_20.04-1_amd64.tar.gz" -Storage "local-lvm" -Memory 512 -Swap 512 -Cores 1 -DiskSize 8 -Unprivileged -StartOnBoot -Start
```
To create a new container using a builder (for more complex configurations):
```powershell
$builder = New-ProxmoxContainerBuilder -Name "db-container"
$builder.WithOSTemplate("local:vztmpl/ubuntu-20.04-standard_20.04-1_amd64.tar.gz")
.WithStorage("local-lvm")
.WithMemory(1024)
.WithSwap(1024)
.WithCores(2)
.WithDiskSize(16)
.WithUnprivileged($true)
.WithStartOnBoot($true)
.WithStart($true)
.WithDescription("Database container")
New-ProxmoxContainer -Node "pve1" -Builder $builder
```
### Managing Container State
To start a container:
```powershell
Start-ProxmoxContainer -Node "pve1" -CTID 100 -Wait
```
To stop a container:
```powershell
Stop-ProxmoxContainer -Node "pve1" -CTID 100 -Wait
```
To restart a container:
```powershell
Restart-ProxmoxContainer -Node "pve1" -CTID 100 -Wait
```
### Removing Containers
To remove a container:
```powershell
Remove-ProxmoxContainer -Node "pve1" -CTID 100 -Confirm:$false
```
## Working with TurnKey Linux Templates
TurnKey Linux provides pre-built appliances that can be used as templates for LXC containers.
### Listing TurnKey Templates
To list all available TurnKey templates:
```powershell
Get-ProxmoxTurnKeyTemplate
```
To list templates by name pattern:
```powershell
Get-ProxmoxTurnKeyTemplate -Name "wordpress*"
```
To include templates that have already been downloaded:
```powershell
Get-ProxmoxTurnKeyTemplate -IncludeDownloaded
```
### Downloading TurnKey Templates
To download a TurnKey template to a storage:
```powershell
Save-ProxmoxTurnKeyTemplate -Node "pve1" -Name "wordpress" -Storage "local"
```
### Creating Containers from TurnKey Templates
To create a container from a TurnKey template:
```powershell
New-ProxmoxContainerFromTurnKey -Node "pve1" -Name "wordpress" -Template "wordpress" -Storage "local-lvm" -Memory 512 -Cores 1 -DiskSize 8 -Start
```
## Best Practices
1. **Use Unprivileged Containers**: For better security, create unprivileged containers when possible.
2. **Resource Allocation**: Allocate appropriate resources (memory, CPU, disk) based on the container's purpose.
3. **Storage Selection**: Choose the appropriate storage type for your containers (local-lvm is often a good choice for performance).
4. **Naming Convention**: Use a consistent naming convention for your containers to make management easier.
5. **Template Management**: Download and maintain templates on a central storage for easy access from all nodes.
## Examples
See the [LXC Container Management Examples](../examples/LXC-Container-Management.ps1) for more detailed examples.
## Related Documentation
- [Proxmox VE LXC Documentation](https://pve.proxmox.com/wiki/Linux_Container)
- [TurnKey Linux](https://www.turnkeylinux.org/)
+17 -3
View File
@@ -1,5 +1,5 @@
@{
ModuleVersion = '2025.05.10.1500'
ModuleVersion = '2025.05.10.1600'
GUID = 'd24f0894-3d0c-4ef1-a41e-b273c3db86ad'
Author = 'PSProxmox Team'
CompanyName = 'PSProxmox'
@@ -83,7 +83,21 @@
'Save-ProxmoxCloudImage',
'Invoke-ProxmoxCloudImageCustomization',
'New-ProxmoxCloudImageTemplate',
'Set-ProxmoxVMCloudInit'
'Set-ProxmoxVMCloudInit',
# LXC Container Management
'Get-ProxmoxContainer',
'New-ProxmoxContainer',
'New-ProxmoxContainerBuilder',
'Remove-ProxmoxContainer',
'Start-ProxmoxContainer',
'Stop-ProxmoxContainer',
'Restart-ProxmoxContainer',
# TurnKey Template Management
'Get-ProxmoxTurnKeyTemplate',
'Save-ProxmoxTurnKeyTemplate',
'New-ProxmoxContainerFromTurnKey'
)
VariablesToExport = @()
AliasesToExport = @()
@@ -92,7 +106,7 @@
Tags = @('Proxmox', 'VirtualMachine', 'Cluster', 'Management')
LicenseUri = 'https://github.com/Grace-Solutions/PSProxmox/blob/main/LICENSE'
ProjectUri = 'https://github.com/Grace-Solutions/PSProxmox'
ReleaseNotes = 'Added cloud image template functionality. See https://github.com/Grace-Solutions/PSProxmox/releases/tag/v2025.05.10.1500'
ReleaseNotes = 'Added LXC container and TurnKey template support. See https://github.com/Grace-Solutions/PSProxmox/releases/tag/v2025.05.10.1600'
}
}
}
@@ -0,0 +1,223 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq;
using PSProxmox.Models;
using PSProxmox.Session;
namespace PSProxmox.Cmdlets
{
/// <summary>
/// <para type="synopsis">Gets Proxmox LXC containers</para>
/// <para type="description">Gets Proxmox LXC containers from a Proxmox server</para>
/// <para type="description">If no parameters are specified, all containers are returned</para>
/// <para type="description">If a CTID is specified, only that container is returned</para>
/// <para type="description">If a node is specified, only containers on that node are returned</para>
/// <para type="description">If a name is specified, only containers with that name are returned (supports wildcards and regex)</para>
/// </summary>
/// <example>
/// <code>Get-ProxmoxContainer</code>
/// <para>Gets all containers from the Proxmox server</para>
/// </example>
/// <example>
/// <code>Get-ProxmoxContainer -CTID 100</code>
/// <para>Gets the container with CTID 100</para>
/// </example>
/// <example>
/// <code>Get-ProxmoxContainer -Node "pve1"</code>
/// <para>Gets all containers on node pve1</para>
/// </example>
/// <example>
/// <code>Get-ProxmoxContainer -Name "web*"</code>
/// <para>Gets all containers with names starting with "web" (wildcard)</para>
/// </example>
/// <example>
/// <code>Get-ProxmoxContainer -Name "^web\d+$"</code>
/// <para>Gets all containers with names matching the regex pattern "^web\d+$"</para>
/// </example>
[Cmdlet(VerbsCommon.Get, "ProxmoxContainer")]
[OutputType(typeof(ProxmoxContainer))]
public class GetProxmoxContainerCmdlet : ProxmoxCmdlet
{
/// <summary>
/// Gets or sets the container ID
/// </summary>
[Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
public int? CTID { get; set; }
/// <summary>
/// Gets or sets the node name
/// </summary>
[Parameter(Position = 1, ValueFromPipelineByPropertyName = true)]
public string Node { get; set; }
/// <summary>
/// Gets or sets the container name (supports wildcards and regex)
/// </summary>
[Parameter(Position = 2, ValueFromPipelineByPropertyName = true)]
public string Name { get; set; }
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
{
base.ProcessRecord();
try
{
if (CTID.HasValue && !string.IsNullOrEmpty(Node))
{
// Get a specific container on a specific node
var container = GetContainer(Node, CTID.Value);
if (container != null)
{
WriteObject(container);
}
}
else if (CTID.HasValue)
{
// Get a specific container on any node
var nodes = GetNodes();
foreach (var node in nodes)
{
var container = GetContainer(node.Name, CTID.Value);
if (container != null)
{
WriteObject(container);
break;
}
}
}
else if (!string.IsNullOrEmpty(Node))
{
// Get all containers on a specific node
var containers = GetContainers(Node);
// Filter by name if specified
if (!string.IsNullOrEmpty(Name))
{
containers = FilterContainersByName(containers, Name);
}
WriteObject(containers, true);
}
else
{
// Get all containers on all nodes
var nodes = GetNodes();
var allContainers = new List<ProxmoxContainer>();
foreach (var node in nodes)
{
var containers = GetContainers(node.Name);
allContainers.AddRange(containers);
}
// Filter by name if specified
if (!string.IsNullOrEmpty(Name))
{
allContainers = FilterContainersByName(allContainers, Name);
}
WriteObject(allContainers, true);
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "GetProxmoxContainerError", ErrorCategory.OperationStopped, null));
}
}
private List<ProxmoxNode> GetNodes()
{
var response = Connection.GetJson("/nodes");
var data = response["data"];
var nodes = new List<ProxmoxNode>();
foreach (var item in data)
{
var node = item.ToObject<ProxmoxNode>();
nodes.Add(node);
}
return nodes;
}
private List<ProxmoxContainer> GetContainers(string node)
{
var response = Connection.GetJson($"/nodes/{node}/lxc");
var data = response["data"];
var containers = new List<ProxmoxContainer>();
foreach (var item in data)
{
var container = item.ToObject<ProxmoxContainer>();
container.Node = node;
containers.Add(container);
}
return containers;
}
private ProxmoxContainer GetContainer(string node, int ctid)
{
try
{
var response = Connection.GetJson($"/nodes/{node}/lxc/{ctid}/status/current");
var data = response["data"];
var container = data.ToObject<ProxmoxContainer>();
container.Node = node;
container.CTID = ctid;
// Get additional configuration
var configResponse = Connection.GetJson($"/nodes/{node}/lxc/{ctid}/config");
var configData = configResponse["data"];
container.Config = configData.ToObject<Dictionary<string, object>>();
return container;
}
catch (Exception)
{
// Container not found on this node
return null;
}
}
private List<ProxmoxContainer> FilterContainersByName(List<ProxmoxContainer> containers, string namePattern)
{
// Check if the pattern is a regex
if (IsRegexPattern(namePattern))
{
var regex = new Regex(namePattern);
return containers.Where(c => regex.IsMatch(c.Name)).ToList();
}
// Otherwise, treat it as a wildcard pattern
return containers.Where(c => IsWildcardMatch(c.Name, namePattern)).ToList();
}
private bool IsRegexPattern(string pattern)
{
// Simple heuristic: if the pattern contains regex-specific characters, treat it as regex
return pattern.StartsWith("^") || pattern.EndsWith("$") ||
pattern.Contains("(") || pattern.Contains(")") ||
pattern.Contains("[") || pattern.Contains("]") ||
pattern.Contains("\\");
}
private bool IsWildcardMatch(string input, string pattern)
{
// Convert wildcard pattern to regex
string regexPattern = "^" + Regex.Escape(pattern)
.Replace("\\*", ".*")
.Replace("\\?", ".") + "$";
return Regex.IsMatch(input, regexPattern, RegexOptions.IgnoreCase);
}
}
}
@@ -0,0 +1,242 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq;
using PSProxmox.Models;
using PSProxmox.Session;
namespace PSProxmox.Cmdlets
{
/// <summary>
/// <para type="synopsis">Gets TurnKey Linux templates for Proxmox LXC containers</para>
/// <para type="description">Gets TurnKey Linux templates for Proxmox LXC containers from a Proxmox server</para>
/// <para type="description">If no parameters are specified, all templates are returned</para>
/// <para type="description">If a node is specified, only templates available on that node are returned</para>
/// <para type="description">If a name is specified, only templates with that name are returned (supports wildcards and regex)</para>
/// </summary>
/// <example>
/// <code>Get-ProxmoxTurnKeyTemplate</code>
/// <para>Gets all TurnKey Linux templates from the Proxmox server</para>
/// </example>
/// <example>
/// <code>Get-ProxmoxTurnKeyTemplate -Node "pve1"</code>
/// <para>Gets all TurnKey Linux templates available on node pve1</para>
/// </example>
/// <example>
/// <code>Get-ProxmoxTurnKeyTemplate -Name "wordpress*"</code>
/// <para>Gets all TurnKey Linux templates with names starting with "wordpress" (wildcard)</para>
/// </example>
/// <example>
/// <code>Get-ProxmoxTurnKeyTemplate -Name "^wordpress\d+$"</code>
/// <para>Gets all TurnKey Linux templates with names matching the regex pattern "^wordpress\d+$"</para>
/// </example>
[Cmdlet(VerbsCommon.Get, "ProxmoxTurnKeyTemplate")]
[OutputType(typeof(ProxmoxTurnKeyTemplate))]
public class GetProxmoxTurnKeyTemplateCmdlet : ProxmoxCmdlet
{
/// <summary>
/// Gets or sets the node name
/// </summary>
[Parameter(Position = 0, ValueFromPipelineByPropertyName = true)]
public string Node { get; set; }
/// <summary>
/// Gets or sets the template name (supports wildcards and regex)
/// </summary>
[Parameter(Position = 1, ValueFromPipelineByPropertyName = true)]
public string Name { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to include downloaded templates
/// </summary>
[Parameter(Mandatory = false)]
public SwitchParameter IncludeDownloaded { get; set; }
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
{
base.ProcessRecord();
try
{
if (string.IsNullOrEmpty(Node))
{
// Get all nodes
var nodes = GetNodes();
var allTemplates = new List<ProxmoxTurnKeyTemplate>();
foreach (var node in nodes)
{
var templates = GetTemplates(node.Name);
allTemplates.AddRange(templates);
}
// Remove duplicates
allTemplates = allTemplates.GroupBy(t => t.Name).Select(g => g.First()).ToList();
// Filter by name if specified
if (!string.IsNullOrEmpty(Name))
{
allTemplates = FilterTemplatesByName(allTemplates, Name);
}
WriteObject(allTemplates, true);
}
else
{
// Get templates for the specified node
var templates = GetTemplates(Node);
// Filter by name if specified
if (!string.IsNullOrEmpty(Name))
{
templates = FilterTemplatesByName(templates, Name);
}
WriteObject(templates, true);
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "GetProxmoxTurnKeyTemplateError", ErrorCategory.OperationStopped, null));
}
}
private List<ProxmoxNode> GetNodes()
{
var response = Connection.GetJson("/nodes");
var data = response["data"];
var nodes = new List<ProxmoxNode>();
foreach (var item in data)
{
var node = item.ToObject<ProxmoxNode>();
nodes.Add(node);
}
return nodes;
}
private List<ProxmoxTurnKeyTemplate> GetTemplates(string node)
{
var templates = new List<ProxmoxTurnKeyTemplate>();
try
{
// Get available templates from the appliance info
var response = Connection.GetJson($"/nodes/{node}/aplinfo");
var data = response["data"];
foreach (var item in data)
{
// Only include TurnKey templates
if (item["package"] != null && item["package"].ToString().Contains("turnkey"))
{
var template = item.ToObject<ProxmoxTurnKeyTemplate>();
templates.Add(template);
}
}
// Get downloaded templates if requested
if (IncludeDownloaded.IsPresent)
{
var storages = GetStorages(node);
foreach (var storage in storages)
{
try
{
var contentResponse = Connection.GetJson($"/nodes/{node}/storage/{storage.Storage}/content");
var contentData = contentResponse["data"];
foreach (var item in contentData)
{
if (item["content"] != null && item["content"].ToString() == "vztmpl" &&
item["volid"] != null && item["volid"].ToString().Contains("turnkey"))
{
var volid = item["volid"].ToString();
var name = System.IO.Path.GetFileNameWithoutExtension(volid.Split('/').Last());
// Check if this template is already in the list
if (!templates.Any(t => t.Name == name))
{
var template = new ProxmoxTurnKeyTemplate
{
Name = name,
Title = name,
Description = "Downloaded template",
Source = storage.Storage,
Location = volid
};
templates.Add(template);
}
}
}
}
catch (Exception)
{
// Skip this storage if there's an error
}
}
}
}
catch (Exception)
{
// Skip this node if there's an error
}
return templates;
}
private List<ProxmoxStorage> GetStorages(string node)
{
var response = Connection.GetJson($"/nodes/{node}/storage");
var data = response["data"];
var storages = new List<ProxmoxStorage>();
foreach (var item in data)
{
var storage = item.ToObject<ProxmoxStorage>();
storages.Add(storage);
}
return storages;
}
private List<ProxmoxTurnKeyTemplate> FilterTemplatesByName(List<ProxmoxTurnKeyTemplate> templates, string namePattern)
{
// Check if the pattern is a regex
if (IsRegexPattern(namePattern))
{
var regex = new Regex(namePattern);
return templates.Where(t => regex.IsMatch(t.Name)).ToList();
}
// Otherwise, treat it as a wildcard pattern
return templates.Where(t => IsWildcardMatch(t.Name, namePattern)).ToList();
}
private bool IsRegexPattern(string pattern)
{
// Simple heuristic: if the pattern contains regex-specific characters, treat it as regex
return pattern.StartsWith("^") || pattern.EndsWith("$") ||
pattern.Contains("(") || pattern.Contains(")") ||
pattern.Contains("[") || pattern.Contains("]") ||
pattern.Contains("\\");
}
private bool IsWildcardMatch(string input, string pattern)
{
// Convert wildcard pattern to regex
string regexPattern = "^" + Regex.Escape(pattern)
.Replace("\\*", ".*")
.Replace("\\?", ".") + "$";
return Regex.IsMatch(input, regexPattern, RegexOptions.IgnoreCase);
}
}
}
@@ -0,0 +1,43 @@
using System.Management.Automation;
using PSProxmox.Models;
namespace PSProxmox.Cmdlets
{
/// <summary>
/// <para type="synopsis">Creates a new Proxmox container builder</para>
/// <para type="description">Creates a new Proxmox container builder for creating LXC containers</para>
/// </summary>
/// <example>
/// <code>$builder = New-ProxmoxContainerBuilder -Name "web-container"
/// $builder.WithOSTemplate("local:vztmpl/ubuntu-20.04-standard_20.04-1_amd64.tar.gz")
/// .WithStorage("local-lvm")
/// .WithMemory(512)
/// .WithSwap(512)
/// .WithCores(1)
/// .WithDiskSize(8)
/// .WithUnprivileged($true)
/// .WithStartOnBoot($true)
/// .WithStart($true)
/// New-ProxmoxContainer -Node "pve1" -Builder $builder</code>
/// <para>Creates a new container builder and uses it to create a container</para>
/// </example>
[Cmdlet(VerbsCommon.New, "ProxmoxContainerBuilder")]
[OutputType(typeof(ProxmoxContainerBuilder))]
public class NewProxmoxContainerBuilderCmdlet : PSCmdlet
{
/// <summary>
/// Gets or sets the container name
/// </summary>
[Parameter(Mandatory = true, Position = 0)]
public string Name { get; set; }
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
{
var builder = new ProxmoxContainerBuilder(Name);
WriteObject(builder);
}
}
}
@@ -0,0 +1,298 @@
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Security;
using PSProxmox.Models;
using PSProxmox.Session;
namespace PSProxmox.Cmdlets
{
/// <summary>
/// <para type="synopsis">Creates a new Proxmox LXC container</para>
/// <para type="description">Creates a new Proxmox LXC container on a Proxmox server</para>
/// </summary>
/// <example>
/// <code>New-ProxmoxContainer -Node "pve1" -Name "web-container" -OSTemplate "local:vztmpl/ubuntu-20.04-standard_20.04-1_amd64.tar.gz" -Storage "local-lvm" -Memory 512 -Swap 512 -Cores 1 -DiskSize 8</code>
/// <para>Creates a new LXC container on node pve1</para>
/// </example>
/// <example>
/// <code>$builder = New-ProxmoxContainerBuilder -Name "web-container"
/// $builder.WithOSTemplate("local:vztmpl/ubuntu-20.04-standard_20.04-1_amd64.tar.gz")
/// .WithStorage("local-lvm")
/// .WithMemory(512)
/// .WithSwap(512)
/// .WithCores(1)
/// .WithDiskSize(8)
/// .WithUnprivileged($true)
/// .WithStartOnBoot($true)
/// .WithStart($true)
/// New-ProxmoxContainer -Node "pve1" -Builder $builder</code>
/// <para>Creates a new LXC container on node pve1 using a builder</para>
/// </example>
[Cmdlet(VerbsCommon.New, "ProxmoxContainer")]
[OutputType(typeof(ProxmoxContainer))]
public class NewProxmoxContainerCmdlet : ProxmoxCmdlet
{
/// <summary>
/// Gets or sets the node name
/// </summary>
[Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
public string Node { get; set; }
/// <summary>
/// Gets or sets the container builder
/// </summary>
[Parameter(Mandatory = false, Position = 1, ValueFromPipeline = true)]
public ProxmoxContainerBuilder Builder { get; set; }
/// <summary>
/// Gets or sets the container ID
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public int? CTID { get; set; }
/// <summary>
/// Gets or sets the container name
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public string Name { get; set; }
/// <summary>
/// Gets or sets the container OS template
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public string OSTemplate { get; set; }
/// <summary>
/// Gets or sets the container storage
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public string Storage { get; set; }
/// <summary>
/// Gets or sets the container memory limit in MB
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public int? Memory { get; set; }
/// <summary>
/// Gets or sets the container swap limit in MB
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public int? Swap { get; set; }
/// <summary>
/// Gets or sets the container CPU cores
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public int? Cores { get; set; }
/// <summary>
/// Gets or sets the container disk size in GB
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public int? DiskSize { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the container is unprivileged
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public SwitchParameter Unprivileged { get; set; }
/// <summary>
/// Gets or sets the container password
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public SecureString Password { get; set; }
/// <summary>
/// Gets or sets the container SSH public key
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public string SSHKey { get; set; }
/// <summary>
/// Gets or sets the container description
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public string Description { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to start the container on boot
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public SwitchParameter StartOnBoot { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to start the container after creation
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public SwitchParameter Start { get; set; }
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
{
base.ProcessRecord();
try
{
Dictionary<string, object> parameters;
if (Builder != null)
{
// Use the builder parameters
parameters = Builder.Parameters;
}
else
{
// Build parameters from individual properties
parameters = new Dictionary<string, object>();
if (!string.IsNullOrEmpty(Name))
{
parameters["hostname"] = Name;
}
if (!string.IsNullOrEmpty(OSTemplate))
{
parameters["ostemplate"] = OSTemplate;
}
if (!string.IsNullOrEmpty(Storage))
{
parameters["storage"] = Storage;
}
if (Memory.HasValue)
{
parameters["memory"] = Memory.Value;
}
if (Swap.HasValue)
{
parameters["swap"] = Swap.Value;
}
if (Cores.HasValue)
{
parameters["cores"] = Cores.Value;
}
if (DiskSize.HasValue && !string.IsNullOrEmpty(Storage))
{
parameters["rootfs"] = $"{Storage}:{DiskSize.Value}";
}
if (Unprivileged.IsPresent)
{
parameters["unprivileged"] = 1;
}
if (Password != null)
{
parameters["password"] = ConvertSecureStringToString(Password);
}
if (!string.IsNullOrEmpty(SSHKey))
{
parameters["ssh-public-keys"] = SSHKey;
}
if (!string.IsNullOrEmpty(Description))
{
parameters["description"] = Description;
}
if (StartOnBoot.IsPresent)
{
parameters["onboot"] = 1;
}
if (Start.IsPresent)
{
parameters["start"] = 1;
}
}
// Add CTID if specified
if (CTID.HasValue)
{
parameters["vmid"] = CTID.Value;
}
// Create the container
var response = Connection.PostJson($"/nodes/{Node}/lxc", parameters);
var data = response["data"];
var ctid = (int)data["vmid"];
// Wait for the task to complete
var taskId = (string)data["upid"];
var taskStatus = WaitForTask(Node, taskId);
if (taskStatus != "OK")
{
throw new Exception($"Failed to create container: {taskStatus}");
}
// Get the created container
var container = GetContainer(Node, ctid);
WriteObject(container);
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "NewProxmoxContainerError", ErrorCategory.OperationStopped, null));
}
}
private string WaitForTask(string node, string taskId)
{
var status = "";
var attempts = 0;
var maxAttempts = 60; // Wait up to 60 seconds
while (attempts < maxAttempts)
{
var response = Connection.GetJson($"/nodes/{node}/tasks/{taskId}/status");
var data = response["data"];
status = (string)data["status"];
if (status == "stopped")
{
return (string)data["exitstatus"];
}
System.Threading.Thread.Sleep(1000);
attempts++;
}
throw new Exception("Timeout waiting for task to complete");
}
private ProxmoxContainer GetContainer(string node, int ctid)
{
var response = Connection.GetJson($"/nodes/{node}/lxc/{ctid}/status/current");
var data = response["data"];
var container = data.ToObject<ProxmoxContainer>();
container.Node = node;
container.CTID = ctid;
return container;
}
private string ConvertSecureStringToString(SecureString secureString)
{
var ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(secureString);
try
{
return System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
}
}
}
}
@@ -0,0 +1,277 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Security;
using PSProxmox.Models;
using PSProxmox.Session;
namespace PSProxmox.Cmdlets
{
/// <summary>
/// <para type="synopsis">Creates a new Proxmox LXC container from a TurnKey Linux template</para>
/// <para type="description">Creates a new Proxmox LXC container from a TurnKey Linux template on a Proxmox server</para>
/// </summary>
/// <example>
/// <code>New-ProxmoxContainerFromTurnKey -Node "pve1" -Name "wordpress" -Template "wordpress" -Storage "local-lvm" -Memory 512 -Cores 1 -DiskSize 8</code>
/// <para>Creates a new LXC container from the WordPress TurnKey Linux template on node pve1</para>
/// </example>
[Cmdlet(VerbsCommon.New, "ProxmoxContainerFromTurnKey")]
[OutputType(typeof(ProxmoxContainer))]
public class NewProxmoxContainerFromTurnKeyCmdlet : ProxmoxCmdlet
{
/// <summary>
/// Gets or sets the node name
/// </summary>
[Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
public string Node { get; set; }
/// <summary>
/// Gets or sets the container name
/// </summary>
[Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
public string Name { get; set; }
/// <summary>
/// Gets or sets the TurnKey template name
/// </summary>
[Parameter(Mandatory = true, Position = 2, ValueFromPipelineByPropertyName = true)]
public string Template { get; set; }
/// <summary>
/// Gets or sets the container ID
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public int? CTID { get; set; }
/// <summary>
/// Gets or sets the storage name
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public string Storage { get; set; } = "local";
/// <summary>
/// Gets or sets the container memory limit in MB
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public int Memory { get; set; } = 512;
/// <summary>
/// Gets or sets the container swap limit in MB
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public int Swap { get; set; } = 512;
/// <summary>
/// Gets or sets the container CPU cores
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public int Cores { get; set; } = 1;
/// <summary>
/// Gets or sets the container disk size in GB
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public int DiskSize { get; set; } = 8;
/// <summary>
/// Gets or sets a value indicating whether the container is unprivileged
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public SwitchParameter Unprivileged { get; set; }
/// <summary>
/// Gets or sets the container password
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public SecureString Password { get; set; }
/// <summary>
/// Gets or sets the container SSH public key
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public string SSHKey { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to start the container on boot
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public SwitchParameter StartOnBoot { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to start the container after creation
/// </summary>
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public SwitchParameter Start { get; set; }
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
{
base.ProcessRecord();
try
{
// Get the template
var templatePath = GetTemplatePath(Node, Template, Storage);
if (string.IsNullOrEmpty(templatePath))
{
// Try to download the template
WriteVerbose($"Template '{Template}' not found, attempting to download...");
var downloadCmdlet = new SaveProxmoxTurnKeyTemplateCmdlet
{
Connection = Connection,
Node = Node,
Name = Template,
Storage = Storage
};
var result = InvokeCommand.InvokeScript(false, ScriptBlock.Create("param($cmdlet) & { $cmdlet.ProcessRecord(); return $cmdlet.CommandRuntime.ToString() }"), null, downloadCmdlet).FirstOrDefault();
templatePath = result?.ToString();
if (string.IsNullOrEmpty(templatePath))
{
throw new Exception($"Failed to download template '{Template}'");
}
}
// Create the container
var parameters = new Dictionary<string, object>
{
{ "hostname", Name },
{ "ostemplate", templatePath },
{ "storage", Storage },
{ "memory", Memory },
{ "swap", Swap },
{ "cores", Cores },
{ "rootfs", $"{Storage}:{DiskSize}" }
};
if (CTID.HasValue)
{
parameters["vmid"] = CTID.Value;
}
if (Unprivileged.IsPresent)
{
parameters["unprivileged"] = 1;
}
if (Password != null)
{
parameters["password"] = ConvertSecureStringToString(Password);
}
if (!string.IsNullOrEmpty(SSHKey))
{
parameters["ssh-public-keys"] = SSHKey;
}
if (StartOnBoot.IsPresent)
{
parameters["onboot"] = 1;
}
if (Start.IsPresent)
{
parameters["start"] = 1;
}
var response = Connection.PostJson($"/nodes/{Node}/lxc", parameters);
var data = response["data"];
var ctid = (int)data["vmid"];
// Wait for the task to complete
var taskId = (string)data["upid"];
var taskStatus = WaitForTask(Node, taskId);
if (taskStatus != "OK")
{
throw new Exception($"Failed to create container: {taskStatus}");
}
// Get the created container
var container = GetContainer(Node, ctid);
WriteObject(container);
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "NewProxmoxContainerFromTurnKeyError", ErrorCategory.OperationStopped, null));
}
}
private string GetTemplatePath(string node, string templateName, string storage)
{
try
{
var response = Connection.GetJson($"/nodes/{node}/storage/{storage}/content");
var data = response["data"];
foreach (var item in data)
{
if (item["content"] != null && item["content"].ToString() == "vztmpl" &&
item["volid"] != null && item["volid"].ToString().Contains(templateName))
{
return item["volid"].ToString();
}
}
}
catch (Exception)
{
// Ignore errors and return null
}
return null;
}
private string WaitForTask(string node, string taskId)
{
var status = "";
var attempts = 0;
var maxAttempts = 60; // Wait up to 60 seconds
while (attempts < maxAttempts)
{
var response = Connection.GetJson($"/nodes/{node}/tasks/{taskId}/status");
var data = response["data"];
status = (string)data["status"];
if (status == "stopped")
{
return (string)data["exitstatus"];
}
System.Threading.Thread.Sleep(1000);
attempts++;
}
throw new Exception("Timeout waiting for task to complete");
}
private ProxmoxContainer GetContainer(string node, int ctid)
{
var response = Connection.GetJson($"/nodes/{node}/lxc/{ctid}/status/current");
var data = response["data"];
var container = data.ToObject<ProxmoxContainer>();
container.Node = node;
container.CTID = ctid;
return container;
}
private string ConvertSecureStringToString(SecureString secureString)
{
var ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(secureString);
try
{
return System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
}
}
}
}
@@ -0,0 +1,101 @@
using System;
using System.Management.Automation;
using PSProxmox.Session;
namespace PSProxmox.Cmdlets
{
/// <summary>
/// <para type="synopsis">Removes a Proxmox LXC container</para>
/// <para type="description">Removes a Proxmox LXC container from a Proxmox server</para>
/// </summary>
/// <example>
/// <code>Remove-ProxmoxContainer -Node "pve1" -CTID 100</code>
/// <para>Removes the container with CTID 100 from node pve1</para>
/// </example>
/// <example>
/// <code>Remove-ProxmoxContainer -Node "pve1" -CTID 100 -Confirm:$false</code>
/// <para>Removes the container with CTID 100 from node pve1 without confirmation</para>
/// </example>
[Cmdlet(VerbsCommon.Remove, "ProxmoxContainer", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
public class RemoveProxmoxContainerCmdlet : ProxmoxCmdlet
{
/// <summary>
/// Gets or sets the node name
/// </summary>
[Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
public string Node { get; set; }
/// <summary>
/// Gets or sets the container ID
/// </summary>
[Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
public int CTID { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to force removal
/// </summary>
[Parameter(Mandatory = false)]
public SwitchParameter Force { get; set; }
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
{
base.ProcessRecord();
try
{
if (ShouldProcess($"Container {CTID} on node {Node}", "Remove"))
{
var parameters = new System.Collections.Generic.Dictionary<string, object>();
if (Force.IsPresent)
{
parameters["force"] = 1;
}
var response = Connection.DeleteJson($"/nodes/{Node}/lxc/{CTID}", parameters);
var data = response["data"];
var taskId = (string)data["upid"];
var taskStatus = WaitForTask(Node, taskId);
if (taskStatus != "OK")
{
throw new Exception($"Failed to remove container: {taskStatus}");
}
WriteVerbose($"Container {CTID} on node {Node} removed successfully");
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "RemoveProxmoxContainerError", ErrorCategory.OperationStopped, null));
}
}
private string WaitForTask(string node, string taskId)
{
var status = "";
var attempts = 0;
var maxAttempts = 60; // Wait up to 60 seconds
while (attempts < maxAttempts)
{
var response = Connection.GetJson($"/nodes/{node}/tasks/{taskId}/status");
var data = response["data"];
status = (string)data["status"];
if (status == "stopped")
{
return (string)data["exitstatus"];
}
System.Threading.Thread.Sleep(1000);
attempts++;
}
throw new Exception("Timeout waiting for task to complete");
}
}
}
@@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PSProxmox.Models;
using PSProxmox.Session;
namespace PSProxmox.Cmdlets
{
/// <summary>
/// <para type="synopsis">Restarts a Proxmox LXC container</para>
/// <para type="description">Restarts a Proxmox LXC container on a Proxmox server</para>
/// </summary>
/// <example>
/// <code>Restart-ProxmoxContainer -Node "pve1" -CTID 100</code>
/// <para>Restarts the container with CTID 100 on node pve1</para>
/// </example>
[Cmdlet(VerbsLifecycle.Restart, "ProxmoxContainer")]
[OutputType(typeof(ProxmoxContainer))]
public class RestartProxmoxContainerCmdlet : ProxmoxCmdlet
{
/// <summary>
/// Gets or sets the node name
/// </summary>
[Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
public string Node { get; set; }
/// <summary>
/// Gets or sets the container ID
/// </summary>
[Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
public int CTID { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to wait for the container to restart
/// </summary>
[Parameter(Mandatory = false)]
public SwitchParameter Wait { get; set; }
/// <summary>
/// Gets or sets the timeout in seconds
/// </summary>
[Parameter(Mandatory = false)]
public int Timeout { get; set; } = 60;
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
{
base.ProcessRecord();
try
{
var parameters = new Dictionary<string, object>();
if (Timeout > 0)
{
parameters["timeout"] = Timeout;
}
var response = Connection.PostJson($"/nodes/{Node}/lxc/{CTID}/status/restart", parameters);
var data = response["data"];
var taskId = (string)data["upid"];
if (Wait.IsPresent)
{
var taskStatus = WaitForTask(Node, taskId);
if (taskStatus != "OK")
{
throw new Exception($"Failed to restart container: {taskStatus}");
}
// Get the container status
var container = GetContainer(Node, CTID);
WriteObject(container);
}
else
{
WriteVerbose($"Container {CTID} on node {Node} restart initiated");
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "RestartProxmoxContainerError", ErrorCategory.OperationStopped, null));
}
}
private string WaitForTask(string node, string taskId)
{
var status = "";
var attempts = 0;
var maxAttempts = Timeout > 0 ? Timeout : 60;
while (attempts < maxAttempts)
{
var response = Connection.GetJson($"/nodes/{node}/tasks/{taskId}/status");
var data = response["data"];
status = (string)data["status"];
if (status == "stopped")
{
return (string)data["exitstatus"];
}
System.Threading.Thread.Sleep(1000);
attempts++;
}
throw new Exception("Timeout waiting for task to complete");
}
private ProxmoxContainer GetContainer(string node, int ctid)
{
var response = Connection.GetJson($"/nodes/{node}/lxc/{ctid}/status/current");
var data = response["data"];
var container = data.ToObject<ProxmoxContainer>();
container.Node = node;
container.CTID = ctid;
return container;
}
}
}
@@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using PSProxmox.Models;
using PSProxmox.Session;
namespace PSProxmox.Cmdlets
{
/// <summary>
/// <para type="synopsis">Downloads a TurnKey Linux template to a Proxmox server</para>
/// <para type="description">Downloads a TurnKey Linux template to a Proxmox server for use with LXC containers</para>
/// </summary>
/// <example>
/// <code>Save-ProxmoxTurnKeyTemplate -Node "pve1" -Name "wordpress" -Storage "local"</code>
/// <para>Downloads the WordPress TurnKey Linux template to the local storage on node pve1</para>
/// </example>
[Cmdlet(VerbsData.Save, "ProxmoxTurnKeyTemplate")]
[OutputType(typeof(string))]
public class SaveProxmoxTurnKeyTemplateCmdlet : ProxmoxCmdlet
{
/// <summary>
/// Gets or sets the node name
/// </summary>
[Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
public string Node { get; set; }
/// <summary>
/// Gets or sets the template name
/// </summary>
[Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
public string Name { get; set; }
/// <summary>
/// Gets or sets the storage name
/// </summary>
[Parameter(Mandatory = true, Position = 2, ValueFromPipelineByPropertyName = true)]
public string Storage { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to force download even if the template already exists
/// </summary>
[Parameter(Mandatory = false)]
public SwitchParameter Force { get; set; }
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
{
base.ProcessRecord();
try
{
// Get the template information
var templates = GetTemplates(Node);
var template = templates.FirstOrDefault(t => t.Name.Equals(Name, StringComparison.OrdinalIgnoreCase));
if (template == null)
{
throw new Exception($"Template '{Name}' not found");
}
// Check if the template is already downloaded
if (!Force.IsPresent)
{
var existingTemplates = GetDownloadedTemplates(Node, Storage);
var existingTemplate = existingTemplates.FirstOrDefault(t => t.Contains(template.Name));
if (existingTemplate != null)
{
WriteVerbose($"Template '{Name}' already exists at '{existingTemplate}'");
WriteObject(existingTemplate);
return;
}
}
// Download the template
var parameters = new Dictionary<string, object>
{
{ "template", template.URL },
{ "storage", Storage }
};
var response = Connection.PostJson($"/nodes/{Node}/aplinfo", parameters);
var data = response["data"];
var taskId = (string)data["upid"];
var taskStatus = WaitForTask(Node, taskId);
if (taskStatus != "OK")
{
throw new Exception($"Failed to download template: {taskStatus}");
}
// Get the downloaded template path
var downloadedTemplates = GetDownloadedTemplates(Node, Storage);
var downloadedTemplate = downloadedTemplates.FirstOrDefault(t => t.Contains(template.Name));
if (downloadedTemplate == null)
{
throw new Exception($"Failed to find downloaded template '{Name}'");
}
WriteVerbose($"Template '{Name}' downloaded to '{downloadedTemplate}'");
WriteObject(downloadedTemplate);
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "SaveProxmoxTurnKeyTemplateError", ErrorCategory.OperationStopped, null));
}
}
private List<ProxmoxTurnKeyTemplate> GetTemplates(string node)
{
var templates = new List<ProxmoxTurnKeyTemplate>();
try
{
// Get available templates from the appliance info
var response = Connection.GetJson($"/nodes/{node}/aplinfo");
var data = response["data"];
foreach (var item in data)
{
// Only include TurnKey templates
if (item["package"] != null && item["package"].ToString().Contains("turnkey"))
{
var template = item.ToObject<ProxmoxTurnKeyTemplate>();
templates.Add(template);
}
}
}
catch (Exception ex)
{
throw new Exception($"Failed to get templates: {ex.Message}");
}
return templates;
}
private List<string> GetDownloadedTemplates(string node, string storage)
{
var templates = new List<string>();
try
{
var response = Connection.GetJson($"/nodes/{node}/storage/{storage}/content");
var data = response["data"];
foreach (var item in data)
{
if (item["content"] != null && item["content"].ToString() == "vztmpl" &&
item["volid"] != null && item["volid"].ToString().Contains("turnkey"))
{
templates.Add(item["volid"].ToString());
}
}
}
catch (Exception ex)
{
throw new Exception($"Failed to get downloaded templates: {ex.Message}");
}
return templates;
}
private string WaitForTask(string node, string taskId)
{
var status = "";
var attempts = 0;
var maxAttempts = 300; // Wait up to 5 minutes
while (attempts < maxAttempts)
{
var response = Connection.GetJson($"/nodes/{node}/tasks/{taskId}/status");
var data = response["data"];
status = (string)data["status"];
if (status == "stopped")
{
return (string)data["exitstatus"];
}
// Show progress
if (data["pid"] != null)
{
var progressResponse = Connection.GetJson($"/nodes/{node}/tasks/{taskId}/log?start=0");
var progressData = progressResponse["data"];
foreach (var item in progressData)
{
if (item["t"] != null && item["t"].ToString() == "TASK_STATUS")
{
WriteProgress(new ProgressRecord(1, "Downloading template", item["t"].ToString()));
}
}
}
System.Threading.Thread.Sleep(1000);
attempts++;
}
throw new Exception("Timeout waiting for task to complete");
}
}
}
@@ -0,0 +1,110 @@
using System;
using System.Management.Automation;
using PSProxmox.Models;
using PSProxmox.Session;
namespace PSProxmox.Cmdlets
{
/// <summary>
/// <para type="synopsis">Starts a Proxmox LXC container</para>
/// <para type="description">Starts a Proxmox LXC container on a Proxmox server</para>
/// </summary>
/// <example>
/// <code>Start-ProxmoxContainer -Node "pve1" -CTID 100</code>
/// <para>Starts the container with CTID 100 on node pve1</para>
/// </example>
[Cmdlet(VerbsLifecycle.Start, "ProxmoxContainer")]
[OutputType(typeof(ProxmoxContainer))]
public class StartProxmoxContainerCmdlet : ProxmoxCmdlet
{
/// <summary>
/// Gets or sets the node name
/// </summary>
[Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
public string Node { get; set; }
/// <summary>
/// Gets or sets the container ID
/// </summary>
[Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
public int CTID { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to wait for the container to start
/// </summary>
[Parameter(Mandatory = false)]
public SwitchParameter Wait { get; set; }
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
{
base.ProcessRecord();
try
{
var response = Connection.PostJson($"/nodes/{Node}/lxc/{CTID}/status/start", null);
var data = response["data"];
var taskId = (string)data["upid"];
if (Wait.IsPresent)
{
var taskStatus = WaitForTask(Node, taskId);
if (taskStatus != "OK")
{
throw new Exception($"Failed to start container: {taskStatus}");
}
// Get the container status
var container = GetContainer(Node, CTID);
WriteObject(container);
}
else
{
WriteVerbose($"Container {CTID} on node {Node} start initiated");
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "StartProxmoxContainerError", ErrorCategory.OperationStopped, null));
}
}
private string WaitForTask(string node, string taskId)
{
var status = "";
var attempts = 0;
var maxAttempts = 60; // Wait up to 60 seconds
while (attempts < maxAttempts)
{
var response = Connection.GetJson($"/nodes/{node}/tasks/{taskId}/status");
var data = response["data"];
status = (string)data["status"];
if (status == "stopped")
{
return (string)data["exitstatus"];
}
System.Threading.Thread.Sleep(1000);
attempts++;
}
throw new Exception("Timeout waiting for task to complete");
}
private ProxmoxContainer GetContainer(string node, int ctid)
{
var response = Connection.GetJson($"/nodes/{node}/lxc/{ctid}/status/current");
var data = response["data"];
var container = data.ToObject<ProxmoxContainer>();
container.Node = node;
container.CTID = ctid;
return container;
}
}
}
@@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PSProxmox.Models;
using PSProxmox.Session;
namespace PSProxmox.Cmdlets
{
/// <summary>
/// <para type="synopsis">Stops a Proxmox LXC container</para>
/// <para type="description">Stops a Proxmox LXC container on a Proxmox server</para>
/// </summary>
/// <example>
/// <code>Stop-ProxmoxContainer -Node "pve1" -CTID 100</code>
/// <para>Stops the container with CTID 100 on node pve1</para>
/// </example>
/// <example>
/// <code>Stop-ProxmoxContainer -Node "pve1" -CTID 100 -Force</code>
/// <para>Forces the container with CTID 100 on node pve1 to stop</para>
/// </example>
[Cmdlet(VerbsLifecycle.Stop, "ProxmoxContainer")]
[OutputType(typeof(ProxmoxContainer))]
public class StopProxmoxContainerCmdlet : ProxmoxCmdlet
{
/// <summary>
/// Gets or sets the node name
/// </summary>
[Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
public string Node { get; set; }
/// <summary>
/// Gets or sets the container ID
/// </summary>
[Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
public int CTID { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to force stop the container
/// </summary>
[Parameter(Mandatory = false)]
public SwitchParameter Force { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to wait for the container to stop
/// </summary>
[Parameter(Mandatory = false)]
public SwitchParameter Wait { get; set; }
/// <summary>
/// Gets or sets the timeout in seconds
/// </summary>
[Parameter(Mandatory = false)]
public int Timeout { get; set; } = 60;
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
{
base.ProcessRecord();
try
{
var parameters = new Dictionary<string, object>();
if (Force.IsPresent)
{
parameters["force"] = 1;
}
if (Timeout > 0)
{
parameters["timeout"] = Timeout;
}
var response = Connection.PostJson($"/nodes/{Node}/lxc/{CTID}/status/stop", parameters);
var data = response["data"];
var taskId = (string)data["upid"];
if (Wait.IsPresent)
{
var taskStatus = WaitForTask(Node, taskId);
if (taskStatus != "OK")
{
throw new Exception($"Failed to stop container: {taskStatus}");
}
// Get the container status
var container = GetContainer(Node, CTID);
WriteObject(container);
}
else
{
WriteVerbose($"Container {CTID} on node {Node} stop initiated");
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "StopProxmoxContainerError", ErrorCategory.OperationStopped, null));
}
}
private string WaitForTask(string node, string taskId)
{
var status = "";
var attempts = 0;
var maxAttempts = Timeout > 0 ? Timeout : 60;
while (attempts < maxAttempts)
{
var response = Connection.GetJson($"/nodes/{node}/tasks/{taskId}/status");
var data = response["data"];
status = (string)data["status"];
if (status == "stopped")
{
return (string)data["exitstatus"];
}
System.Threading.Thread.Sleep(1000);
attempts++;
}
throw new Exception("Timeout waiting for task to complete");
}
private ProxmoxContainer GetContainer(string node, int ctid)
{
var response = Connection.GetJson($"/nodes/{node}/lxc/{ctid}/status/current");
var data = response["data"];
var container = data.ToObject<ProxmoxContainer>();
container.Node = node;
container.CTID = ctid;
return container;
}
}
}
+229
View File
@@ -0,0 +1,229 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace PSProxmox.Models
{
/// <summary>
/// Represents a Proxmox LXC container
/// </summary>
public class ProxmoxContainer
{
/// <summary>
/// Gets or sets the container ID
/// </summary>
[JsonProperty("vmid")]
public int CTID { get; set; }
/// <summary>
/// Gets or sets the container name
/// </summary>
[JsonProperty("name")]
public string Name { get; set; }
/// <summary>
/// Gets or sets the node name
/// </summary>
[JsonProperty("node")]
public string Node { get; set; }
/// <summary>
/// Gets or sets the container status
/// </summary>
[JsonProperty("status")]
public string Status { get; set; }
/// <summary>
/// Gets or sets the container uptime in seconds
/// </summary>
[JsonProperty("uptime")]
public long Uptime { get; set; }
/// <summary>
/// Gets or sets the container CPU usage
/// </summary>
[JsonProperty("cpu")]
public double CPU { get; set; }
/// <summary>
/// Gets or sets the container memory usage in bytes
/// </summary>
[JsonProperty("mem")]
public long Memory { get; set; }
/// <summary>
/// Gets or sets the container maximum memory in bytes
/// </summary>
[JsonProperty("maxmem")]
public long MaxMemory { get; set; }
/// <summary>
/// Gets or sets the container disk usage in bytes
/// </summary>
[JsonProperty("disk")]
public long Disk { get; set; }
/// <summary>
/// Gets or sets the container maximum disk size in bytes
/// </summary>
[JsonProperty("maxdisk")]
public long MaxDisk { get; set; }
/// <summary>
/// Gets or sets the container swap usage in bytes
/// </summary>
[JsonProperty("swap")]
public long Swap { get; set; }
/// <summary>
/// Gets or sets the container maximum swap in bytes
/// </summary>
[JsonProperty("maxswap")]
public long MaxSwap { get; set; }
/// <summary>
/// Gets or sets the container network receive rate in bytes per second
/// </summary>
[JsonProperty("netin")]
public long NetworkIn { get; set; }
/// <summary>
/// Gets or sets the container network transmit rate in bytes per second
/// </summary>
[JsonProperty("netout")]
public long NetworkOut { get; set; }
/// <summary>
/// Gets or sets the container disk read rate in bytes per second
/// </summary>
[JsonProperty("diskread")]
public long DiskRead { get; set; }
/// <summary>
/// Gets or sets the container disk write rate in bytes per second
/// </summary>
[JsonProperty("diskwrite")]
public long DiskWrite { get; set; }
/// <summary>
/// Gets or sets the container template flag
/// </summary>
[JsonProperty("template")]
public int Template { get; set; }
/// <summary>
/// Gets or sets the container description
/// </summary>
[JsonProperty("description")]
public string Description { get; set; }
/// <summary>
/// Gets or sets the container OS type
/// </summary>
[JsonProperty("ostype")]
public string OSType { get; set; }
/// <summary>
/// Gets or sets the container IP address
/// </summary>
[JsonProperty("ip")]
public string IPAddress { get; set; }
/// <summary>
/// Gets or sets the container hostname
/// </summary>
[JsonProperty("hostname")]
public string Hostname { get; set; }
/// <summary>
/// Gets or sets the container creation time
/// </summary>
[JsonProperty("creation")]
public long CreationTime { get; set; }
/// <summary>
/// Gets or sets the container tags
/// </summary>
[JsonProperty("tags")]
public string Tags { get; set; }
/// <summary>
/// Gets or sets the container lock
/// </summary>
[JsonProperty("lock")]
public string Lock { get; set; }
/// <summary>
/// Gets or sets the container unprivileged flag
/// </summary>
[JsonProperty("unprivileged")]
public int Unprivileged { get; set; }
/// <summary>
/// Gets or sets the container features
/// </summary>
[JsonProperty("features")]
public string Features { get; set; }
/// <summary>
/// Gets or sets the container configuration
/// </summary>
[JsonProperty("config")]
public Dictionary<string, object> Config { get; set; }
/// <summary>
/// Gets the container creation date
/// </summary>
public DateTime CreationDate
{
get
{
return DateTimeOffset.FromUnixTimeSeconds(CreationTime).DateTime;
}
}
/// <summary>
/// Gets the container uptime as a TimeSpan
/// </summary>
public TimeSpan UptimeSpan
{
get
{
return TimeSpan.FromSeconds(Uptime);
}
}
/// <summary>
/// Gets a value indicating whether the container is running
/// </summary>
public bool IsRunning
{
get
{
return Status == "running";
}
}
/// <summary>
/// Gets a value indicating whether the container is a template
/// </summary>
public bool IsTemplate
{
get
{
return Template == 1;
}
}
/// <summary>
/// Gets a value indicating whether the container is unprivileged
/// </summary>
public bool IsUnprivileged
{
get
{
return Unprivileged == 1;
}
}
}
}
+187
View File
@@ -0,0 +1,187 @@
using System.Collections.Generic;
namespace PSProxmox.Models
{
/// <summary>
/// Builder class for creating Proxmox LXC containers
/// </summary>
public class ProxmoxContainerBuilder
{
private readonly Dictionary<string, object> _parameters;
/// <summary>
/// Initializes a new instance of the <see cref="ProxmoxContainerBuilder"/> class
/// </summary>
/// <param name="name">The container name</param>
public ProxmoxContainerBuilder(string name)
{
_parameters = new Dictionary<string, object>
{
{ "hostname", name }
};
}
/// <summary>
/// Gets the parameters for creating the container
/// </summary>
public Dictionary<string, object> Parameters => _parameters;
/// <summary>
/// Sets the container OS template
/// </summary>
/// <param name="ostemplate">The OS template</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithOSTemplate(string ostemplate)
{
_parameters["ostemplate"] = ostemplate;
return this;
}
/// <summary>
/// Sets the container storage
/// </summary>
/// <param name="storage">The storage name</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithStorage(string storage)
{
_parameters["storage"] = storage;
return this;
}
/// <summary>
/// Sets the container memory limit
/// </summary>
/// <param name="memory">The memory limit in MB</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithMemory(int memory)
{
_parameters["memory"] = memory;
return this;
}
/// <summary>
/// Sets the container swap limit
/// </summary>
/// <param name="swap">The swap limit in MB</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithSwap(int swap)
{
_parameters["swap"] = swap;
return this;
}
/// <summary>
/// Sets the container CPU cores
/// </summary>
/// <param name="cores">The number of CPU cores</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithCores(int cores)
{
_parameters["cores"] = cores;
return this;
}
/// <summary>
/// Sets the container disk size
/// </summary>
/// <param name="diskSize">The disk size in GB</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithDiskSize(int diskSize)
{
_parameters["rootfs"] = $"local-lvm:{diskSize}";
return this;
}
/// <summary>
/// Sets the container disk size with specific storage
/// </summary>
/// <param name="storage">The storage name</param>
/// <param name="diskSize">The disk size in GB</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithDiskSize(string storage, int diskSize)
{
_parameters["rootfs"] = $"{storage}:{diskSize}";
return this;
}
/// <summary>
/// Sets the container to be unprivileged
/// </summary>
/// <param name="unprivileged">Whether the container is unprivileged</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithUnprivileged(bool unprivileged)
{
_parameters["unprivileged"] = unprivileged ? 1 : 0;
return this;
}
/// <summary>
/// Sets the container password
/// </summary>
/// <param name="password">The container password</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithPassword(string password)
{
_parameters["password"] = password;
return this;
}
/// <summary>
/// Sets the container SSH public key
/// </summary>
/// <param name="sshKey">The SSH public key</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithSSHKey(string sshKey)
{
_parameters["ssh-public-keys"] = sshKey;
return this;
}
/// <summary>
/// Sets the container network interface
/// </summary>
/// <param name="name">The interface name</param>
/// <param name="bridge">The bridge name</param>
/// <param name="ip">The IP address</param>
/// <param name="gateway">The gateway address</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithNetwork(string name, string bridge, string ip, string gateway)
{
_parameters[$"net{name}"] = $"name=eth0,bridge={bridge},ip={ip},gw={gateway}";
return this;
}
/// <summary>
/// Sets the container description
/// </summary>
/// <param name="description">The container description</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithDescription(string description)
{
_parameters["description"] = description;
return this;
}
/// <summary>
/// Sets the container start on boot flag
/// </summary>
/// <param name="start">Whether to start the container on boot</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithStartOnBoot(bool start)
{
_parameters["onboot"] = start ? 1 : 0;
return this;
}
/// <summary>
/// Sets the container start after creation flag
/// </summary>
/// <param name="start">Whether to start the container after creation</param>
/// <returns>The builder instance</returns>
public ProxmoxContainerBuilder WithStart(bool start)
{
_parameters["start"] = start ? 1 : 0;
return this;
}
}
}
+137
View File
@@ -0,0 +1,137 @@
using System;
using Newtonsoft.Json;
namespace PSProxmox.Models
{
/// <summary>
/// Represents a TurnKey Linux template for Proxmox LXC containers
/// </summary>
public class ProxmoxTurnKeyTemplate
{
/// <summary>
/// Gets or sets the template name
/// </summary>
[JsonProperty("template")]
public string Name { get; set; }
/// <summary>
/// Gets or sets the template title
/// </summary>
[JsonProperty("title")]
public string Title { get; set; }
/// <summary>
/// Gets or sets the template description
/// </summary>
[JsonProperty("description")]
public string Description { get; set; }
/// <summary>
/// Gets or sets the template section
/// </summary>
[JsonProperty("section")]
public string Section { get; set; }
/// <summary>
/// Gets or sets the template OS
/// </summary>
[JsonProperty("os")]
public string OS { get; set; }
/// <summary>
/// Gets or sets the template version
/// </summary>
[JsonProperty("version")]
public string Version { get; set; }
/// <summary>
/// Gets or sets the template package
/// </summary>
[JsonProperty("package")]
public string Package { get; set; }
/// <summary>
/// Gets or sets the template source
/// </summary>
[JsonProperty("source")]
public string Source { get; set; }
/// <summary>
/// Gets or sets the template URL
/// </summary>
[JsonProperty("url")]
public string URL { get; set; }
/// <summary>
/// Gets or sets the template size in bytes
/// </summary>
[JsonProperty("size")]
public long Size { get; set; }
/// <summary>
/// Gets or sets the template MD5 checksum
/// </summary>
[JsonProperty("md5sum")]
public string MD5Sum { get; set; }
/// <summary>
/// Gets or sets the template SHA1 checksum
/// </summary>
[JsonProperty("sha1sum")]
public string SHA1Sum { get; set; }
/// <summary>
/// Gets or sets the template SHA256 checksum
/// </summary>
[JsonProperty("sha256sum")]
public string SHA256Sum { get; set; }
/// <summary>
/// Gets or sets the template architecture
/// </summary>
[JsonProperty("architecture")]
public string Architecture { get; set; }
/// <summary>
/// Gets or sets the template infopage URL
/// </summary>
[JsonProperty("infopage")]
public string InfoPage { get; set; }
/// <summary>
/// Gets or sets the template download URL
/// </summary>
[JsonProperty("location")]
public string Location { get; set; }
/// <summary>
/// Gets the template size in a human-readable format
/// </summary>
public string HumanSize
{
get
{
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
double len = Size;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}
return $"{len:0.##} {sizes[order]}";
}
}
/// <summary>
/// Gets the full template name including version
/// </summary>
public string FullName
{
get
{
return $"{Name}-{Version}";
}
}
}
}
+57 -1
View File
@@ -5,10 +5,12 @@ PSProxmox is a C#-based PowerShell module for managing Proxmox VE clusters. It p
## Features
- **Session Management**: Authenticate and persist sessions with Proxmox VE clusters
- **Core CRUD Operations**: Manage VMs, Storage, Network, Users, Roles, SDN, and Clusters
- **Core CRUD Operations**: Manage VMs, LXC Containers, Storage, Network, Users, Roles, SDN, and Clusters
- **Templates**: Create and use VM deployment templates
- **Cloud Images**: Download, customize, and create templates from cloud images
- **Cloud-Init Support**: Configure VMs with Cloud-Init for easy customization
- **LXC Containers**: Create and manage Linux Containers with full CRUD operations
- **TurnKey Templates**: Download and use TurnKey Linux templates for LXC containers
- **Mass Creation**: Bulk create VMs with prefix/counter
- **IP Management**: CIDR parsing, subnetting, FIFO IP queue assignment
- **Structured Objects**: All outputs are typed C# classes (PowerShell-native)
@@ -249,6 +251,59 @@ $pool = Get-ProxmoxIPPool -Name "Production"
Clear-ProxmoxIPPool -Name "Production"
```
### Managing LXC Containers
```powershell
# Get all LXC containers
$containers = Get-ProxmoxContainer
# Get a specific container
$container = Get-ProxmoxContainer -CTID 100
# Get containers by name pattern (supports wildcards and regex)
$webContainers = Get-ProxmoxContainer -Name "web*"
$dbContainers = Get-ProxmoxContainer -Name "^db\d+$"
# Create a new container
$container = New-ProxmoxContainer -Node "pve1" -Name "web-container" -OSTemplate "local:vztmpl/ubuntu-20.04-standard_20.04-1_amd64.tar.gz" -Storage "local-lvm" -Memory 512 -Cores 1 -DiskSize 8 -Unprivileged -Start
# Create a container using a builder
$builder = New-ProxmoxContainerBuilder -Name "db-container"
$builder.WithOSTemplate("local:vztmpl/ubuntu-20.04-standard_20.04-1_amd64.tar.gz")
.WithStorage("local-lvm")
.WithMemory(1024)
.WithCores(2)
.WithDiskSize(16)
.WithUnprivileged($true)
.WithStart($true)
$container = New-ProxmoxContainer -Node "pve1" -Builder $builder
# Start, stop, and restart containers
Start-ProxmoxContainer -Node "pve1" -CTID 100 -Wait
Stop-ProxmoxContainer -Node "pve1" -CTID 100 -Wait
Restart-ProxmoxContainer -Node "pve1" -CTID 100 -Wait
# Remove a container
Remove-ProxmoxContainer -Node "pve1" -CTID 100 -Confirm:$false
```
### Working with TurnKey Linux Templates
```powershell
# List available TurnKey templates
$templates = Get-ProxmoxTurnKeyTemplate
# Get TurnKey templates by name pattern
$wordpressTemplates = Get-ProxmoxTurnKeyTemplate -Name "wordpress*"
# Download a TurnKey template
$templatePath = Save-ProxmoxTurnKeyTemplate -Node "pve1" -Name "wordpress" -Storage "local"
# Create a container from a TurnKey template
$container = New-ProxmoxContainerFromTurnKey -Node "pve1" -Name "wordpress" -Template "wordpress" -Storage "local-lvm" -Memory 512 -Cores 1 -DiskSize 8 -Start
```
## Disconnecting
```powershell
@@ -290,6 +345,7 @@ For detailed documentation, see the [Documentation](Documentation) directory. Th
- [Guides](Documentation/guides/README.md)
- [Installation Guide](Documentation/guides/Installation.md)
- [Cloud Image Templates Guide](Documentation/guides/CloudImageTemplates.md)
- [LXC Containers Guide](Documentation/guides/LXCContainers.md)
## Contributing