vagrant-libvirt 0.8.2 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +51 -2079
  3. data/lib/vagrant-libvirt/action/create_domain.rb +57 -94
  4. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +1 -1
  5. data/lib/vagrant-libvirt/action/create_networks.rb +3 -3
  6. data/lib/vagrant-libvirt/action/destroy_domain.rb +21 -5
  7. data/lib/vagrant-libvirt/action/destroy_networks.rb +2 -2
  8. data/lib/vagrant-libvirt/action/handle_box_image.rb +3 -1
  9. data/lib/vagrant-libvirt/action/package_domain.rb +1 -5
  10. data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +3 -1
  11. data/lib/vagrant-libvirt/action/resolve_disk_settings.rb +181 -0
  12. data/lib/vagrant-libvirt/action/snapshot_delete.rb +26 -0
  13. data/lib/vagrant-libvirt/action/snapshot_restore.rb +22 -0
  14. data/lib/vagrant-libvirt/action/snapshot_save.rb +27 -0
  15. data/lib/vagrant-libvirt/action/start_domain.rb +80 -11
  16. data/lib/vagrant-libvirt/action.rb +53 -1
  17. data/lib/vagrant-libvirt/cap/snapshots.rb +12 -0
  18. data/lib/vagrant-libvirt/cap/synced_folder_9p.rb +4 -4
  19. data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +4 -4
  20. data/lib/vagrant-libvirt/config.rb +104 -6
  21. data/lib/vagrant-libvirt/driver.rb +108 -46
  22. data/lib/vagrant-libvirt/errors.rb +23 -3
  23. data/lib/vagrant-libvirt/plugin.rb +7 -3
  24. data/lib/vagrant-libvirt/provider.rb +1 -1
  25. data/lib/vagrant-libvirt/templates/domain.xml.erb +32 -6
  26. data/lib/vagrant-libvirt/util/byte_number.rb +0 -1
  27. data/lib/vagrant-libvirt/util/compat.rb +23 -0
  28. data/lib/vagrant-libvirt/util/domain_flags.rb +15 -0
  29. data/lib/vagrant-libvirt/util/unindent.rb +7 -0
  30. data/lib/vagrant-libvirt/util.rb +1 -0
  31. data/lib/vagrant-libvirt/version +1 -1
  32. data/locales/en.yml +28 -4
  33. data/spec/acceptance/additional_storage_spec.rb +32 -0
  34. data/spec/acceptance/package_domain_spec.rb +90 -0
  35. data/spec/acceptance/provider_settings_spec.rb +54 -0
  36. data/spec/acceptance/simple_vm_provision_via_shell_spec.rb +31 -0
  37. data/spec/acceptance/snapshots_spec.rb +41 -0
  38. data/spec/acceptance/support-skeletons/package_complex/Vagrantfile.testbox +14 -0
  39. data/spec/acceptance/support-skeletons/package_complex/scripts/sysprep.sh +32 -0
  40. data/spec/acceptance/support-skeletons/package_simple/Vagrantfile.testbox +10 -0
  41. data/spec/acceptance/two_disks_spec.rb +29 -0
  42. data/spec/acceptance/use_qemu_agent_for_connectivity_spec.rb +35 -0
  43. data/spec/spec_helper.rb +3 -0
  44. data/spec/support/acceptance/configuration.rb +21 -0
  45. data/spec/support/acceptance/context.rb +70 -0
  46. data/spec/support/acceptance/isolated_environment.rb +41 -0
  47. data/spec/support/libvirt_acceptance_context.rb +64 -0
  48. data/spec/support/libvirt_context.rb +4 -0
  49. data/spec/support/sharedcontext.rb +1 -0
  50. data/spec/unit/action/cleanup_on_failure_spec.rb +0 -2
  51. data/spec/unit/action/create_domain_spec/sysinfo.xml +66 -0
  52. data/spec/unit/action/create_domain_spec/sysinfo_only_required.xml +49 -0
  53. data/spec/unit/action/create_domain_spec.rb +188 -140
  54. data/spec/unit/action/create_domain_volume_spec.rb +0 -3
  55. data/spec/unit/action/destroy_domain_spec.rb +43 -10
  56. data/spec/unit/action/forward_ports_spec.rb +0 -1
  57. data/spec/unit/action/handle_box_image_spec.rb +31 -14
  58. data/spec/unit/action/package_domain_spec.rb +0 -5
  59. data/spec/unit/action/remove_libvirt_image_spec.rb +43 -0
  60. data/spec/unit/action/resolve_disk_settings_spec/default_domain.xml +43 -0
  61. data/spec/unit/action/resolve_disk_settings_spec/default_no_aliases.xml +42 -0
  62. data/spec/unit/action/{create_domain_spec → resolve_disk_settings_spec}/default_system_storage_pool.xml +0 -0
  63. data/spec/unit/action/resolve_disk_settings_spec/multi_volume_box.xml +55 -0
  64. data/spec/unit/action/resolve_disk_settings_spec/multi_volume_box_additional_and_custom_no_aliases.xml +67 -0
  65. data/spec/unit/action/resolve_disk_settings_spec/multi_volume_box_additional_storage.xml +67 -0
  66. data/spec/unit/action/resolve_disk_settings_spec.rb +385 -0
  67. data/spec/unit/action/start_domain_spec/clock_timer_removed.xml +38 -0
  68. data/spec/unit/action/start_domain_spec/clock_timer_rtc_tsc.xml +39 -0
  69. data/spec/unit/action/start_domain_spec/existing_added_nvram.xml +62 -0
  70. data/spec/unit/action/start_domain_spec/nvram_domain.xml +64 -0
  71. data/spec/unit/action/start_domain_spec/nvram_domain_other_setting.xml +64 -0
  72. data/spec/unit/action/start_domain_spec/nvram_domain_removed.xml +64 -0
  73. data/spec/unit/action/start_domain_spec.rb +122 -22
  74. data/spec/unit/action/wait_till_up_spec.rb +0 -2
  75. data/spec/unit/action_spec.rb +88 -3
  76. data/spec/unit/cap/synced_folder_9p_spec.rb +120 -0
  77. data/spec/unit/cap/synced_folder_virtiofs_spec.rb +120 -0
  78. data/spec/unit/config_spec.rb +153 -6
  79. data/spec/unit/driver_spec.rb +3 -1
  80. data/spec/unit/plugin_spec.rb +42 -0
  81. data/spec/unit/templates/domain_all_settings.xml +15 -6
  82. data/spec/unit/templates/domain_scsi_bus_storage.xml +44 -0
  83. data/spec/unit/templates/domain_scsi_device_storage.xml +44 -0
  84. data/spec/unit/templates/domain_scsi_multiple_controllers_storage.xml +130 -0
  85. data/spec/unit/templates/domain_spec.rb +105 -21
  86. data/spec/unit/util/byte_number_spec.rb +1 -1
  87. metadata +169 -79
  88. data/spec/unit/provider_spec.rb +0 -11
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'diffy'
3
4
  require 'log4r'
4
5
  require 'rexml/document'
5
6
 
@@ -14,8 +15,6 @@ module VagrantPlugins
14
15
  end
15
16
 
16
17
  def call(env)
17
- env[:ui].info(I18n.t('vagrant_libvirt.starting_domain'))
18
-
19
18
  domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
20
19
  raise Errors::NoDomainError if domain.nil?
21
20
  config = env[:machine].provider_config
@@ -33,6 +32,7 @@ module VagrantPlugins
33
32
  libvirt_domain.memory = libvirt_domain.max_memory
34
33
  end
35
34
  end
35
+
36
36
  begin
37
37
  # XML definition manipulation
38
38
  descr = libvirt_domain.xml_desc(1)
@@ -64,7 +64,7 @@ module VagrantPlugins
64
64
  disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
65
65
  end
66
66
 
67
- # Iterface type
67
+ # Interface type
68
68
  unless config.nic_model_type.nil?
69
69
  REXML::XPath.each(xml_descr, '/domain/devices/interface/model') do |iface_model|
70
70
  if iface_model.attributes['type'] != config.nic_model_type
@@ -248,7 +248,7 @@ module VagrantPlugins
248
248
  # TPM
249
249
  if [config.tpm_path, config.tpm_version].any?
250
250
  if config.tpm_path
251
- raise Errors::FogCreateServerError, 'The TPM Path must be fully qualified' unless config.tpm_path[0].chr == '/'
251
+ raise Errors::UpdateServerError, 'The TPM Path must be fully qualified' unless config.tpm_path[0].chr == '/'
252
252
  end
253
253
 
254
254
  # just build the tpm element every time
@@ -375,20 +375,88 @@ module VagrantPlugins
375
375
  end
376
376
  end
377
377
 
378
+ loader = REXML::XPath.first(xml_descr, '/domain/os/loader')
379
+ if config.loader
380
+ if loader.nil?
381
+ descr_changed = true
382
+ loader = REXML::Element.new('loader')
383
+ REXML::XPath.first(xml_descr, '/domain/os').insert_after('//type', loader)
384
+ loader.text = config.loader
385
+ else
386
+ if (loader.text or '').strip != config.loader
387
+ descr_changed = true
388
+ loader.text = config.loader
389
+ end
390
+ end
391
+ loader.attributes['type'] = config.nvram ? 'pflash' : 'rom'
392
+ elsif !loader.nil?
393
+ descr_changed = true
394
+ loader.parent.delete_element(loader)
395
+ end
396
+
397
+ nvram = REXML::XPath.first(xml_descr, '/domain/os/nvram')
398
+ if config.nvram
399
+ if nvram.nil?
400
+ descr_changed = true
401
+ nvram = REXML::Element.new('nvram')
402
+ REXML::XPath.first(xml_descr, '/domain/os').insert_after(loader, nvram)
403
+ nvram.text = config.nvram
404
+ else
405
+ if (nvram.text or '').strip != config.nvram
406
+ descr_changed = true
407
+ nvram.text = config.nvram
408
+ end
409
+ end
410
+ elsif !nvram.nil?
411
+ descr_changed = true
412
+ nvram.parent.delete_element(nvram)
413
+ end
414
+
378
415
  # Apply
379
416
  if descr_changed
417
+ env[:ui].info(I18n.t('vagrant_libvirt.updating_domain'))
418
+ new_xml = String.new
419
+ xml_descr.write(new_xml)
420
+ begin
421
+ # providing XML for the same name and UUID will update the existing domain
422
+ libvirt_domain = env[:machine].provider.driver.connection.define_domain(new_xml)
423
+ rescue ::Libvirt::Error => e
424
+ raise Errors::UpdateServerError, error_message: e.message
425
+ end
426
+
380
427
  begin
381
- libvirt_domain.undefine
382
- new_descr = String.new
383
- xml_descr.write new_descr
384
- env[:machine].provider.driver.connection.servers.create(xml: new_descr)
385
- rescue Fog::Errors::Error => e
386
- env[:machine].provider.driver.connection.servers.create(xml: descr)
387
- raise Errors::FogCreateServerError, error_message: e.message
428
+ proposed = Nokogiri::XML(new_xml, &:noblanks)
429
+
430
+ # This normalizes the attribute order to be consistent across both XML docs to eliminate differences
431
+ # for subsequent comparison by diffy
432
+ updated_xml_descr = REXML::Document.new(libvirt_domain.xml_desc(1))
433
+ updated_xml = String.new
434
+ updated_xml_descr.write(updated_xml)
435
+
436
+ updated = Nokogiri::XML(updated_xml, &:noblanks)
437
+
438
+ pretty_proposed = StringIO.new
439
+ pretty_updated = StringIO.new
440
+ proposed.write_xml_to(pretty_proposed, indent: 2)
441
+ updated.write_xml_to(pretty_updated, indent: 2)
442
+
443
+ diff = Diffy::Diff.new(pretty_proposed.string, pretty_updated.string, :context => 3).to_s(:text)
444
+
445
+ unless diff.empty?
446
+ error_msg = "Libvirt failed to fully update the domain with the specified XML. Result differs from requested:\n" +
447
+ "--- requested\n+++ result\n#{diff}\n" +
448
+ "Typically this means there is a bug in the XML being sent, please log an issue"
449
+
450
+ raise Errors::UpdateServerError, error_message: error_msg
451
+ end
452
+ rescue Exception => e
453
+ env[:machine].provider.driver.connection.define_domain(descr)
454
+ raise
388
455
  end
389
456
  end
390
457
  rescue Errors::VagrantLibvirtError => e
391
458
  env[:ui].error("Error when updating domain settings: #{e.message}")
459
+ raise
392
460
  end
393
461
  # Autostart with host if enabled in Vagrantfile
394
462
  libvirt_domain.autostart = config.autostart
@@ -396,6 +464,7 @@ module VagrantPlugins
396
464
  "Starting Domain with XML:\n#{libvirt_domain.xml_desc}"
397
465
  }
398
466
  # Actually start the domain
467
+ env[:ui].info(I18n.t('vagrant_libvirt.starting_domain'))
399
468
  domain.start
400
469
  rescue Fog::Errors::Error, Errors::VagrantLibvirtError => e
401
470
  raise Errors::FogError, message: e.message
@@ -35,10 +35,17 @@ module VagrantPlugins
35
35
  autoload :ReadMacAddresses, action_root.join('read_mac_addresses')
36
36
  autoload :RemoveLibvirtImage, action_root.join('remove_libvirt_image')
37
37
  autoload :RemoveStaleVolume, action_root.join('remove_stale_volume')
38
+ autoload :ResolveDiskSettings, action_root.join('resolve_disk_settings')
38
39
  autoload :ResumeDomain, action_root.join('resume_domain')
39
40
  autoload :SetNameOfDomain, action_root.join('set_name_of_domain')
40
41
  autoload :SetBootOrder, action_root.join('set_boot_order')
41
42
  autoload :SetupComplete, action_root.join('cleanup_on_failure')
43
+ # Snapshot autoload
44
+ autoload :SnapshotDelete, action_root.join('snapshot_delete')
45
+ autoload :SnapshotSave, action_root.join('snapshot_save')
46
+ autoload :SnapshotRestore, action_root.join('snapshot_restore')
47
+
48
+
42
49
  # I don't think we need it anymore
43
50
  autoload :ShareFolders, action_root.join('share_folders')
44
51
  autoload :ShutdownDomain, action_root.join('shutdown_domain')
@@ -81,6 +88,7 @@ module VagrantPlugins
81
88
  b2.use SetNameOfDomain
82
89
 
83
90
  if !env[:machine].config.vm.box
91
+ b2.use ResolveDiskSettings
84
92
  b2.use CreateDomain
85
93
  b2.use CreateNetworks
86
94
  b2.use CreateNetworkInterfaces
@@ -94,6 +102,7 @@ module VagrantPlugins
94
102
  b2.use HandleBox
95
103
  b2.use HandleBoxImage
96
104
  b2.use CreateDomainVolume
105
+ b2.use ResolveDiskSettings
97
106
  b2.use CreateDomain
98
107
  b2.use CreateNetworks
99
108
  b2.use CreateNetworkInterfaces
@@ -104,6 +113,7 @@ module VagrantPlugins
104
113
  end
105
114
  else
106
115
  env[:halt_on_error] = true
116
+ b2.use ResolveDiskSettings
107
117
  b2.use CreateNetworks
108
118
  b2.use action_start
109
119
  end
@@ -152,7 +162,7 @@ module VagrantPlugins
152
162
  # Start it..
153
163
  b3.use StartDomain
154
164
 
155
- # Machine should gain IP address when comming up,
165
+ # Machine should gain IP address when coming up,
156
166
  # so wait for dhcp lease and store IP into machines data_dir.
157
167
  b3.use WaitTillUp
158
168
  require 'vagrant/action/builtin/wait_for_communicator'
@@ -388,6 +398,48 @@ module VagrantPlugins
388
398
  end
389
399
  end
390
400
 
401
+ # This is the action that is primarily responsible for deleting a snapshot
402
+ def self.action_snapshot_delete
403
+ Vagrant::Action::Builder.new.tap do |b|
404
+ b.use ConfigValidate
405
+ b.use Call, IsCreated do |env, b2|
406
+ unless env[:result]
407
+ raise Vagrant::Errors::VMNotCreatedError
408
+ end
409
+
410
+ b2.use SnapshotDelete
411
+ end
412
+ end
413
+ end
414
+
415
+ # This is the action that is primarily responsible for restoring a snapshot
416
+ def self.action_snapshot_restore
417
+ Vagrant::Action::Builder.new.tap do |b|
418
+ b.use ConfigValidate
419
+ b.use Call, IsCreated do |env, b2|
420
+ unless env[:result]
421
+ raise Vagrant::Errors::VMNotCreatedError
422
+ end
423
+
424
+ b2.use SnapshotRestore
425
+ end
426
+ end
427
+ end
428
+
429
+ # This is the action that is primarily responsible for saving a snapshot
430
+ def self.action_snapshot_save
431
+ Vagrant::Action::Builder.new.tap do |b|
432
+ b.use ConfigValidate
433
+ b.use Call, IsCreated do |env, b2|
434
+ unless env[:result]
435
+ raise Vagrant::Errors::VMNotCreatedError
436
+ end
437
+
438
+ b2.use SnapshotSave
439
+ end
440
+ end
441
+ end
442
+
391
443
  end
392
444
  end
393
445
  end
@@ -0,0 +1,12 @@
1
+ module VagrantPlugins
2
+ module ProviderLibvirt
3
+ module Cap
4
+ class Snapshots
5
+ def self.snapshot_list(machine)
6
+ return if machine.state.id == :not_created
7
+ machine.provider.driver.list_snapshots(machine)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -34,6 +34,8 @@ module VagrantPlugins
34
34
  raise Vagrant::Errors::Error('No Libvirt connection') if machine.provider.driver.connection.nil?
35
35
  @conn = machine.provider.driver.connection.client
36
36
 
37
+ machine.ui.info I18n.t("vagrant_libvirt.cap.9p.preparing")
38
+
37
39
  begin
38
40
  # loop through folders
39
41
  folders.each do |id, folder_opts|
@@ -45,8 +47,6 @@ module VagrantPlugins
45
47
  mount_tag = Digest::MD5.new.update(folder_opts[:hostpath]).to_s[0, 31]
46
48
  folder_opts[:mount_tag] = mount_tag
47
49
 
48
- machine.ui.info "================\nMachine id: #{machine.id}\nShould be mounting folders\n #{id}, opts: #{folder_opts}"
49
-
50
50
  xml = Nokogiri::XML::Builder.new do |xml|
51
51
  xml.filesystem(type: 'mount', accessmode: folder_opts[:accessmode]) do
52
52
  xml.driver(type: 'path', wrpolicy: 'immediate')
@@ -74,7 +74,7 @@ module VagrantPlugins
74
74
  # once up, mount folders
75
75
  def enable(machine, folders, _opts)
76
76
  # Go through each folder and mount
77
- machine.ui.info('mounting 9p share in guest')
77
+ machine.ui.info I18n.t("vagrant_libvirt.cap.9p.mounting")
78
78
  # Only mount folders that have a guest path specified.
79
79
  mount_folders = {}
80
80
  folders.each do |id, opts|
@@ -94,6 +94,7 @@ module VagrantPlugins
94
94
  raise Vagrant::Errors::Error('No Libvirt connection')
95
95
  end
96
96
  @conn = machine.provider.driver.connection.client
97
+ machine.ui.info I18n.t("vagrant_libvirt.cap.9p.cleanup")
97
98
  begin
98
99
  if machine.id && machine.id != ''
99
100
  dom = @conn.lookup_domain_by_uuid(machine.id)
@@ -101,7 +102,6 @@ module VagrantPlugins
101
102
  '/domain/devices/filesystem'
102
103
  ).each do |xml|
103
104
  dom.detach_device(xml.to_s)
104
- machine.ui.info 'Cleaned up shared folders'
105
105
  end
106
106
  end
107
107
  rescue => e
@@ -34,6 +34,8 @@ module VagrantPlugins
34
34
  raise Vagrant::Errors::Error('No Libvirt connection') if machine.provider.driver.connection.nil?
35
35
  @conn = machine.provider.driver.connection.client
36
36
 
37
+ machine.ui.info I18n.t("vagrant_libvirt.cap.virtiofs.preparing")
38
+
37
39
  begin
38
40
  # loop through folders
39
41
  folders.each do |id, folder_opts|
@@ -44,8 +46,6 @@ module VagrantPlugins
44
46
  mount_tag = Digest::MD5.new.update(folder_opts[:hostpath]).to_s[0, 31]
45
47
  folder_opts[:mount_tag] = mount_tag
46
48
 
47
- machine.ui.info "================\nMachine id: #{machine.id}\nShould be mounting folders\n #{id}, opts: #{folder_opts}"
48
-
49
49
  xml = Nokogiri::XML::Builder.new do |xml|
50
50
  xml.filesystem(type: 'mount', accessmode: 'passthrough') do
51
51
  xml.driver(type: 'virtiofs')
@@ -73,7 +73,7 @@ module VagrantPlugins
73
73
  # once up, mount folders
74
74
  def enable(machine, folders, _opts)
75
75
  # Go through each folder and mount
76
- machine.ui.info('mounting virtiofs share in guest')
76
+ machine.ui.info I18n.t("vagrant_libvirt.cap.virtiofs.mounting")
77
77
  # Only mount folders that have a guest path specified.
78
78
  mount_folders = {}
79
79
  folders.each do |id, opts|
@@ -91,6 +91,7 @@ module VagrantPlugins
91
91
  raise Vagrant::Errors::Error('No Libvirt connection')
92
92
  end
93
93
  @conn = machine.provider.driver.connection.client
94
+ machine.ui.info I18n.t("vagrant_libvirt.cap.virtiofs.cleanup")
94
95
  begin
95
96
  if machine.id && machine.id != ''
96
97
  dom = @conn.lookup_domain_by_uuid(machine.id)
@@ -98,7 +99,6 @@ module VagrantPlugins
98
99
  '/domain/devices/filesystem'
99
100
  ).each do |xml|
100
101
  dom.detach_device(xml.to_s)
101
- machine.ui.info 'Cleaned up shared folders'
102
102
  end
103
103
  end
104
104
  rescue => e
@@ -11,7 +11,7 @@ module VagrantPlugins
11
11
  module ProviderLibvirt
12
12
  class Config < Vagrant.plugin('2', :config)
13
13
  # manually specify URI
14
- # will supercede most other options if provided
14
+ # will supersede most other options if provided
15
15
  attr_accessor :uri
16
16
 
17
17
  # A hypervisor name to access via Libvirt.
@@ -99,6 +99,7 @@ module VagrantPlugins
99
99
  attr_accessor :machine_virtual_size
100
100
  attr_accessor :disk_bus
101
101
  attr_accessor :disk_device
102
+ attr_accessor :disk_controller_model
102
103
  attr_accessor :disk_driver_opts
103
104
  attr_accessor :nic_model_type
104
105
  attr_accessor :nested
@@ -128,6 +129,9 @@ module VagrantPlugins
128
129
  attr_accessor :tpm_path
129
130
  attr_accessor :tpm_version
130
131
 
132
+ # Configure sysinfo values
133
+ attr_accessor :sysinfo
134
+
131
135
  # Configure the memballoon
132
136
  attr_accessor :memballoon_enabled
133
137
  attr_accessor :memballoon_model
@@ -195,6 +199,9 @@ module VagrantPlugins
195
199
  # serial consoles
196
200
  attr_accessor :serials
197
201
 
202
+ # internal helper attributes
203
+ attr_accessor :host_device_exclude_prefixes
204
+
198
205
  def initialize
199
206
  @uri = UNSET_VALUE
200
207
  @driver = UNSET_VALUE
@@ -253,6 +260,7 @@ module VagrantPlugins
253
260
  @machine_virtual_size = UNSET_VALUE
254
261
  @disk_bus = UNSET_VALUE
255
262
  @disk_device = UNSET_VALUE
263
+ @disk_controller_model = UNSET_VALUE
256
264
  @disk_driver_opts = {}
257
265
  @nic_model_type = UNSET_VALUE
258
266
  @nested = UNSET_VALUE
@@ -280,6 +288,8 @@ module VagrantPlugins
280
288
  @tpm_path = UNSET_VALUE
281
289
  @tpm_version = UNSET_VALUE
282
290
 
291
+ @sysinfo = UNSET_VALUE
292
+
283
293
  @memballoon_enabled = UNSET_VALUE
284
294
  @memballoon_model = UNSET_VALUE
285
295
  @memballoon_pci_bus = UNSET_VALUE
@@ -342,6 +352,9 @@ module VagrantPlugins
342
352
  @qemu_use_agent = UNSET_VALUE
343
353
 
344
354
  @serials = UNSET_VALUE
355
+
356
+ # internal options to help override behaviour
357
+ @host_device_exclude_prefixes = UNSET_VALUE
345
358
  end
346
359
 
347
360
  def boot(device)
@@ -865,8 +878,15 @@ module VagrantPlugins
865
878
  @machine_type = nil if @machine_type == UNSET_VALUE
866
879
  @machine_arch = nil if @machine_arch == UNSET_VALUE
867
880
  @machine_virtual_size = nil if @machine_virtual_size == UNSET_VALUE
868
- @disk_bus = 'virtio' if @disk_bus == UNSET_VALUE
869
- @disk_device = 'vda' if @disk_device == UNSET_VALUE
881
+ @disk_device = @disk_bus == 'scsi' ? 'sda' : 'vda' if @disk_device == UNSET_VALUE
882
+ @disk_bus = @disk_device.start_with?('sd') ? 'scsi' : 'virtio' if @disk_bus == UNSET_VALUE
883
+ if @disk_controller_model == UNSET_VALUE
884
+ if @disk_bus == 'scsi' or @disk_device.start_with?('sd') == 'sd'
885
+ @disk_controller_model = 'virtio-scsi'
886
+ else
887
+ @disk_controller_model = nil
888
+ end
889
+ end
870
890
  @disk_driver_opts = {} if @disk_driver_opts == UNSET_VALUE
871
891
  @nic_model_type = nil if @nic_model_type == UNSET_VALUE
872
892
  @nested = false if @nested == UNSET_VALUE
@@ -902,6 +922,8 @@ module VagrantPlugins
902
922
  @nic_adapter_count = 8 if @nic_adapter_count == UNSET_VALUE
903
923
  @emulator_path = nil if @emulator_path == UNSET_VALUE
904
924
 
925
+ @sysinfo = {} if @sysinfo == UNSET_VALUE
926
+
905
927
  # Boot order
906
928
  @boot_order = [] if @boot_order == UNSET_VALUE
907
929
 
@@ -972,6 +994,8 @@ module VagrantPlugins
972
994
  @qemu_use_agent = false if @qemu_use_agent == UNSET_VALUE
973
995
 
974
996
  @serials = [{:type => 'pty', :source => nil}] if @serials == UNSET_VALUE
997
+
998
+ @host_device_exclude_prefixes = ['docker', 'macvtap', 'virbr', 'vnet'] if @host_device_exclude_prefixes == UNSET_VALUE
975
999
  end
976
1000
 
977
1001
  def validate(machine)
@@ -994,8 +1018,12 @@ module VagrantPlugins
994
1018
  errors << "libvirt.qemu_use_agent must be a boolean."
995
1019
  end
996
1020
 
1021
+ if !@nvram.nil? && @loader.nil?
1022
+ errors << "use of 'nvram' requires a 'loader' to be specified, please add one to the configuration"
1023
+ end
1024
+
997
1025
  if @qemu_use_agent == true
998
- # if qemu agent is used to optain domain ip configuration, at least
1026
+ # if qemu agent is used to obtain domain ip configuration, at least
999
1027
  # one qemu channel has to be configured. As there are various options,
1000
1028
  # error out and leave configuration to the user
1001
1029
  unless machine.provider_config.channels.any? { |channel| channel[:target_name].start_with?("org.qemu.guest_agent") }
@@ -1025,7 +1053,9 @@ module VagrantPlugins
1025
1053
  errors << "#{e}"
1026
1054
  end
1027
1055
 
1028
- machine.config.vm.networks.each do |_type, opts|
1056
+ machine.config.vm.networks.each_with_index do |network, index|
1057
+ type, opts = network
1058
+
1029
1059
  if opts[:mac]
1030
1060
  if opts[:mac] =~ /\A([0-9a-fA-F]{12})\z/
1031
1061
  opts[:mac] = opts[:mac].scan(/../).join(':')
@@ -1034,6 +1064,14 @@ module VagrantPlugins
1034
1064
  errors << "Configured NIC MAC '#{opts[:mac]}' is not in 'xx:xx:xx:xx:xx:xx' or 'xxxxxxxxxxxx' format"
1035
1065
  end
1036
1066
  end
1067
+
1068
+ # only interested in public networks where portgroup is nil, as then source will be a host device
1069
+ if type == :public_network && opts[:portgroup] == nil
1070
+ devices = host_devices(machine)
1071
+ if !devices.include?(opts[:dev])
1072
+ errors << "network configuration #{index} for machine #{machine.name} is a public_network referencing host device '#{opts[:dev]}' which does not exist, consider adding ':dev => ....' referencing one of #{devices.join(", ")}"
1073
+ end
1074
+ end
1037
1075
  end
1038
1076
 
1039
1077
  if !machine.provider_config.volume_cache.nil? and machine.provider_config.volume_cache != UNSET_VALUE
@@ -1044,6 +1082,8 @@ module VagrantPlugins
1044
1082
  end
1045
1083
  end
1046
1084
 
1085
+ errors = validate_sysinfo(machine, errors)
1086
+
1047
1087
  { 'Libvirt Provider' => errors }
1048
1088
  end
1049
1089
 
@@ -1058,7 +1098,11 @@ module VagrantPlugins
1058
1098
  result.cdroms = c
1059
1099
 
1060
1100
  result.disk_driver_opts = disk_driver_opts.merge(other.disk_driver_opts)
1061
-
1101
+
1102
+ c = sysinfo == UNSET_VALUE ? {} : sysinfo.dup
1103
+ c.merge!(other.sysinfo) { |_k, x, y| x.respond_to?(:each_pair) ? x.merge(y) : x + y } if other.sysinfo != UNSET_VALUE
1104
+ result.sysinfo = c
1105
+
1062
1106
  c = clock_timers.dup
1063
1107
  c += other.clock_timers
1064
1108
  result.clock_timers = c
@@ -1166,6 +1210,60 @@ module VagrantPlugins
1166
1210
  @proxy_command = nil
1167
1211
  end
1168
1212
  end
1213
+
1214
+ def host_devices(machine)
1215
+ @host_devices ||= begin
1216
+ machine.provider.driver.connection.client.list_all_interfaces().map { |iface| iface.name }.uniq.select do |dev|
1217
+ dev != "lo" && !@host_device_exclude_prefixes.any? { |exclude| dev.start_with?(exclude) }
1218
+ end
1219
+ end
1220
+ end
1221
+
1222
+ def validate_sysinfo(machine, errors)
1223
+ valid_sysinfo = {
1224
+ 'bios' => %w[vendor version date release],
1225
+ 'system' => %w[manufacturer product version serial uuid sku family],
1226
+ 'base board' => %w[manufacturer product version serial asset location],
1227
+ 'chassis' => %w[manufacturer version serial asset sku],
1228
+ 'oem strings' => nil,
1229
+ }
1230
+
1231
+ machine.provider_config.sysinfo.each_pair do |block_name, entries|
1232
+ block_name = block_name.to_s
1233
+ unless valid_sysinfo.key?(block_name)
1234
+ errors << "invalid sysinfo element '#{block_name}'; smbios sysinfo elements supported: #{valid_sysinfo.keys.join(', ')}"
1235
+ next
1236
+ end
1237
+
1238
+ if valid_sysinfo[block_name].nil?
1239
+ # assume simple array of text entries
1240
+ entries.each do |entry|
1241
+ if entry.respond_to?(:to_str)
1242
+ if entry.to_s.empty?
1243
+ machine.ui.warn("Libvirt Provider: 'sysinfo.#{block_name}' contains an empty or nil entry and will be discarded")
1244
+ end
1245
+ else
1246
+ errors << "sysinfo.#{block_name} expects entries to be stringy, got #{entry.class} containing '#{entry}'"
1247
+ end
1248
+ end
1249
+ else
1250
+ entries.each_pair do |entry_name, entry_text|
1251
+ entry_name = entry_name.to_s
1252
+ unless valid_sysinfo[block_name].include?(entry_name)
1253
+ errors << "'sysinfo.#{block_name}' does not support entry name '#{entry_name}'; entries supported: #{valid_sysinfo[block_name].join(', ')}"
1254
+ next
1255
+ end
1256
+
1257
+ # this allows removal of entries specified by other Vagrantfile's in the hierarchy
1258
+ if entry_text.to_s.empty?
1259
+ machine.ui.warn("Libvirt Provider: sysinfo.#{block_name}.#{entry_name} is nil or empty and therefore has no effect.")
1260
+ end
1261
+ end
1262
+ end
1263
+ end
1264
+
1265
+ errors
1266
+ end
1169
1267
  end
1170
1268
  end
1171
1269
  end