From 2fc710be16f2b4d2439a280193a629fd69b5d505 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Tue, 17 Jul 2018 22:04:36 +0200 Subject: [PATCH 1/7] IMPR: Ported the code for creating and attaching new drives in the Hyper-V provider from Vagrant 2.0.1 to 2.1.3-dev. I can now verify locally that it works. --- plugins/providers/hyperv/action/import.rb | 9 +++- plugins/providers/hyperv/config.rb | 4 ++ .../providers/hyperv/scripts/configure_vm.ps1 | 4 +- .../providers/hyperv/scripts/import_vm.ps1 | 46 ++++++++++++++++++- 4 files changed, 60 insertions(+), 3 deletions(-) diff --git a/plugins/providers/hyperv/action/import.rb b/plugins/providers/hyperv/action/import.rb index afec6f39a..3192d2f45 100644 --- a/plugins/providers/hyperv/action/import.rb +++ b/plugins/providers/hyperv/action/import.rb @@ -1,5 +1,6 @@ require "fileutils" require "log4r" +require "json" module VagrantPlugins module HyperV @@ -16,7 +17,7 @@ module VagrantPlugins def call(env) vm_dir = env[:machine].box.directory.join("Virtual Machines") hd_dir = env[:machine].box.directory.join("Virtual Hard Disks") - + disks_config = env[:machine].provider_config.disks_config if !vm_dir.directory? || !hd_dir.directory? @logger.error("Required virtual machine directory not found!") raise Errors::BoxInvalid, name: env[:machine].name @@ -68,6 +69,7 @@ module VagrantPlugins "SourcePath" => Vagrant::Util::Platform.wsl_to_windows_path(image_path).gsub("/", "\\"), "VMName" => env[:machine].provider_config.vmname, } + options[:disks_config] = add_abs_path(disks_config, env[:machine].data_dir).to_json.to_s.gsub('"', '"""') if disks_config env[:ui].detail("Creating and registering the VM...") @@ -77,7 +79,12 @@ module VagrantPlugins env[:machine].id = server["id"] @app.call(env) end + + private + def add_abs_path(disks_config, data_dir) + disks_config.each {|controller| controller.each {|disk| disk['name'] = data_dir.join("#{disk['name']}.vhdx").to_s.gsub("/", "\\") if disk['name'] }} end end end end +end diff --git a/plugins/providers/hyperv/config.rb b/plugins/providers/hyperv/config.rb index 3403ef682..38039a732 100644 --- a/plugins/providers/hyperv/config.rb +++ b/plugins/providers/hyperv/config.rb @@ -46,6 +46,8 @@ module VagrantPlugins attr_accessor :enable_virtualization_extensions # @return [Hash] Options for VMServiceIntegration attr_accessor :vm_integration_services + # @return [Hash] Config of disks and controllers + attr_accessor :disks_config def initialize @ip_address_timeout = UNSET_VALUE @@ -62,6 +64,7 @@ module VagrantPlugins @enable_virtualization_extensions = UNSET_VALUE @enable_checkpoints = UNSET_VALUE @vm_integration_services = {} + @disks_config = UNSET_VALUE end def finalize! @@ -90,6 +93,7 @@ module VagrantPlugins else @enable_checkpoints = !!@enable_checkpoints end + @disks_config = nil if @disks_config == UNSET_VALUE end def validate(machine) diff --git a/plugins/providers/hyperv/scripts/configure_vm.ps1 b/plugins/providers/hyperv/scripts/configure_vm.ps1 index ff2b8ca3b..a9cdbf88c 100644 --- a/plugins/providers/hyperv/scripts/configure_vm.ps1 +++ b/plugins/providers/hyperv/scripts/configure_vm.ps1 @@ -18,7 +18,9 @@ param( [parameter (Mandatory=$false)] [switch] $VirtualizationExtensions, [parameter (Mandatory=$false)] - [switch] $EnableCheckpoints + [switch] $EnableCheckpoints, + [parameter (Mandatory=$false)] + [string] $disks_config=$null ) $ErrorActionPreference = "Stop" diff --git a/plugins/providers/hyperv/scripts/import_vm.ps1 b/plugins/providers/hyperv/scripts/import_vm.ps1 index e339a754e..84ef2f581 100644 --- a/plugins/providers/hyperv/scripts/import_vm.ps1 +++ b/plugins/providers/hyperv/scripts/import_vm.ps1 @@ -12,7 +12,9 @@ param( [parameter (Mandatory=$false)] [switch] $LinkedClone, [parameter (Mandatory=$false)] - [string] $VMName=$null + [string] $VMName=$null, + [parameter (Mandatory=$false)] + [string] $disks_config=$null ) $ErrorActionPreference = "Stop" @@ -35,3 +37,45 @@ try { Write-ErrorMessage "${PSItem}" exit 1 } + + +#controller - path (for existent) +# path, +# sizeGB, name (for new) +function AddDisks($vm, $controller) { + #get controller + + $contNumber = ($vm | Add-VMScsiController -PassThru).ControllerNumber + foreach($disk in $controller) { + #get vhd + $vhd = $null + if($disk.Path) { + if (Test-Path -Path $disk.Path) { + $vhd = Resolve-Path -Path $disk.Path + } + } + else { + $vhd = $disk.Name + if (!(Test-Path -Path $vhd)) { + New-VHD -Path $vhd -SizeBytes ([UInt64]$disk.Size * 1GB) -Dynamic + } + } + if (!(Test-Path -Path $vhd)) { + Write-Error "There is error in virtual disk (VHD) configuration" + break + } + + $driveParam = @{ + ControllerNumber = $contNumber + Path = $vhd + ControllerType = "SCSI" + } + $vm | Add-VMHardDiskDrive @driveParam + } +} + +if ($disks_config) { + $parsed_disks_config = $disks_config | ConvertFrom-Json + $parsed_disks_config | ForEach-Object { AddDisks -vm $VMName -controller $_ } +} + From 5449b7053c6e4f374213d2f73f51e2da46a71813 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Tue, 17 Jul 2018 23:06:36 +0200 Subject: [PATCH 2/7] MISC: Following the same style guide as the rest of the PowerShell scripts. MISC: Fix indentation. --- plugins/providers/hyperv/action/import.rb | 4 ++-- plugins/providers/hyperv/scripts/configure_vm.ps1 | 2 +- plugins/providers/hyperv/scripts/import_vm.ps1 | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/providers/hyperv/action/import.rb b/plugins/providers/hyperv/action/import.rb index 3192d2f45..3710f3ab2 100644 --- a/plugins/providers/hyperv/action/import.rb +++ b/plugins/providers/hyperv/action/import.rb @@ -69,7 +69,7 @@ module VagrantPlugins "SourcePath" => Vagrant::Util::Platform.wsl_to_windows_path(image_path).gsub("/", "\\"), "VMName" => env[:machine].provider_config.vmname, } - options[:disks_config] = add_abs_path(disks_config, env[:machine].data_dir).to_json.to_s.gsub('"', '"""') if disks_config + options[:DisksConfig] = add_abs_path(disks_config, env[:machine].data_dir).to_json.to_s.gsub('"', '"""') if disks_config env[:ui].detail("Creating and registering the VM...") @@ -83,8 +83,8 @@ module VagrantPlugins private def add_abs_path(disks_config, data_dir) disks_config.each {|controller| controller.each {|disk| disk['name'] = data_dir.join("#{disk['name']}.vhdx").to_s.gsub("/", "\\") if disk['name'] }} + end end end end end -end diff --git a/plugins/providers/hyperv/scripts/configure_vm.ps1 b/plugins/providers/hyperv/scripts/configure_vm.ps1 index a9cdbf88c..262c40a57 100644 --- a/plugins/providers/hyperv/scripts/configure_vm.ps1 +++ b/plugins/providers/hyperv/scripts/configure_vm.ps1 @@ -20,7 +20,7 @@ param( [parameter (Mandatory=$false)] [switch] $EnableCheckpoints, [parameter (Mandatory=$false)] - [string] $disks_config=$null + [string] $DisksConfig=$null ) $ErrorActionPreference = "Stop" diff --git a/plugins/providers/hyperv/scripts/import_vm.ps1 b/plugins/providers/hyperv/scripts/import_vm.ps1 index 84ef2f581..b422824a0 100644 --- a/plugins/providers/hyperv/scripts/import_vm.ps1 +++ b/plugins/providers/hyperv/scripts/import_vm.ps1 @@ -14,7 +14,7 @@ param( [parameter (Mandatory=$false)] [string] $VMName=$null, [parameter (Mandatory=$false)] - [string] $disks_config=$null + [string] $DisksConfig=$null ) $ErrorActionPreference = "Stop" @@ -74,8 +74,8 @@ function AddDisks($vm, $controller) { } } -if ($disks_config) { - $parsed_disks_config = $disks_config | ConvertFrom-Json - $parsed_disks_config | ForEach-Object { AddDisks -vm $VMName -controller $_ } +if ($DisksConfig) { + $ParsedDisksConfig = $DisksConfig | ConvertFrom-Json + $ParsedDisksConfig | ForEach-Object { AddDisks -vm $VMName -controller $_ } } From bdde32415890ac6358bc15f616da09d4332a5fdc Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 19 Jul 2018 20:11:00 +0200 Subject: [PATCH 3/7] IMPR: Changes format of configuration of this. Now it better represent concept discussed in https://github.com/hashicorp/vagrant/pull/6321#issuecomment-179687930. IMPR: Now the size of a new disk is specified in MB instead GB as wished in https://github.com/hashicorp/vagrant/pull/6321#issuecomment-179687930. MISC: Got this working on creating a new machine. Seems to be problems when halting and up'ing the machine again. It says it can't attach the disk again. Perhaps it was better having this code in import_vm.ps1 anyway? MISC: Lots of puts for debug purposes. --- plugins/providers/hyperv/action/configure.rb | 52 +++++++++++++++ plugins/providers/hyperv/action/import.rb | 4 +- plugins/providers/hyperv/config.rb | 63 +++++++++++++++++-- plugins/providers/hyperv/driver.rb | 3 +- .../providers/hyperv/scripts/configure_vm.ps1 | 48 +++++++++++++- .../providers/hyperv/scripts/import_vm.ps1 | 44 +------------ .../source/docs/hyperv/configuration.html.md | 1 + 7 files changed, 163 insertions(+), 52 deletions(-) diff --git a/plugins/providers/hyperv/action/configure.rb b/plugins/providers/hyperv/action/configure.rb index 30831ac12..839e227ee 100644 --- a/plugins/providers/hyperv/action/configure.rb +++ b/plugins/providers/hyperv/action/configure.rb @@ -34,6 +34,57 @@ module VagrantPlugins end end end + + + # TODO: Should be controllers as we want to be able to have several lines. + #if !env[:machine].provider_config.controllers.empty? + # puts "hej: controller not empty" + # #env[:ui].detail("Controllers set") + # #controller.each do [key, value] + # # puts "key: #{id} value: #{value}" + # # if [type].include?(key) + # # puts "key matches type" + # # end + # #end + # + # env[:machine].provider_config.controller.each do |key, value| + # env[:ui].output("#{key} is #{value}") + # end + # + # #env[:machine].provider.driver.set_vm_integration_services( + # # env[:machine].provider_config.vm_integration_services) + #end + + disks_to_create = [] + env[:machine].provider_config.controllers.each { |controller| + #puts "configure.rb: controller: #{controller}" + + next_is_size = false + disk_name = '' + controller[:disks].each { |i| + #puts "configure.rb: i: #{i} disk_name: #{disk_name}" + if !next_is_size + if File.file?(i) + create_disk = false + filename_for_disk = i + next_is_size = false + + @logger.error("Attaching disks is not implemented yet") + else + create_disk = true + disk_name = i + next_is_size = true + #puts "configure.rb: disk_name set to: #{disk_name}" + end + else + #puts "configure.rb: Adding disk to create. name: #{disk_name}" + disks_to_create << { name: "\"#{disk_name}\"", size: i} + end + } + } + #puts "configure.rb: disks_to_create:#{disks_to_create}" + disks_to_create_json = disks_to_create.to_json + puts "configure.rb: json: #{disks_to_create_json}" # If we already configured previously don't prompt for switch sentinel = env[:machine].data_dir.join("action_configure") @@ -71,6 +122,7 @@ module VagrantPlugins "AutoStopAction" => env[:machine].provider_config.auto_stop_action, "EnableCheckpoints" => env[:machine].provider_config.enable_checkpoints, "VirtualizationExtensions" => !!env[:machine].provider_config.enable_virtualization_extensions, + "DisksToCreate" => disks_to_create_json } options.delete_if{|_,v| v.nil? } diff --git a/plugins/providers/hyperv/action/import.rb b/plugins/providers/hyperv/action/import.rb index 3710f3ab2..3d37a2729 100644 --- a/plugins/providers/hyperv/action/import.rb +++ b/plugins/providers/hyperv/action/import.rb @@ -17,7 +17,7 @@ module VagrantPlugins def call(env) vm_dir = env[:machine].box.directory.join("Virtual Machines") hd_dir = env[:machine].box.directory.join("Virtual Hard Disks") - disks_config = env[:machine].provider_config.disks_config + controller = env[:machine].provider_config.controller if !vm_dir.directory? || !hd_dir.directory? @logger.error("Required virtual machine directory not found!") raise Errors::BoxInvalid, name: env[:machine].name @@ -69,7 +69,7 @@ module VagrantPlugins "SourcePath" => Vagrant::Util::Platform.wsl_to_windows_path(image_path).gsub("/", "\\"), "VMName" => env[:machine].provider_config.vmname, } - options[:DisksConfig] = add_abs_path(disks_config, env[:machine].data_dir).to_json.to_s.gsub('"', '"""') if disks_config + #options[:DisksConfig] = add_abs_path(controller, env[:machine].data_dir).to_json.to_s.gsub('"', '"""') if controller env[:ui].detail("Creating and registering the VM...") diff --git a/plugins/providers/hyperv/config.rb b/plugins/providers/hyperv/config.rb index 38039a732..9468fc217 100644 --- a/plugins/providers/hyperv/config.rb +++ b/plugins/providers/hyperv/config.rb @@ -46,9 +46,9 @@ module VagrantPlugins attr_accessor :enable_virtualization_extensions # @return [Hash] Options for VMServiceIntegration attr_accessor :vm_integration_services - # @return [Hash] Config of disks and controllers - attr_accessor :disks_config - + # @return [Array] Config of disks and controllers + attr_accessor :controllers + def initialize @ip_address_timeout = UNSET_VALUE @memory = UNSET_VALUE @@ -64,7 +64,12 @@ module VagrantPlugins @enable_virtualization_extensions = UNSET_VALUE @enable_checkpoints = UNSET_VALUE @vm_integration_services = {} - @disks_config = UNSET_VALUE + @controllers = [] + end + + def controller(controller={}) + #puts "hej: controller called in config.rb" + @controllers << controller end def finalize! @@ -93,7 +98,6 @@ module VagrantPlugins else @enable_checkpoints = !!@enable_checkpoints end - @disks_config = nil if @disks_config == UNSET_VALUE end def validate(machine) @@ -125,6 +129,55 @@ module VagrantPlugins allowed_actions: ALLOWED_AUTO_STOP_ACTIONS.join(", ")) end + # This can happen when creating new on up. + controllers.delete_if &:empty? + + controllers.each { |controller| + #puts "controller: #{controller}" + + if ![:ide, :scsi].include?(controller[:type]) + errors << I18n.t("vagrant_hyperv.config.invalid_controller_type", + type: controller[:type]) + end + + if [:ide].include?(controller[:type]) + errors << I18n.t("vagrant_hyperv.config.invalid_controller_type_ide_not_implemeented_yet", + type: controller[:type]) + end + + if !controller[:disks].is_a?(Array) + errors << I18n.t("vagrant_hyperv.config.invalid_controller_disks_is_not_an_array", + disks: controller[:disks]) + next + end + + next_is_size = false + controller[:disks].each { |i| + if !next_is_size + if i.is_a?(String) + if File.file?(i) + next_is_size = false + + # TODO: This part not implemented yet. + errors << I18n.t("vagrant_hyperv.config.invalid_controller_disks_attaching_disks_not_implemented_yet", + element: i) + else + next_is_size = true + end + else + errors << I18n.t("vagrant_hyperv.config.invalid_controller_disks_element_is_not_a_string", + element: i) + end + else + #puts "next_is_size: true" + if !i.is_a?(Integer) + errors << I18n.t("vagrant_hyperv.config.invalid_controller_disks_element_is_not_an_integer", + element: i) + end + end + } + } + {"Hyper-V" => errors} end end diff --git a/plugins/providers/hyperv/driver.rb b/plugins/providers/hyperv/driver.rb index e200a8224..e1ea3a381 100644 --- a/plugins/providers/hyperv/driver.rb +++ b/plugins/providers/hyperv/driver.rb @@ -241,7 +241,8 @@ module VagrantPlugins notify: [:stdout, :stderr, :stdin], module_path: mod_path } - + + #puts "execute_powershell: options: #{ps_options}" Vagrant::Util::PowerShell.execute(path, *ps_options, **opts, &block) end end diff --git a/plugins/providers/hyperv/scripts/configure_vm.ps1 b/plugins/providers/hyperv/scripts/configure_vm.ps1 index 262c40a57..ee405e692 100644 --- a/plugins/providers/hyperv/scripts/configure_vm.ps1 +++ b/plugins/providers/hyperv/scripts/configure_vm.ps1 @@ -20,7 +20,7 @@ param( [parameter (Mandatory=$false)] [switch] $EnableCheckpoints, [parameter (Mandatory=$false)] - [string] $DisksConfig=$null + [string] $DisksToCreate=$null ) $ErrorActionPreference = "Stop" @@ -95,3 +95,49 @@ try { Write-ErrorMessage "Failed to ${CheckpointAction} checkpoints on VM: ${PSItem}" exit 1 } + + +#controller - path (for existent) +# path, +# sizeMB, name (for new) +function AddDisks($vm, $controller) { + #get controller + + $contNumber = ($vm | Add-VMScsiController -PassThru).ControllerNumber + foreach($disk in $controller) { + #get vhd + $vhd = $null + if($disk.Path) { + if (Test-Path -Path $disk.Path) { + $vhd = Resolve-Path -Path $disk.Path + } + } + else { + $vhd = "$($disk.Name).vhdx" + Add-Content "c:/ps_debug.log" -value "vhd: $vhd" + if (!(Test-Path -Path $vhd)) { + New-VHD -Path $vhd -SizeBytes ([UInt64]$disk.Size * 1MB) -Dynamic + } + } + if (!(Test-Path -Path $vhd)) { + Write-Error "There is error in virtual disk (VHD) configuration" + break + } + + $driveParam = @{ + ControllerNumber = $contNumber + Path = $vhd + ControllerType = "SCSI" + } + Add-Content "c:/ps_debug.log" -value "$vm | Add-VMHardDiskDrive @driveParam" + Add-Content "c:/ps_debug.log" -value "vhd: $vhd" + $vm | Add-VMHardDiskDrive @driveParam + } +} + +if ($DisksToCreate) { + Add-Content "c:/ps_debug.log" -value "DisksToCreate: $DisksToCreate" + $ParsedDisksToCreate = $DisksToCreate | ConvertFrom-Json + Add-Content "c:/ps_debug.log" -value "ParsedDisksToCreate: $ParsedDisksToCreate" + $ParsedDisksToCreate | ForEach-Object { AddDisks -vm $VM -controller $_ } +} \ No newline at end of file diff --git a/plugins/providers/hyperv/scripts/import_vm.ps1 b/plugins/providers/hyperv/scripts/import_vm.ps1 index b422824a0..538544553 100644 --- a/plugins/providers/hyperv/scripts/import_vm.ps1 +++ b/plugins/providers/hyperv/scripts/import_vm.ps1 @@ -14,7 +14,7 @@ param( [parameter (Mandatory=$false)] [string] $VMName=$null, [parameter (Mandatory=$false)] - [string] $DisksConfig=$null + [string] $DisksConfig=$null ) $ErrorActionPreference = "Stop" @@ -37,45 +37,3 @@ try { Write-ErrorMessage "${PSItem}" exit 1 } - - -#controller - path (for existent) -# path, -# sizeGB, name (for new) -function AddDisks($vm, $controller) { - #get controller - - $contNumber = ($vm | Add-VMScsiController -PassThru).ControllerNumber - foreach($disk in $controller) { - #get vhd - $vhd = $null - if($disk.Path) { - if (Test-Path -Path $disk.Path) { - $vhd = Resolve-Path -Path $disk.Path - } - } - else { - $vhd = $disk.Name - if (!(Test-Path -Path $vhd)) { - New-VHD -Path $vhd -SizeBytes ([UInt64]$disk.Size * 1GB) -Dynamic - } - } - if (!(Test-Path -Path $vhd)) { - Write-Error "There is error in virtual disk (VHD) configuration" - break - } - - $driveParam = @{ - ControllerNumber = $contNumber - Path = $vhd - ControllerType = "SCSI" - } - $vm | Add-VMHardDiskDrive @driveParam - } -} - -if ($DisksConfig) { - $ParsedDisksConfig = $DisksConfig | ConvertFrom-Json - $ParsedDisksConfig | ForEach-Object { AddDisks -vm $VMName -controller $_ } -} - diff --git a/website/source/docs/hyperv/configuration.html.md b/website/source/docs/hyperv/configuration.html.md index 178fadf10..b16006122 100644 --- a/website/source/docs/hyperv/configuration.html.md +++ b/website/source/docs/hyperv/configuration.html.md @@ -32,6 +32,7 @@ you may set. A complete reference is shown below: * `shutdown` (boolean) * `time_synchronization` (boolean) * `vss` (boolean) +* `controller` (hash) Config of disks and controllers. ## VM Integration Services From 7429e861e71b8b1a7b820131963ff4908ec2e804 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 19 Jul 2018 23:49:44 +0200 Subject: [PATCH 4/7] IMPR: Cleaned up source from puts and debug output. BUG: Moved source for attaching disk from config.rb to import.rb which makes it much more stable when halting and uping the vm several times. IMPR: Implemented all I18n messages in English for this feature. FEAT: Improved the documentation and added an example. --- plugins/providers/hyperv/action/configure.rb | 52 ------------------- plugins/providers/hyperv/action/import.rb | 38 +++++++++++--- plugins/providers/hyperv/config.rb | 12 ++--- .../providers/hyperv/scripts/configure_vm.ps1 | 50 +----------------- .../providers/hyperv/scripts/import_vm.ps1 | 47 ++++++++++++++++- templates/locales/providers_hyperv.yml | 19 +++++++ .../source/docs/hyperv/configuration.html.md | 22 +++++++- 7 files changed, 122 insertions(+), 118 deletions(-) diff --git a/plugins/providers/hyperv/action/configure.rb b/plugins/providers/hyperv/action/configure.rb index 839e227ee..00a952986 100644 --- a/plugins/providers/hyperv/action/configure.rb +++ b/plugins/providers/hyperv/action/configure.rb @@ -35,57 +35,6 @@ module VagrantPlugins end end - - # TODO: Should be controllers as we want to be able to have several lines. - #if !env[:machine].provider_config.controllers.empty? - # puts "hej: controller not empty" - # #env[:ui].detail("Controllers set") - # #controller.each do [key, value] - # # puts "key: #{id} value: #{value}" - # # if [type].include?(key) - # # puts "key matches type" - # # end - # #end - # - # env[:machine].provider_config.controller.each do |key, value| - # env[:ui].output("#{key} is #{value}") - # end - # - # #env[:machine].provider.driver.set_vm_integration_services( - # # env[:machine].provider_config.vm_integration_services) - #end - - disks_to_create = [] - env[:machine].provider_config.controllers.each { |controller| - #puts "configure.rb: controller: #{controller}" - - next_is_size = false - disk_name = '' - controller[:disks].each { |i| - #puts "configure.rb: i: #{i} disk_name: #{disk_name}" - if !next_is_size - if File.file?(i) - create_disk = false - filename_for_disk = i - next_is_size = false - - @logger.error("Attaching disks is not implemented yet") - else - create_disk = true - disk_name = i - next_is_size = true - #puts "configure.rb: disk_name set to: #{disk_name}" - end - else - #puts "configure.rb: Adding disk to create. name: #{disk_name}" - disks_to_create << { name: "\"#{disk_name}\"", size: i} - end - } - } - #puts "configure.rb: disks_to_create:#{disks_to_create}" - disks_to_create_json = disks_to_create.to_json - puts "configure.rb: json: #{disks_to_create_json}" - # If we already configured previously don't prompt for switch sentinel = env[:machine].data_dir.join("action_configure") @@ -122,7 +71,6 @@ module VagrantPlugins "AutoStopAction" => env[:machine].provider_config.auto_stop_action, "EnableCheckpoints" => env[:machine].provider_config.enable_checkpoints, "VirtualizationExtensions" => !!env[:machine].provider_config.enable_virtualization_extensions, - "DisksToCreate" => disks_to_create_json } options.delete_if{|_,v| v.nil? } diff --git a/plugins/providers/hyperv/action/import.rb b/plugins/providers/hyperv/action/import.rb index 3d37a2729..b282df5d1 100644 --- a/plugins/providers/hyperv/action/import.rb +++ b/plugins/providers/hyperv/action/import.rb @@ -17,7 +17,7 @@ module VagrantPlugins def call(env) vm_dir = env[:machine].box.directory.join("Virtual Machines") hd_dir = env[:machine].box.directory.join("Virtual Hard Disks") - controller = env[:machine].provider_config.controller + controllers = env[:machine].provider_config.controllers if !vm_dir.directory? || !hd_dir.directory? @logger.error("Required virtual machine directory not found!") raise Errors::BoxInvalid, name: env[:machine].name @@ -61,6 +61,35 @@ module VagrantPlugins env[:ui].output("Importing a Hyper-V instance") dest_path = env[:machine].data_dir.join("Virtual Hard Disks").join(image_path.basename).to_s + disks_to_create = [] + data_dir = env[:machine].data_dir + # This can happen when creating new on up. + controllers.delete_if &:empty? + + controllers.each { |controller| + next_is_size = false + disk_name = '' + controller[:disks].each { |i| + if !next_is_size + if File.file?(i) + create_disk = false + filename_for_disk = i + next_is_size = false + + @logger.error("Attaching disks is not implemented yet") + else + create_disk = true + disk_name = i + disk_name = data_dir.join("#{disk_name}.vhdx").to_s.gsub("/", "\\") + next_is_size = true + end + else + disks_to_create << { name: disk_name, size: i} + end + } + } + disks_to_create_json = disks_to_create.to_json.to_s.gsub('"', '"""') + options = { "VMConfigFile" => Vagrant::Util::Platform.wsl_to_windows_path(config_path).gsub("/", "\\"), "DestinationPath" => Vagrant::Util::Platform.wsl_to_windows_path(dest_path).gsub("/", "\\"), @@ -68,9 +97,8 @@ module VagrantPlugins "LinkedClone" => !!env[:machine].provider_config.linked_clone, "SourcePath" => Vagrant::Util::Platform.wsl_to_windows_path(image_path).gsub("/", "\\"), "VMName" => env[:machine].provider_config.vmname, + "DisksToCreate" => disks_to_create_json, } - #options[:DisksConfig] = add_abs_path(controller, env[:machine].data_dir).to_json.to_s.gsub('"', '"""') if controller - env[:ui].detail("Creating and registering the VM...") server = env[:machine].provider.driver.import(options) @@ -80,10 +108,6 @@ module VagrantPlugins @app.call(env) end - private - def add_abs_path(disks_config, data_dir) - disks_config.each {|controller| controller.each {|disk| disk['name'] = data_dir.join("#{disk['name']}.vhdx").to_s.gsub("/", "\\") if disk['name'] }} - end end end end diff --git a/plugins/providers/hyperv/config.rb b/plugins/providers/hyperv/config.rb index 9468fc217..8281f5784 100644 --- a/plugins/providers/hyperv/config.rb +++ b/plugins/providers/hyperv/config.rb @@ -68,7 +68,6 @@ module VagrantPlugins end def controller(controller={}) - #puts "hej: controller called in config.rb" @controllers << controller end @@ -133,7 +132,6 @@ module VagrantPlugins controllers.delete_if &:empty? controllers.each { |controller| - #puts "controller: #{controller}" if ![:ide, :scsi].include?(controller[:type]) errors << I18n.t("vagrant_hyperv.config.invalid_controller_type", @@ -141,13 +139,12 @@ module VagrantPlugins end if [:ide].include?(controller[:type]) - errors << I18n.t("vagrant_hyperv.config.invalid_controller_type_ide_not_implemeented_yet", - type: controller[:type]) + errors << I18n.t("vagrant_hyperv.config.invalid_controller_type_ide_not_implemeented_yet") end if !controller[:disks].is_a?(Array) errors << I18n.t("vagrant_hyperv.config.invalid_controller_disks_is_not_an_array", - disks: controller[:disks]) + received: controller[:disks].class) next end @@ -166,13 +163,12 @@ module VagrantPlugins end else errors << I18n.t("vagrant_hyperv.config.invalid_controller_disks_element_is_not_a_string", - element: i) + element: i, element_class: i.class) end else - #puts "next_is_size: true" if !i.is_a?(Integer) errors << I18n.t("vagrant_hyperv.config.invalid_controller_disks_element_is_not_an_integer", - element: i) + element: i, element_class: i.class) end end } diff --git a/plugins/providers/hyperv/scripts/configure_vm.ps1 b/plugins/providers/hyperv/scripts/configure_vm.ps1 index ee405e692..ff2b8ca3b 100644 --- a/plugins/providers/hyperv/scripts/configure_vm.ps1 +++ b/plugins/providers/hyperv/scripts/configure_vm.ps1 @@ -18,9 +18,7 @@ param( [parameter (Mandatory=$false)] [switch] $VirtualizationExtensions, [parameter (Mandatory=$false)] - [switch] $EnableCheckpoints, - [parameter (Mandatory=$false)] - [string] $DisksToCreate=$null + [switch] $EnableCheckpoints ) $ErrorActionPreference = "Stop" @@ -95,49 +93,3 @@ try { Write-ErrorMessage "Failed to ${CheckpointAction} checkpoints on VM: ${PSItem}" exit 1 } - - -#controller - path (for existent) -# path, -# sizeMB, name (for new) -function AddDisks($vm, $controller) { - #get controller - - $contNumber = ($vm | Add-VMScsiController -PassThru).ControllerNumber - foreach($disk in $controller) { - #get vhd - $vhd = $null - if($disk.Path) { - if (Test-Path -Path $disk.Path) { - $vhd = Resolve-Path -Path $disk.Path - } - } - else { - $vhd = "$($disk.Name).vhdx" - Add-Content "c:/ps_debug.log" -value "vhd: $vhd" - if (!(Test-Path -Path $vhd)) { - New-VHD -Path $vhd -SizeBytes ([UInt64]$disk.Size * 1MB) -Dynamic - } - } - if (!(Test-Path -Path $vhd)) { - Write-Error "There is error in virtual disk (VHD) configuration" - break - } - - $driveParam = @{ - ControllerNumber = $contNumber - Path = $vhd - ControllerType = "SCSI" - } - Add-Content "c:/ps_debug.log" -value "$vm | Add-VMHardDiskDrive @driveParam" - Add-Content "c:/ps_debug.log" -value "vhd: $vhd" - $vm | Add-VMHardDiskDrive @driveParam - } -} - -if ($DisksToCreate) { - Add-Content "c:/ps_debug.log" -value "DisksToCreate: $DisksToCreate" - $ParsedDisksToCreate = $DisksToCreate | ConvertFrom-Json - Add-Content "c:/ps_debug.log" -value "ParsedDisksToCreate: $ParsedDisksToCreate" - $ParsedDisksToCreate | ForEach-Object { AddDisks -vm $VM -controller $_ } -} \ No newline at end of file diff --git a/plugins/providers/hyperv/scripts/import_vm.ps1 b/plugins/providers/hyperv/scripts/import_vm.ps1 index 538544553..010cf7299 100644 --- a/plugins/providers/hyperv/scripts/import_vm.ps1 +++ b/plugins/providers/hyperv/scripts/import_vm.ps1 @@ -14,7 +14,7 @@ param( [parameter (Mandatory=$false)] [string] $VMName=$null, [parameter (Mandatory=$false)] - [string] $DisksConfig=$null + [string] $DisksToCreate=$null ) $ErrorActionPreference = "Stop" @@ -37,3 +37,48 @@ try { Write-ErrorMessage "${PSItem}" exit 1 } + + +#controller - path (for existent) +# path, +# sizeMB, name (for new) +function AddDisks($vm, $controller) { + #get controller + + $contNumber = ($vm | Add-VMScsiController -PassThru).ControllerNumber + foreach($disk in $controller) { + #get vhd + $vhd = $null + if($disk.Path) { + if (Test-Path -Path $disk.Path) { + $vhd = Resolve-Path -Path $disk.Path + } + } + else { + $vhd = $disk.Name + if (!(Test-Path -Path $vhd)) { + New-VHD -Path $vhd -SizeBytes ([UInt64]$disk.Size * 1MB) -Dynamic + } + } + if (!(Test-Path -Path $vhd)) { + Write-Error "There is error in virtual disk (VHD) configuration" + break + } + + $driveParam = @{ + ControllerNumber = $contNumber + Path = $vhd + ControllerType = "SCSI" + } + $vm | Add-VMHardDiskDrive @driveParam + } +} + +if ($DisksToCreate) { + $ParsedDisksToCreate = $DisksToCreate | ConvertFrom-Json + $ParsedDisksToCreate | ForEach-Object { AddDisks -vm $VMName -controller $_ } +} + + + + diff --git a/templates/locales/providers_hyperv.yml b/templates/locales/providers_hyperv.yml index dd2a13c44..d993308f5 100644 --- a/templates/locales/providers_hyperv.yml +++ b/templates/locales/providers_hyperv.yml @@ -39,6 +39,25 @@ en: The `differencing_disk` configuration option is deprecated and should no longer be used. The `linked_clone` configuration option should be used instead. + invalid_controller_type: |- + Invalid controller type provided for :type. Type receiver is + `%{type}` but `:ide` or `:scsi` was expected. + + Received: %{type} + Allowed: :ide, :scsi + invalid_controller_type_ide_not_implemeented_yet: |- + Controller type IDE is not implemented yet. + invalid_controller_disks_is_not_an_array: |- + Invalid type provided for `disks` in controller. Type received + is `%{received}` but `Array` was expected. + invalid_controller_disks_attaching_disks_not_implemented_yet: |- + Attaching existing disks is not implemented yet. + invalid_controller_disks_element_is_not_a_string: |- + Invalid type provided for element `%{element}`. Type received is + `%{element_class}` but `String` was expected. + invalid_controller_disks_element_is_not_an_integer: |- + Invalid type provided for element `%{element}`. Type received is + `%{element_class}` but `Integer` was expected. errors: admin_required: |- The Hyper-V provider requires that Vagrant be run with diff --git a/website/source/docs/hyperv/configuration.html.md b/website/source/docs/hyperv/configuration.html.md index b16006122..86dfb5d41 100644 --- a/website/source/docs/hyperv/configuration.html.md +++ b/website/source/docs/hyperv/configuration.html.md @@ -32,7 +32,9 @@ you may set. A complete reference is shown below: * `shutdown` (boolean) * `time_synchronization` (boolean) * `vss` (boolean) -* `controller` (hash) Config of disks and controllers. +* `controller` (hash) - Config of disks and controllers. + * `type` (:scsi) - Determines type of controller. Only supports SCSI right now. IDE is to be implemented. + * `disks` (array) - Disks to be created on the controller. First element is a string specifying name of disk, example d1. Second is size of disk in MB, example 10 * 1024 is 10 GB. Name of disk comes first and size after on every disk. ## VM Integration Services @@ -55,3 +57,21 @@ end This example would enable the `GuestServiceInterface` (which Vagrant is aware) and `CustomVMSRV` (which Vagrant is _not_ aware) VM integration services. + +## Attaching extra controllers and disks + +The `controller` configuration option is a simple hash that describes what kind of controller it is. +Such as `:scsi` or `:ide`. Right now only `:scsi` is supported. After this the disks that will be +created is specified in the `disks` array. This is an array where several disks to create can be +specified. First comes the name of the disk, for example d1, and after that followes the size of the +disk specified in MB, for example 10 * 1024 for a 10 GB disk. Repeat this for the number of disks you +want to attach on the controller. To attach existing vhd- or vhdx-files is not implemented yet. + +```ruby +config.vm.provider "hyperv" do |h| + h.controller type: :scsi, disks: [ "d1", 10 * 1024 ] +end +``` + +This example would create a SCSI controller and also create a d1.vhdx file and attach it as a dynamic +disk that is 10 * 1024 MB big, in other words 10 GB. From e53983515495a59d191c81cb5e36e9c49d2ade99 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 20 Jul 2018 09:46:21 +0200 Subject: [PATCH 5/7] MISC: Cleanup up unnecessary formating and style changes in the code to make the difference as minimal as possible. --- plugins/providers/hyperv/action/configure.rb | 2 +- plugins/providers/hyperv/action/import.rb | 2 +- plugins/providers/hyperv/config.rb | 2 +- plugins/providers/hyperv/driver.rb | 3 +-- plugins/providers/hyperv/scripts/import_vm.ps1 | 3 --- 5 files changed, 4 insertions(+), 8 deletions(-) diff --git a/plugins/providers/hyperv/action/configure.rb b/plugins/providers/hyperv/action/configure.rb index 00a952986..30831ac12 100644 --- a/plugins/providers/hyperv/action/configure.rb +++ b/plugins/providers/hyperv/action/configure.rb @@ -34,7 +34,7 @@ module VagrantPlugins end end end - + # If we already configured previously don't prompt for switch sentinel = env[:machine].data_dir.join("action_configure") diff --git a/plugins/providers/hyperv/action/import.rb b/plugins/providers/hyperv/action/import.rb index b282df5d1..3ead30bd9 100644 --- a/plugins/providers/hyperv/action/import.rb +++ b/plugins/providers/hyperv/action/import.rb @@ -100,6 +100,7 @@ module VagrantPlugins "DisksToCreate" => disks_to_create_json, } + env[:ui].detail("Creating and registering the VM...") server = env[:machine].provider.driver.import(options) @@ -107,7 +108,6 @@ module VagrantPlugins env[:machine].id = server["id"] @app.call(env) end - end end end diff --git a/plugins/providers/hyperv/config.rb b/plugins/providers/hyperv/config.rb index 8281f5784..0e80ccf58 100644 --- a/plugins/providers/hyperv/config.rb +++ b/plugins/providers/hyperv/config.rb @@ -48,7 +48,7 @@ module VagrantPlugins attr_accessor :vm_integration_services # @return [Array] Config of disks and controllers attr_accessor :controllers - + def initialize @ip_address_timeout = UNSET_VALUE @memory = UNSET_VALUE diff --git a/plugins/providers/hyperv/driver.rb b/plugins/providers/hyperv/driver.rb index e1ea3a381..e200a8224 100644 --- a/plugins/providers/hyperv/driver.rb +++ b/plugins/providers/hyperv/driver.rb @@ -241,8 +241,7 @@ module VagrantPlugins notify: [:stdout, :stderr, :stdin], module_path: mod_path } - - #puts "execute_powershell: options: #{ps_options}" + Vagrant::Util::PowerShell.execute(path, *ps_options, **opts, &block) end end diff --git a/plugins/providers/hyperv/scripts/import_vm.ps1 b/plugins/providers/hyperv/scripts/import_vm.ps1 index 010cf7299..21d0a2b87 100644 --- a/plugins/providers/hyperv/scripts/import_vm.ps1 +++ b/plugins/providers/hyperv/scripts/import_vm.ps1 @@ -79,6 +79,3 @@ if ($DisksToCreate) { $ParsedDisksToCreate | ForEach-Object { AddDisks -vm $VMName -controller $_ } } - - - From e5641c826f0997a158881ab9eba986773bfbdc39 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 20 Jul 2018 10:03:39 +0200 Subject: [PATCH 6/7] MISC: Replaced tab with spaces for indenting. --- plugins/providers/hyperv/scripts/import_vm.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/providers/hyperv/scripts/import_vm.ps1 b/plugins/providers/hyperv/scripts/import_vm.ps1 index 21d0a2b87..814539687 100644 --- a/plugins/providers/hyperv/scripts/import_vm.ps1 +++ b/plugins/providers/hyperv/scripts/import_vm.ps1 @@ -45,7 +45,7 @@ try { function AddDisks($vm, $controller) { #get controller - $contNumber = ($vm | Add-VMScsiController -PassThru).ControllerNumber + $contNumber = ($vm | Add-VMScsiController -PassThru).ControllerNumber foreach($disk in $controller) { #get vhd $vhd = $null From 7a44cf58c72227a487056e45df6393fd2da666ab Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 20 Jul 2018 14:25:17 +0200 Subject: [PATCH 7/7] BUG: Solved problems that happened in unit test "VagrantPlugins::HyperV::Action::Configure", "should call the app on success". The problems occured because controllers was being called when it wasn't defined. Solved by implementing if test for this. --- plugins/providers/hyperv/action/import.rb | 55 ++++++++++++----------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/plugins/providers/hyperv/action/import.rb b/plugins/providers/hyperv/action/import.rb index 3ead30bd9..ec16cd072 100644 --- a/plugins/providers/hyperv/action/import.rb +++ b/plugins/providers/hyperv/action/import.rb @@ -17,7 +17,7 @@ module VagrantPlugins def call(env) vm_dir = env[:machine].box.directory.join("Virtual Machines") hd_dir = env[:machine].box.directory.join("Virtual Hard Disks") - controllers = env[:machine].provider_config.controllers + if !vm_dir.directory? || !hd_dir.directory? @logger.error("Required virtual machine directory not found!") raise Errors::BoxInvalid, name: env[:machine].name @@ -61,34 +61,37 @@ module VagrantPlugins env[:ui].output("Importing a Hyper-V instance") dest_path = env[:machine].data_dir.join("Virtual Hard Disks").join(image_path.basename).to_s - disks_to_create = [] - data_dir = env[:machine].data_dir - # This can happen when creating new on up. - controllers.delete_if &:empty? - - controllers.each { |controller| - next_is_size = false - disk_name = '' - controller[:disks].each { |i| - if !next_is_size - if File.file?(i) - create_disk = false - filename_for_disk = i - next_is_size = false - - @logger.error("Attaching disks is not implemented yet") + if defined? env[:machine].provider_config.controllers + controllers = env[:machine].provider_config.controllers + disks_to_create = [] + data_dir = env[:machine].data_dir + # This can happen when creating new on up. + controllers.delete_if &:empty? + + controllers.each { |controller| + next_is_size = false + disk_name = '' + controller[:disks].each { |i| + if !next_is_size + if File.file?(i) + create_disk = false + filename_for_disk = i + next_is_size = false + + @logger.error("Attaching disks is not implemented yet") + else + create_disk = true + disk_name = i + disk_name = data_dir.join("#{disk_name}.vhdx").to_s.gsub("/", "\\") + next_is_size = true + end else - create_disk = true - disk_name = i - disk_name = data_dir.join("#{disk_name}.vhdx").to_s.gsub("/", "\\") - next_is_size = true + disks_to_create << { name: disk_name, size: i} end - else - disks_to_create << { name: disk_name, size: i} - end + } } - } - disks_to_create_json = disks_to_create.to_json.to_s.gsub('"', '"""') + disks_to_create_json = disks_to_create.to_json.to_s.gsub('"', '"""') + end options = { "VMConfigFile" => Vagrant::Util::Platform.wsl_to_windows_path(config_path).gsub("/", "\\"),