vagrant-mutate 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +6 -0
- data/lib/vagrant-mutate/box/box.rb +27 -0
- data/lib/vagrant-mutate/box/kvm.rb +18 -0
- data/lib/vagrant-mutate/box/libvirt.rb +18 -0
- data/lib/vagrant-mutate/{provider → box}/virtualbox.rb +17 -16
- data/lib/vagrant-mutate/{box.rb → box_loader.rb} +49 -41
- data/lib/vagrant-mutate/converter/converter.rb +136 -0
- data/lib/vagrant-mutate/converter/kvm.rb +53 -0
- data/lib/vagrant-mutate/converter/libvirt.rb +19 -0
- data/lib/vagrant-mutate/mutate.rb +11 -12
- data/lib/vagrant-mutate/version.rb +1 -1
- data/test/expected_output/virtualbox/kvm/box-disk1.img +0 -0
- data/test/expected_output/virtualbox/kvm/box.xml +2 -2
- metadata +10 -8
- data/lib/vagrant-mutate/converter.rb +0 -119
- data/lib/vagrant-mutate/provider/kvm.rb +0 -57
- data/lib/vagrant-mutate/provider/libvirt.rb +0 -27
- data/lib/vagrant-mutate/provider/provider.rb +0 -24
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# 0.1.4 (2013-12-08)
|
2
|
+
* Rework box and converter implementation (#7)
|
3
|
+
* Write disk images as sparse files (#13)
|
4
|
+
* Switch vagrant-kvm disk format from raw to qcow2 (#16)
|
5
|
+
* Prefer the binary named qemu-system-* over qemu-kvm or kvm (#20)
|
6
|
+
|
1
7
|
# 0.1.3 (2013-12-03)
|
2
8
|
|
3
9
|
* Add support for vagrant-kvm (#12)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module VagrantMutate
|
2
|
+
module Box
|
3
|
+
class Box
|
4
|
+
|
5
|
+
attr_reader :name, :dir, :provider_name, :supported_input, :supported_output, :image_format, :image_name
|
6
|
+
|
7
|
+
def initialize(env, name, dir)
|
8
|
+
@env = env
|
9
|
+
@name = name
|
10
|
+
@dir = dir
|
11
|
+
@logger = Log4r::Logger.new('vagrant::mutate')
|
12
|
+
end
|
13
|
+
|
14
|
+
def virtual_size
|
15
|
+
input_file = File.join( @dir, @image_name )
|
16
|
+
info = `qemu-img info #{input_file}`
|
17
|
+
@logger.debug "qemu-img info output\n#{info}"
|
18
|
+
if info =~ /(\d+) bytes/
|
19
|
+
return $1
|
20
|
+
else
|
21
|
+
raise Errors::DetermineImageSizeFailed
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'box'
|
2
|
+
|
3
|
+
module VagrantMutate
|
4
|
+
module Box
|
5
|
+
class Kvm < Box
|
6
|
+
|
7
|
+
def initialize(env, name, dir)
|
8
|
+
super
|
9
|
+
@provider_name = 'kvm'
|
10
|
+
@supported_input = false,
|
11
|
+
@supported_output = true,
|
12
|
+
@image_format = 'qcow2',
|
13
|
+
@image_name = 'box-disk1.img'
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'box'
|
2
|
+
|
3
|
+
module VagrantMutate
|
4
|
+
module Box
|
5
|
+
class Libvirt < Box
|
6
|
+
|
7
|
+
def initialize(env, name, dir)
|
8
|
+
super
|
9
|
+
@provider_name = 'libvirt'
|
10
|
+
@supported_input = false,
|
11
|
+
@supported_output = true,
|
12
|
+
@image_format = 'qcow2',
|
13
|
+
@image_name = 'box.img'
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,19 +1,17 @@
|
|
1
1
|
require "rexml/document"
|
2
|
+
require_relative 'box'
|
2
3
|
|
3
4
|
module VagrantMutate
|
4
|
-
module
|
5
|
+
module Box
|
6
|
+
class Virtualbox < Box
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@image_name = 'box-disk1.vmdk'
|
14
|
-
|
15
|
-
definition = File.read( File.join( box.dir, 'box.ovf') )
|
16
|
-
@ovf = REXML::Document.new(definition)
|
8
|
+
def initialize(env, name, dir)
|
9
|
+
super
|
10
|
+
@provider_name = 'virtualbox'
|
11
|
+
@supported_input = true,
|
12
|
+
@supported_output = false,
|
13
|
+
@image_format = 'vmdk',
|
14
|
+
@image_name = 'box-disk1.vmdk'
|
17
15
|
end
|
18
16
|
|
19
17
|
# the architecture is not defined in the ovf file,
|
@@ -28,7 +26,7 @@ module VagrantMutate
|
|
28
26
|
|
29
27
|
# use mac from the first enabled nic
|
30
28
|
def mac_address
|
31
|
-
|
29
|
+
ovf.elements.each("//vbox:Machine/Hardware//Adapter") do |ele|
|
32
30
|
if ele.attributes['enabled'] == 'true'
|
33
31
|
mac = ele.attributes['MACAddress']
|
34
32
|
# convert to more standarad format with colons
|
@@ -40,7 +38,7 @@ module VagrantMutate
|
|
40
38
|
end
|
41
39
|
|
42
40
|
def cpus
|
43
|
-
|
41
|
+
ovf.elements.each("//VirtualHardwareSection/Item") do |device|
|
44
42
|
if device.elements["rasd:ResourceType"].text == '3'
|
45
43
|
return device.elements["rasd:VirtualQuantity"].text
|
46
44
|
end
|
@@ -48,7 +46,7 @@ module VagrantMutate
|
|
48
46
|
end
|
49
47
|
|
50
48
|
def memory
|
51
|
-
|
49
|
+
ovf.elements.each("//VirtualHardwareSection/Item") do |device|
|
52
50
|
if device.elements["rasd:ResourceType"].text == '4'
|
53
51
|
return size_in_bytes(device.elements["rasd:VirtualQuantity"].text,
|
54
52
|
device.elements["rasd:AllocationUnits"].text)
|
@@ -58,6 +56,10 @@ module VagrantMutate
|
|
58
56
|
|
59
57
|
private
|
60
58
|
|
59
|
+
def ovf
|
60
|
+
@ovf ||= REXML::Document.new( File.read( File.join( @dir, 'box.ovf') ) )
|
61
|
+
end
|
62
|
+
|
61
63
|
# Takes a quantity and a unit
|
62
64
|
# returns quantity in bytes
|
63
65
|
# mib = true to use mebibytes, etc
|
@@ -99,4 +101,3 @@ module VagrantMutate
|
|
99
101
|
|
100
102
|
end
|
101
103
|
end
|
102
|
-
|
@@ -4,73 +4,80 @@ require 'json'
|
|
4
4
|
require 'zlib'
|
5
5
|
|
6
6
|
module VagrantMutate
|
7
|
-
class
|
7
|
+
class BoxLoader
|
8
8
|
|
9
9
|
include Archive::Tar
|
10
10
|
|
11
|
-
attr_reader :dir, :name, :provider
|
12
|
-
|
13
11
|
def initialize( env )
|
14
12
|
@env = env
|
15
13
|
@logger = Log4r::Logger.new('vagrant::mutate')
|
14
|
+
@tmp_dir = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_box(provider_name, name, dir)
|
18
|
+
@logger.info "Creating box #{name} with provider #{provider_name} in #{dir}"
|
19
|
+
case provider_name
|
20
|
+
when 'kvm'
|
21
|
+
require_relative 'box/kvm'
|
22
|
+
Box::Kvm.new(@env, name, dir)
|
23
|
+
when 'libvirt'
|
24
|
+
require_relative 'box/libvirt'
|
25
|
+
Box::Libvirt.new(@env, name, dir)
|
26
|
+
when 'virtualbox'
|
27
|
+
require_relative 'box/virtualbox'
|
28
|
+
Box::Virtualbox.new(@env, name, dir)
|
29
|
+
else
|
30
|
+
raise Errors::ProviderNotSupported, :provider => provider_name, :direction => 'input or output'
|
31
|
+
end
|
16
32
|
end
|
17
33
|
|
18
|
-
def prepare_for_output(
|
19
|
-
@logger.info "Preparing #{
|
20
|
-
|
21
|
-
|
22
|
-
@dir = create_output_dir()
|
23
|
-
@dir_is_tmp = false
|
34
|
+
def prepare_for_output(name, provider_name)
|
35
|
+
@logger.info "Preparing #{name} for output as #{provider_name}"
|
36
|
+
dir = create_output_dir(name, provider_name)
|
37
|
+
box = create_box(provider_name, name, dir)
|
24
38
|
|
25
|
-
unless
|
39
|
+
unless box.supported_output
|
26
40
|
raise Errors::ProviderNotSupported, :provider => provider_name, :direction => 'output'
|
27
41
|
end
|
42
|
+
|
43
|
+
return box
|
28
44
|
end
|
29
45
|
|
30
46
|
def load_from_file(file)
|
31
47
|
@logger.info "Loading box from file #{file}"
|
32
|
-
|
33
|
-
|
34
|
-
@
|
35
|
-
|
48
|
+
name = File.basename( file, File.extname(file) )
|
49
|
+
dir = unpack(file)
|
50
|
+
@tmp_dir = dir
|
51
|
+
provider_name = determine_provider(dir)
|
52
|
+
box = create_box(provider_name, name, dir)
|
36
53
|
|
37
|
-
unless
|
54
|
+
unless box.supported_input
|
38
55
|
raise Errors::ProviderNotSupported, :provider => provider_name, :direction => 'input'
|
39
56
|
end
|
57
|
+
|
58
|
+
return box
|
40
59
|
end
|
41
60
|
|
42
61
|
def load_by_name(name)
|
43
62
|
@logger.info "Loading box from name #{name}"
|
44
|
-
|
63
|
+
dir = find_input_dir(name)
|
45
64
|
# cheat for now since only supported input is virtualbox
|
46
|
-
|
47
|
-
|
48
|
-
@dir_is_tmp = false
|
65
|
+
box = create_box('virtualbox', name, dir)
|
66
|
+
return box
|
49
67
|
end
|
50
68
|
|
51
69
|
def cleanup
|
52
|
-
if @
|
70
|
+
if @tmp_dir
|
53
71
|
@env.ui.info "Cleaning up temporary files."
|
54
|
-
@logger.info "Deleting #{
|
55
|
-
FileUtils.remove_entry_secure(@
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def virtual_size
|
60
|
-
input_file = File.join( @dir, @provider.image_name )
|
61
|
-
info = `qemu-img info #{input_file}`
|
62
|
-
@logger.debug "qemu-img info output\n#{info}"
|
63
|
-
if info =~ /(\d+) bytes/
|
64
|
-
return $1
|
65
|
-
else
|
66
|
-
raise Errors::DetermineImageSizeFailed
|
72
|
+
@logger.info "Deleting #{@tmp_dir}"
|
73
|
+
FileUtils.remove_entry_secure(@tmp_dir)
|
67
74
|
end
|
68
75
|
end
|
69
76
|
|
70
77
|
private
|
71
78
|
|
72
|
-
def determine_provider
|
73
|
-
metadata_file = File.join(
|
79
|
+
def determine_provider(dir)
|
80
|
+
metadata_file = File.join(dir, 'metadata.json')
|
74
81
|
if File.exists? metadata_file
|
75
82
|
begin
|
76
83
|
metadata = JSON.load( File.new( metadata_file, 'r') )
|
@@ -78,15 +85,16 @@ module VagrantMutate
|
|
78
85
|
raise Errors::DetermineProviderFailed, :error_message => e.message
|
79
86
|
end
|
80
87
|
@logger.info "Determined input provider is #{metadata['provider']}"
|
81
|
-
return
|
88
|
+
return metadata['provider']
|
82
89
|
else
|
83
90
|
@logger.info "No metadata found, so assuming input provider is virtualbox"
|
84
|
-
return
|
91
|
+
return 'virtualbox'
|
85
92
|
end
|
86
93
|
end
|
87
94
|
|
88
|
-
def find_input_dir
|
89
|
-
|
95
|
+
def find_input_dir(name)
|
96
|
+
# cheat for now since only supported input is virtualbox
|
97
|
+
in_dir = File.join( @env.boxes_path, name, 'virtualbox' )
|
90
98
|
if File.directory?(in_dir)
|
91
99
|
@logger.info "Found input directory #{in_dir}"
|
92
100
|
return in_dir
|
@@ -95,9 +103,9 @@ module VagrantMutate
|
|
95
103
|
end
|
96
104
|
end
|
97
105
|
|
98
|
-
def create_output_dir
|
106
|
+
def create_output_dir(name, provider_name)
|
99
107
|
# e.g. $HOME/.vagrant.d/boxes/fedora-19/libvirt
|
100
|
-
out_dir = File.join( @env.boxes_path,
|
108
|
+
out_dir = File.join( @env.boxes_path, name, provider_name )
|
101
109
|
begin
|
102
110
|
FileUtils.mkdir_p(out_dir)
|
103
111
|
rescue => e
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module VagrantMutate
|
4
|
+
module Converter
|
5
|
+
class Converter
|
6
|
+
|
7
|
+
def self.create(env, input_box, output_box)
|
8
|
+
case output_box.provider_name
|
9
|
+
when 'kvm'
|
10
|
+
require_relative 'kvm'
|
11
|
+
Kvm.new(env, input_box, output_box)
|
12
|
+
when 'libvirt'
|
13
|
+
require_relative 'libvirt'
|
14
|
+
Libvirt.new(env, input_box, output_box)
|
15
|
+
else
|
16
|
+
raise Errors::ProviderNotSupported, :provider => output_box.provider_name, :direction => 'output'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(env, input_box, output_box)
|
21
|
+
@env = env
|
22
|
+
@input_box = input_box
|
23
|
+
@output_box = output_box
|
24
|
+
@logger = Log4r::Logger.new('vagrant::mutate')
|
25
|
+
verify_qemu_installed
|
26
|
+
verify_qemu_version
|
27
|
+
end
|
28
|
+
|
29
|
+
def convert()
|
30
|
+
@env.ui.info "Converting #{@input_box.name} from #{@input_box.provider_name} "\
|
31
|
+
"to #{@output_box.provider_name}."
|
32
|
+
|
33
|
+
write_metadata
|
34
|
+
copy_vagrantfile
|
35
|
+
write_specific_files
|
36
|
+
write_disk
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# http://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
|
42
|
+
def verify_qemu_installed
|
43
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
44
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
45
|
+
exts.each do |ext|
|
46
|
+
exe = File.join(path, "qemu-img#{ext}")
|
47
|
+
if File.executable? exe
|
48
|
+
@logger.info "Found qemu"
|
49
|
+
return
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
# if we make it here qemu-img command was not found
|
54
|
+
raise Errors::QemuNotFound
|
55
|
+
end
|
56
|
+
|
57
|
+
def verify_qemu_version
|
58
|
+
usage = `qemu-img`
|
59
|
+
if usage =~ /(\d+\.\d+\.\d+)/
|
60
|
+
recommended_version = Gem::Version.new('1.2.0')
|
61
|
+
installed_version = Gem::Version.new($1)
|
62
|
+
if installed_version < recommended_version
|
63
|
+
@env.ui.warn "You have qemu #{installed_version} installed. "\
|
64
|
+
"This version is too old to read some virtualbox boxes. "\
|
65
|
+
"If conversion fails, try upgrading to qemu 1.2.0 or newer."
|
66
|
+
end
|
67
|
+
else
|
68
|
+
raise Errors::ParseQemuVersionFailed
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def write_metadata
|
74
|
+
metadata = generate_metadata
|
75
|
+
begin
|
76
|
+
File.open( File.join( @output_box.dir, 'metadata.json'), 'w') do |f|
|
77
|
+
f.write( JSON.generate(metadata) )
|
78
|
+
end
|
79
|
+
rescue => e
|
80
|
+
raise Errors::WriteMetadataFailed, :error_message => e.message
|
81
|
+
end
|
82
|
+
@logger.info "Wrote metadata"
|
83
|
+
end
|
84
|
+
|
85
|
+
def copy_vagrantfile
|
86
|
+
input = File.join( @input_box.dir, 'Vagrantfile' )
|
87
|
+
if File.exists? input
|
88
|
+
output = File.join( @output_box.dir, 'Vagrantfile' )
|
89
|
+
@logger.info "Copying #{input} to #{output}"
|
90
|
+
begin
|
91
|
+
FileUtils.copy_file(input, output)
|
92
|
+
rescue => e
|
93
|
+
raise Errors::WriteVagrantfileFailed, :error_message => e.message
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def write_disk
|
99
|
+
if @input_box.image_format == @output_box.image_format
|
100
|
+
copy_disk
|
101
|
+
else
|
102
|
+
convert_disk
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def copy_disk
|
107
|
+
input = File.join( @input_box.dir, @input_box.image_name )
|
108
|
+
output = File.join( @output_box.dir, @output_box.image_name )
|
109
|
+
@logger.info "Copying #{input} to #{output}"
|
110
|
+
begin
|
111
|
+
FileUtils.copy_file(input, output)
|
112
|
+
rescue => e
|
113
|
+
raise Errors::WriteDiskFailed, :error_message => e.message
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def convert_disk
|
118
|
+
input_file = File.join( @input_box.dir, @input_box.image_name )
|
119
|
+
output_file = File.join( @output_box.dir, @output_box.image_name )
|
120
|
+
input_format = @input_box.image_format
|
121
|
+
output_format = @output_box.image_format
|
122
|
+
|
123
|
+
# p for progress bar
|
124
|
+
# S for sparse file
|
125
|
+
qemu_options = '-p -S 16k'
|
126
|
+
|
127
|
+
command = "qemu-img convert #{qemu_options} -f #{input_format} -O #{output_format} #{input_file} #{output_file}"
|
128
|
+
@logger.info "Running #{command}"
|
129
|
+
unless system(command)
|
130
|
+
raise Errors::WriteDiskFailed, :error_message => "qemu-img exited with status #{$?.exitstatus}"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module VagrantMutate
|
4
|
+
module Converter
|
5
|
+
class Kvm < Converter
|
6
|
+
|
7
|
+
def generate_metadata
|
8
|
+
metadata = {
|
9
|
+
'provider' => @output_box.provider_name,
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def write_specific_files
|
14
|
+
template_path = VagrantMutate.source_root.join('templates', 'kvm', 'box.xml.erb')
|
15
|
+
template = File.read(template_path)
|
16
|
+
|
17
|
+
uuid = nil
|
18
|
+
gui = true
|
19
|
+
disk_bus = 'virtio'
|
20
|
+
|
21
|
+
image_type = @output_box.image_format
|
22
|
+
disk = @output_box.image_name
|
23
|
+
|
24
|
+
name = @input_box.name
|
25
|
+
memory = @input_box.memory / 1024 # convert bytes to kib
|
26
|
+
cpus = @input_box.cpus
|
27
|
+
mac = @input_box.mac_address
|
28
|
+
arch = @input_box.architecture
|
29
|
+
|
30
|
+
qemu_bin = find_kvm
|
31
|
+
|
32
|
+
File.open( File.join( @output_box.dir, 'box.xml'), 'w') do |f|
|
33
|
+
f.write( ERB.new(template).result(binding) )
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def find_kvm
|
40
|
+
qemu_bin_list = [ '/usr/bin/qemu-system-x86_64',
|
41
|
+
'/usr/bin/qemu-system-i386',
|
42
|
+
'/usr/bin/qemu-kvm',
|
43
|
+
'/usr/bin/kvm' ]
|
44
|
+
qemu_bin = qemu_bin_list.detect { |binary| File.exists? binary }
|
45
|
+
unless qemu_bin
|
46
|
+
raise Errors::QemuNotFound
|
47
|
+
end
|
48
|
+
return qemu_bin
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module VagrantMutate
|
2
|
+
module Converter
|
3
|
+
class Libvirt < Converter
|
4
|
+
|
5
|
+
def generate_metadata
|
6
|
+
metadata = {
|
7
|
+
'provider' => @output_box.provider_name,
|
8
|
+
'format' => @output_box.image_format,
|
9
|
+
'virtual_size' => ( @input_box.virtual_size.to_f / (1024 * 1024 * 1024) ).ceil
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def write_specific_files
|
14
|
+
# nothing to do here
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
|
-
require 'vagrant-mutate/
|
2
|
-
require 'vagrant-mutate/converter'
|
3
|
-
require 'vagrant-mutate/provider/provider'
|
1
|
+
require 'vagrant-mutate/box_loader'
|
2
|
+
require 'vagrant-mutate/converter/converter'
|
4
3
|
|
5
4
|
module VagrantMutate
|
6
5
|
|
@@ -21,23 +20,23 @@ module VagrantMutate
|
|
21
20
|
box_arg = argv[0]
|
22
21
|
output_provider_arg = argv[1]
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
output_box = Box.new(@env)
|
23
|
+
input_loader = BoxLoader.new(@env)
|
24
|
+
output_loader = BoxLoader.new(@env)
|
27
25
|
|
28
26
|
if box_arg =~ /\.box$/
|
29
|
-
input_box.load_from_file(box_arg)
|
27
|
+
input_box = input_loader.load_from_file(box_arg)
|
30
28
|
else
|
31
|
-
input_box.load_by_name(box_arg)
|
29
|
+
input_box = input_loader.load_by_name(box_arg)
|
32
30
|
end
|
33
31
|
|
34
|
-
output_box.prepare_for_output( input_box.name, output_provider_arg)
|
32
|
+
output_box = output_loader.prepare_for_output( input_box.name, output_provider_arg)
|
35
33
|
|
36
|
-
converter.
|
34
|
+
converter = Converter::Converter.create(@env, input_box, output_box)
|
35
|
+
converter.convert
|
37
36
|
|
38
|
-
|
37
|
+
input_loader.cleanup
|
39
38
|
|
40
|
-
@env.ui.info "The box #{output_box.name} (#{output_box.
|
39
|
+
@env.ui.info "The box #{output_box.name} (#{output_box.provider_name}) is now ready to use."
|
41
40
|
|
42
41
|
end
|
43
42
|
|
Binary file
|
@@ -18,9 +18,9 @@
|
|
18
18
|
<on_reboot>restart</on_reboot>
|
19
19
|
<on_crash>restart</on_crash>
|
20
20
|
<devices>
|
21
|
-
<emulator>/usr/bin/
|
21
|
+
<emulator>/usr/bin/qemu-system-x86_64</emulator>
|
22
22
|
<disk type='file' device='disk'>
|
23
|
-
<driver name='qemu' type='
|
23
|
+
<driver name='qemu' type='qcow2'/>
|
24
24
|
<source file='box-disk1.img'/>
|
25
25
|
<target dev='vda' bus='virtio'/>
|
26
26
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vagrant-mutate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-12-
|
12
|
+
date: 2013-12-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: archive-tar-minitar
|
@@ -73,14 +73,16 @@ files:
|
|
73
73
|
- README.md
|
74
74
|
- Rakefile
|
75
75
|
- lib/vagrant-mutate.rb
|
76
|
-
- lib/vagrant-mutate/box.rb
|
77
|
-
- lib/vagrant-mutate/
|
76
|
+
- lib/vagrant-mutate/box/box.rb
|
77
|
+
- lib/vagrant-mutate/box/kvm.rb
|
78
|
+
- lib/vagrant-mutate/box/libvirt.rb
|
79
|
+
- lib/vagrant-mutate/box/virtualbox.rb
|
80
|
+
- lib/vagrant-mutate/box_loader.rb
|
81
|
+
- lib/vagrant-mutate/converter/converter.rb
|
82
|
+
- lib/vagrant-mutate/converter/kvm.rb
|
83
|
+
- lib/vagrant-mutate/converter/libvirt.rb
|
78
84
|
- lib/vagrant-mutate/errors.rb
|
79
85
|
- lib/vagrant-mutate/mutate.rb
|
80
|
-
- lib/vagrant-mutate/provider/kvm.rb
|
81
|
-
- lib/vagrant-mutate/provider/libvirt.rb
|
82
|
-
- lib/vagrant-mutate/provider/provider.rb
|
83
|
-
- lib/vagrant-mutate/provider/virtualbox.rb
|
84
86
|
- lib/vagrant-mutate/version.rb
|
85
87
|
- locales/en.yml
|
86
88
|
- templates/kvm/box.xml.erb
|
@@ -1,119 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
|
3
|
-
module VagrantMutate
|
4
|
-
class Converter
|
5
|
-
|
6
|
-
def initialize(env)
|
7
|
-
@env = env
|
8
|
-
@logger = Log4r::Logger.new('vagrant::mutate')
|
9
|
-
verify_qemu_installed
|
10
|
-
verify_qemu_version
|
11
|
-
end
|
12
|
-
|
13
|
-
def convert(input_box, output_box)
|
14
|
-
@input_box = input_box
|
15
|
-
@output_box = output_box
|
16
|
-
|
17
|
-
@env.ui.info "Converting #{input_box.name} from #{input_box.provider.name} "\
|
18
|
-
"to #{output_box.provider.name}."
|
19
|
-
|
20
|
-
write_metadata
|
21
|
-
# will have to rethink this if any providers need to alter the vagrantfile
|
22
|
-
copy_vagrantfile
|
23
|
-
output_box.provider.write_specific_files(input_box)
|
24
|
-
write_disk
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
# http://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
|
30
|
-
def verify_qemu_installed
|
31
|
-
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
32
|
-
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
33
|
-
exts.each do |ext|
|
34
|
-
exe = File.join(path, "qemu-img#{ext}")
|
35
|
-
if File.executable? exe
|
36
|
-
@logger.info "Found qemu"
|
37
|
-
return
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
# if we make it here qemu-img command was not found
|
42
|
-
raise Errors::QemuNotFound
|
43
|
-
end
|
44
|
-
|
45
|
-
def verify_qemu_version
|
46
|
-
usage = `qemu-img`
|
47
|
-
if usage =~ /(\d+\.\d+\.\d+)/
|
48
|
-
recommended_version = Gem::Version.new('1.2.0')
|
49
|
-
installed_version = Gem::Version.new($1)
|
50
|
-
if installed_version < recommended_version
|
51
|
-
@env.ui.warn "You have qemu #{installed_version} installed. "\
|
52
|
-
"This version is too old to read some virtualbox boxes. "\
|
53
|
-
"If conversion fails, try upgrading to qemu 1.2.0 or newer."
|
54
|
-
end
|
55
|
-
else
|
56
|
-
raise Errors::ParseQemuVersionFailed
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
|
61
|
-
def write_metadata
|
62
|
-
metadata = @output_box.provider.generate_metadata(@input_box)
|
63
|
-
begin
|
64
|
-
File.open( File.join( @output_box.dir, 'metadata.json'), 'w') do |f|
|
65
|
-
f.write( JSON.generate(metadata) )
|
66
|
-
end
|
67
|
-
rescue => e
|
68
|
-
raise Errors::WriteMetadataFailed, :error_message => e.message
|
69
|
-
end
|
70
|
-
@logger.info "Wrote metadata"
|
71
|
-
end
|
72
|
-
|
73
|
-
def copy_vagrantfile
|
74
|
-
input = File.join( @input_box.dir, 'Vagrantfile' )
|
75
|
-
if File.exists? input
|
76
|
-
output = File.join( @output_box.dir, 'Vagrantfile' )
|
77
|
-
@logger.info "Copying #{input} to #{output}"
|
78
|
-
begin
|
79
|
-
FileUtils.copy_file(input, output)
|
80
|
-
rescue => e
|
81
|
-
raise Errors::WriteVagrantfileFailed, :error_message => e.message
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def write_disk
|
87
|
-
if @input_box.provider.image_format == @output_box.provider.image_format
|
88
|
-
copy_disk
|
89
|
-
else
|
90
|
-
convert_disk
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def copy_disk
|
95
|
-
input = File.join( @input_box.dir, @input_box.provider.image_name )
|
96
|
-
output = File.join( @output_box.dir, @output_box.provider.image_name )
|
97
|
-
@logger.info "Copying #{input} to #{output}"
|
98
|
-
begin
|
99
|
-
FileUtils.copy_file(input, output)
|
100
|
-
rescue => e
|
101
|
-
raise Errors::WriteDiskFailed, :error_message => e.message
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def convert_disk
|
106
|
-
input_file = File.join( @input_box.dir, @input_box.provider.image_name )
|
107
|
-
output_file = File.join( @output_box.dir, @output_box.provider.image_name )
|
108
|
-
input_format = @input_box.provider.image_format
|
109
|
-
output_format = @output_box.provider.image_format
|
110
|
-
|
111
|
-
command = "qemu-img convert -p -f #{input_format} -O #{output_format} #{input_file} #{output_file}"
|
112
|
-
@logger.info "Running #{command}"
|
113
|
-
unless system(command)
|
114
|
-
raise Errors::WriteDiskFailed, :error_message => "qemu-img exited with status #{$?.exitstatus}"
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
end
|
119
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
require 'erb'
|
2
|
-
|
3
|
-
module VagrantMutate
|
4
|
-
module Provider
|
5
|
-
class Kvm < Provider
|
6
|
-
def initialize(box)
|
7
|
-
@box = box
|
8
|
-
@name = 'kvm'
|
9
|
-
@supported_input = false,
|
10
|
-
@supported_output = true,
|
11
|
-
@image_format = 'raw',
|
12
|
-
@image_name = 'box-disk1.img'
|
13
|
-
end
|
14
|
-
|
15
|
-
def generate_metadata(input_box)
|
16
|
-
metadata = {
|
17
|
-
'provider' => @box.provider.name,
|
18
|
-
}
|
19
|
-
end
|
20
|
-
|
21
|
-
def write_specific_files(input_box)
|
22
|
-
template_path = VagrantMutate.source_root.join('templates', 'kvm', 'box.xml.erb')
|
23
|
-
template = File.read(template_path)
|
24
|
-
|
25
|
-
uuid = nil
|
26
|
-
gui = true
|
27
|
-
disk_bus = 'virtio'
|
28
|
-
name = input_box.name
|
29
|
-
image_type = @image_format
|
30
|
-
disk = @image_name
|
31
|
-
qemu_bin = find_kvm
|
32
|
-
memory = input_box.provider.memory / 1024 # convert bytes to kib
|
33
|
-
cpus = input_box.provider.cpus
|
34
|
-
mac = input_box.provider.mac_address
|
35
|
-
arch = input_box.provider.architecture
|
36
|
-
|
37
|
-
File.open( File.join( @box.dir, 'box.xml'), 'w') do |f|
|
38
|
-
f.write( ERB.new(template).result(binding) )
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def find_kvm
|
45
|
-
qemu_bin_list = [ '/usr/bin/qemu-kvm', '/usr/bin/kvm',
|
46
|
-
'/usr/bin/qemu-system-x86_64',
|
47
|
-
'/usr/bin/qemu-system-i386' ]
|
48
|
-
qemu_bin = qemu_bin_list.detect { |binary| File.exists? binary }
|
49
|
-
unless qemu_bin
|
50
|
-
raise Errors::QemuNotFound
|
51
|
-
end
|
52
|
-
return qemu_bin
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module VagrantMutate
|
2
|
-
module Provider
|
3
|
-
class Libvirt < Provider
|
4
|
-
def initialize(box)
|
5
|
-
@box = box
|
6
|
-
@name = 'libvirt'
|
7
|
-
@supported_input = false,
|
8
|
-
@supported_output = true,
|
9
|
-
@image_format = 'qcow2',
|
10
|
-
@image_name = 'box.img'
|
11
|
-
end
|
12
|
-
|
13
|
-
def generate_metadata(input_box)
|
14
|
-
metadata = {
|
15
|
-
'provider' => @box.provider.name,
|
16
|
-
'format' => 'qcow2',
|
17
|
-
'virtual_size' => ( input_box.virtual_size.to_f / (1024 * 1024 * 1024) ).ceil
|
18
|
-
}
|
19
|
-
end
|
20
|
-
|
21
|
-
def write_specific_files(input_box)
|
22
|
-
# nothing to do here
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module VagrantMutate
|
2
|
-
module Provider
|
3
|
-
class Provider
|
4
|
-
attr_reader :name, :supported_input, :supported_output, :image_format, :image_name
|
5
|
-
|
6
|
-
def self.create(name, box)
|
7
|
-
case name
|
8
|
-
when 'kvm'
|
9
|
-
require_relative 'kvm'
|
10
|
-
Kvm.new(box)
|
11
|
-
when 'libvirt'
|
12
|
-
require_relative 'libvirt'
|
13
|
-
Libvirt.new(box)
|
14
|
-
when 'virtualbox'
|
15
|
-
require_relative 'virtualbox'
|
16
|
-
Virtualbox.new(box)
|
17
|
-
else
|
18
|
-
raise Errors::ProviderNotSupported, :provider => name, :direction => 'input or output'
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|