diff --git a/plugins/providers/hyperv/action/import.rb b/plugins/providers/hyperv/action/import.rb index 6c11a2105..7e27994ed 100644 --- a/plugins/providers/hyperv/action/import.rb +++ b/plugins/providers/hyperv/action/import.rb @@ -22,6 +22,7 @@ module VagrantPlugins auto_start_action = env[:machine].provider_config.auto_start_action auto_stop_action = env[:machine].provider_config.auto_stop_action enable_virtualization_extensions = env[:machine].provider_config.enable_virtualization_extensions + vm_integration_services = env[:machine].provider_config.vm_integration_services env[:ui].output("Configured Dynamic memory allocation, maxmemory is #{maxmemory}") if maxmemory env[:ui].output("Configured startup memory is #{memory}") if memory @@ -151,6 +152,21 @@ module VagrantPlugins env[:ui].detail("Creating and registering the VM...") server = env[:machine].provider.driver.import(options) + + env[:ui].detail("Setting VM Integration Services") + vm_integration_services.each do |key, value| + state = false + if value === true + state = "enabled" + elsif value === false + state = "disabled" + end + env[:ui].output("#{key} is #{state}") if state + end + + vm_integration_services[:VmId] = server["id"] + env[:machine].provider.driver.set_vm_integration_services(vm_integration_services) + env[:ui].detail("Successfully imported a VM with name: #{server['name']}") env[:machine].id = server["id"] @app.call(env) diff --git a/plugins/providers/hyperv/config.rb b/plugins/providers/hyperv/config.rb index eec67d1b3..9a4296701 100644 --- a/plugins/providers/hyperv/config.rb +++ b/plugins/providers/hyperv/config.rb @@ -3,7 +3,6 @@ require "vagrant" module VagrantPlugins module HyperV class Config < Vagrant.plugin("2", :config) - attr_accessor :ip_address_timeout # Time to wait for an IP address when booting, in seconds @return [Integer] attr_accessor :memory # Memory size in mb @return [Integer] attr_accessor :maxmemory # Maximal memory size in mb enables dynamical memory allocation @return [Integer] @@ -15,6 +14,7 @@ module VagrantPlugins attr_accessor :auto_start_action #action on automatic start of VM. Values: Nothing, StartIfRunning, Start attr_accessor :auto_stop_action #action on automatic stop of VM. Values: ShutDown, TurnOff, Save attr_accessor :enable_virtualization_extensions # Enable virtualization extensions (nested virtualization). Values: true, false + attr_accessor :vm_integration_services # Options for VMServiceIntegration [Hash] def initialize @ip_address_timeout = UNSET_VALUE @@ -22,12 +22,20 @@ module VagrantPlugins @maxmemory = UNSET_VALUE @cpus = UNSET_VALUE @vmname = UNSET_VALUE - @vlan_id = UNSET_VALUE - @mac = UNSET_VALUE + @vlan_id = UNSET_VALUE + @mac = UNSET_VALUE @differencing_disk = UNSET_VALUE @auto_start_action = UNSET_VALUE @auto_stop_action = UNSET_VALUE @enable_virtualization_extensions = UNSET_VALUE + @vm_integration_services = { + guest_service_interface: UNSET_VALUE, + heartbeat: UNSET_VALUE, + key_value_pair_exchange: UNSET_VALUE, + shutdown: UNSET_VALUE, + time_synchronization: UNSET_VALUE, + vss: UNSET_VALUE + } end def finalize! @@ -44,12 +52,17 @@ module VagrantPlugins @auto_start_action = nil if @auto_start_action == UNSET_VALUE @auto_stop_action = nil if @auto_stop_action == UNSET_VALUE @enable_virtualization_extensions = false if @enable_virtualization_extensions == UNSET_VALUE # TODO will this work? + + @vm_integration_services.each { |key, value| + @vm_integration_services[key] = nil if value == UNSET_VALUE + } + @vm_integration_services = nil if @vm_integration_services.length == 0 end def validate(machine) errors = _detected_errors - { "Hyper-V" => errors } + {"Hyper-V" => errors} end end end diff --git a/plugins/providers/hyperv/driver.rb b/plugins/providers/hyperv/driver.rb index abd353663..359e14b12 100644 --- a/plugins/providers/hyperv/driver.rb +++ b/plugins/providers/hyperv/driver.rb @@ -118,6 +118,10 @@ module VagrantPlugins execute("delete_snapshot.ps1", {VmID: vm_id, SnapName: snapshot_name}) end + def set_vm_integration_services(config) + execute("set_vm_integration_services.ps1", config) + end + protected def execute_powershell(path, options, &block) diff --git a/plugins/providers/hyperv/scripts/import_vm_vmcx.ps1 b/plugins/providers/hyperv/scripts/import_vm_vmcx.ps1 index e4e13e913..7f9db5c43 100644 --- a/plugins/providers/hyperv/scripts/import_vm_vmcx.ps1 +++ b/plugins/providers/hyperv/scripts/import_vm_vmcx.ps1 @@ -16,6 +16,7 @@ [string]$auto_start_action=$null, [string]$auto_stop_action=$null, [string]$differencing_disk=$null + [string]$enable_virtualization_extensions=$False ) # Include the following modules @@ -86,6 +87,11 @@ if (!$switchname) { $switchname = (Get-VMNetworkAdapter -VM $vmConfig.VM).SwitchName } +# Enable nested virtualization if configured +if ($enable_virtualization_extensions) { + Set-VMProcessor -VM $vmConfig.VM -ExposeVirtualizationExtensions $true +} + $vmNetworkAdapter = Get-VMNetworkAdapter -VM $vmConfig.VM Connect-VMNetworkAdapter -VMNetworkAdapter $vmNetworkAdapter -SwitchName $switchname Set-VM -VM $vmConfig.VM -NewVMName $vm_name diff --git a/plugins/providers/hyperv/scripts/set_vm_integration_services.ps1 b/plugins/providers/hyperv/scripts/set_vm_integration_services.ps1 new file mode 100644 index 000000000..da4df1822 --- /dev/null +++ b/plugins/providers/hyperv/scripts/set_vm_integration_services.ps1 @@ -0,0 +1,37 @@ +param ( + [string] $VmId, + [string] $guest_service_interface = $null, + [string] $heartbeat = $null, + [string] $key_value_pair_exchange = $null, + [string] $shutdown = $null, + [string] $time_synchronization = $null, + [string] $vss = $null +) + +# Include the following modules +$Dir = Split-Path $script:MyInvocation.MyCommand.Path +. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1")) + +$vm = Get-VM -Id $VmId -ErrorAction "stop" + +# Set the service based on value +function VmSetService +{ + param ([string] $Name, [string] $Value, [Microsoft.HyperV.PowerShell.VirtualMachine] $Vm) + + if ($Value -ne $null){ + if($Value -eq "true"){ + Enable-VMIntegrationService -VM $Vm -Name $Name + } + if($Value -eq "false"){ + Disable-VMIntegrationService -VM $Vm -Name $Name + } + } +} + +VmSetService -Name "Guest Service Interface" -Value $guest_service_interface -Vm $vm +VmSetService -Name "Heartbeat" -Value $heartbeat -Vm $vm +VmSetService -Name "Key-Value Pair Exchange" -Value $key_value_pair_exchange -Vm $vm +VmSetService -Name "Shutdown" -Value $shutdown -Vm $vm +VmSetService -Name "Time Synchronization" -Value $time_synchronization -Vm $vm +VmSetService -Name "VSS" -Value $vss -Vm $vm \ No newline at end of file diff --git a/website/source/docs/hyperv/configuration.html.md b/website/source/docs/hyperv/configuration.html.md index 59f12e54c..d0a94524d 100644 --- a/website/source/docs/hyperv/configuration.html.md +++ b/website/source/docs/hyperv/configuration.html.md @@ -31,4 +31,22 @@ you may set. A complete reference is shown below: * `differencing_disk` (boolean) - Switch to use differencing disk intead of cloning whole VHD. * `enable_virtualization_extensions` (boolean) - Enable virtualization extensions for the virtual CPUs. This allows Hyper-V to be nested and run inside another Hyper-VM VM. It requires Windows 10 - 1511 (build 10586) or newer. - Default is not defined. This will be disabled if not set. \ No newline at end of file + Default is not defined. This will be disabled if not set. + * `vm_integration_services` (Hash) - Hash to set the state of integration services. + + Example: + + ```ruby + config.vm.provider "hyperv" do |h| + h.vm_integration_services = { + guest_service_interface: true, + heartbeat: true, + key_value_pair_exchange: false, + shutdown: true, + time_synchronization: true, + vss: true + } + end + ``` + + \ No newline at end of file