vagrant-mutate 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +6 -0
- data/README.md +6 -3
- data/lib/vagrant-mutate/box/virtualbox.rb +67 -8
- data/lib/vagrant-mutate/box_loader.rb +72 -29
- data/lib/vagrant-mutate/converter/kvm.rb +1 -1
- data/lib/vagrant-mutate/errors.rb +9 -1
- data/lib/vagrant-mutate/mutate.rb +3 -7
- data/lib/vagrant-mutate/version.rb +1 -1
- data/locales/en.yml +5 -0
- data/templates/kvm/box.xml.erb +7 -3
- data/test/expected_output/virtualbox/kvm/box.xml +7 -4
- metadata +2 -2
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# 0.1.5 (2013-12-17)
|
2
|
+
* Preserve dsik interface type when coverting to KVM (#21)
|
3
|
+
* Remove dependency in minitar (#24)
|
4
|
+
* Support downloading input box (#9)
|
5
|
+
* Handle errors when reading ovf file
|
6
|
+
|
1
7
|
# 0.1.4 (2013-12-08)
|
2
8
|
* Rework box and converter implementation (#7)
|
3
9
|
* Write disk images as sparse files (#13)
|
data/README.md
CHANGED
@@ -41,14 +41,17 @@ To install from source, clone the repository and run `rake build`. That will pro
|
|
41
41
|
|
42
42
|
The basic usage is
|
43
43
|
|
44
|
-
vagrant mutate box-name-or-file output-provider
|
44
|
+
vagrant mutate box-name-or-file-or-url output-provider
|
45
45
|
|
46
46
|
For example, if you wanted to download a box created for virtualbox and add it to vagrant for libvirt
|
47
47
|
|
48
|
-
|
48
|
+
vagrant mutate http://files.vagrantup.com/precise32.box libvirt
|
49
|
+
|
50
|
+
Or if you had already downloaded it
|
51
|
+
|
49
52
|
vagrant mutate precise32.box libvirt
|
50
53
|
|
51
|
-
Or
|
54
|
+
Or if you had already added the virtualbox version of the box to vagrant and now want to use it with libvirt
|
52
55
|
|
53
56
|
vagrant mutate precise32 libvirt
|
54
57
|
|
@@ -26,38 +26,97 @@ module VagrantMutate
|
|
26
26
|
|
27
27
|
# use mac from the first enabled nic
|
28
28
|
def mac_address
|
29
|
+
mac = nil
|
30
|
+
|
29
31
|
ovf.elements.each("//vbox:Machine/Hardware//Adapter") do |ele|
|
30
32
|
if ele.attributes['enabled'] == 'true'
|
31
|
-
mac = ele.attributes['MACAddress']
|
32
|
-
|
33
|
-
return mac[0..1] + ":" + mac[2..3] + ":" +
|
34
|
-
mac[4..5] + ":" + mac[6..7] + ":" +
|
35
|
-
mac[8..9] + ":" + mac[10..11]
|
33
|
+
mac = format_mac( ele.attributes['MACAddress'] )
|
34
|
+
break
|
36
35
|
end
|
37
36
|
end
|
37
|
+
|
38
|
+
if mac
|
39
|
+
return mac
|
40
|
+
else
|
41
|
+
raise Errors::BoxAttributeError, :error_message => 'Could not determine mac address'
|
42
|
+
end
|
38
43
|
end
|
39
44
|
|
40
45
|
def cpus
|
46
|
+
cpu_count = nil
|
47
|
+
|
41
48
|
ovf.elements.each("//VirtualHardwareSection/Item") do |device|
|
42
49
|
if device.elements["rasd:ResourceType"].text == '3'
|
43
|
-
|
50
|
+
cpu_count = device.elements["rasd:VirtualQuantity"].text
|
44
51
|
end
|
45
52
|
end
|
53
|
+
|
54
|
+
if cpu_count
|
55
|
+
return cpu_count
|
56
|
+
else
|
57
|
+
raise Errors::BoxAttributeError, :error_message => 'Could not determine number of CPUs'
|
58
|
+
end
|
46
59
|
end
|
47
60
|
|
48
61
|
def memory
|
62
|
+
memory_in_bytes = nil
|
63
|
+
|
49
64
|
ovf.elements.each("//VirtualHardwareSection/Item") do |device|
|
50
65
|
if device.elements["rasd:ResourceType"].text == '4'
|
51
|
-
|
66
|
+
memory_in_bytes = size_in_bytes(device.elements["rasd:VirtualQuantity"].text,
|
52
67
|
device.elements["rasd:AllocationUnits"].text)
|
53
68
|
end
|
54
69
|
end
|
70
|
+
|
71
|
+
if memory_in_bytes
|
72
|
+
return memory_in_bytes
|
73
|
+
else
|
74
|
+
raise Errors::BoxAttributeError, :error_message => 'Could not determine amount of memory'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def disk_interface
|
79
|
+
controller_type = {}
|
80
|
+
controller_used_by_disk = nil
|
81
|
+
ovf.elements.each("//VirtualHardwareSection/Item") do |device|
|
82
|
+
# when we find a controller, store its ID and type
|
83
|
+
# when we find a disk, store the ID of the controller it is connected to
|
84
|
+
case device.elements["rasd:ResourceType"].text
|
85
|
+
when "5"
|
86
|
+
controller_type[device.elements["rasd:InstanceID"].text] = 'ide'
|
87
|
+
when "6"
|
88
|
+
controller_type[device.elements["rasd:InstanceID"].text] = 'scsi'
|
89
|
+
when "20"
|
90
|
+
controller_type[device.elements["rasd:InstanceID"].text] = 'sata'
|
91
|
+
when "17"
|
92
|
+
controller_used_by_disk = device.elements["rasd:Parent"].text
|
93
|
+
end
|
94
|
+
end
|
95
|
+
if controller_used_by_disk and controller_type[controller_used_by_disk]
|
96
|
+
return controller_type[controller_used_by_disk]
|
97
|
+
else
|
98
|
+
raise Errors::BoxAttributeError, :error_message => 'Could not determine disk interface'
|
99
|
+
end
|
55
100
|
end
|
56
101
|
|
57
102
|
private
|
58
103
|
|
59
104
|
def ovf
|
60
|
-
|
105
|
+
if @ovf
|
106
|
+
return @ovf
|
107
|
+
end
|
108
|
+
|
109
|
+
ovf_file = File.join( @dir, 'box.ovf')
|
110
|
+
begin
|
111
|
+
@ovf = REXML::Document.new( File.read(ovf_file) )
|
112
|
+
rescue => e
|
113
|
+
raise Errors::BoxAttributeError, :error_message => e.message
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# convert to more standard format with colons
|
118
|
+
def format_mac(mac)
|
119
|
+
mac.scan(/(.{2})/).join(':')
|
61
120
|
end
|
62
121
|
|
63
122
|
# Takes a quantity and a unit
|
@@ -1,17 +1,16 @@
|
|
1
|
-
require 'archive/tar/minitar'
|
2
1
|
require 'fileutils'
|
3
2
|
require 'json'
|
4
|
-
require '
|
3
|
+
require 'uri'
|
4
|
+
require "vagrant/util/subprocess"
|
5
|
+
require "vagrant/util/downloader"
|
5
6
|
|
6
7
|
module VagrantMutate
|
7
8
|
class BoxLoader
|
8
9
|
|
9
|
-
include Archive::Tar
|
10
|
-
|
11
10
|
def initialize( env )
|
12
11
|
@env = env
|
13
12
|
@logger = Log4r::Logger.new('vagrant::mutate')
|
14
|
-
@
|
13
|
+
@tmp_files = []
|
15
14
|
end
|
16
15
|
|
17
16
|
def create_box(provider_name, name, dir)
|
@@ -36,26 +35,74 @@ module VagrantMutate
|
|
36
35
|
dir = create_output_dir(name, provider_name)
|
37
36
|
box = create_box(provider_name, name, dir)
|
38
37
|
|
39
|
-
|
38
|
+
if box.supported_output
|
39
|
+
return box
|
40
|
+
else
|
40
41
|
raise Errors::ProviderNotSupported, :provider => provider_name, :direction => 'output'
|
41
42
|
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def load(box_arg)
|
46
|
+
if box_arg =~ /:\/\//
|
47
|
+
box = load_from_url(box_arg)
|
48
|
+
elsif box_arg =~ /\.box$/
|
49
|
+
box = load_from_file(box_arg)
|
50
|
+
else
|
51
|
+
box = load_by_name(box_arg)
|
52
|
+
end
|
53
|
+
|
54
|
+
if box.supported_input
|
55
|
+
return box
|
56
|
+
else
|
57
|
+
raise Errors::ProviderNotSupported, :provider => provider_name, :direction => 'input'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def load_from_url(url)
|
62
|
+
@logger.info "Loading box from url #{url}"
|
63
|
+
|
64
|
+
# test that we have a valid url
|
65
|
+
url = URI(url)
|
66
|
+
unless url.scheme and url.host and url.path
|
67
|
+
raise Errors::URLError, :url => url
|
68
|
+
end
|
69
|
+
|
70
|
+
# extract the name of the box from the url
|
71
|
+
# if it ends in .box remove that extension
|
72
|
+
# if not just remove leading slash
|
73
|
+
name = nil
|
74
|
+
if url.path =~ /(\w+).box$/
|
75
|
+
name = $1
|
76
|
+
else
|
77
|
+
name = url.path.sub(/^\//, '')
|
78
|
+
end
|
79
|
+
if name.empty?
|
80
|
+
raise Errors::URLError, :url => url
|
81
|
+
end
|
82
|
+
|
83
|
+
# using same path as in vagrants box add action
|
84
|
+
download_path = File.join(@env.tmp_path, 'box' + Digest::SHA1.hexdigest(url.to_s))
|
85
|
+
@tmp_files << download_path
|
86
|
+
|
87
|
+
# if this fails it will raise an error and we'll quit
|
88
|
+
@env.ui.info "Downloading box #{name} from #{url}"
|
89
|
+
downloader = Vagrant::Util::Downloader.new(url, download_path, { :ui => @env.ui })
|
90
|
+
downloader.download!
|
42
91
|
|
43
|
-
|
92
|
+
dir = unpack(download_path)
|
93
|
+
|
94
|
+
provider_name = determine_provider(dir)
|
95
|
+
|
96
|
+
box = create_box(provider_name, name, dir)
|
44
97
|
end
|
45
98
|
|
46
99
|
def load_from_file(file)
|
47
100
|
@logger.info "Loading box from file #{file}"
|
48
101
|
name = File.basename( file, File.extname(file) )
|
49
102
|
dir = unpack(file)
|
50
|
-
@tmp_dir = dir
|
51
103
|
provider_name = determine_provider(dir)
|
52
|
-
box = create_box(provider_name, name, dir)
|
53
104
|
|
54
|
-
|
55
|
-
raise Errors::ProviderNotSupported, :provider => provider_name, :direction => 'input'
|
56
|
-
end
|
57
|
-
|
58
|
-
return box
|
105
|
+
box = create_box(provider_name, name, dir)
|
59
106
|
end
|
60
107
|
|
61
108
|
def load_by_name(name)
|
@@ -63,14 +110,15 @@ module VagrantMutate
|
|
63
110
|
dir = find_input_dir(name)
|
64
111
|
# cheat for now since only supported input is virtualbox
|
65
112
|
box = create_box('virtualbox', name, dir)
|
66
|
-
return box
|
67
113
|
end
|
68
114
|
|
69
115
|
def cleanup
|
70
|
-
|
116
|
+
unless @tmp_files.empty?
|
71
117
|
@env.ui.info "Cleaning up temporary files."
|
72
|
-
@
|
73
|
-
|
118
|
+
@tmp_files.each do |f|
|
119
|
+
@logger.info "Deleting #{f}"
|
120
|
+
FileUtils.remove_entry_secure(f)
|
121
|
+
end
|
74
122
|
end
|
75
123
|
end
|
76
124
|
|
@@ -120,17 +168,12 @@ module VagrantMutate
|
|
120
168
|
unless File.exists? file
|
121
169
|
raise Errors::BoxNotFound, :box => file
|
122
170
|
end
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
begin
|
130
|
-
tmp_dir = Dir.mktmpdir
|
131
|
-
Minitar.unpack(tar, tmp_dir)
|
132
|
-
rescue => e
|
133
|
-
raise Errors::ExtractBoxFailed, :error_message => e.message
|
171
|
+
tmp_dir = Dir.mktmpdir(nil, @env.tmp_path)
|
172
|
+
@tmp_files << tmp_dir
|
173
|
+
result = Vagrant::Util::Subprocess.execute(
|
174
|
+
"bsdtar", "-v", "-x", "-m", "-C", tmp_dir.to_s, "-f", file)
|
175
|
+
if result.exit_code != 0
|
176
|
+
raise Errors::ExtractBoxFailed, :error_message => result.stderr.to_s
|
134
177
|
end
|
135
178
|
@logger.info "Unpacked box to #{tmp_dir}"
|
136
179
|
return tmp_dir
|
@@ -46,9 +46,17 @@ module VagrantMutate
|
|
46
46
|
error_key(:parse_qemu_version_failed)
|
47
47
|
end
|
48
48
|
|
49
|
-
class
|
49
|
+
class DetermineImageSizeFailed < VagrantMutateError
|
50
50
|
error_key(:determine_image_size_failed)
|
51
51
|
end
|
52
52
|
|
53
|
+
class BoxAttributeError < VagrantMutateError
|
54
|
+
error_key(:box_attribute_error)
|
55
|
+
end
|
56
|
+
|
57
|
+
class URLError < VagrantMutateError
|
58
|
+
error_key(:url_error)
|
59
|
+
end
|
60
|
+
|
53
61
|
end
|
54
62
|
end
|
@@ -20,15 +20,11 @@ module VagrantMutate
|
|
20
20
|
box_arg = argv[0]
|
21
21
|
output_provider_arg = argv[1]
|
22
22
|
|
23
|
-
input_loader = BoxLoader.new(@env)
|
24
|
-
output_loader = BoxLoader.new(@env)
|
25
23
|
|
26
|
-
|
27
|
-
|
28
|
-
else
|
29
|
-
input_box = input_loader.load_by_name(box_arg)
|
30
|
-
end
|
24
|
+
input_loader = BoxLoader.new(@env)
|
25
|
+
input_box = input_loader.load(box_arg)
|
31
26
|
|
27
|
+
output_loader = BoxLoader.new(@env)
|
32
28
|
output_box = output_loader.prepare_for_output( input_box.name, output_provider_arg)
|
33
29
|
|
34
30
|
converter = Converter::Converter.create(@env, input_box, output_box)
|
data/locales/en.yml
CHANGED
@@ -29,3 +29,8 @@ en:
|
|
29
29
|
Determining the version of qemu-img installed failed
|
30
30
|
determine_image_size_failed: |-
|
31
31
|
Determining the virtual size of the disk image failed
|
32
|
+
box_attribute_error: |-
|
33
|
+
Error determining information about the input box:
|
34
|
+
%{error_message}
|
35
|
+
url_error: |-
|
36
|
+
The url %{url} is not valid
|
data/templates/kvm/box.xml.erb
CHANGED
@@ -25,12 +25,16 @@
|
|
25
25
|
<driver name='qemu' type='<%= image_type %>'/>
|
26
26
|
<source file='<%= disk %>'/>
|
27
27
|
<target dev='vda' bus='<%= disk_bus %>'/>
|
28
|
-
|
28
|
+
<% if disk_bus == 'virtio' %>
|
29
29
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
|
30
|
-
|
30
|
+
</disk>
|
31
|
+
<% else %>
|
31
32
|
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
|
32
|
-
<% end %>
|
33
33
|
</disk>
|
34
|
+
<controller type='<%= disk_bus %>' index='0'>
|
35
|
+
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
|
36
|
+
</controller>
|
37
|
+
<% end %>
|
34
38
|
<controller type='usb' index='0'>
|
35
39
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
|
36
40
|
</controller>
|
@@ -22,11 +22,14 @@
|
|
22
22
|
<disk type='file' device='disk'>
|
23
23
|
<driver name='qemu' type='qcow2'/>
|
24
24
|
<source file='box-disk1.img'/>
|
25
|
-
<target dev='vda' bus='
|
26
|
-
|
27
|
-
<address type='
|
28
|
-
|
25
|
+
<target dev='vda' bus='sata'/>
|
26
|
+
|
27
|
+
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
|
29
28
|
</disk>
|
29
|
+
<controller type='sata' index='0'>
|
30
|
+
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
|
31
|
+
</controller>
|
32
|
+
|
30
33
|
<controller type='usb' index='0'>
|
31
34
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
|
32
35
|
</controller>
|
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.5
|
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-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: archive-tar-minitar
|