vagrant-libvirt 0.5.0 → 0.6.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 (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