From b432b9c8caff7d69ecd95144aa57862e6bce7957 Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Thu, 27 Apr 2017 14:37:08 +0100 Subject: [PATCH] scripts: Add simple Powershell script to manage Hyper-V VMs This script can create/start/stop/remove Hyper-V VMs. The VMs are configured as Gen2 VMs which boot from EFI ISOs. Network and Disk configuration is optional. Signed-off-by: Rolf Neugebauer --- scripts/LinuxKit.ps1 | 184 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 scripts/LinuxKit.ps1 diff --git a/scripts/LinuxKit.ps1 b/scripts/LinuxKit.ps1 new file mode 100644 index 000000000..239e7a502 --- /dev/null +++ b/scripts/LinuxKit.ps1 @@ -0,0 +1,184 @@ +<# + .SYNOPSIS + Manages a LinuxKit VM on Hyper-V + + .DESCRIPTION + Creates/Destroys/Starts/Stops a LinuxKit VM. + It creates a Gen2 VM which boots EFI ISOs + + .PARAMETER VmName + If passed, use this name for the LinuxKit VM, otherwise 'LinuxKitVM' + + .PARAMETER IsoFile + Path to the ISO image to boot from, must be set for Create/ReCreate + + .PARAMETER SwitchName + Use this switch to connect the VM to + + .PARAMETER Create + Create a LinuxKit VM + + .PARAMETER Memory + Memory allocated for the VM in MB (optional on Create, default: 1024 MB) + + .PARAMETER CPUs + Number of CPUs to use (optional on Create, default: 1) + + .PARAMETER DiskSize + Disk size in MB (optional on Create, default: 0, no disk) + + .PARAMETER Destroy + Remove a LinuxKit VM + + .PARAMETER Start + Start an existing LinuxKit VM + + .PARAMETER Stop + Stop a running LinuxKit VM + + .EXAMPLE + .\LinuxKit.ps1 -IsoFile .\linuxkit-efi.iso -Create + .\LinuxKit.ps1 -Start +#> + +Param( + [string] $VmName = "LinuxKitVM", + [string] $IsoFile = ".\linuxkit-efi.iso", + [string] $SwicthName = ".\linuxkit-efi.iso", + + [Parameter(ParameterSetName='Create',Mandatory=$false)][switch] $Create, + [Parameter(ParameterSetName='Create',Mandatory=$false)][int] $CPUs = 1, + [Parameter(ParameterSetName='Create',Mandatory=$false)][long] $Memory = 1024, + [Parameter(ParameterSetName='Create',Mandatory=$false)][long] $DiskSize = 0, + [Parameter(ParameterSetName='Create',Mandatory=$false)][string] $SwitchName = "", + [Parameter(ParameterSetName='Remove',Mandatory=$false)][switch] $Remove, + [Parameter(ParameterSetName='Start',Mandatory=$false)][switch] $Start, + [Parameter(ParameterSetName='Stop',Mandatory=$false)][switch] $Stop +) + +# Make sure we stop at Errors unless otherwise explicitly specified +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +# Explicitly disable Module autoloading and explicitly import the +# Modules this script relies on. This is not strictly necessary but +# good practise as it prevents arbitrary errors +$PSModuleAutoloadingPreference = 'None' + +Import-Module Microsoft.PowerShell.Utility +Import-Module Microsoft.PowerShell.Management +Import-Module Hyper-V + +function Get-Vhd-Root { + if($VhdPathOverride){ + return $VhdPathOverride + } + # Default location for VHDs + $VhdRoot = "$((Get-VMHost).VirtualHardDiskPath)".TrimEnd("\") + return "$VhdRoot\$VmName.vhdx" +} + +# Posh thinks that Create is an unapproved verb +function New-LinuxKitVM { + if (!(Test-Path $IsoFile)) { + Fatal "ISO file at $IsoFile does not exist" + } + + $CPUs = [Math]::min((Get-VMHost).LogicalProcessorCount, $CPUs) + + $vm = Get-VM $VmName -ea SilentlyContinue + if ($vm) { + if ($vm.Length -ne 1) { + Fatal "Multiple VMs exist with the name $VmName. Delete invalid ones or reset Docker to factory defaults." + } + } else { + Write-Output "Creating VM $VmName..." + $vm = New-VM -Name $VmName -Generation 2 -NoVHD + $vm | Set-VM -AutomaticStartAction Nothing -AutomaticStopAction ShutDown -CheckpointType Disabled + } + + if ($vm.Generation -ne 2) { + Fatal "VM $VmName is a Generation $($vm.Generation) VM. It should be a Generation 2." + } + + if ($vm.State -ne "Off") { + Write-Output "VM $VmName is $($vm.State). Cannot change its settings." + return + } + + Write-Output "Setting CPUs to $CPUs and Memory to $Memory MB" + $Memory = ([Math]::min($Memory, ($vm | Get-VMMemory).MaximumPerNumaNode)) + $vm | Set-VM -MemoryStartupBytes ($Memory*1024*1024) -ProcessorCount $CPUs -StaticMemory + + if ($DiskSize -ne 0) { + $VmVhdFile = Get-Vhd-Root + $vhd = Get-VHD -Path $VmVhdFile -ea SilentlyContinue + if (!$vhd) { + Write-Output "Creating dynamic VHD: $VmVhdFile" + $vhd = New-VHD -Path $VmVhdFile -Dynamic -SizeBytes ($DiskSize*1024*1024) + } + Write-Output "Attach VHD $VmVhdFile" + $vm | Add-VMHardDiskDrive -Path $VmVhdFile + } + + if ($SwitchName -ne "") { + $vmNetAdapter = $vm | Get-VMNetworkAdapter + if (!$vmNetAdapter) { + Write-Output "Attach Net Adapter" + $vmNetAdapter = $vm | Add-VMNetworkAdapter -Passthru + } + + Write-Output "Connect to switch $SwicthName" + $vmNetAdapter | Connect-VMNetworkAdapter -VMSwitch $(Get-VMSwitch $SwitchName) + } + + Write-Output "Attach DVD $IsoFile" + $vm | Add-VMDvdDrive -Path $IsoFile + + $iso = $vm | Get-VMFirmware | select -ExpandProperty BootOrder | ? { $_.FirmwarePath.EndsWith("Scsi(0,1)") } + $vm | Set-VMFirmware -EnableSecureBoot Off -FirstBootDevice $iso + $vm | Set-VMComPort -number 1 -Path "\\.\pipe\docker$VmName-com1" + + Write-Output "VM created." +} + +function Remove-LinuxKitVM { + Write-Output "Removing VM $VmName..." + + Remove-VM $VmName -Force -ea SilentlyContinue +} + +function Start-LinuxKitVM { + Write-Output "Starting VM $VmName..." + Start-VM -VMName $VmName +} + +function Stop-LinuxKitVM { + $vm = Get-VM $VmName -ea SilentlyContinue + if (!$vm) { + Write-Output "VM $VmName does not exist" + return + } + + # This is a bit harsh, we poweroff + $vm | Stop-VM -Confirm:$false -TurnOff -Force -ea SilentlyContinue +} + + +function Fatal { + throw "$args" + Exit 1 +} + +# Main entry point +Try { + Switch ($PSBoundParameters.GetEnumerator().Where({$_.Value -eq $true}).Key) { + 'Create' { New-LinuxKitVM } + 'Start' { Start-LinuxKitVM } + 'Stop' { Stop-LinuxKitVM } + 'Remove' { Stop-LinuxKitVM; Remove-LinuxKitVM } + } +} Catch { + throw + Exit 1 +}