Update VM import for VirtualBox 6 driver

The dry run import with VirtualBox 6 no longer provides full paths
for disks. Extract base path from suggested settings file location
and use that to generate full path name using provided disk base
name.
This commit is contained in:
Chris Roberts 2018-11-15 11:04:08 -08:00
parent 1225114a15
commit b8f5752a82
1 changed files with 89 additions and 0 deletions

View File

@ -10,6 +10,95 @@ module VagrantPlugins
@logger = Log4r::Logger.new("vagrant::provider::virtualbox_6_0")
end
def import(ovf)
ovf = Vagrant::Util::Platform.windows_path(ovf)
output = ""
total = ""
last = 0
# Dry-run the import to get the suggested name and path
@logger.debug("Doing dry-run import to determine parallel-safe name...")
output = execute("import", "-n", ovf)
result = /Suggested VM name "(.+?)"/.match(output)
if !result
raise Vagrant::Errors::VirtualBoxNoName, output: output
end
suggested_name = result[1].to_s
# Append millisecond plus a random to the path in case we're
# importing the same box elsewhere.
specified_name = "#{suggested_name}_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
@logger.debug("-- Parallel safe name: #{specified_name}")
# Build the specified name param list
name_params = [
"--vsys", "0",
"--vmname", specified_name,
]
# Target path for disks is no longer a full path. Extract the path for the
# settings file to determine the base directory which we can then use to
# build the disk paths
result = /Suggested VM settings file name "(?<settings_path>.+?)"/.match(output)
if !result
@logger.warn("Failed to locate base path for disks. Using current working directory.")
base_path = "."
else
base_path = File.dirname(result[:settings_path])
end
@logger.info("Base path for disk import: #{base_path}")
# Extract the disks list and build the disk target params
disk_params = []
disks = output.scan(/(\d+): Hard disk image: source image=.+, target path=(.+),/)
disks.each do |unit_num, path|
path = File.join(base_path, File.basename(path))
disk_params << "--vsys"
disk_params << "0"
disk_params << "--unit"
disk_params << unit_num
disk_params << "--disk"
if Vagrant::Util::Platform.windows?
# we use the block form of sub here to ensure that if the specified_name happens to end with a number (which is fairly likely) then
# we won't end up having the character sequence of a \ followed by a number be interpreted as a back reference. For example, if
# specified_name were "abc123", then "\\abc123\\".reverse would be "\\321cba\\", and the \3 would be treated as a back reference by the sub
disk_params << path.reverse.sub("\\#{suggested_name}\\".reverse) { "\\#{specified_name}\\".reverse }.reverse # Replace only last occurrence
else
disk_params << path.reverse.sub("/#{suggested_name}/".reverse, "/#{specified_name}/".reverse).reverse # Replace only last occurrence
end
end
execute("import", ovf , *name_params, *disk_params, retryable: true) do |type, data|
if type == :stdout
# Keep track of the stdout so that we can get the VM name
output << data
elsif type == :stderr
# Append the data so we can see the full view
total << data.gsub("\r", "")
# Break up the lines. We can't get the progress until we see an "OK"
lines = total.split("\n")
if lines.include?("OK.")
# The progress of the import will be in the last line. Do a greedy
# regular expression to find what we're looking for.
match = /.+(\d{2})%/.match(lines.last)
if match
current = match[1].to_i
if current > last
last = current
yield current if block_given?
end
end
end
end
end
return get_machine_id specified_name
end
end
end
end