vagrant-libvirt 0.1.2 → 0.5.0

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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +530 -100
  3. data/lib/vagrant-libvirt/action.rb +7 -1
  4. data/lib/vagrant-libvirt/action/clean_machine_folder.rb +28 -0
  5. data/lib/vagrant-libvirt/action/create_domain.rb +78 -22
  6. data/lib/vagrant-libvirt/action/create_domain_volume.rb +57 -57
  7. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +1 -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 +40 -40
  11. data/lib/vagrant-libvirt/action/halt_domain.rb +25 -9
  12. data/lib/vagrant-libvirt/action/handle_box_image.rb +163 -72
  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 +10 -4
  16. data/lib/vagrant-libvirt/action/start_domain.rb +86 -29
  17. data/lib/vagrant-libvirt/action/wait_till_up.rb +8 -52
  18. data/lib/vagrant-libvirt/cap/{mount_p9.rb → mount_9p.rb} +2 -2
  19. data/lib/vagrant-libvirt/cap/mount_virtiofs.rb +37 -0
  20. data/lib/vagrant-libvirt/cap/public_address.rb +16 -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 +257 -34
  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 +19 -5
  27. data/lib/vagrant-libvirt/provider.rb +2 -9
  28. data/lib/vagrant-libvirt/templates/domain.xml.erb +40 -10
  29. data/lib/vagrant-libvirt/templates/private_network.xml.erb +1 -1
  30. data/lib/vagrant-libvirt/templates/public_interface.xml.erb +5 -1
  31. data/lib/vagrant-libvirt/util.rb +1 -0
  32. data/lib/vagrant-libvirt/util/erb_template.rb +6 -7
  33. data/lib/vagrant-libvirt/util/network_util.rb +21 -3
  34. data/lib/vagrant-libvirt/util/ui.rb +23 -0
  35. data/lib/vagrant-libvirt/version +1 -0
  36. data/lib/vagrant-libvirt/version.rb +72 -1
  37. data/locales/en.yml +12 -0
  38. data/spec/spec_helper.rb +37 -3
  39. data/spec/support/binding_proc.rb +24 -0
  40. data/spec/support/libvirt_context.rb +3 -1
  41. data/spec/support/matchers/have_file_content.rb +63 -0
  42. data/spec/support/sharedcontext.rb +7 -3
  43. data/spec/unit/action/clean_machine_folder_spec.rb +48 -0
  44. data/spec/unit/action/create_domain_spec.rb +166 -0
  45. data/spec/unit/action/create_domain_spec/default_system_storage_pool.xml +17 -0
  46. data/spec/unit/action/create_domain_spec/default_user_storage_pool.xml +17 -0
  47. data/spec/unit/action/create_domain_volume_spec.rb +102 -0
  48. data/spec/unit/action/create_domain_volume_spec/one_disk_in_storage.xml +21 -0
  49. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_0.xml +21 -0
  50. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_1.xml +21 -0
  51. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_2.xml +21 -0
  52. data/spec/unit/action/destroy_domain_spec.rb +3 -3
  53. data/spec/unit/action/forward_ports_spec.rb +202 -0
  54. data/spec/unit/action/halt_domain_spec.rb +90 -0
  55. data/spec/unit/action/handle_box_image_spec.rb +363 -0
  56. data/spec/unit/action/set_name_of_domain_spec.rb +2 -2
  57. data/spec/unit/action/start_domain_spec.rb +231 -0
  58. data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +50 -0
  59. data/spec/unit/action/start_domain_spec/default.xml +48 -0
  60. data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +48 -0
  61. data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +48 -0
  62. data/spec/unit/action/wait_till_up_spec.rb +22 -21
  63. data/spec/unit/config_spec.rb +438 -0
  64. data/spec/unit/provider_spec.rb +11 -0
  65. data/spec/unit/templates/domain_all_settings.xml +16 -3
  66. data/spec/unit/templates/domain_custom_cpu_model.xml +4 -1
  67. data/spec/unit/templates/domain_defaults.xml +4 -1
  68. data/spec/unit/templates/domain_spec.rb +102 -3
  69. data/spec/unit/templates/tpm/version_1.2.xml +54 -0
  70. data/spec/unit/templates/tpm/version_2.0.xml +53 -0
  71. metadata +108 -16
  72. data/lib/vagrant-libvirt/action/halt_confirm.rb +0 -20
@@ -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