Chris Roberts e47e1df228 Reference Hyper-V switch by ID instead of name
Keep track of selected Hyper-V switch using the ID instead of name
to prevent any encoding issues that may occur switching between
PowerShell and Ruby. With the IDs staying consistent, the switch
name can be fetched from the provided ID.

Fixes #9679 #8794 #9451
2018-04-27 16:52:16 -07:00

178 lines
7.0 KiB
Ruby

require "fileutils"
require "log4r"
module VagrantPlugins
module HyperV
module Action
class Import
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant::hyperv::import")
end
def call(env)
vm_dir = env[:machine].box.directory.join("Virtual Machines")
hd_dir = env[:machine].box.directory.join("Virtual Hard Disks")
memory = env[:machine].provider_config.memory
maxmemory = env[:machine].provider_config.maxmemory
cpus = env[:machine].provider_config.cpus
vmname = env[:machine].provider_config.vmname
differencing_disk = env[:machine].provider_config.differencing_disk
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
env[:ui].output("Configured cpus number is #{cpus}") if cpus
env[:ui].output("Configured enable virtualization extensions is #{enable_virtualization_extensions}") if enable_virtualization_extensions
env[:ui].output("Configured vmname is #{vmname}") if vmname
env[:ui].output("Configured differencing disk instead of cloning") if differencing_disk
env[:ui].output("Configured automatic start action is #{auto_start_action}") if auto_start_action
env[:ui].output("Configured automatic stop action is #{auto_stop_action}") if auto_stop_action
if !vm_dir.directory? || !hd_dir.directory?
raise Errors::BoxInvalid
end
config_path = nil
config_type = nil
vm_dir.each_child do |f|
if f.extname.downcase == '.xml'
@logger.debug("Found XML config...")
config_path = f
config_type = 'xml'
break
end
end
vmcx_support = env[:machine].provider.driver.execute("has_vmcx_support.ps1", {})['result']
if vmcx_support
vm_dir.each_child do |f|
if f.extname.downcase == '.vmcx'
@logger.debug("Found VMCX config and support...")
config_path = f
config_type = 'vmcx'
break
end
end
end
image_path = nil
image_ext = nil
image_filename = nil
hd_dir.each_child do |f|
if %w{.vhd .vhdx}.include?(f.extname.downcase)
image_path = f
image_ext = f.extname.downcase
image_filename = File.basename(f, image_ext)
break
end
end
if !config_path || !image_path
raise Errors::BoxInvalid
end
env[:ui].output("Importing a Hyper-V instance")
switches = env[:machine].provider.driver.execute("get_switches.ps1", {})
raise Errors::NoSwitches if switches.empty?
switch = nil
env[:machine].config.vm.networks.each do |type, opts|
next if type != :public_network && type != :private_network
switchToFind = opts[:bridge]
if switchToFind
@logger.debug("Looking for switch with name: #{switchToFind}")
switch = switches.find { |s| s["Name"].downcase == switchToFind.downcase }["Id"]
@logger.debug("Found switch: #{switch}")
end
end
if switch.nil?
if switches.length > 1
env[:ui].detail(I18n.t("vagrant_hyperv.choose_switch") + "\n ")
switches.each_index do |i|
switch = switches[i]
env[:ui].detail("#{i+1}) #{switch["Name"]}")
end
env[:ui].detail(" ")
switch = nil
while !switch
switch = env[:ui].ask("What switch would you like to use? ")
next if !switch
switch = switch.to_i - 1
switch = nil if switch < 0 || switch >= switches.length
end
switch = switches[switch]["Id"]
else
switch = switches[0]["Id"]
end
end
env[:ui].detail("Cloning virtual hard drive...")
source_path = image_path.to_s
dest_path = env[:machine].data_dir.join("Virtual Hard Disks").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.mkdir_p(env[:machine].data_dir.join("Virtual Hard Disks"))
FileUtils.cp(source_path, dest_path)
end
end
image_path = dest_path
# We have to normalize the paths to be Windows paths since
# we're executing PowerShell.
options = {
vm_config_file: config_path.to_s.gsub("/", "\\"),
vm_config_type: config_type,
source_path: source_path.to_s,
dest_path: dest_path,
data_path: env[:machine].data_dir.to_s.gsub("/", "\\")
}
options[:switchname] = switch if switch
options[:memory] = memory if memory
options[:maxmemory] = maxmemory if maxmemory
options[:cpus] = cpus if cpus
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
options[:enable_virtualization_extensions] = "True" if enable_virtualization_extensions and enable_virtualization_extensions == true
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)
end
end
end
end
end