vagrant-mutate 0.1.4 → 0.1.5

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 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
- wget http://files.vagrantup.com/precise32.box
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, if you had already added the virtualbox version of the box to vagrant and now want to use it with libvirt
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
- # convert to more standarad format with colons
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
- return device.elements["rasd:VirtualQuantity"].text
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
- return size_in_bytes(device.elements["rasd:VirtualQuantity"].text,
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
- @ovf ||= REXML::Document.new( File.read( File.join( @dir, 'box.ovf') ) )
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 'zlib'
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
- @tmp_dir = nil
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
- unless box.supported_output
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
- return box
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
- unless box.supported_input
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
- if @tmp_dir
116
+ unless @tmp_files.empty?
71
117
  @env.ui.info "Cleaning up temporary files."
72
- @logger.info "Deleting #{@tmp_dir}"
73
- FileUtils.remove_entry_secure(@tmp_dir)
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
- # box may or may not be gzipped
124
- begin
125
- tar = Zlib::GzipReader.new(File.open(file, 'rb'))
126
- rescue
127
- tar = file
128
- end
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
@@ -16,7 +16,7 @@ module VagrantMutate
16
16
 
17
17
  uuid = nil
18
18
  gui = true
19
- disk_bus = 'virtio'
19
+ disk_bus = @input_box.disk_interface
20
20
 
21
21
  image_type = @output_box.image_format
22
22
  disk = @output_box.image_name
@@ -46,9 +46,17 @@ module VagrantMutate
46
46
  error_key(:parse_qemu_version_failed)
47
47
  end
48
48
 
49
- class Errors::DetermineImageSizeFailed < VagrantMutateError
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
- if box_arg =~ /\.box$/
27
- input_box = input_loader.load_from_file(box_arg)
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)
@@ -1,3 +1,3 @@
1
1
  module VagrantMutate
2
- VERSION = '0.1.4'
2
+ VERSION = '0.1.5'
3
3
  end
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
@@ -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
- <% if disk_bus == 'virtio' %>
28
+ <% if disk_bus == 'virtio' %>
29
29
  <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
30
- <% else %>
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='virtio'/>
26
-
27
- <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
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
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-08 00:00:00.000000000 Z
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