Public/VM/New-VergeDrive.ps1
|
function New-VergeDrive { <# .SYNOPSIS Adds a new drive to a VergeOS virtual machine. .DESCRIPTION New-VergeDrive creates a new virtual drive and attaches it to a VM. Supports disk, CD-ROM, and EFI disk types with various interface options. .PARAMETER VM A VM object from Get-VergeVM. Accepts pipeline input. .PARAMETER VMName The name of the VM to add the drive to. .PARAMETER VMKey The key (ID) of the VM to add the drive to. .PARAMETER Name The name for the new drive. If not specified, uses auto-generated name. .PARAMETER SizeGB The size of the drive in gigabytes. Required for disk media type. .PARAMETER Interface The drive interface type. Default is 'virtio-scsi'. Valid values: virtio, ide, ahci, nvme, virtio-scsi, virtio-scsi-dedicated .PARAMETER Media The media type. Default is 'disk'. Valid values: disk, cdrom, efidisk .PARAMETER Tier The preferred storage tier (1-5). Default is determined by system. .PARAMETER Description An optional description for the drive. .PARAMETER ReadOnly Make the drive read-only. .PARAMETER Disabled Create the drive in disabled state. .PARAMETER PassThru Return the created drive object. .PARAMETER Server The VergeOS connection to use. Defaults to the current default connection. .EXAMPLE New-VergeDrive -VMName "WebServer01" -SizeGB 100 Adds a 100GB disk to the VM using default settings. .EXAMPLE New-VergeDrive -VMName "WebServer01" -Name "DataDisk" -SizeGB 500 -Tier 2 Adds a 500GB disk on tier 2 storage with a custom name. .EXAMPLE Get-VergeVM -Name "Database*" | New-VergeDrive -SizeGB 200 -Interface nvme Adds a 200GB NVMe disk to all database VMs. .EXAMPLE New-VergeDrive -VMName "WebServer01" -Media cdrom -Name "ISO" Adds a CD-ROM drive to the VM. .OUTPUTS None by default. Verge.Drive when -PassThru is specified. .NOTES The VM should be powered off when adding drives for best results, though hot-add may be supported depending on configuration. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'ByVMName')] [OutputType([PSCustomObject])] param( [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'ByVMObject')] [PSTypeName('Verge.VM')] [PSCustomObject]$VM, [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByVMName')] [string]$VMName, [Parameter(Mandatory, ParameterSetName = 'ByVMKey')] [int]$VMKey, [Parameter()] [ValidateLength(1, 128)] [string]$Name, [Parameter()] [ValidateRange(1, 65536)] [int]$SizeGB, [Parameter()] [ValidateSet('virtio', 'ide', 'ahci', 'nvme', 'virtio-scsi', 'virtio-scsi-dedicated')] [string]$Interface = 'virtio-scsi', [Parameter()] [ValidateSet('disk', 'cdrom', 'efidisk')] [string]$Media = 'disk', [Parameter()] [ValidateRange(1, 5)] [ValidateScript({ if ($_ -eq 0) { throw "Tier 0 is reserved for system metadata and cannot be used for VM drives." } $true })] [int]$Tier, [Parameter()] [ValidateLength(0, 2048)] [string]$Description, [Parameter()] [switch]$ReadOnly, [Parameter()] [switch]$Disabled, [Parameter()] [switch]$PassThru, [Parameter()] [object]$Server ) begin { # Resolve connection if (-not $Server) { $Server = $script:DefaultConnection } if (-not $Server) { throw [System.InvalidOperationException]::new( 'Not connected to VergeOS. Use Connect-VergeOS to establish a connection.' ) } } process { # Resolve VM based on parameter set $targetVMs = switch ($PSCmdlet.ParameterSetName) { 'ByVMName' { Get-VergeVM -Name $VMName -Server $Server } 'ByVMKey' { Get-VergeVM -Key $VMKey -Server $Server } 'ByVMObject' { $VM } } foreach ($targetVM in $targetVMs) { if (-not $targetVM) { continue } # Check if VM is a snapshot if ($targetVM.IsSnapshot) { Write-Error -Message "Cannot add drive to '$($targetVM.Name)': VM is a snapshot" -ErrorId 'CannotModifySnapshot' continue } # Validate SizeGB for disk media if ($Media -eq 'disk' -and -not $SizeGB) { Write-Error -Message "SizeGB is required when Media is 'disk'" -ErrorId 'SizeRequired' continue } # Auto-detect CDROM interface based on VM machine type if not explicitly specified $effectiveInterface = $Interface if ($Media -eq 'cdrom' -and -not $PSBoundParameters.ContainsKey('Interface')) { # Q35 chipset requires AHCI, i440FX requires IDE if ($targetVM.IsQ35) { $effectiveInterface = 'ahci' Write-Verbose "Auto-selected 'ahci' interface for CDROM (Q35 chipset)" } else { $effectiveInterface = 'ide' Write-Verbose "Auto-selected 'ide' interface for CDROM (i440FX chipset)" } } # Build request body $body = @{ machine = $targetVM.MachineKey interface = $effectiveInterface media = $Media enabled = -not $Disabled.IsPresent } if ($Name) { $body['name'] = $Name } if ($SizeGB -and $Media -eq 'disk') { # Convert GB to bytes $body['disksize'] = [int64]$SizeGB * 1073741824 } if ($Tier) { $body['preferred_tier'] = $Tier.ToString() } if ($Description) { $body['description'] = $Description } if ($ReadOnly) { $body['readonly'] = $true } $driveDesc = if ($Name) { $Name } else { "$Media drive" } $sizeDesc = if ($SizeGB) { " (${SizeGB}GB)" } else { '' } if ($PSCmdlet.ShouldProcess($targetVM.Name, "Add $driveDesc$sizeDesc")) { try { Write-Verbose "Adding $Media drive to VM '$($targetVM.Name)'" $response = Invoke-VergeAPI -Method POST -Endpoint 'machine_drives' -Body $body -Connection $Server if ($response) { Write-Verbose "Drive added successfully with key: $($response.'$key' ?? $response.key ?? 'unknown')" if ($PassThru) { # Return the drive using Get-VergeDrive $driveKey = $response.'$key' ?? $response.key if ($driveKey) { Get-VergeDrive -VM $targetVM -Server $Server | Where-Object { $_.Key -eq $driveKey } } } } } catch { Write-Error -Message "Failed to add drive to VM '$($targetVM.Name)': $($_.Exception.Message)" -ErrorId 'DriveAddFailed' } } } } } |