From debe50957b4991cb5d81347a970a3df0d6e43fb6 Mon Sep 17 00:00:00 2001 From: Bjorn Brala Date: Sat, 8 Oct 2016 16:38:42 +0200 Subject: [PATCH] Refactor the import script to fully use Compare-VM for creating the new VM. Implemented the differencing disk for vmcx. This means the disk is now copied by Hyper-V (Powershell) instead of Ruby for new machines. This does mean EFI Firmware now does work for machines since it is quite a feep copy. Compare-VM will report incompatibilities should they be found. --- plugins/providers/hyperv/action/import.rb | 23 +++-- plugins/providers/hyperv/driver.rb | 3 + .../hyperv/scripts/import_vm_vmcx.ps1 | 99 +++++++++---------- .../hyperv/scripts/import_vm_xml.ps1 | 4 +- 4 files changed, 63 insertions(+), 66 deletions(-) diff --git a/plugins/providers/hyperv/action/import.rb b/plugins/providers/hyperv/action/import.rb index e31949475..7be7265e0 100644 --- a/plugins/providers/hyperv/action/import.rb +++ b/plugins/providers/hyperv/action/import.rb @@ -44,7 +44,6 @@ module VagrantPlugins end end - # Only check for .vmcx if there is no XML found to not # risk breaking older vagrant boxes that added an XML # file manually @@ -58,7 +57,6 @@ module VagrantPlugins end end - image_path = nil image_ext = nil image_filename = nil @@ -116,12 +114,16 @@ module VagrantPlugins end env[:ui].detail("Cloning virtual hard drive...") - source_path = image_path.to_s - dest_path = env[:machine].data_dir.join("#{image_filename}#{image_ext}").to_s - if differencing_disk - env[:machine].provider.driver.execute("clone_vhd.ps1", {Source: source_path, Destination: dest_path}) - else - FileUtils.cp(source_path, dest_path) + source_path = image_path.to_s + dest_path = env[:machine].data_dir.join("#{image_filename}#{image_ext}").to_s + + # Still hard copy the disk of old XML configurations + if config_type == 'xml' + if differencing_disk + env[:machine].provider.driver.execute("clone_vhd.ps1", {Source: source_path, Destination: dest_path}) + else + FileUtils.cp(source_path, dest_path) + end end image_path = dest_path @@ -130,7 +132,9 @@ module VagrantPlugins options = { vm_config_file: config_path.to_s.gsub("/", "\\"), vm_config_type: config_type, - image_path: image_path.to_s.gsub("/", "\\") + source_path: source_path.to_s, + dest_path: env[:machine].data_dir.join("Virtual Hard Disks").join("#{image_filename}#{image_ext}").to_s, + data_path: env[:machine].data_dir.to_s.gsub("/", "\\") } options[:switchname] = switch if switch options[:memory] = memory if memory @@ -139,6 +143,7 @@ module VagrantPlugins options[:vmname] = vmname if vmname options[:auto_start_action] = auto_start_action if auto_start_action options[:auto_stop_action] = auto_stop_action if auto_stop_action + options[:differencing_disk] = differencing_disk if differencing_disk env[:ui].detail("Creating and registering the VM...") server = env[:machine].provider.driver.import(options) diff --git a/plugins/providers/hyperv/driver.rb b/plugins/providers/hyperv/driver.rb index 73fb2eb74..d348cb79e 100644 --- a/plugins/providers/hyperv/driver.rb +++ b/plugins/providers/hyperv/driver.rb @@ -78,6 +78,9 @@ module VagrantPlugins if config_type === "vmcx" execute('import_vm_vmcx.ps1', options) else + option.delete(:data_path) + option.delete(:source_path) + option.delete(:differencing_disk) execute('import_vm_xml.ps1', options) end end diff --git a/plugins/providers/hyperv/scripts/import_vm_vmcx.ps1 b/plugins/providers/hyperv/scripts/import_vm_vmcx.ps1 index 21e3132de..b31c1528d 100644 --- a/plugins/providers/hyperv/scripts/import_vm_vmcx.ps1 +++ b/plugins/providers/hyperv/scripts/import_vm_vmcx.ps1 @@ -2,7 +2,11 @@ [Parameter(Mandatory=$true)] [string]$vm_config_file, [Parameter(Mandatory=$true)] - [string]$image_path, + [string]$source_path, + [Parameter(Mandatory=$true)] + [string]$dest_path, + [Parameter(Mandatory=$true)] + [string]$data_path, [string]$switchname=$null, [string]$memory=$null, @@ -10,15 +14,19 @@ [string]$cpus=$null, [string]$vmname=$null, [string]$auto_start_action=$null, - [string]$auto_stop_action=$null + [string]$auto_stop_action=$null, + [string]$differencing_disk=$null ) +"$($data_path)/Snapshots" + # Include the following modules $Dir = Split-Path $script:MyInvocation.MyCommand.Path . ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1")) # load the config from the vmcx and make a copy for editing, use TMP path so we are sure there is no vhd at the destination -$vmConfig = (Compare-VM -Copy -Path $vm_config_file -GenerateNewID -VhdDestinationPath $env:Temp) +$vmConfig = (Compare-VM -Copy -Path $vm_config_file -GenerateNewID -SnapshotFilePath "$($data_path)Snapshots" -VhdDestinationPath "$($data_path)Virtual Hard Disks" -VirtualMachinePath "$($data_path)Virtual Machines") + $generation = $vmConfig.VM.Generation @@ -32,7 +40,6 @@ if (!$vmname) { if (!$cpus) { # Get the processorcount of the VM $processors = (Get-VMProcessor -VM $vmConfig.VM).Count - }else { $processors = $cpus } @@ -80,82 +87,64 @@ if (!$switchname) { $switchname = (Get-VMNetworkAdapter -VM $vmConfig.VM).SwitchName } -$vm_params = @{ - Name = $vm_name - NoVHD = $True - MemoryStartupBytes = $MemoryStartupBytes - SwitchName = $switchname - ErrorAction = "Stop" -} -# Generation parameter was added in ps v4 -if((get-command New-VM).Parameters.Keys.Contains("generation")) { - $vm_params.Generation = $generation -} - -# Create the VM using the values in the hash map -$vm = New-VM @vm_params - -$notes = $vmConfig.VM.Notes - -# Set-VM parameters to configure new VM with old values - -$more_vm_params = @{ - ProcessorCount = $processors - MemoryStartupBytes = $MemoryStartupBytes -} +Connect-VMNetworkAdapter -VMNetworkAdapter (Get-VMNetworkAdapter -VM $vmConfig.VM) -SwitchName $switchname +Set-VM -VM $vmConfig.VM -NewVMName $vm_name -MemoryStartupBytes $MemoryStartupBytes +Set-VM -VM $vmConfig.VM -MemoryMinimumBytes $MemoryMinimumBytes -MemoryMaximumBytes $MemoryMaximumBytes +Set-VM -VM $vmConfig.VM -ErrorAction "Stop" -ProcessorCount $processors If ($dynamicmemory) { - $more_vm_params.Add("DynamicMemory",$True) - $more_vm_params.Add("MemoryMinimumBytes",$MemoryMinimumBytes) - $more_vm_params.Add("MemoryMaximumBytes", $MemoryMaximumBytes) + Set-VM -VM $vmConfig.VM -DynamicMemory } else { - $more_vm_params.Add("StaticMemory",$True) + Set-VM -VM $vmConfig.VM -StaticMemory } if ($notes) { - $more_vm_params.Add("Notes",$notes) + Set-VM -VM $vmConfig.VM -Notes $notes } if ($auto_start_action) { - $more_vm_params.Add("AutomaticStartAction",$auto_start_action) + Set-VM -VM $vmConfig.VM -AutomaticStartAction $auto_start_action } if ($auto_stop_action) { - $more_vm_params.Add("AutomaticStopAction",$auto_stop_action) + Set-VM -VM $vmConfig.VM -AutomaticStartAction $auto_stop_action } -# Set the values on the VM -$vm | Set-VM @more_vm_params -Passthru - # Only set EFI secure boot for Gen 2 machines, not gen 1 if ($generation -ne 1) { - Set-VMFirmware -VM $vm -EnableSecureBoot (Get-VMFirmware -VM $vmConfig.VM).SecureBoot + Set-VMFirmware -VM $vmConfig.VM -EnableSecureBoot (Get-VMFirmware -VM $vmConfig.VM).SecureBoot } -# Get all controller on the VM, first scsi, then IDE if it is a Gen 1 device -$controllers = Get-VMScsiController -VM $vmConfig.VM -if($generation -eq 1){ - $controllers = @($controllers) + @(Get-VMIdeController -VM $vmConfig.VM) +$report = Compare-VM -CompatibilityReport $vmConfig +if($report.Incompatibilities.Length -gt 0){ +$report.Incompatibilities + Write-Error-Message ConvertTo-Json $report.Incompatibilities } -foreach($controller in $controllers){ - foreach($drive in $controller.Drives){ - $addDriveParam = @{ - ControllerNumber = $drive.ControllerNumber - Path = $image_path - } - if($drive.PoolName){ - $addDriveParam.Add("ResourcePoolname",$drive.PoolName) - } +# Differencing disk +if($differencing_disk){ + # Get all controller on the VM, first scsi, then IDE if it is a Gen 1 device + $controllers = Get-VMScsiController -VM $vmConfig.VM + if($generation -eq 1){ + $controllers = @($controllers) + @(Get-VMIdeController -VM $vmConfig.VM) + } - # If the drive path is set, it is a harddisk, only support single harddisk - if ($drive.Path) { - $addDriveParam.add("ControllerType", $ControllerType) - $vm | Add-VMHardDiskDrive @AddDriveparam + foreach($controller in $controllers){ + foreach($drive in $controller.Drives){ + if([System.IO.Path]::GetFileName($drive.Path) -eq [System.IO.Path]::GetFileName($source_path)){ + # Remove the old disk and replace it with a differencing version + $path = $drive.Path + Remove-VMHardDiskDrive $drive + New-VHD -Path $dest_path -ParentPath $source_path -ErrorAction Stop + Add-VMHardDiskDrive -VM $vmConfig.VM -Path $dest_path + } } } + } + +Import-VM -CompatibilityReport $vmConfig $vm_id = (Get-VM $vm_name).id.guid $resultHash = @{ diff --git a/plugins/providers/hyperv/scripts/import_vm_xml.ps1 b/plugins/providers/hyperv/scripts/import_vm_xml.ps1 index cccb0a75c..16055e135 100644 --- a/plugins/providers/hyperv/scripts/import_vm_xml.ps1 +++ b/plugins/providers/hyperv/scripts/import_vm_xml.ps1 @@ -2,7 +2,7 @@ Param( [Parameter(Mandatory=$true)] [string]$vm_config_file, [Parameter(Mandatory=$true)] - [string]$image_path, + [string]$dest_path, [string]$switchname=$null, [string]$memory=$null, @@ -190,7 +190,7 @@ foreach ($controller in $controllers) { $addDriveParam = @{ ControllerNumber = $rx.Match($controller.node.name).value - Path = $image_path + Path = $dest_path } if ($drive.pool_id."#text") {