Skip to content

Commit

Permalink
Add multiple disk image support
Browse files Browse the repository at this point in the history
See: #1
See: sciurus#91
  • Loading branch information
TJ committed Aug 6, 2018
1 parent e495bb0 commit b0da186
Show file tree
Hide file tree
Showing 21 changed files with 119 additions and 42 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ test/actual_output
test/tmp
test/version_tmp
tmp
.project
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)

Expand Down
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion lib/vagrant-mutate/box/bhyve.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
47 changes: 40 additions & 7 deletions lib/vagrant-mutate/box/box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
4 changes: 3 additions & 1 deletion lib/vagrant-mutate/box/kvm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion lib/vagrant-mutate/box/libvirt.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require_relative 'box'
require 'shellwords'

module VagrantMutate
module Box
Expand All @@ -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
Expand Down
18 changes: 16 additions & 2 deletions lib/vagrant-mutate/box/virtualbox.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions lib/vagrant-mutate/box_loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 = []
Expand Down
4 changes: 2 additions & 2 deletions lib/vagrant-mutate/converter/bhyve.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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}`

Expand Down
31 changes: 24 additions & 7 deletions lib/vagrant-mutate/converter/converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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))
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions lib/vagrant-mutate/converter/kvm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module VagrantMutate
module Converter
class Kvm < Converter
def generate_metadata
def generate_metadata(index)
{ 'provider' => @output_box.provider_name }
end

Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions lib/vagrant-mutate/converter/libvirt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions lib/vagrant-mutate/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion lib/vagrant-mutate/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module VagrantMutate
VERSION = '1.2.0'
VERSION = '1.2.1-tj'
end
12 changes: 6 additions & 6 deletions templates/kvm/box.xml.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@
<on_crash>restart</on_crash>
<devices>
<emulator><%= qemu_bin %></emulator>
<disk type='file' device='disk'>
<% dev = 'vda'; for index in 0..pathnames.length-1 do %><disk type='file' device='disk'>
<driver name='qemu' type='<%= image_type %>'/>
<source file='<%= disk %>'/>
<target dev='vda' bus='<%= disk_bus %>'/>
<source file='<%= pathnames[index][1].basename %>'/>
<target dev='<%= dev %>' bus='<%= disk_bus %>'/>
<% if disk_bus == 'virtio' %>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x<%= index %>'/>
<% else %>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
<address type='drive' controller='0' bus='0' target='0' unit='<%= index %>'/>
<% end %>
</disk>
</disk><% dev.succ!; end %>
<interface type='network'>
<mac address='<%= mac %>'/>
<source network='vagrant'/>
Expand Down
File renamed without changes.
Binary file modified test/expected_output/virtualbox/kvm/box-disk1.img
Binary file not shown.
Binary file not shown.
6 changes: 3 additions & 3 deletions vagrant-mutate.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -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($/)
Expand Down

0 comments on commit b0da186

Please sign in to comment.