vagrant-libvirt 0.3.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +421 -50
  3. data/lib/vagrant-libvirt/action.rb +7 -1
  4. data/lib/vagrant-libvirt/action/clean_machine_folder.rb +30 -0
  5. data/lib/vagrant-libvirt/action/create_domain.rb +56 -18
  6. data/lib/vagrant-libvirt/action/create_domain_volume.rb +57 -55
  7. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +0 -3
  8. data/lib/vagrant-libvirt/action/create_networks.rb +11 -4
  9. data/lib/vagrant-libvirt/action/destroy_domain.rb +1 -1
  10. data/lib/vagrant-libvirt/action/forward_ports.rb +37 -38
  11. data/lib/vagrant-libvirt/action/halt_domain.rb +25 -9
  12. data/lib/vagrant-libvirt/action/handle_box_image.rb +163 -74
  13. data/lib/vagrant-libvirt/action/is_running.rb +1 -3
  14. data/lib/vagrant-libvirt/action/is_suspended.rb +4 -4
  15. data/lib/vagrant-libvirt/action/package_domain.rb +2 -1
  16. data/lib/vagrant-libvirt/action/set_boot_order.rb +6 -2
  17. data/lib/vagrant-libvirt/action/start_domain.rb +86 -29
  18. data/lib/vagrant-libvirt/action/wait_till_up.rb +8 -52
  19. data/lib/vagrant-libvirt/cap/{mount_p9.rb → mount_9p.rb} +2 -2
  20. data/lib/vagrant-libvirt/cap/mount_virtiofs.rb +37 -0
  21. data/lib/vagrant-libvirt/cap/{synced_folder.rb → synced_folder_9p.rb} +4 -5
  22. data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +109 -0
  23. data/lib/vagrant-libvirt/config.rb +236 -43
  24. data/lib/vagrant-libvirt/driver.rb +49 -32
  25. data/lib/vagrant-libvirt/errors.rb +24 -1
  26. data/lib/vagrant-libvirt/plugin.rb +14 -5
  27. data/lib/vagrant-libvirt/provider.rb +2 -9
  28. data/lib/vagrant-libvirt/templates/domain.xml.erb +35 -10
  29. data/lib/vagrant-libvirt/templates/private_network.xml.erb +1 -1
  30. data/lib/vagrant-libvirt/util/network_util.rb +21 -3
  31. data/lib/vagrant-libvirt/version +1 -1
  32. data/lib/vagrant-libvirt/version.rb +57 -9
  33. data/locales/en.yml +12 -0
  34. data/spec/spec_helper.rb +37 -3
  35. data/spec/support/binding_proc.rb +24 -0
  36. data/spec/support/libvirt_context.rb +2 -0
  37. data/spec/support/matchers/have_file_content.rb +63 -0
  38. data/spec/support/sharedcontext.rb +4 -0
  39. data/spec/unit/action/clean_machine_folder_spec.rb +58 -0
  40. data/spec/unit/action/create_domain_spec.rb +121 -36
  41. data/spec/unit/action/create_domain_spec/additional_disks_domain.xml +54 -0
  42. data/spec/unit/action/create_domain_spec/default_domain.xml +49 -0
  43. data/spec/unit/action/create_domain_spec/{default_storage_pool.xml → default_system_storage_pool.xml} +0 -0
  44. data/spec/unit/action/create_domain_spec/default_user_storage_pool.xml +17 -0
  45. data/spec/unit/action/create_domain_volume_spec.rb +102 -0
  46. data/spec/unit/action/create_domain_volume_spec/one_disk_in_storage.xml +21 -0
  47. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_0.xml +21 -0
  48. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_1.xml +21 -0
  49. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_2.xml +21 -0
  50. data/spec/unit/action/destroy_domain_spec.rb +1 -1
  51. data/spec/unit/action/forward_ports_spec.rb +202 -0
  52. data/spec/unit/action/halt_domain_spec.rb +90 -0
  53. data/spec/unit/action/handle_box_image_spec.rb +363 -0
  54. data/spec/unit/action/start_domain_spec.rb +183 -1
  55. data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +50 -0
  56. data/spec/unit/action/start_domain_spec/default.xml +2 -2
  57. data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +48 -0
  58. data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +48 -0
  59. data/spec/unit/action/wait_till_up_spec.rb +22 -21
  60. data/spec/unit/config_spec.rb +395 -127
  61. data/spec/unit/templates/domain_all_settings.xml +14 -3
  62. data/spec/unit/templates/domain_custom_cpu_model.xml +2 -1
  63. data/spec/unit/templates/domain_defaults.xml +2 -1
  64. data/spec/unit/templates/domain_spec.rb +100 -3
  65. data/spec/unit/templates/tpm/version_1.2.xml +54 -0
  66. data/spec/unit/templates/tpm/version_2.0.xml +53 -0
  67. metadata +105 -19
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+ require 'support/sharedcontext'
3
+ require 'support/libvirt_context'
4
+ require 'vagrant-libvirt/action/destroy_domain'
5
+
6
+ describe VagrantPlugins::ProviderLibvirt::Action::HaltDomain do
7
+ subject { described_class.new(app, env) }
8
+
9
+ include_context 'unit'
10
+ include_context 'libvirt'
11
+
12
+ let(:libvirt_domain) { double('libvirt_domain') }
13
+ let(:servers) { double('servers') }
14
+
15
+ describe '#call' do
16
+ before do
17
+ allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver)
18
+ .to receive(:connection).and_return(connection)
19
+ allow(connection).to receive(:servers).and_return(servers)
20
+ allow(servers).to receive(:get).and_return(domain)
21
+ # always see this at the start of #call
22
+ expect(ui).to receive(:info).with('Halting domain...')
23
+ end
24
+
25
+ context 'with graceful timeout' do
26
+ it "should shutdown" do
27
+ expect(guest).to receive(:capability).with(:halt).and_return(true)
28
+ expect(domain).to receive(:wait_for).with(60).and_return(false)
29
+ expect(subject.call(env)).to be_nil
30
+ end
31
+
32
+ context 'when halt fails' do
33
+ before do
34
+ expect(logger).to receive(:info).with('Trying Libvirt graceful shutdown.')
35
+ expect(guest).to receive(:capability).with(:halt).and_raise(IOError)
36
+ expect(domain).to receive(:state).and_return('running')
37
+ end
38
+
39
+ it "should call shutdown" do
40
+ expect(domain).to receive(:shutdown)
41
+ expect(domain).to receive(:wait_for).with(60).and_return(false)
42
+ expect(subject.call(env)).to be_nil
43
+ end
44
+
45
+ context 'when shutdown fails' do
46
+ it "should call power off" do
47
+ expect(logger).to receive(:error).with('Failed to shutdown cleanly. Calling force poweroff.')
48
+ expect(domain).to receive(:shutdown).and_raise(IOError)
49
+ expect(domain).to receive(:poweroff)
50
+ expect(subject.call(env)).to be_nil
51
+ end
52
+ end
53
+
54
+ context 'when shutdown exceeds the timeout' do
55
+ it "should call poweroff" do
56
+ expect(logger).to receive(:info).with('VM is still running. Calling force poweroff.')
57
+ expect(domain).to receive(:shutdown).and_raise(Timeout::Error)
58
+ expect(domain).to receive(:poweroff)
59
+ expect(subject.call(env)).to be_nil
60
+ end
61
+ end
62
+ end
63
+
64
+ context 'when halt exceeds the timeout' do
65
+ before do
66
+ expect(logger).to_not receive(:info).with('Trying Libvirt graceful shutdown.')
67
+ expect(guest).to receive(:capability).with(:halt).and_raise(Timeout::Error)
68
+ end
69
+
70
+ it "should call poweroff" do
71
+ expect(logger).to receive(:info).with('VM is still running. Calling force poweroff.')
72
+ expect(domain).to receive(:poweroff)
73
+ expect(subject.call(env)).to be_nil
74
+ end
75
+ end
76
+ end
77
+
78
+ context 'with force halt enabled' do
79
+ before do
80
+ allow(env).to receive(:[]).and_call_original
81
+ expect(env).to receive(:[]).with(:force_halt).and_return(true)
82
+ end
83
+
84
+ it "should just call poweroff" do
85
+ expect(domain).to receive(:poweroff)
86
+ expect(subject.call(env)).to be_nil
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,363 @@
1
+ require 'spec_helper'
2
+ require 'support/sharedcontext'
3
+ require 'support/libvirt_context'
4
+
5
+ require 'vagrant-libvirt/action/destroy_domain'
6
+
7
+ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
8
+ subject { described_class.new(app, env) }
9
+
10
+ include_context 'unit'
11
+ include_context 'libvirt'
12
+
13
+ let(:libvirt_client) { double('libvirt_client') }
14
+ let(:volumes) { double('volumes') }
15
+ let(:all) { double('all') }
16
+ let(:box_volume) { double('box_volume') }
17
+ let(:fog_volume) { double('fog_volume') }
18
+
19
+ describe '#call' do
20
+ before do
21
+ allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver)
22
+ .to receive(:connection).and_return(connection)
23
+ allow(connection).to receive(:client).and_return(libvirt_client)
24
+ allow(connection).to receive(:volumes).and_return(volumes)
25
+ allow(volumes).to receive(:all).and_return(all)
26
+ allow(env[:ui]).to receive(:clear_line)
27
+
28
+ end
29
+
30
+ context 'when one disk in metadata.json' do
31
+ before do
32
+ allow(all).to receive(:first).and_return(box_volume)
33
+ allow(box_volume).to receive(:id).and_return(1)
34
+ allow(env[:machine]).to receive_message_chain("box.name") { 'test' }
35
+ allow(env[:machine]).to receive_message_chain("box.version") { '1.1.1' }
36
+ allow(env[:machine]).to receive_message_chain("box.metadata") { Hash[
37
+ 'virtual_size'=> 5,
38
+ 'format' => 'qcow2'
39
+ ]
40
+ }
41
+ allow(env[:machine]).to receive_message_chain("box.directory.join") do |arg|
42
+ '/test/'.concat(arg.to_s)
43
+ end
44
+ end
45
+
46
+ it 'should have one disk in machine env' do
47
+ expect(subject.call(env)).to be_nil
48
+ expect(env[:box_volume_number]).to eq(1)
49
+ expect(env[:box_volumes]).to eq(
50
+ [
51
+ {
52
+ :path=>"/test/box.img",
53
+ :name=>"test_vagrant_box_image_1.1.1_box.img",
54
+ :virtual_size=>5,
55
+ :format=>"qcow2"
56
+ }
57
+ ]
58
+ )
59
+ end
60
+
61
+ context 'when disk image not in storage pool' do
62
+ before do
63
+ allow(File).to receive(:exist?).and_return(true)
64
+ allow(File).to receive(:size).and_return(5*1024*1024*1024)
65
+ allow(all).to receive(:first).and_return(nil)
66
+ allow(subject).to receive(:upload_image).and_return(true)
67
+ allow(volumes).to receive(:create).and_return(fog_volume)
68
+ end
69
+
70
+ it 'should upload disk' do
71
+ expect(ui).to receive(:info).with('Uploading base box image as volume into Libvirt storage...')
72
+ expect(logger).to receive(:info).with('Creating volume test_vagrant_box_image_1.1.1_box.img in storage pool default.')
73
+ expect(volumes).to receive(:create).with(
74
+ hash_including(
75
+ :name => "test_vagrant_box_image_1.1.1_box.img",
76
+ :allocation => "5120M",
77
+ :capacity => "5G",
78
+ )
79
+ )
80
+ expect(subject).to receive(:upload_image)
81
+ expect(subject.call(env)).to be_nil
82
+ end
83
+ end
84
+
85
+ context 'when disk image already in storage pool' do
86
+ before do
87
+ allow(all).to receive(:first).and_return(box_volume)
88
+ allow(box_volume).to receive(:id).and_return(1)
89
+ end
90
+
91
+ it 'should skip disk upload' do
92
+ expect(volumes).not_to receive(:create)
93
+ expect(subject).not_to receive(:upload_image)
94
+ expect(subject.call(env)).to be_nil
95
+ end
96
+ end
97
+ end
98
+
99
+ context 'when three disks in metadata.json' do
100
+ let(:status) { double }
101
+
102
+ before do
103
+ allow(all).to receive(:first).and_return(box_volume)
104
+ allow(box_volume).to receive(:id).and_return(1)
105
+ allow(env[:machine]).to receive_message_chain("box.name") { 'test' }
106
+ allow(env[:machine]).to receive_message_chain("box.version") { '1.1.1' }
107
+ allow(env[:machine]).to receive_message_chain("box.metadata") { Hash[
108
+ 'disks' => [
109
+ {
110
+ 'path' => 'box.img',
111
+ 'name' => 'send_box_name',
112
+ },
113
+ {
114
+ 'path' => 'disk.qcow2',
115
+ },
116
+ {
117
+ 'path' => 'box_2.img',
118
+ },
119
+ ],
120
+ ]}
121
+ allow(env[:machine]).to receive_message_chain("box.directory.join") do |arg|
122
+ '/test/'.concat(arg.to_s)
123
+ end
124
+ allow(status).to receive(:success?).and_return(true)
125
+ allow(Open3).to receive(:capture3).with('qemu-img', 'info', '/test/box.img').and_return([
126
+ "image: /test/box.img\nfile format: qcow2\nvirtual size: 5 GiB (5368709120 bytes)\ndisk size: 1.45 GiB\n", "", status
127
+ ])
128
+ allow(Open3).to receive(:capture3).with('qemu-img', 'info', '/test/disk.qcow2').and_return([
129
+ "image: /test/disk.qcow2\nfile format: qcow2\nvirtual size: 10 GiB (10737418240 bytes)\ndisk size: 1.45 GiB\n", "", status
130
+ ])
131
+ allow(Open3).to receive(:capture3).with('qemu-img', 'info', '/test/box_2.img').and_return([
132
+ "image: /test/box_2.img\nfile format: qcow2\nvirtual size: 20 GiB (21474836480 bytes)\ndisk size: 1.45 GiB\n", "", status
133
+ ])
134
+ end
135
+
136
+ it 'should have three disks in machine env' do
137
+ expect(subject.call(env)).to be_nil
138
+ expect(env[:box_volume_number]).to eq(3)
139
+ expect(env[:box_volumes]).to eq(
140
+ [
141
+ {
142
+ :path=>"/test/box.img",
143
+ :name=>"test_vagrant_box_image_1.1.1_send_box_name.img",
144
+ :virtual_size=>5,
145
+ :format=>"qcow2"
146
+ },
147
+ {
148
+ :path=>"/test/disk.qcow2",
149
+ :name=>"test_vagrant_box_image_1.1.1_disk.img",
150
+ :virtual_size=>10,
151
+ :format=>"qcow2"
152
+ },
153
+ {
154
+ :path=>"/test/box_2.img",
155
+ :name=>"test_vagrant_box_image_1.1.1_box_2.img",
156
+ :virtual_size=>20,
157
+ :format=>"qcow2"
158
+ }
159
+ ]
160
+ )
161
+ end
162
+
163
+ context 'when none of the disks in storage pool' do
164
+ before do
165
+ allow(File).to receive(:exist?).and_return(true)
166
+ allow(File).to receive(:size).and_return(5*1024*1024*1024, 10*1024*1024*1024, 20*1024*1024*1024)
167
+ allow(all).to receive(:first).and_return(nil)
168
+ allow(subject).to receive(:upload_image).and_return(true)
169
+ allow(volumes).to receive(:create).and_return(fog_volume)
170
+ end
171
+
172
+ it 'should upload all 3 disks' do
173
+ expect(ui).to receive(:info).with('Uploading base box image as volume into Libvirt storage...')
174
+ expect(logger).to receive(:info).with('Creating volume test_vagrant_box_image_1.1.1_send_box_name.img in storage pool default.')
175
+ expect(volumes).to receive(:create).with(
176
+ hash_including(
177
+ :name => "test_vagrant_box_image_1.1.1_send_box_name.img",
178
+ :allocation => "5120M",
179
+ :capacity => "5G",
180
+ )
181
+ )
182
+ expect(subject).to receive(:upload_image)
183
+ expect(ui).to receive(:info).with('Uploading base box image as volume into Libvirt storage...')
184
+ expect(logger).to receive(:info).with('Creating volume test_vagrant_box_image_1.1.1_disk.img in storage pool default.')
185
+ expect(volumes).to receive(:create).with(
186
+ hash_including(
187
+ :name => "test_vagrant_box_image_1.1.1_disk.img",
188
+ :allocation => "10240M",
189
+ :capacity => "10G",
190
+ )
191
+ )
192
+ expect(subject).to receive(:upload_image)
193
+ expect(ui).to receive(:info).with('Uploading base box image as volume into Libvirt storage...')
194
+ expect(logger).to receive(:info).with('Creating volume test_vagrant_box_image_1.1.1_box_2.img in storage pool default.')
195
+ expect(volumes).to receive(:create).with(
196
+ hash_including(
197
+ :name => "test_vagrant_box_image_1.1.1_box_2.img",
198
+ :allocation => "20480M",
199
+ :capacity => "20G",
200
+ )
201
+ )
202
+ expect(subject).to receive(:upload_image)
203
+
204
+ expect(subject.call(env)).to be_nil
205
+ end
206
+ end
207
+
208
+ context 'when only disk 0 in storage pool' do
209
+ before do
210
+ allow(File).to receive(:exist?).and_return(true)
211
+ allow(File).to receive(:size).and_return(10*1024*1024*1024, 20*1024*1024*1024)
212
+ allow(all).to receive(:first).and_return(box_volume, nil, nil)
213
+ allow(box_volume).to receive(:id).and_return(1)
214
+ allow(subject).to receive(:upload_image).and_return(true)
215
+ allow(volumes).to receive(:create).and_return(fog_volume)
216
+ end
217
+
218
+ it 'upload disks 1 and 2 only' do
219
+ expect(ui).to receive(:info).with('Uploading base box image as volume into Libvirt storage...')
220
+ expect(logger).to receive(:info).with('Creating volume test_vagrant_box_image_1.1.1_disk.img in storage pool default.')
221
+ expect(volumes).to receive(:create).with(hash_including(:name => "test_vagrant_box_image_1.1.1_disk.img"))
222
+ expect(subject).to receive(:upload_image)
223
+ expect(ui).to receive(:info).with('Uploading base box image as volume into Libvirt storage...')
224
+ expect(logger).to receive(:info).with('Creating volume test_vagrant_box_image_1.1.1_box_2.img in storage pool default.')
225
+ expect(volumes).to receive(:create).with(hash_including(:name => "test_vagrant_box_image_1.1.1_box_2.img"))
226
+ expect(subject).to receive(:upload_image)
227
+
228
+ expect(subject.call(env)).to be_nil
229
+ end
230
+ end
231
+
232
+ context 'when has all disks on storage pool' do
233
+ before do
234
+ allow(all).to receive(:first).and_return(box_volume)
235
+ allow(box_volume).to receive(:id).and_return(1)
236
+ end
237
+
238
+ it 'should skip disk upload' do
239
+ expect(ui).not_to receive(:info).with('Uploading base box image as volume into Libvirt storage...')
240
+ expect(volumes).not_to receive(:create)
241
+ expect(subject).not_to receive(:upload_image)
242
+ expect(subject.call(env)).to be_nil
243
+ end
244
+ end
245
+ end
246
+
247
+ context 'when wrong box format in metadata.json' do
248
+ before do
249
+ allow(all).to receive(:first).and_return(box_volume)
250
+ allow(box_volume).to receive(:id).and_return(1)
251
+ allow(env[:machine]).to receive_message_chain("box.name") { 'test' }
252
+ allow(env[:machine]).to receive_message_chain("box.version") { '1.1.1' }
253
+ allow(env[:machine]).to receive_message_chain("box.metadata") { Hash[
254
+ 'virtual_size'=> 5,
255
+ 'format' => 'wrongFormat'
256
+ ]
257
+ }
258
+ allow(env[:machine]).to receive_message_chain("box.directory.join") do |arg|
259
+ '/test/'.concat(arg.to_s)
260
+ end
261
+ end
262
+
263
+ it 'should raise WrongBoxFormatSet exception' do
264
+ expect{ subject.call(env) }.to raise_error(VagrantPlugins::ProviderLibvirt::Errors::WrongBoxFormatSet)
265
+ end
266
+
267
+ end
268
+
269
+ context 'when invalid format in metadata.json' do
270
+ let(:status) { double }
271
+
272
+ before do
273
+ allow(all).to receive(:first).and_return(box_volume)
274
+ allow(box_volume).to receive(:id).and_return(1)
275
+ allow(env[:machine]).to receive_message_chain("box.name") { 'test' }
276
+ allow(env[:machine]).to receive_message_chain("box.version") { '1.1.1' }
277
+ allow(env[:machine]).to receive_message_chain("box.metadata") { box_metadata }
278
+ allow(env[:machine]).to receive_message_chain("box.directory.join") do |arg|
279
+ '/test/'.concat(arg.to_s)
280
+ end
281
+ allow(status).to receive(:success?).and_return(true)
282
+ allow(Open3).to receive(:capture3).with('qemu-img', 'info', '/test/box.img').and_return([
283
+ "image: /test/box.img\nfile format: qcow2\nvirtual size: 5 GiB (5368709120 bytes)\ndisk size: 1.45 GiB\n", "", status
284
+ ])
285
+ allow(Open3).to receive(:capture3).with('qemu-img', 'info', '/test/disk.qcow2').and_return([
286
+ "image: /test/disk.qcow2\nfile format: qcow2\nvirtual size: 10 GiB (10737418240 bytes)\ndisk size: 1.45 GiB\n", "", status
287
+ ])
288
+ allow(Open3).to receive(:capture3).with('qemu-img', 'info', '/test/box_2.img').and_return([
289
+ "image: /test/box_2.img\nfile format: qcow2\nvirtual size: 20 GiB (21474836480 bytes)\ndisk size: 1.45 GiB\n", "", status
290
+ ])
291
+ end
292
+
293
+ context 'with one disk having wrong disk format' do
294
+ let(:box_metadata) {
295
+ Hash[
296
+ 'disks' => [
297
+ {
298
+ 'path' => 'box.img',
299
+ 'name' =>'send_box_name.img',
300
+ 'format' => 'wrongFormat'
301
+ },
302
+ {
303
+ 'path' => 'disk.qcow2',
304
+ },
305
+ {
306
+ 'path' => 'box_2.img',
307
+ },
308
+ ],
309
+ ]
310
+ }
311
+
312
+ it 'should be ignored' do
313
+ expect(subject.call(env)).to be_nil
314
+ end
315
+ end
316
+
317
+ context 'with one disk missing path' do
318
+ let(:box_metadata) {
319
+ Hash[
320
+ 'disks' => [
321
+ {
322
+ 'path' => 'box.img',
323
+ },
324
+ {
325
+ 'name' => 'send_box_name',
326
+ },
327
+ {
328
+ 'path' => 'box_2.img',
329
+ },
330
+ ],
331
+ ]
332
+ }
333
+
334
+ it 'should raise an exception' do
335
+ expect{ subject.call(env) }.to raise_error(VagrantPlugins::ProviderLibvirt::Errors::BoxFormatMissingAttribute, /: 'disks\[1\]\['path'\]'/)
336
+ end
337
+ end
338
+
339
+ context 'with one disk name duplicating a path of another' do
340
+ let(:box_metadata) {
341
+ Hash[
342
+ 'disks' => [
343
+ {
344
+ 'path' => 'box.img',
345
+ 'name' => 'box_2',
346
+ },
347
+ {
348
+ 'path' => 'disk.qcow2',
349
+ },
350
+ {
351
+ 'path' => 'box_2.img',
352
+ },
353
+ ],
354
+ ]
355
+ }
356
+
357
+ it 'should raise an exception' do
358
+ expect{ subject.call(env) }.to raise_error(VagrantPlugins::ProviderLibvirt::Errors::BoxFormatDuplicateVolume, /test_vagrant_box_image_1.1.1_box_2.img.*'disks\[2\]'.*'disks\[0\]'/)
359
+ end
360
+ end
361
+ end
362
+ end
363
+ end