From b0da186104032e038cb164913af2233b7e9c0853 Mon Sep 17 00:00:00 2001 From: TJ Date: Mon, 6 Aug 2018 14:39:35 +0100 Subject: [PATCH] Add multiple disk image support See: https://github.com/iam-TJ/vagrant-mutate/issues/1 See: https://github.com/sciurus/vagrant-mutate/issues/91 --- .gitignore | 1 + CHANGELOG.md | 5 ++ README.md | 4 -- lib/vagrant-mutate/box/bhyve.rb | 4 +- lib/vagrant-mutate/box/box.rb | 47 +++++++++++++++--- lib/vagrant-mutate/box/kvm.rb | 4 +- lib/vagrant-mutate/box/libvirt.rb | 5 +- lib/vagrant-mutate/box/virtualbox.rb | 18 ++++++- lib/vagrant-mutate/box_loader.rb | 6 +-- lib/vagrant-mutate/converter/bhyve.rb | 4 +- lib/vagrant-mutate/converter/converter.rb | 31 +++++++++--- lib/vagrant-mutate/converter/kvm.rb | 4 +- lib/vagrant-mutate/converter/libvirt.rb | 4 +- lib/vagrant-mutate/errors.rb | 4 ++ lib/vagrant-mutate/version.rb | 2 +- templates/kvm/box.xml.erb | 12 ++--- .../kvm/libvirt/{box.img => box1.img} | Bin .../virtualbox/bhyve/{disk.img => disk1.img} | Bin .../virtualbox/kvm/box-disk1.img | Bin 197120 -> 196616 bytes .../virtualbox/libvirt/{box.img => box1.img} | Bin 197120 -> 196616 bytes vagrant-mutate.gemspec | 6 +-- 21 files changed, 119 insertions(+), 42 deletions(-) rename test/expected_output/kvm/libvirt/{box.img => box1.img} (100%) rename test/expected_output/virtualbox/bhyve/{disk.img => disk1.img} (100%) rename test/expected_output/virtualbox/libvirt/{box.img => box1.img} (99%) diff --git a/.gitignore b/.gitignore index b557e05..2c85ff7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ test/actual_output test/tmp test/version_tmp tmp +.project diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f2e702..b2ac5de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.2.1-tj (2018-08-01) +* This version forked and released by Tj via https://github.com/iam-TJ/vagrant-mutate +* Add support for converting boxes containing multiple disk images +* updated test/expected_output for virtualbox-to-{libvirt,kvm} due to qemu-img version 2.11.1 + # 1.2.0 (2016-08-15) * Add support for converting to bhyve (#86) diff --git a/README.md b/README.md index e8c7c0a..9bd3d68 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,6 @@ Vagrant-mutate is a vagrant plugin to convert vagrant boxes to work with different providers. -## Maintenance Notice - -I am no longer actively maintaining vagrant-mutate. If you are interested in taking over, let me know. - ## Supported Conversions * Virtualbox to kvm diff --git a/lib/vagrant-mutate/box/bhyve.rb b/lib/vagrant-mutate/box/bhyve.rb index 736fd27..2fe1d07 100644 --- a/lib/vagrant-mutate/box/bhyve.rb +++ b/lib/vagrant-mutate/box/bhyve.rb @@ -9,7 +9,9 @@ def initialize(env, name, version, dir) @supported_input = true @supported_output = true @image_format = 'raw' - @image_name = 'disk.img' + @prefix_default = 'disk' + @suffix_default = '.img' + @suffixes = /img$/ end # TODO diff --git a/lib/vagrant-mutate/box/box.rb b/lib/vagrant-mutate/box/box.rb index 62f8fce..6a44b71 100644 --- a/lib/vagrant-mutate/box/box.rb +++ b/lib/vagrant-mutate/box/box.rb @@ -11,22 +11,23 @@ def initialize(env, name, version, dir) @dir = dir @version = version @logger = Log4r::Logger.new('vagrant::mutate') + @pathnames = [] end - def virtual_size - extract_from_qemu_info(/(\d+) bytes/) + def virtual_size(index) + extract_from_qemu_info(index, /(\d+) bytes/) end - def verify_format - format_found = extract_from_qemu_info(/file format: (\w+)/) + def verify_format(index) + format_found = extract_from_qemu_info(index, /file format: (\w+)/) unless format_found == @image_format @env.ui.warn "Expected input image format to be #{@image_format} but "\ "it is #{format_found}. Attempting conversion anyway." end end - def extract_from_qemu_info(expression) - input_file = File.join(@dir, image_name).shellescape + def extract_from_qemu_info(index, expression) + input_file = @pathnames[index].to_s.shellescape info = `qemu-img info #{input_file}` @logger.debug "qemu-img info output\n#{info}" if info =~ expression @@ -35,6 +36,38 @@ def extract_from_qemu_info(expression) fail Errors::QemuInfoFailed end end - end + + # generate an incrementing name on each invocation + def image_name_output + # start from 1 so virtualbox doesn't need to over-ride this method + index = 1 + lambda do + tmp = @pathnames[index-1] = Pathname.new(@dir).join("#{@prefix_default}#{index}#{@suffix_default}") + index += 1 + return tmp + end + end + + # obtain all the valid names but return only 1 per invocation + def image_name_input + index = 0 + @pathnames = Pathname.new(@dir).children.select {|f| + f.file? && f.to_s.match(@suffixes) + } if @pathnames.length == 0 + lambda do + tmp = @pathnames[index] + index += 1 + return tmp + end + end + + def image_name(type='input') + if type == 'input' + return image_name_input + else + return image_name_output + end + end + end end end diff --git a/lib/vagrant-mutate/box/kvm.rb b/lib/vagrant-mutate/box/kvm.rb index d0abd30..4f6ee92 100644 --- a/lib/vagrant-mutate/box/kvm.rb +++ b/lib/vagrant-mutate/box/kvm.rb @@ -10,7 +10,9 @@ def initialize(env, name, version, dir) @supported_input = true @supported_output = true @image_format = 'qcow2' - @image_name = 'box-disk1.img' + @prefix_default = 'box-disk' + @suffix_default = '.img' + @suffixes = /img$/ end # TODO: implement these methods diff --git a/lib/vagrant-mutate/box/libvirt.rb b/lib/vagrant-mutate/box/libvirt.rb index 9932322..455cf94 100644 --- a/lib/vagrant-mutate/box/libvirt.rb +++ b/lib/vagrant-mutate/box/libvirt.rb @@ -1,4 +1,5 @@ require_relative 'box' +require 'shellwords' module VagrantMutate module Box @@ -9,8 +10,10 @@ def initialize(env, name, version, dir) @supported_input = true @supported_output = true @image_format = 'qcow2' - @image_name = 'box.img' @mac = nil + @prefix_default = 'box' + @suffix_default = '.img' + @suffixes = /(qcow|qcow.|img)$/ end # since none of below can be determined from the box diff --git a/lib/vagrant-mutate/box/virtualbox.rb b/lib/vagrant-mutate/box/virtualbox.rb index 34ec175..d167d52 100644 --- a/lib/vagrant-mutate/box/virtualbox.rb +++ b/lib/vagrant-mutate/box/virtualbox.rb @@ -10,11 +10,25 @@ def initialize(env, name, version, dir) @supported_input = true @supported_output = false @image_format = 'vmdk' + @prefix_default = 'box-disk' + @suffix_default = '.vmdk' + @suffixes = /vmdk$/ end # this is usually box-disk1.vmdk but some tools like packer customize it - def image_name - ovf.xpath("//*[local-name()='References']/*[local-name()='File']")[0].attribute("href").value + # return the next available filename on each invocation + def image_name_input + index = 0 + files = ovf.xpath("//*[local-name()='References']/*[local-name()='File']") + lambda do + if files[index] + tmp = @pathnames[index] = Pathname.new(@dir).join(files[index].attribute("href").value) + index += 1 + return tmp + else + return nil + end + end end # the architecture is not defined in the ovf file, diff --git a/lib/vagrant-mutate/box_loader.rb b/lib/vagrant-mutate/box_loader.rb index 62fe532..edaa847 100644 --- a/lib/vagrant-mutate/box_loader.rb +++ b/lib/vagrant-mutate/box_loader.rb @@ -210,11 +210,11 @@ def determine_version(dir) end # Handle single or multiple versions if metadata['versions'].nil? - @logger.info 'No versions provided by metadata, asuming version 0' + @logger.info 'No versions provided by metadata, assuming version 0' version = '0' elsif metadata['versions'].length > 1 metadata['versions'].each do |metadata_version| - @logger.info 'Itterating available metadata versions for active version.' + @logger.info 'Iterating available metadata versions for active version.' next unless metadata_version['status'] == 'active' version = metadata_version['version'] end @@ -246,7 +246,7 @@ def find_input_dir(name) box_parent_dir = File.join(@env.boxes_path, name, version) if Dir.exist?(box_parent_dir) - providers = Dir.entries(box_parent_dir).reject { |entry| entry =~ /^\./ } + providers = Pathname.new(box_parent_dir).children(with_directory=false).select(&:directory?).map(&:to_s) @logger.info "Found potential providers #{providers}" else providers = [] diff --git a/lib/vagrant-mutate/converter/bhyve.rb b/lib/vagrant-mutate/converter/bhyve.rb index 18f0fc5..3992bac 100644 --- a/lib/vagrant-mutate/converter/bhyve.rb +++ b/lib/vagrant-mutate/converter/bhyve.rb @@ -3,9 +3,9 @@ module VagrantMutate module Converter class Bhyve < Converter - def generate_metadata + def generate_metadata(index) - output_name = File.join(@output_box.dir, @output_box.image_name).shellescape + output_name = File.join(@output_box.dir, @pathnames[index][1]).to_s.shellescape file_output = `file #{output_name}` diff --git a/lib/vagrant-mutate/converter/converter.rb b/lib/vagrant-mutate/converter/converter.rb index f137491..a939988 100644 --- a/lib/vagrant-mutate/converter/converter.rb +++ b/lib/vagrant-mutate/converter/converter.rb @@ -26,6 +26,7 @@ def initialize(env, input_box, output_box, force_virtio='false') @output_box = output_box @force_virtio = force_virtio @logger = Log4r::Logger.new('vagrant::mutate') + @pathnames = [] end def convert @@ -35,8 +36,15 @@ def convert @env.ui.info "Converting #{@input_box.name} from #{@input_box.provider_name} "\ "to #{@output_box.provider_name}." - - @input_box.verify_format + in_lambda = @input_box.image_name('input') + out_lambda = @output_box.image_name('output') + until (image_name_tmp = in_lambda.call) == nil do + @pathnames += [[image_name_tmp, out_lambda.call ]] + @logger.debug "@pathnames=#{@pathnames}" + end + for index in 0..@pathnames.length-1 do + @input_box.verify_format(index) + end write_disk write_metadata write_vagrantfile @@ -46,7 +54,10 @@ def convert private def write_metadata - metadata = generate_metadata + metadata = {} + for index in 0..@pathnames.length-1 + metadata.merge!(generate_metadata(index)) + end begin File.open(File.join(@output_box.dir, 'metadata.json'), 'w') do |f| f.write(JSON.generate(metadata)) @@ -80,19 +91,24 @@ def write_disk end def copy_disk - input = File.join(@input_box.dir, @input_box.image_name) - output = File.join(@output_box.dir, @output_box.image_name) + fail Errors::PathnamesNotExtracted, error_message: "copy_disk" if @pathnames.length == 0 + @pathnames.each { |file_in, file_out| + input = file_in.to_s.shellescape + output = file_out.to_s.shellescape @logger.info "Copying #{input} to #{output}" begin FileUtils.copy_file(input, output) rescue => e raise Errors::WriteDiskFailed, error_message: e.message end + } end def convert_disk - input_file = File.join(@input_box.dir, @input_box.image_name).shellescape - output_file = File.join(@output_box.dir, @output_box.image_name).shellescape + fail Errors::PathnamesNotExtracted, error_message: "convert_disk" if @pathnames.length == 0 + @pathnames.each { |file_in, file_out| + input_file = file_in.to_s.shellescape + output_file = file_out.to_s.shellescape output_format = @output_box.image_format # p for progress bar @@ -110,6 +126,7 @@ def convert_disk unless system(command) fail Errors::WriteDiskFailed, error_message: "qemu-img exited with status #{$CHILD_STATUS.exitstatus}" end + } end end end diff --git a/lib/vagrant-mutate/converter/kvm.rb b/lib/vagrant-mutate/converter/kvm.rb index a1a7f50..1b02028 100644 --- a/lib/vagrant-mutate/converter/kvm.rb +++ b/lib/vagrant-mutate/converter/kvm.rb @@ -3,7 +3,7 @@ module VagrantMutate module Converter class Kvm < Converter - def generate_metadata + def generate_metadata(index) { 'provider' => @output_box.provider_name } end @@ -25,7 +25,7 @@ def write_specific_files end image_type = @output_box.image_format - disk = @output_box.image_name + pathnames = @pathnames name = @input_box.name memory = @input_box.memory / 1024 # convert bytes to kib diff --git a/lib/vagrant-mutate/converter/libvirt.rb b/lib/vagrant-mutate/converter/libvirt.rb index 66f7cbd..d8f2b76 100644 --- a/lib/vagrant-mutate/converter/libvirt.rb +++ b/lib/vagrant-mutate/converter/libvirt.rb @@ -2,11 +2,11 @@ module VagrantMutate module Converter class Libvirt < Converter - def generate_metadata + def generate_metadata(index) { 'provider' => @output_box.provider_name, 'format' => @output_box.image_format, - 'virtual_size' => ( @input_box.virtual_size.to_f / (1024 * 1024 * 1024)).ceil + 'virtual_size' => ( @input_box.virtual_size(index).to_f / (1024 * 1024 * 1024)).ceil } end diff --git a/lib/vagrant-mutate/errors.rb b/lib/vagrant-mutate/errors.rb index f061ca9..9cadf08 100644 --- a/lib/vagrant-mutate/errors.rb +++ b/lib/vagrant-mutate/errors.rb @@ -81,5 +81,9 @@ class URLError < VagrantMutateError class MetadataNotFound < VagrantMutateError error_key(:metadata_not_found) end + + class PathnamesNotExtracted < VagrantMutateError + error_key(:pathnames_not_extracted) + end end end diff --git a/lib/vagrant-mutate/version.rb b/lib/vagrant-mutate/version.rb index 9f631d4..2cb2c6b 100644 --- a/lib/vagrant-mutate/version.rb +++ b/lib/vagrant-mutate/version.rb @@ -1,3 +1,3 @@ module VagrantMutate - VERSION = '1.2.0' + VERSION = '1.2.1-tj' end diff --git a/templates/kvm/box.xml.erb b/templates/kvm/box.xml.erb index c2ac62b..7e2a370 100644 --- a/templates/kvm/box.xml.erb +++ b/templates/kvm/box.xml.erb @@ -21,16 +21,16 @@ restart <%= qemu_bin %> - + <% dev = 'vda'; for index in 0..pathnames.length-1 do %> - - + + <% if disk_bus == 'virtio' %> -
+
<% else %> -
+
<% end %> - + <% dev.succ!; end %> diff --git a/test/expected_output/kvm/libvirt/box.img b/test/expected_output/kvm/libvirt/box1.img similarity index 100% rename from test/expected_output/kvm/libvirt/box.img rename to test/expected_output/kvm/libvirt/box1.img diff --git a/test/expected_output/virtualbox/bhyve/disk.img b/test/expected_output/virtualbox/bhyve/disk1.img similarity index 100% rename from test/expected_output/virtualbox/bhyve/disk.img rename to test/expected_output/virtualbox/bhyve/disk1.img diff --git a/test/expected_output/virtualbox/kvm/box-disk1.img b/test/expected_output/virtualbox/kvm/box-disk1.img index 25d7c1064075c42a3c6eefe4e941734b304dd7eb..ef1c3c7d8beeb56607f6761d9a8c5f2b8ef4999d 100644 GIT binary patch delta 78 zcmZo@;pu4LnUEoz!Tckffq`KH14Bw?QAwpjQfA4-LNy-7oFVCT5^+0Q`s;_W%F@ delta 25 hcmeBZ;Av>#nUJyZq00Y>A1Yf}8CzMIHh%cc2mqC(3xEIs diff --git a/test/expected_output/virtualbox/libvirt/box.img b/test/expected_output/virtualbox/libvirt/box1.img similarity index 99% rename from test/expected_output/virtualbox/libvirt/box.img rename to test/expected_output/virtualbox/libvirt/box1.img index 25d7c1064075c42a3c6eefe4e941734b304dd7eb..ef1c3c7d8beeb56607f6761d9a8c5f2b8ef4999d 100644 GIT binary patch delta 78 zcmZo@;pu4LnUEoz!Tckffq`KH14Bw?QAwpjQfA4-LNy-7oFVCT5^+0Q`s;_W%F@ delta 25 hcmeBZ;Av>#nUJyZq00Y>A1Yf}8CzMIHh%cc2mqC(3xEIs diff --git a/vagrant-mutate.gemspec b/vagrant-mutate.gemspec index 562b50d..50fe47a 100644 --- a/vagrant-mutate.gemspec +++ b/vagrant-mutate.gemspec @@ -6,11 +6,11 @@ require 'vagrant-mutate/version' Gem::Specification.new do |spec| spec.name = "vagrant-mutate" spec.version = VagrantMutate::VERSION - spec.authors = ["Brian Pitts"] - spec.email = ["brian@polibyte.com"] + spec.authors = ["Brian Pitts", "Tj"] + spec.email = ["brian@polibyte.com", "hacker@iam.tj"] spec.description = %q{Convert vagrant boxes to work with different providers} spec.summary = spec.description - spec.homepage = "" + spec.homepage = "https://github.com/iam-TJ/vagrant-mutate" spec.license = "MIT" spec.files = `git ls-files`.split($/)