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.
- checksums.yaml +4 -4
- data/README.md +51 -2079
- data/lib/vagrant-libvirt/action/create_domain.rb +57 -94
- data/lib/vagrant-libvirt/action/create_network_interfaces.rb +1 -1
- data/lib/vagrant-libvirt/action/create_networks.rb +3 -3
- data/lib/vagrant-libvirt/action/destroy_domain.rb +21 -5
- data/lib/vagrant-libvirt/action/destroy_networks.rb +2 -2
- data/lib/vagrant-libvirt/action/handle_box_image.rb +3 -1
- data/lib/vagrant-libvirt/action/package_domain.rb +1 -5
- data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +3 -1
- data/lib/vagrant-libvirt/action/resolve_disk_settings.rb +181 -0
- data/lib/vagrant-libvirt/action/snapshot_delete.rb +26 -0
- data/lib/vagrant-libvirt/action/snapshot_restore.rb +22 -0
- data/lib/vagrant-libvirt/action/snapshot_save.rb +27 -0
- data/lib/vagrant-libvirt/action/start_domain.rb +80 -11
- data/lib/vagrant-libvirt/action.rb +53 -1
- data/lib/vagrant-libvirt/cap/snapshots.rb +12 -0
- data/lib/vagrant-libvirt/cap/synced_folder_9p.rb +4 -4
- data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +4 -4
- data/lib/vagrant-libvirt/config.rb +104 -6
- data/lib/vagrant-libvirt/driver.rb +108 -46
- data/lib/vagrant-libvirt/errors.rb +23 -3
- data/lib/vagrant-libvirt/plugin.rb +7 -3
- data/lib/vagrant-libvirt/provider.rb +1 -1
- data/lib/vagrant-libvirt/templates/domain.xml.erb +32 -6
- data/lib/vagrant-libvirt/util/byte_number.rb +0 -1
- data/lib/vagrant-libvirt/util/compat.rb +23 -0
- data/lib/vagrant-libvirt/util/domain_flags.rb +15 -0
- data/lib/vagrant-libvirt/util/unindent.rb +7 -0
- data/lib/vagrant-libvirt/util.rb +1 -0
- data/lib/vagrant-libvirt/version +1 -1
- data/locales/en.yml +28 -4
- data/spec/acceptance/additional_storage_spec.rb +32 -0
- data/spec/acceptance/package_domain_spec.rb +90 -0
- data/spec/acceptance/provider_settings_spec.rb +54 -0
- data/spec/acceptance/simple_vm_provision_via_shell_spec.rb +31 -0
- data/spec/acceptance/snapshots_spec.rb +41 -0
- data/spec/acceptance/support-skeletons/package_complex/Vagrantfile.testbox +14 -0
- data/spec/acceptance/support-skeletons/package_complex/scripts/sysprep.sh +32 -0
- data/spec/acceptance/support-skeletons/package_simple/Vagrantfile.testbox +10 -0
- data/spec/acceptance/two_disks_spec.rb +29 -0
- data/spec/acceptance/use_qemu_agent_for_connectivity_spec.rb +35 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/acceptance/configuration.rb +21 -0
- data/spec/support/acceptance/context.rb +70 -0
- data/spec/support/acceptance/isolated_environment.rb +41 -0
- data/spec/support/libvirt_acceptance_context.rb +64 -0
- data/spec/support/libvirt_context.rb +4 -0
- data/spec/support/sharedcontext.rb +1 -0
- data/spec/unit/action/cleanup_on_failure_spec.rb +0 -2
- data/spec/unit/action/create_domain_spec/sysinfo.xml +66 -0
- data/spec/unit/action/create_domain_spec/sysinfo_only_required.xml +49 -0
- data/spec/unit/action/create_domain_spec.rb +188 -140
- data/spec/unit/action/create_domain_volume_spec.rb +0 -3
- data/spec/unit/action/destroy_domain_spec.rb +43 -10
- data/spec/unit/action/forward_ports_spec.rb +0 -1
- data/spec/unit/action/handle_box_image_spec.rb +31 -14
- data/spec/unit/action/package_domain_spec.rb +0 -5
- data/spec/unit/action/remove_libvirt_image_spec.rb +43 -0
- data/spec/unit/action/resolve_disk_settings_spec/default_domain.xml +43 -0
- data/spec/unit/action/resolve_disk_settings_spec/default_no_aliases.xml +42 -0
- data/spec/unit/action/{create_domain_spec → resolve_disk_settings_spec}/default_system_storage_pool.xml +0 -0
- data/spec/unit/action/resolve_disk_settings_spec/multi_volume_box.xml +55 -0
- data/spec/unit/action/resolve_disk_settings_spec/multi_volume_box_additional_and_custom_no_aliases.xml +67 -0
- data/spec/unit/action/resolve_disk_settings_spec/multi_volume_box_additional_storage.xml +67 -0
- data/spec/unit/action/resolve_disk_settings_spec.rb +385 -0
- data/spec/unit/action/start_domain_spec/clock_timer_removed.xml +38 -0
- data/spec/unit/action/start_domain_spec/clock_timer_rtc_tsc.xml +39 -0
- data/spec/unit/action/start_domain_spec/existing_added_nvram.xml +62 -0
- data/spec/unit/action/start_domain_spec/nvram_domain.xml +64 -0
- data/spec/unit/action/start_domain_spec/nvram_domain_other_setting.xml +64 -0
- data/spec/unit/action/start_domain_spec/nvram_domain_removed.xml +64 -0
- data/spec/unit/action/start_domain_spec.rb +122 -22
- data/spec/unit/action/wait_till_up_spec.rb +0 -2
- data/spec/unit/action_spec.rb +88 -3
- data/spec/unit/cap/synced_folder_9p_spec.rb +120 -0
- data/spec/unit/cap/synced_folder_virtiofs_spec.rb +120 -0
- data/spec/unit/config_spec.rb +153 -6
- data/spec/unit/driver_spec.rb +3 -1
- data/spec/unit/plugin_spec.rb +42 -0
- data/spec/unit/templates/domain_all_settings.xml +15 -6
- data/spec/unit/templates/domain_scsi_bus_storage.xml +44 -0
- data/spec/unit/templates/domain_scsi_device_storage.xml +44 -0
- data/spec/unit/templates/domain_scsi_multiple_controllers_storage.xml +130 -0
- data/spec/unit/templates/domain_spec.rb +105 -21
- data/spec/unit/util/byte_number_spec.rb +1 -1
- metadata +169 -79
- 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
|
-
#
|
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::
|
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
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
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
|
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
|
@@ -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(
|
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(
|
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
|
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
|
-
@
|
869
|
-
@
|
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
|
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.
|
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
|