vagrant-libvirt 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +134 -23
  3. data/lib/vagrant-libvirt/action/clean_machine_folder.rb +4 -0
  4. data/lib/vagrant-libvirt/action/create_domain.rb +11 -3
  5. data/lib/vagrant-libvirt/action/create_domain_volume.rb +7 -2
  6. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +8 -2
  7. data/lib/vagrant-libvirt/action/create_networks.rb +12 -8
  8. data/lib/vagrant-libvirt/action/destroy_domain.rb +2 -0
  9. data/lib/vagrant-libvirt/action/destroy_networks.rb +2 -0
  10. data/lib/vagrant-libvirt/action/forward_ports.rb +7 -5
  11. data/lib/vagrant-libvirt/action/halt_domain.rb +4 -34
  12. data/lib/vagrant-libvirt/action/handle_box_image.rb +18 -13
  13. data/lib/vagrant-libvirt/action/handle_storage_pool.rb +7 -1
  14. data/lib/vagrant-libvirt/action/is_created.rb +2 -0
  15. data/lib/vagrant-libvirt/action/is_running.rb +2 -0
  16. data/lib/vagrant-libvirt/action/is_suspended.rb +2 -0
  17. data/lib/vagrant-libvirt/action/message_already_created.rb +2 -0
  18. data/lib/vagrant-libvirt/action/message_not_created.rb +2 -0
  19. data/lib/vagrant-libvirt/action/message_not_running.rb +2 -0
  20. data/lib/vagrant-libvirt/action/message_not_suspended.rb +2 -0
  21. data/lib/vagrant-libvirt/action/message_will_not_destroy.rb +2 -0
  22. data/lib/vagrant-libvirt/action/package_domain.rb +133 -68
  23. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +2 -0
  24. data/lib/vagrant-libvirt/action/prepare_nfs_valid_ids.rb +2 -0
  25. data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +2 -0
  26. data/lib/vagrant-libvirt/action/read_mac_addresses.rb +2 -0
  27. data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +2 -0
  28. data/lib/vagrant-libvirt/action/remove_stale_volume.rb +2 -0
  29. data/lib/vagrant-libvirt/action/resume_domain.rb +2 -0
  30. data/lib/vagrant-libvirt/action/set_boot_order.rb +8 -2
  31. data/lib/vagrant-libvirt/action/set_name_of_domain.rb +3 -1
  32. data/lib/vagrant-libvirt/action/share_folders.rb +2 -0
  33. data/lib/vagrant-libvirt/action/shutdown_domain.rb +49 -0
  34. data/lib/vagrant-libvirt/action/start_domain.rb +26 -17
  35. data/lib/vagrant-libvirt/action/suspend_domain.rb +2 -0
  36. data/lib/vagrant-libvirt/action/wait_till_up.rb +2 -0
  37. data/lib/vagrant-libvirt/action.rb +34 -4
  38. data/lib/vagrant-libvirt/cap/mount_9p.rb +2 -0
  39. data/lib/vagrant-libvirt/cap/mount_virtiofs.rb +2 -0
  40. data/lib/vagrant-libvirt/cap/nic_mac_addresses.rb +2 -0
  41. data/lib/vagrant-libvirt/cap/public_address.rb +2 -0
  42. data/lib/vagrant-libvirt/cap/synced_folder_9p.rb +5 -2
  43. data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +5 -2
  44. data/lib/vagrant-libvirt/config.rb +58 -24
  45. data/lib/vagrant-libvirt/driver.rb +67 -12
  46. data/lib/vagrant-libvirt/errors.rb +2 -0
  47. data/lib/vagrant-libvirt/plugin.rb +2 -0
  48. data/lib/vagrant-libvirt/provider.rb +2 -0
  49. data/lib/vagrant-libvirt/templates/domain.xml.erb +4 -2
  50. data/lib/vagrant-libvirt/templates/public_interface.xml.erb +1 -0
  51. data/lib/vagrant-libvirt/util/byte_number.rb +71 -0
  52. data/lib/vagrant-libvirt/util/collection.rb +2 -0
  53. data/lib/vagrant-libvirt/util/erb_template.rb +2 -0
  54. data/lib/vagrant-libvirt/util/error_codes.rb +2 -0
  55. data/lib/vagrant-libvirt/util/network_util.rb +3 -0
  56. data/lib/vagrant-libvirt/util/nfs.rb +2 -0
  57. data/lib/vagrant-libvirt/util/storage_util.rb +1 -0
  58. data/lib/vagrant-libvirt/util/timer.rb +2 -0
  59. data/lib/vagrant-libvirt/util/ui.rb +1 -0
  60. data/lib/vagrant-libvirt/util.rb +2 -0
  61. data/lib/vagrant-libvirt/version +1 -1
  62. data/lib/vagrant-libvirt/version.rb +2 -0
  63. data/lib/vagrant-libvirt.rb +2 -0
  64. data/locales/en.yml +2 -0
  65. data/spec/spec_helper.rb +2 -0
  66. data/spec/support/binding_proc.rb +2 -0
  67. data/spec/support/environment_helper.rb +2 -0
  68. data/spec/support/libvirt_context.rb +2 -0
  69. data/spec/support/matchers/have_file_content.rb +2 -0
  70. data/spec/support/sharedcontext.rb +3 -0
  71. data/spec/support/temporary_dir.rb +12 -0
  72. data/spec/unit/action/clean_machine_folder_spec.rb +16 -4
  73. data/spec/unit/action/create_domain_spec/additional_disks_domain.xml +61 -0
  74. data/spec/unit/action/create_domain_spec/default_domain.xml +55 -0
  75. data/spec/unit/action/create_domain_spec.rb +68 -32
  76. data/spec/unit/action/create_domain_volume_spec/one_disk_in_storage.xml +1 -1
  77. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_0.xml +1 -1
  78. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_1.xml +1 -1
  79. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_2.xml +1 -1
  80. data/spec/unit/action/create_domain_volume_spec.rb +10 -4
  81. data/spec/unit/action/destroy_domain_spec.rb +8 -2
  82. data/spec/unit/action/forward_ports_spec.rb +2 -0
  83. data/spec/unit/action/halt_domain_spec.rb +30 -57
  84. data/spec/unit/action/handle_box_image_spec.rb +104 -24
  85. data/spec/unit/action/package_domain_spec.rb +304 -0
  86. data/spec/unit/action/set_name_of_domain_spec.rb +2 -0
  87. data/spec/unit/action/shutdown_domain_spec.rb +131 -0
  88. data/spec/unit/action/start_domain_spec/existing.xml +62 -0
  89. data/spec/unit/action/start_domain_spec.rb +18 -28
  90. data/spec/unit/action/wait_till_up_spec.rb +2 -0
  91. data/spec/unit/action_spec.rb +96 -0
  92. data/spec/unit/config_spec.rb +56 -3
  93. data/spec/unit/driver_spec.rb +155 -0
  94. data/spec/unit/templates/domain_all_settings.xml +4 -0
  95. data/spec/unit/templates/domain_spec.rb +2 -0
  96. data/spec/unit/util/byte_number_spec.rb +28 -0
  97. metadata +59 -38
@@ -1,8 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
4
+ require 'json'
2
5
  require 'support/sharedcontext'
3
6
  require 'support/libvirt_context'
4
7
 
5
8
  require 'vagrant-libvirt/action/destroy_domain'
9
+ require 'vagrant-libvirt/util/byte_number'
10
+
6
11
 
7
12
  describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
8
13
  subject { described_class.new(app, env) }
@@ -15,6 +20,41 @@ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
15
20
  let(:all) { double('all') }
16
21
  let(:box_volume) { double('box_volume') }
17
22
  let(:fog_volume) { double('fog_volume') }
23
+ let(:config) { double('config') }
24
+
25
+ qemu_json_return_5G = JSON.dump({
26
+ "virtual-size": 5368709120,
27
+ "filename": "/test/box.img",
28
+ "cluster-size": 65536,
29
+ "format": "qcow2",
30
+ "actual-size": 655360,
31
+ "dirty-flag": false
32
+ })
33
+ byte_number_5G = ByteNumber.new(5368709120)
34
+
35
+
36
+ qemu_json_return_10G = JSON.dump({
37
+ "virtual-size": 10737423360,
38
+ "filename": "/test/disk.qcow2",
39
+ "cluster-size": 65536,
40
+ "format": "qcow2",
41
+ "actual-size": 655360,
42
+ "dirty-flag": false
43
+ })
44
+ byte_number_10G = ByteNumber.new(10737423360)
45
+
46
+ qemu_json_return_20G = JSON.dump({
47
+ "virtual-size": 21474836480,
48
+ "filename": "/test/box_2.img",
49
+ "cluster-size": 65536,
50
+ "format": "qcow2",
51
+ "actual-size": 1508708352,
52
+ "dirty-flag": false
53
+ })
54
+ byte_number_20G = ByteNumber.new(21474836480)
55
+
56
+
57
+
18
58
 
19
59
  describe '#call' do
20
60
  before do
@@ -39,7 +79,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
39
79
  ]
40
80
  }
41
81
  allow(env[:machine]).to receive_message_chain("box.directory.join") do |arg|
42
- '/test/'.concat(arg.to_s)
82
+ '/test/' + arg.to_s
43
83
  end
44
84
  end
45
85
 
@@ -51,13 +91,53 @@ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
51
91
  {
52
92
  :path=>"/test/box.img",
53
93
  :name=>"test_vagrant_box_image_1.1.1_box.img",
54
- :virtual_size=>5,
94
+ :virtual_size=>byte_number_5G,
55
95
  :format=>"qcow2"
56
96
  }
57
97
  ]
58
98
  )
59
99
  end
60
100
 
101
+ context 'When config.machine_virtual_size is set and smaller than box_virtual_size' do
102
+ before do
103
+ allow(env[:machine]).to receive_message_chain("provider_config.machine_virtual_size").and_return(1)
104
+ end
105
+ it 'should warning must be raise' do
106
+ expect(ui).to receive(:warn).with("Ignoring requested virtual disk size of '1' as it is below\nthe minimum box image size of '5'.")
107
+ expect(subject.call(env)).to be_nil
108
+ expect(env[:box_volumes]).to eq(
109
+ [
110
+ {
111
+ :path=>"/test/box.img",
112
+ :name=>"test_vagrant_box_image_1.1.1_box.img",
113
+ :virtual_size=>byte_number_5G,
114
+ :format=>"qcow2"
115
+ }
116
+ ]
117
+ )
118
+ end
119
+ end
120
+
121
+ context 'When config.machine_virtual_size is set and higher than box_virtual_size' do
122
+ before do
123
+ allow(env[:machine]).to receive_message_chain("provider_config.machine_virtual_size").and_return(20)
124
+ end
125
+ it 'should be use' do
126
+ expect(ui).to receive(:info).with("Created volume larger than box defaults, will require manual resizing of\nfilesystems to utilize.")
127
+ expect(subject.call(env)).to be_nil
128
+ expect(env[:box_volumes]).to eq(
129
+ [
130
+ {
131
+ :path=>"/test/box.img",
132
+ :name=>"test_vagrant_box_image_1.1.1_box.img",
133
+ :virtual_size=>byte_number_20G,
134
+ :format=>"qcow2"
135
+ }
136
+ ]
137
+ )
138
+ end
139
+ end
140
+
61
141
  context 'when disk image not in storage pool' do
62
142
  before do
63
143
  allow(File).to receive(:exist?).and_return(true)
@@ -74,7 +154,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
74
154
  hash_including(
75
155
  :name => "test_vagrant_box_image_1.1.1_box.img",
76
156
  :allocation => "5120M",
77
- :capacity => "5G",
157
+ :capacity => "5368709120B",
78
158
  )
79
159
  )
80
160
  expect(subject).to receive(:upload_image)
@@ -119,17 +199,17 @@ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
119
199
  ],
120
200
  ]}
121
201
  allow(env[:machine]).to receive_message_chain("box.directory.join") do |arg|
122
- '/test/'.concat(arg.to_s)
202
+ '/test/' + arg.to_s
123
203
  end
124
204
  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
205
+ allow(Open3).to receive(:capture3).with('qemu-img', 'info', '--output=json', '/test/box.img').and_return([
206
+ qemu_json_return_5G, "", status
127
207
  ])
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
208
+ allow(Open3).to receive(:capture3).with('qemu-img', 'info', '--output=json', '/test/disk.qcow2').and_return([
209
+ qemu_json_return_10G, "", status
130
210
  ])
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
211
+ allow(Open3).to receive(:capture3).with('qemu-img', 'info', '--output=json', '/test/box_2.img').and_return([
212
+ qemu_json_return_20G, "", status
133
213
  ])
134
214
  end
135
215
 
@@ -141,19 +221,19 @@ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
141
221
  {
142
222
  :path=>"/test/box.img",
143
223
  :name=>"test_vagrant_box_image_1.1.1_send_box_name.img",
144
- :virtual_size=>5,
224
+ :virtual_size=>byte_number_5G,
145
225
  :format=>"qcow2"
146
226
  },
147
227
  {
148
228
  :path=>"/test/disk.qcow2",
149
229
  :name=>"test_vagrant_box_image_1.1.1_disk.img",
150
- :virtual_size=>10,
230
+ :virtual_size=>byte_number_10G,
151
231
  :format=>"qcow2"
152
232
  },
153
233
  {
154
234
  :path=>"/test/box_2.img",
155
235
  :name=>"test_vagrant_box_image_1.1.1_box_2.img",
156
- :virtual_size=>20,
236
+ :virtual_size=>byte_number_20G,
157
237
  :format=>"qcow2"
158
238
  }
159
239
  ]
@@ -176,7 +256,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
176
256
  hash_including(
177
257
  :name => "test_vagrant_box_image_1.1.1_send_box_name.img",
178
258
  :allocation => "5120M",
179
- :capacity => "5G",
259
+ :capacity => "5368709120B",
180
260
  )
181
261
  )
182
262
  expect(subject).to receive(:upload_image)
@@ -186,7 +266,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
186
266
  hash_including(
187
267
  :name => "test_vagrant_box_image_1.1.1_disk.img",
188
268
  :allocation => "10240M",
189
- :capacity => "10G",
269
+ :capacity => "10737423360B",
190
270
  )
191
271
  )
192
272
  expect(subject).to receive(:upload_image)
@@ -196,7 +276,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
196
276
  hash_including(
197
277
  :name => "test_vagrant_box_image_1.1.1_box_2.img",
198
278
  :allocation => "20480M",
199
- :capacity => "20G",
279
+ :capacity => "21474836480B",
200
280
  )
201
281
  )
202
282
  expect(subject).to receive(:upload_image)
@@ -256,7 +336,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
256
336
  ]
257
337
  }
258
338
  allow(env[:machine]).to receive_message_chain("box.directory.join") do |arg|
259
- '/test/'.concat(arg.to_s)
339
+ '/test/' + arg.to_s
260
340
  end
261
341
  end
262
342
 
@@ -276,17 +356,17 @@ describe VagrantPlugins::ProviderLibvirt::Action::HandleBoxImage do
276
356
  allow(env[:machine]).to receive_message_chain("box.version") { '1.1.1' }
277
357
  allow(env[:machine]).to receive_message_chain("box.metadata") { box_metadata }
278
358
  allow(env[:machine]).to receive_message_chain("box.directory.join") do |arg|
279
- '/test/'.concat(arg.to_s)
359
+ '/test/' + arg.to_s
280
360
  end
281
361
  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
362
+ allow(Open3).to receive(:capture3).with('qemu-img', 'info', "--output=json", '/test/box.img').and_return([
363
+ qemu_json_return_5G, "", status
284
364
  ])
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
365
+ allow(Open3).to receive(:capture3).with('qemu-img', 'info', "--output=json", '/test/disk.qcow2').and_return([
366
+ qemu_json_return_10G, "", status
287
367
  ])
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
368
+ allow(Open3).to receive(:capture3).with('qemu-img', 'info', "--output=json", '/test/box_2.img').and_return([
369
+ qemu_json_return_20G, "", status
290
370
  ])
291
371
  end
292
372
 
@@ -0,0 +1,304 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'support/sharedcontext'
5
+
6
+ require 'vagrant-libvirt/action/clean_machine_folder'
7
+
8
+ describe VagrantPlugins::ProviderLibvirt::Action::PackageDomain do
9
+ subject { described_class.new(app, env) }
10
+
11
+ include_context 'unit'
12
+ include_context 'libvirt'
13
+ include_context 'temporary_dir'
14
+
15
+ let(:libvirt_client) { double('libvirt_client') }
16
+ let(:libvirt_domain) { double('libvirt_domain') }
17
+ let(:servers) { double('servers') }
18
+ let(:volumes) { double('volumes') }
19
+ let(:metadata_file) { double('file') }
20
+ let(:vagrantfile_file) { double('file') }
21
+
22
+ describe '#call' do
23
+ before do
24
+ allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver)
25
+ .to receive(:connection).and_return(connection)
26
+ allow(connection).to receive(:client).and_return(libvirt_client)
27
+ allow(libvirt_client).to receive(:lookup_domain_by_uuid).and_return(libvirt_domain)
28
+
29
+ allow(connection).to receive(:servers).and_return(servers)
30
+ allow(servers).to receive(:get).and_return(domain)
31
+
32
+ allow(connection).to receive(:volumes).and_return(volumes)
33
+
34
+ allow(logger).to receive(:info)
35
+
36
+ env["package.directory"] = temp_dir
37
+ end
38
+
39
+ context 'with defaults' do
40
+ let(:root_disk) { double('libvirt_domain_disk') }
41
+ before do
42
+ allow(root_disk).to receive(:name).and_return('default_domain.img')
43
+ allow(domain).to receive(:volumes).and_return([root_disk])
44
+ allow(libvirt_domain).to receive(:name).and_return('default_domain')
45
+ allow(subject).to receive(:download_image).and_return(true)
46
+ end
47
+
48
+ it 'should succeed' do
49
+ expect(ui).to receive(:info).with('Packaging domain...')
50
+ expect(ui).to receive(:info).with(/Downloading default_domain.img to .*\/box.img/)
51
+ expect(ui).to receive(:info).with('Image has backing image, copying image and rebasing ...')
52
+ expect(subject).to receive(:`).with(/qemu-img info .*\/box.img | grep 'backing file:' | cut -d ':' -f2/).and_return("some image")
53
+ expect(subject).to receive(:`).with(/qemu-img rebase -p -b "" .*\/box.img/)
54
+ expect(subject).to receive(:`).with(/virt-sysprep --no-logfile --operations .* -a .*\/box.img .*/)
55
+ expect(subject).to receive(:`).with(/virt-sparsify --in-place .*\/box.img/)
56
+ expect(subject).to receive(:`).with(/qemu-img info --output=json .*\/box.img/).and_return(
57
+ { 'virtual-size': 5*1024*1024*1024 }.to_json
58
+ )
59
+ expect(File).to receive(:write).with(
60
+ /.*\/metadata.json/,
61
+ <<-EOF.unindent
62
+ {
63
+ "provider": "libvirt",
64
+ "format": "qcow2",
65
+ "virtual_size": 5
66
+ }
67
+ EOF
68
+ )
69
+ expect(File).to receive(:write).with(/.*\/Vagrantfile/, /.*/)
70
+
71
+ expect(subject.call(env)).to be_nil
72
+ end
73
+ end
74
+
75
+ context 'with nil volume' do
76
+ let(:root_disk) { double('libvirt_domain_disk') }
77
+ before do
78
+ allow(root_disk).to receive(:name).and_return('default_domain.img')
79
+ allow(domain).to receive(:volumes).and_return([nil, root_disk])
80
+ allow(libvirt_domain).to receive(:name).and_return('default_domain')
81
+ allow(subject).to receive(:download_image).and_return(true)
82
+ end
83
+
84
+ it 'should succeed' do
85
+ expect(ui).to receive(:info).with('Packaging domain...')
86
+ expect(ui).to receive(:info).with(/Downloading default_domain.img to .*\/box.img/)
87
+ expect(ui).to receive(:info).with('Image has backing image, copying image and rebasing ...')
88
+ expect(subject).to receive(:`).with(/qemu-img info .*\/box.img | grep 'backing file:' | cut -d ':' -f2/).and_return("some image")
89
+ expect(subject).to receive(:`).with(/qemu-img rebase -p -b "" .*\/box.img/)
90
+ expect(subject).to receive(:`).with(/virt-sysprep --no-logfile --operations .* -a .*\/box.img .*/)
91
+ expect(subject).to receive(:`).with(/virt-sparsify --in-place .*\/box.img/)
92
+ expect(subject).to receive(:`).with(/qemu-img info --output=json .*\/box.img/).and_return(
93
+ { 'virtual-size': 5*1024*1024*1024 }.to_json
94
+ )
95
+
96
+ expect(subject.call(env)).to be_nil
97
+ end
98
+ end
99
+
100
+ context 'when detecting the format' do
101
+ let(:root_disk) { double('libvirt_domain_disk') }
102
+ let(:disk2) { double('libvirt_additional_disk') }
103
+ let(:fake_env) { Hash.new }
104
+
105
+ before do
106
+ allow(root_disk).to receive(:name).and_return('default_domain.img')
107
+ allow(disk2).to receive(:name).and_return('disk2.img')
108
+ allow(libvirt_domain).to receive(:name).and_return('default_domain')
109
+ end
110
+
111
+ context 'with two disks' do
112
+ before do
113
+ allow(domain).to receive(:volumes).and_return([root_disk, disk2])
114
+ end
115
+
116
+ it 'should emit a warning' do
117
+ expect(ui).to receive(:info).with('Packaging domain...')
118
+ expect(ui).to receive(:warn).with(/Detected more than one volume for machine.*\n.*/)
119
+ expect(subject).to receive(:package_v1)
120
+
121
+ expect(subject.call(env)).to be_nil
122
+ end
123
+ end
124
+
125
+ context 'with format set to v1' do
126
+ before do
127
+ allow(domain).to receive(:volumes).and_return([root_disk])
128
+ stub_const("ENV", fake_env)
129
+ fake_env['VAGRANT_LIBVIRT_BOX_FORMAT_VERSION'] = "v1"
130
+ end
131
+
132
+ it 'should call v1 packaging' do
133
+ expect(ui).to receive(:info).with('Packaging domain...')
134
+ expect(subject).to receive(:package_v1)
135
+
136
+ expect(subject.call(env)).to be_nil
137
+ end
138
+ end
139
+
140
+ context 'with format set to v2' do
141
+ before do
142
+ allow(domain).to receive(:volumes).and_return([root_disk])
143
+ stub_const("ENV", fake_env)
144
+ fake_env['VAGRANT_LIBVIRT_BOX_FORMAT_VERSION'] = "v2"
145
+ end
146
+
147
+ it 'should call v1 packaging' do
148
+ expect(ui).to receive(:info).with('Packaging domain...')
149
+ expect(subject).to receive(:package_v2)
150
+
151
+ expect(subject.call(env)).to be_nil
152
+ end
153
+ end
154
+
155
+ context 'with invalid format' do
156
+ before do
157
+ allow(domain).to receive(:volumes).and_return([root_disk])
158
+ stub_const("ENV", fake_env)
159
+ fake_env['VAGRANT_LIBVIRT_BOX_FORMAT_VERSION'] = "bad format"
160
+ end
161
+
162
+ it 'should emit a warning and default to v1' do
163
+ expect(ui).to receive(:info).with('Packaging domain...')
164
+ expect(ui).to receive(:warn).with(/Unrecognized value for.*defaulting to v1/)
165
+ expect(subject).to receive(:package_v1)
166
+
167
+ expect(subject.call(env)).to be_nil
168
+ end
169
+ end
170
+ end
171
+
172
+ context 'with v2 format' do
173
+ let(:disk1) { double('libvirt_domain_disk') }
174
+ let(:disk2) { double('libvirt_additional_disk') }
175
+ let(:fake_env) { Hash.new }
176
+
177
+ before do
178
+ allow(disk1).to receive(:name).and_return('default_domain.img')
179
+ allow(disk2).to receive(:name).and_return('disk2.img')
180
+ allow(libvirt_domain).to receive(:name).and_return('default_domain')
181
+ allow(subject).to receive(:download_image).and_return(true).twice()
182
+
183
+ stub_const("ENV", fake_env)
184
+ fake_env['VAGRANT_LIBVIRT_BOX_FORMAT_VERSION'] = "v2"
185
+ end
186
+
187
+ context 'with 2 disks' do
188
+ before do
189
+ allow(domain).to receive(:volumes).and_return([disk1, disk2])
190
+ end
191
+
192
+ it 'should succeed' do
193
+ expect(ui).to receive(:info).with('Packaging domain...')
194
+ expect(ui).to receive(:info).with(/Downloading default_domain.img to .*\/box_1.img/)
195
+ expect(ui).to receive(:info).with('Image has backing image, copying image and rebasing ...')
196
+ expect(subject).to receive(:`).with(/qemu-img info .*\/box_1.img | grep 'backing file:' | cut -d ':' -f2/).and_return("some image")
197
+ expect(subject).to receive(:`).with(/qemu-img rebase -p -b "" .*\/box_1.img/)
198
+ expect(subject).to receive(:`).with(/virt-sysprep --no-logfile --operations .* -a .*\/box_1.img .*/)
199
+ expect(subject).to receive(:`).with(/virt-sparsify --in-place .*\/box_1.img/)
200
+ expect(ui).to receive(:info).with(/Downloading disk2.img to .*\/box_2.img/)
201
+ expect(ui).to receive(:info).with('Image has backing image, copying image and rebasing ...')
202
+ expect(subject).to receive(:`).with(/qemu-img info .*\/box_2.img | grep 'backing file:' | cut -d ':' -f2/).and_return("some image")
203
+ expect(subject).to receive(:`).with(/qemu-img rebase -p -b "" .*\/box_2.img/)
204
+ expect(subject).to receive(:`).with(/virt-sparsify --in-place .*\/box_2.img/)
205
+
206
+ expect(File).to receive(:write).with(
207
+ /.*\/metadata.json/,
208
+ <<-EOF.unindent.rstrip()
209
+ {
210
+ "provider": "libvirt",
211
+ "format": "qcow2",
212
+ "disks": [
213
+ {
214
+ "path": "box_1.img"
215
+ },
216
+ {
217
+ "path": "box_2.img"
218
+ }
219
+ ]
220
+ }
221
+ EOF
222
+ )
223
+ expect(File).to receive(:write).with(/.*\/Vagrantfile/, /.*/)
224
+
225
+ expect(subject.call(env)).to be_nil
226
+ end
227
+ end
228
+
229
+ context 'with 1 disk' do
230
+ before do
231
+ allow(domain).to receive(:volumes).and_return([disk1])
232
+ end
233
+
234
+ it 'should succeed' do
235
+ expect(ui).to receive(:info).with('Packaging domain...')
236
+ expect(ui).to receive(:info).with(/Downloading default_domain.img to .*\/box_1.img/)
237
+ expect(ui).to receive(:info).with('Image has backing image, copying image and rebasing ...')
238
+ expect(subject).to receive(:`).with(/qemu-img info .*\/box_1.img | grep 'backing file:' | cut -d ':' -f2/).and_return("some image")
239
+ expect(subject).to receive(:`).with(/qemu-img rebase -p -b "" .*\/box_1.img/)
240
+ expect(subject).to receive(:`).with(/virt-sysprep --no-logfile --operations .* -a .*\/box_1.img .*/)
241
+ expect(subject).to receive(:`).with(/virt-sparsify --in-place .*\/box_1.img/)
242
+
243
+ expect(File).to receive(:write).with(
244
+ /.*\/metadata.json/,
245
+ <<-EOF.unindent.rstrip()
246
+ {
247
+ "provider": "libvirt",
248
+ "format": "qcow2",
249
+ "disks": [
250
+ {
251
+ "path": "box_1.img"
252
+ }
253
+ ]
254
+ }
255
+ EOF
256
+ )
257
+ expect(File).to receive(:write).with(/.*\/Vagrantfile/, /.*/)
258
+
259
+ expect(subject.call(env)).to be_nil
260
+ end
261
+ end
262
+ end
263
+ end
264
+
265
+ describe '#vagrantfile_content' do
266
+ context 'with defaults' do
267
+ it 'should output expected content' do
268
+ expect(subject.vagrantfile_content(env)).to eq(
269
+ <<-EOF.unindent
270
+ Vagrant.configure("2") do |config|
271
+ config.vm.provider :libvirt do |libvirt|
272
+ libvirt.driver = "kvm"
273
+ end
274
+
275
+ end
276
+ EOF
277
+ )
278
+ end
279
+ end
280
+
281
+ context 'with custom user vagrantfile' do
282
+ before do
283
+ env["package.vagrantfile"] = "_Vagrantfile"
284
+ end
285
+ it 'should output Vagrantfile containing reference' do
286
+ expect(subject.vagrantfile_content(env)).to eq(
287
+ <<-EOF.unindent
288
+ Vagrant.configure("2") do |config|
289
+ config.vm.provider :libvirt do |libvirt|
290
+ libvirt.driver = "kvm"
291
+ end
292
+
293
+ # Load include vagrant file if it exists after the auto-generated
294
+ # so it can override any of the settings
295
+ include_vagrantfile = File.expand_path("../include/_Vagrantfile", __FILE__)
296
+ load include_vagrantfile if File.exist?(include_vagrantfile)
297
+
298
+ end
299
+ EOF
300
+ )
301
+ end
302
+ end
303
+ end
304
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe VagrantPlugins::ProviderLibvirt::Action::SetNameOfDomain do
@@ -0,0 +1,131 @@
1
+ require 'spec_helper'
2
+ require 'support/sharedcontext'
3
+ require 'support/libvirt_context'
4
+ require 'vagrant-libvirt/action/shutdown_domain'
5
+
6
+ describe VagrantPlugins::ProviderLibvirt::Action::ShutdownDomain do
7
+ subject { described_class.new(app, env, target_state, current_state) }
8
+
9
+ include_context 'unit'
10
+ include_context 'libvirt'
11
+
12
+ let(:driver) { double('driver') }
13
+ let(:libvirt_domain) { double('libvirt_domain') }
14
+ let(:servers) { double('servers') }
15
+ let(:current_state) { :running }
16
+ let(:target_state) { :shutoff }
17
+
18
+ before do
19
+ allow(machine.provider).to receive('driver').and_return(driver)
20
+ allow(driver).to receive(:created?).and_return(true)
21
+ allow(driver).to receive(:connection).and_return(connection)
22
+ end
23
+
24
+ describe '#call' do
25
+ before do
26
+ allow(connection).to receive(:servers).and_return(servers)
27
+ allow(servers).to receive(:get).and_return(domain)
28
+ allow(ui).to receive(:info).with('Attempting direct shutdown of domain...')
29
+ end
30
+
31
+ context "when state is shutoff" do
32
+ before do
33
+ allow(driver).to receive(:state).and_return(:shutoff)
34
+ end
35
+
36
+ it "should not shutdown" do
37
+ expect(domain).not_to receive(:shutoff)
38
+ subject.call(env)
39
+ end
40
+
41
+ it "should not print shutdown message" do
42
+ expect(ui).not_to receive(:info)
43
+ subject.call(env)
44
+ end
45
+
46
+ it "should provide a true result" do
47
+ subject.call(env)
48
+ expect(env[:result]).to be_truthy
49
+ end
50
+ end
51
+
52
+ context "when state is running" do
53
+ before do
54
+ allow(driver).to receive(:state).and_return(:running)
55
+ end
56
+
57
+ it "should shutdown" do
58
+ expect(domain).to receive(:wait_for)
59
+ expect(domain).to receive(:shutdown)
60
+ subject.call(env)
61
+ end
62
+
63
+ it "should print shutdown message" do
64
+ expect(domain).to receive(:wait_for)
65
+ expect(domain).to receive(:shutdown)
66
+ expect(ui).to receive(:info).with('Attempting direct shutdown of domain...')
67
+ subject.call(env)
68
+ end
69
+
70
+ context "when final state is not shutoff" do
71
+ before do
72
+ expect(driver).to receive(:state).and_return(:running).exactly(3).times
73
+ expect(domain).to receive(:wait_for)
74
+ expect(domain).to receive(:shutdown)
75
+ end
76
+
77
+ it "should provide a false result" do
78
+ subject.call(env)
79
+ expect(env[:result]).to be_falsey
80
+ end
81
+ end
82
+
83
+ context "when final state is shutoff" do
84
+ before do
85
+ expect(driver).to receive(:state).and_return(:running).exactly(2).times
86
+ expect(driver).to receive(:state).and_return(:shutoff).exactly(1).times
87
+ expect(domain).to receive(:wait_for)
88
+ expect(domain).to receive(:shutdown)
89
+ end
90
+
91
+ it "should provide a true result" do
92
+ subject.call(env)
93
+ expect(env[:result]).to be_truthy
94
+ end
95
+ end
96
+
97
+ context "when timeout exceeded" do
98
+ before do
99
+ expect(machine).to receive_message_chain('config.vm.graceful_halt_timeout').and_return(1)
100
+ expect(app).to receive(:call) { sleep 1.5 }
101
+ expect(driver).to receive(:state).and_return(:running).exactly(1).times
102
+ expect(domain).to_not receive(:wait_for)
103
+ expect(domain).to_not receive(:shutdown)
104
+ end
105
+
106
+ it "should provide a false result" do
107
+ subject.call(env)
108
+ expect(env[:result]).to be_falsey
109
+ end
110
+ end
111
+
112
+ context "when timeout not exceeded" do
113
+ before do
114
+ expect(machine).to receive_message_chain('config.vm.graceful_halt_timeout').and_return(2)
115
+ expect(app).to receive(:call) { sleep 1 }
116
+ expect(driver).to receive(:state).and_return(:running).exactly(3).times
117
+ expect(domain).to receive(:wait_for) do |time|
118
+ expect(time).to be < 1
119
+ expect(time).to be > 0
120
+ end
121
+ expect(domain).to receive(:shutdown)
122
+ end
123
+
124
+ it "should wait for the reduced time" do
125
+ subject.call(env)
126
+ expect(env[:result]).to be_falsey
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end