vagrant-libvirt 0.0.41 → 0.0.42
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.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.github/issue_template.md +37 -0
- data/.gitignore +21 -0
- data/.travis.yml +24 -0
- data/Gemfile +26 -0
- data/LICENSE +22 -0
- data/README.md +1380 -0
- data/Rakefile +8 -0
- data/example_box/README.md +29 -0
- data/example_box/Vagrantfile +60 -0
- data/example_box/metadata.json +5 -0
- data/lib/vagrant-libvirt.rb +29 -0
- data/lib/vagrant-libvirt/action.rb +370 -0
- data/lib/vagrant-libvirt/action/create_domain.rb +322 -0
- data/lib/vagrant-libvirt/action/create_domain_volume.rb +87 -0
- data/lib/vagrant-libvirt/action/create_network_interfaces.rb +302 -0
- data/lib/vagrant-libvirt/action/create_networks.rb +361 -0
- data/lib/vagrant-libvirt/action/destroy_domain.rb +83 -0
- data/lib/vagrant-libvirt/action/destroy_networks.rb +95 -0
- data/lib/vagrant-libvirt/action/forward_ports.rb +227 -0
- data/lib/vagrant-libvirt/action/halt_domain.rb +41 -0
- data/lib/vagrant-libvirt/action/handle_box_image.rb +156 -0
- data/lib/vagrant-libvirt/action/handle_storage_pool.rb +57 -0
- data/lib/vagrant-libvirt/action/is_created.rb +18 -0
- data/lib/vagrant-libvirt/action/is_running.rb +21 -0
- data/lib/vagrant-libvirt/action/is_suspended.rb +42 -0
- data/lib/vagrant-libvirt/action/message_already_created.rb +16 -0
- data/lib/vagrant-libvirt/action/message_not_created.rb +16 -0
- data/lib/vagrant-libvirt/action/message_not_running.rb +16 -0
- data/lib/vagrant-libvirt/action/message_not_suspended.rb +16 -0
- data/lib/vagrant-libvirt/action/message_will_not_destroy.rb +17 -0
- data/lib/vagrant-libvirt/action/package_domain.rb +105 -0
- data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +94 -0
- data/lib/vagrant-libvirt/action/prepare_nfs_valid_ids.rb +17 -0
- data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +27 -0
- data/lib/vagrant-libvirt/action/read_mac_addresses.rb +40 -0
- data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +20 -0
- data/lib/vagrant-libvirt/action/remove_stale_volume.rb +50 -0
- data/lib/vagrant-libvirt/action/resume_domain.rb +34 -0
- data/lib/vagrant-libvirt/action/set_boot_order.rb +109 -0
- data/lib/vagrant-libvirt/action/set_name_of_domain.rb +64 -0
- data/lib/vagrant-libvirt/action/share_folders.rb +71 -0
- data/lib/vagrant-libvirt/action/start_domain.rb +307 -0
- data/lib/vagrant-libvirt/action/suspend_domain.rb +40 -0
- data/lib/vagrant-libvirt/action/wait_till_up.rb +109 -0
- data/lib/vagrant-libvirt/cap/mount_p9.rb +42 -0
- data/lib/vagrant-libvirt/cap/nic_mac_addresses.rb +17 -0
- data/lib/vagrant-libvirt/cap/synced_folder.rb +113 -0
- data/lib/vagrant-libvirt/config.rb +746 -0
- data/lib/vagrant-libvirt/driver.rb +118 -0
- data/lib/vagrant-libvirt/errors.rb +153 -0
- data/lib/vagrant-libvirt/plugin.rb +92 -0
- data/lib/vagrant-libvirt/provider.rb +130 -0
- data/lib/vagrant-libvirt/templates/default_storage_pool.xml.erb +13 -0
- data/lib/vagrant-libvirt/templates/domain.xml.erb +244 -0
- data/lib/vagrant-libvirt/templates/private_network.xml.erb +42 -0
- data/lib/vagrant-libvirt/templates/public_interface.xml.erb +26 -0
- data/lib/vagrant-libvirt/util.rb +11 -0
- data/lib/vagrant-libvirt/util/collection.rb +19 -0
- data/lib/vagrant-libvirt/util/erb_template.rb +22 -0
- data/lib/vagrant-libvirt/util/error_codes.rb +100 -0
- data/lib/vagrant-libvirt/util/network_util.rb +151 -0
- data/lib/vagrant-libvirt/util/timer.rb +17 -0
- data/lib/vagrant-libvirt/version.rb +5 -0
- data/locales/en.yml +162 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/environment_helper.rb +46 -0
- data/spec/support/libvirt_context.rb +30 -0
- data/spec/support/sharedcontext.rb +34 -0
- data/spec/unit/action/destroy_domain_spec.rb +97 -0
- data/spec/unit/action/set_name_of_domain_spec.rb +21 -0
- data/spec/unit/action/wait_till_up_spec.rb +127 -0
- data/spec/unit/config_spec.rb +113 -0
- data/spec/unit/templates/domain_all_settings.xml +137 -0
- data/spec/unit/templates/domain_defaults.xml +46 -0
- data/spec/unit/templates/domain_spec.rb +84 -0
- data/tools/create_box.sh +130 -0
- data/tools/prepare_redhat_for_box.sh +119 -0
- data/vagrant-libvirt.gemspec +54 -0
- metadata +93 -3
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module ProviderLibvirt
|
5
|
+
module Action
|
6
|
+
class RemoveLibvirtImage
|
7
|
+
def initialize(app, _env)
|
8
|
+
@logger = Log4r::Logger.new('vagrant_libvirt::action::remove_libvirt_image')
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
env[:ui].info('Vagrant-libvirt plugin removed box only from you LOCAL ~/.vagrant/boxes directory')
|
14
|
+
env[:ui].info('From libvirt storage pool you have to delete image manually(virsh, virt-manager or by any other tool)')
|
15
|
+
@app.call(env)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
# require 'log4r/yamlconfigurator'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module ProviderLibvirt
|
6
|
+
module Action
|
7
|
+
class RemoveStaleVolume
|
8
|
+
def initialize(app, _env)
|
9
|
+
# log4r_config= YAML.load_file(File.join(File.dirname(__FILE__),"log4r.yaml"))
|
10
|
+
# log_cfg = Log4r::YamlConfigurator
|
11
|
+
# log_cfg.decode_yaml( log4r_config['log4r_config'] )
|
12
|
+
|
13
|
+
@logger = Log4r::Logger.new('vagrant_libvirt::action::remove_stale_volume')
|
14
|
+
@app = app
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
# Remove stale server volume
|
19
|
+
env[:ui].info(I18n.t('vagrant_libvirt.remove_stale_volume'))
|
20
|
+
|
21
|
+
config = env[:machine].provider_config
|
22
|
+
# Check for storage pool, where box image should be created
|
23
|
+
fog_pool = ProviderLibvirt::Util::Collection.find_matching(
|
24
|
+
env[:machine].provider.driver.connection.pools.all, config.storage_pool_name
|
25
|
+
)
|
26
|
+
@logger.debug("**** Pool #{fog_pool.name}")
|
27
|
+
|
28
|
+
# This is name of newly created image for vm.
|
29
|
+
name = "#{env[:domain_name]}.img"
|
30
|
+
@logger.debug("**** Volume name #{name}")
|
31
|
+
|
32
|
+
# remove root storage
|
33
|
+
box_volume = ProviderLibvirt::Util::Collection.find_matching(
|
34
|
+
env[:machine].provider.driver.connection.volumes.all, name
|
35
|
+
)
|
36
|
+
if box_volume && box_volume.pool_name == fog_pool.name
|
37
|
+
@logger.info("Deleting volume #{box_volume.key}")
|
38
|
+
box_volume.destroy
|
39
|
+
env[:result] = box_volume
|
40
|
+
else
|
41
|
+
env[:result] = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# Continue the middleware chain.
|
45
|
+
@app.call(env)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module ProviderLibvirt
|
5
|
+
module Action
|
6
|
+
# Resume suspended domain.
|
7
|
+
class ResumeDomain
|
8
|
+
def initialize(app, _env)
|
9
|
+
@logger = Log4r::Logger.new('vagrant_libvirt::action::resume_domain')
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
env[:ui].info(I18n.t('vagrant_libvirt.resuming_domain'))
|
15
|
+
|
16
|
+
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
|
17
|
+
raise Errors::NoDomainError if domain.nil?
|
18
|
+
|
19
|
+
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
|
20
|
+
config = env[:machine].provider_config
|
21
|
+
if config.suspend_mode == 'managedsave'
|
22
|
+
domain.start
|
23
|
+
else
|
24
|
+
domain.resume
|
25
|
+
end
|
26
|
+
|
27
|
+
@logger.info("Machine #{env[:machine].id} is resumed.")
|
28
|
+
|
29
|
+
@app.call(env)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module ProviderLibvirt
|
6
|
+
module Action
|
7
|
+
# boot order useful for pxe in discovery workflow
|
8
|
+
class SetBootOrder
|
9
|
+
def initialize(app, env)
|
10
|
+
@app = app
|
11
|
+
@logger = Log4r::Logger.new('vagrant_libvirt::action::set_boot_order')
|
12
|
+
config = env[:machine].provider_config
|
13
|
+
@boot_order = config.boot_order
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
# Get domain first
|
18
|
+
begin
|
19
|
+
domain = env[:machine].provider
|
20
|
+
.driver
|
21
|
+
.connection
|
22
|
+
.client
|
23
|
+
.lookup_domain_by_uuid(
|
24
|
+
env[:machine].id.to_s
|
25
|
+
)
|
26
|
+
rescue => e
|
27
|
+
raise Errors::NoDomainError,
|
28
|
+
error_message: e.message
|
29
|
+
end
|
30
|
+
|
31
|
+
# Only execute specific boot ordering if this is defined
|
32
|
+
# in the Vagrant file
|
33
|
+
if @boot_order.count >= 1
|
34
|
+
|
35
|
+
# If a domain is initially defined with no box or disk or
|
36
|
+
# with an explicit boot order, libvirt adds <boot dev="foo">
|
37
|
+
# This conflicts with an explicit boot_order configuration,
|
38
|
+
# so we need to remove it from the domain xml and feed it back.
|
39
|
+
# Also see https://bugzilla.redhat.com/show_bug.cgi?id=1248514
|
40
|
+
# as to why we have to do this after all devices have been defined.
|
41
|
+
xml = Nokogiri::XML(domain.xml_desc)
|
42
|
+
xml.search('/domain/os/boot').each(&:remove)
|
43
|
+
|
44
|
+
# Parse the XML and find each defined drive and network interfacee
|
45
|
+
hd = xml.search("/domain/devices/disk[@device='disk']")
|
46
|
+
cdrom = xml.search("/domain/devices/disk[@device='cdrom']")
|
47
|
+
# implemented only for 1 network
|
48
|
+
nets = @boot_order.flat_map do |x|
|
49
|
+
x.class == Hash ? x : nil
|
50
|
+
end.compact
|
51
|
+
raise 'Defined only for 1 network for boot' if nets.size > 1
|
52
|
+
network = search_network(nets, xml)
|
53
|
+
|
54
|
+
# Generate an array per device group and a flattened
|
55
|
+
# array from all of those
|
56
|
+
devices = { 'hd' => hd,
|
57
|
+
'cdrom' => cdrom,
|
58
|
+
'network' => network }
|
59
|
+
|
60
|
+
final_boot_order = final_boot_order(@boot_order, devices)
|
61
|
+
# Loop over the entire defined boot order array and
|
62
|
+
# create boot order entries in the domain XML
|
63
|
+
final_boot_order.each_with_index do |node, index|
|
64
|
+
boot = "<boot order='#{index + 1}'/>"
|
65
|
+
node.add_child(boot)
|
66
|
+
logger_msg(node, index)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Finally redefine the domain XML through libvirt
|
70
|
+
# to apply the boot ordering
|
71
|
+
env[:machine].provider
|
72
|
+
.driver
|
73
|
+
.connection
|
74
|
+
.client
|
75
|
+
.define_domain_xml(xml.to_s)
|
76
|
+
end
|
77
|
+
|
78
|
+
@app.call(env)
|
79
|
+
end
|
80
|
+
|
81
|
+
def final_boot_order(boot_order, devices)
|
82
|
+
boot_order.flat_map do |category|
|
83
|
+
devices[category.class == Hash ? category.keys.first : category]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def search_network(nets, xml)
|
88
|
+
str = '/domain/devices/interface'
|
89
|
+
str += "[(@type='network' or @type='udp' or @type='bridge')"
|
90
|
+
unless nets.empty?
|
91
|
+
str += " and source[@network='#{nets.first['network']}']"
|
92
|
+
end
|
93
|
+
str += ']'
|
94
|
+
@logger.debug(str)
|
95
|
+
xml.search(str)
|
96
|
+
end
|
97
|
+
|
98
|
+
def logger_msg(node, index)
|
99
|
+
name = if node.name == 'disk'
|
100
|
+
node['device']
|
101
|
+
elsif node.name == 'interface'
|
102
|
+
node.name
|
103
|
+
end
|
104
|
+
@logger.debug "Setting #{name} to boot index #{index + 1}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
module VagrantPlugins
|
3
|
+
module ProviderLibvirt
|
4
|
+
module Action
|
5
|
+
# Setup name for domain and domain volumes.
|
6
|
+
class SetNameOfDomain
|
7
|
+
def initialize(app, _env)
|
8
|
+
@logger = Log4r::Logger.new('vagrant_libvirt::action::set_name_of_domain')
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
env[:domain_name] = build_domain_name(env)
|
14
|
+
|
15
|
+
begin
|
16
|
+
@logger.info("Looking for domain #{env[:domain_name]} through list " \
|
17
|
+
"#{env[:machine].provider.driver.connection.servers.all}")
|
18
|
+
# Check if the domain name is not already taken
|
19
|
+
|
20
|
+
domain = ProviderLibvirt::Util::Collection.find_matching(
|
21
|
+
env[:machine].provider.driver.connection.servers.all, env[:domain_name]
|
22
|
+
)
|
23
|
+
rescue Fog::Errors::Error => e
|
24
|
+
@logger.info(e.to_s)
|
25
|
+
domain = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
@logger.info("Looking for domain #{env[:domain_name]}")
|
29
|
+
|
30
|
+
unless domain.nil?
|
31
|
+
raise ProviderLibvirt::Errors::DomainNameExists,
|
32
|
+
domain_name: env[:domain_name]
|
33
|
+
end
|
34
|
+
|
35
|
+
@app.call(env)
|
36
|
+
end
|
37
|
+
|
38
|
+
# build domain name
|
39
|
+
# random_hostname option avoids
|
40
|
+
# `domain about to create is already taken`
|
41
|
+
# parsable and sortable by epoch time
|
42
|
+
# @example
|
43
|
+
# development-centos-6-chef-11_1404488971_3b7a569e2fd7c554b852
|
44
|
+
# @return [String] libvirt domain name
|
45
|
+
def build_domain_name(env)
|
46
|
+
config = env[:machine].provider_config
|
47
|
+
domain_name =
|
48
|
+
if config.default_prefix.nil?
|
49
|
+
env[:root_path].basename.to_s.dup.concat('_')
|
50
|
+
elsif config.default_prefix.empty?
|
51
|
+
# don't have any prefix, not even "_"
|
52
|
+
''
|
53
|
+
else
|
54
|
+
config.default_prefix.to_s.dup.concat('_')
|
55
|
+
end
|
56
|
+
domain_name << env[:machine].name.to_s
|
57
|
+
domain_name.gsub!(/[^-a-z0-9_\.]/i, '')
|
58
|
+
domain_name << "_#{Time.now.utc.to_i}_#{SecureRandom.hex(10)}" if config.random_hostname
|
59
|
+
domain_name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
require 'log4r'
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module ProviderLibvirt
|
7
|
+
module Action
|
8
|
+
class ShareFolders
|
9
|
+
def initialize(app, _env)
|
10
|
+
@logger = Log4r::Logger.new('vagrant::action::vm::share_folders')
|
11
|
+
@app = app
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
@env = env
|
16
|
+
|
17
|
+
prepare_folders
|
18
|
+
create_metadata
|
19
|
+
|
20
|
+
@app.call(env)
|
21
|
+
end
|
22
|
+
|
23
|
+
# This method returns an actual list of shared
|
24
|
+
# folders to create and their proper path.
|
25
|
+
def shared_folders
|
26
|
+
{}.tap do |result|
|
27
|
+
@env[:machine].config.vm.synced_folders.each do |id, data|
|
28
|
+
# Ignore NFS shared folders
|
29
|
+
next if !data[:type] == :nfs
|
30
|
+
|
31
|
+
# This to prevent overwriting the actual shared folders data
|
32
|
+
result[id] = data.dup
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Prepares the shared folders by verifying they exist and creating them
|
38
|
+
# if they don't.
|
39
|
+
def prepare_folders
|
40
|
+
shared_folders.each do |_id, options|
|
41
|
+
hostpath = Pathname.new(options[:hostpath]).expand_path(@env[:root_path])
|
42
|
+
|
43
|
+
next unless !hostpath.directory? && options[:create]
|
44
|
+
# Host path doesn't exist, so let's create it.
|
45
|
+
@logger.debug("Host path doesn't exist, creating: #{hostpath}")
|
46
|
+
|
47
|
+
begin
|
48
|
+
hostpath.mkpath
|
49
|
+
rescue Errno::EACCES
|
50
|
+
raise Vagrant::Errors::SharedFolderCreateFailed,
|
51
|
+
path: hostpath.to_s
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def create_metadata
|
57
|
+
@env[:ui].info I18n.t('vagrant.actions.vm.share_folders.creating')
|
58
|
+
|
59
|
+
folders = []
|
60
|
+
shared_folders.each do |id, data|
|
61
|
+
folders << {
|
62
|
+
name: id,
|
63
|
+
hostpath: File.expand_path(data[:hostpath], @env[:root_path]),
|
64
|
+
transient: data[:transient]
|
65
|
+
}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,307 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require 'rexml/document'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module ProviderLibvirt
|
6
|
+
module Action
|
7
|
+
# Just start the domain.
|
8
|
+
class StartDomain
|
9
|
+
def initialize(app, _env)
|
10
|
+
@logger = Log4r::Logger.new('vagrant_libvirt::action::start_domain')
|
11
|
+
@app = app
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
env[:ui].info(I18n.t('vagrant_libvirt.starting_domain'))
|
16
|
+
|
17
|
+
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
|
18
|
+
raise Errors::NoDomainError if domain.nil?
|
19
|
+
config = env[:machine].provider_config
|
20
|
+
|
21
|
+
begin
|
22
|
+
# update domain settings on change.
|
23
|
+
|
24
|
+
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
|
25
|
+
|
26
|
+
# libvirt API doesn't support modifying memory on NUMA enabled CPUs
|
27
|
+
# http://libvirt.org/git/?p=libvirt.git;a=commit;h=d174394105cf00ed266bf729ddf461c21637c736
|
28
|
+
if config.numa_nodes == nil
|
29
|
+
if config.memory.to_i * 1024 != libvirt_domain.max_memory
|
30
|
+
libvirt_domain.max_memory = config.memory.to_i * 1024
|
31
|
+
libvirt_domain.memory = libvirt_domain.max_memory
|
32
|
+
end
|
33
|
+
end
|
34
|
+
begin
|
35
|
+
# XML definition manipulation
|
36
|
+
descr = libvirt_domain.xml_desc(1)
|
37
|
+
xml_descr = REXML::Document.new descr
|
38
|
+
descr_changed = false
|
39
|
+
|
40
|
+
# additional disk bus
|
41
|
+
config.disks.each do |disk|
|
42
|
+
device = disk[:device]
|
43
|
+
bus = disk[:bus]
|
44
|
+
REXML::XPath.each(xml_descr, '/domain/devices/disk[@device="disk"]/target[@dev="' + device + '"]') do |disk_target|
|
45
|
+
next unless disk_target.attributes['bus'] != bus
|
46
|
+
descr_changed = true
|
47
|
+
disk_target.attributes['bus'] = bus
|
48
|
+
disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# disk_bus
|
53
|
+
REXML::XPath.each(xml_descr, '/domain/devices/disk[@device="disk"]/target[@dev="vda"]') do |disk_target|
|
54
|
+
next unless disk_target.attributes['bus'] != config.disk_bus
|
55
|
+
descr_changed = true
|
56
|
+
disk_target.attributes['bus'] = config.disk_bus
|
57
|
+
disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
|
58
|
+
end
|
59
|
+
|
60
|
+
# Iterface type
|
61
|
+
unless config.nic_model_type.nil?
|
62
|
+
REXML::XPath.each(xml_descr, '/domain/devices/interface/model') do |iface_model|
|
63
|
+
if iface_model.attributes['type'] != config.nic_model_type
|
64
|
+
descr_changed = true
|
65
|
+
iface_model.attributes['type'] = config.nic_model_type
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# vCpu count
|
71
|
+
if config.cpus.to_i != libvirt_domain.vcpus.length
|
72
|
+
descr_changed = true
|
73
|
+
REXML::XPath.first(xml_descr, '/domain/vcpu').text = config.cpus
|
74
|
+
end
|
75
|
+
|
76
|
+
# cpu_mode
|
77
|
+
cpu = REXML::XPath.first(xml_descr, '/domain/cpu')
|
78
|
+
if cpu.nil?
|
79
|
+
descr_changed = true
|
80
|
+
cpu = REXML::Element.new('cpu', REXML::XPath.first(xml_descr, '/domain'))
|
81
|
+
cpu.attributes['mode'] = config.cpu_mode
|
82
|
+
else
|
83
|
+
if cpu.attributes['mode'] != config.cpu_mode
|
84
|
+
descr_changed = true
|
85
|
+
cpu.attributes['mode'] = config.cpu_mode
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
if config.cpu_mode != 'host-passthrough'
|
90
|
+
cpu_model = REXML::XPath.first(xml_descr, '/domain/cpu/model')
|
91
|
+
if cpu_model.nil?
|
92
|
+
descr_changed = true
|
93
|
+
cpu_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/cpu'))
|
94
|
+
cpu_model.attributes['fallback'] = 'allow'
|
95
|
+
cpu_model.text = config.cpu_model
|
96
|
+
else
|
97
|
+
if cpu_model.text != config.cpu_model
|
98
|
+
descr_changed = true
|
99
|
+
cpu_model.text = config.cpu_model
|
100
|
+
end
|
101
|
+
if cpu_model.attributes['fallback'] != config.cpu_fallback
|
102
|
+
descr_changed = true
|
103
|
+
cpu_model.attributes['fallback'] = config.cpu_fallback
|
104
|
+
end
|
105
|
+
end
|
106
|
+
vmx_feature = REXML::XPath.first(xml_descr, '/domain/cpu/feature[@name="vmx"]')
|
107
|
+
svm_feature = REXML::XPath.first(xml_descr, '/domain/cpu/feature[@name="svm"]')
|
108
|
+
if config.nested
|
109
|
+
if vmx_feature.nil?
|
110
|
+
descr_changed = true
|
111
|
+
vmx_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr, '/domain/cpu'))
|
112
|
+
vmx_feature.attributes['policy'] = 'optional'
|
113
|
+
vmx_feature.attributes['name'] = 'vmx'
|
114
|
+
end
|
115
|
+
if svm_feature.nil?
|
116
|
+
descr_changed = true
|
117
|
+
svm_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr, '/domain/cpu'))
|
118
|
+
svm_feature.attributes['policy'] = 'optional'
|
119
|
+
svm_feature.attributes['name'] = 'svm'
|
120
|
+
end
|
121
|
+
else
|
122
|
+
unless vmx_feature.nil?
|
123
|
+
descr_changed = true
|
124
|
+
cpu.delete_element(vmx_feature)
|
125
|
+
end
|
126
|
+
unless svm_feature.nil?
|
127
|
+
descr_changed = true
|
128
|
+
cpu.delete_element(svm_feature)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
elsif config.numa_nodes == nil
|
132
|
+
unless cpu.elements.to_a.empty?
|
133
|
+
descr_changed = true
|
134
|
+
cpu.elements.each do |elem|
|
135
|
+
cpu.delete_element(elem)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Graphics
|
141
|
+
graphics = REXML::XPath.first(xml_descr, '/domain/devices/graphics')
|
142
|
+
if config.graphics_type != 'none'
|
143
|
+
if graphics.nil?
|
144
|
+
descr_changed = true
|
145
|
+
graphics = REXML::Element.new('graphics', REXML::XPath.first(xml_descr, '/domain/devices'))
|
146
|
+
end
|
147
|
+
if graphics.attributes['type'] != config.graphics_type
|
148
|
+
descr_changed = true
|
149
|
+
graphics.attributes['type'] = config.graphics_type
|
150
|
+
end
|
151
|
+
if graphics.attributes['listen'] != config.graphics_ip
|
152
|
+
descr_changed = true
|
153
|
+
graphics.attributes['listen'] = config.graphics_ip
|
154
|
+
graphics.delete_element('//listen')
|
155
|
+
end
|
156
|
+
if graphics.attributes['autoport'] != config.graphics_autoport
|
157
|
+
descr_changed = true
|
158
|
+
graphics.attributes['autoport'] = config.graphics_autoport
|
159
|
+
if config.graphics_autoport == 'no'
|
160
|
+
graphics.attributes['port'] = config.graphics_port
|
161
|
+
end
|
162
|
+
end
|
163
|
+
if graphics.attributes['keymap'] != config.keymap
|
164
|
+
descr_changed = true
|
165
|
+
graphics.attributes['keymap'] = config.keymap
|
166
|
+
end
|
167
|
+
if graphics.attributes['passwd'] != config.graphics_passwd
|
168
|
+
descr_changed = true
|
169
|
+
if config.graphics_passwd.nil?
|
170
|
+
graphics.attributes.delete 'passwd'
|
171
|
+
else
|
172
|
+
graphics.attributes['passwd'] = config.graphics_passwd
|
173
|
+
end
|
174
|
+
end
|
175
|
+
else
|
176
|
+
# graphics_type = none, remove entire element
|
177
|
+
graphics.parent.delete_element(graphics) unless graphics.nil?
|
178
|
+
end
|
179
|
+
|
180
|
+
# TPM
|
181
|
+
if config.tpm_path
|
182
|
+
raise Errors::FogCreateServerError, 'The TPM Path must be fully qualified' unless config.tpm_path[0].chr == '/'
|
183
|
+
|
184
|
+
tpm = REXML::XPath.first(xml_descr, '/domain/devices/tpm')
|
185
|
+
if tpm.nil?
|
186
|
+
descr_changed = true
|
187
|
+
tpm = REXML::Element.new('tpm', REXML::XPath.first(xml_descr, '/domain/devices/tpm/model'))
|
188
|
+
tpm.attributes['model'] = config.tpm_model
|
189
|
+
tpm_backend_type = tpm.add_element('backend')
|
190
|
+
tpm_backend_type.attributes['type'] = config.tpm_type
|
191
|
+
tpm_device_path = tpm_backend_type.add_element('device')
|
192
|
+
tpm_device_path.attributes['path'] = config.tpm_path
|
193
|
+
else
|
194
|
+
if tpm.attributes['model'] != config.tpm_model
|
195
|
+
descr_changed = true
|
196
|
+
tpm.attributes['model'] = config.tpm_model
|
197
|
+
end
|
198
|
+
if tpm.elements['backend'].attributes['type'] != config.tpm_type
|
199
|
+
descr_changed = true
|
200
|
+
tpm.elements['backend'].attributes['type'] = config.tpm_type
|
201
|
+
end
|
202
|
+
if tpm.elements['backend'].elements['device'].attributes['path'] != config.tpm_path
|
203
|
+
descr_changed = true
|
204
|
+
tpm.elements['backend'].elements['device'].attributes['path'] = config.tpm_path
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# Video device
|
210
|
+
video = REXML::XPath.first(xml_descr, '/domain/devices/video')
|
211
|
+
if !video.nil? && (config.graphics_type == 'none')
|
212
|
+
# graphics_type = none, video devices are removed since there is no possible output
|
213
|
+
descr_changed = true
|
214
|
+
video.parent.delete_element(video)
|
215
|
+
else
|
216
|
+
video_model = REXML::XPath.first(xml_descr, '/domain/devices/video/model')
|
217
|
+
if video_model.nil?
|
218
|
+
video_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/devices/video'))
|
219
|
+
video_model.attributes['type'] = config.video_type
|
220
|
+
video_model.attributes['vram'] = config.video_vram
|
221
|
+
else
|
222
|
+
if video_model.attributes['type'] != config.video_type || video_model.attributes['vram'] != config.video_vram
|
223
|
+
descr_changed = true
|
224
|
+
video_model.attributes['type'] = config.video_type
|
225
|
+
video_model.attributes['vram'] = config.video_vram
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Sound device
|
231
|
+
if config.sound_type
|
232
|
+
sound = REXML::XPath.first(xml_descr,'/domain/devices/sound/model')
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
# dtb
|
237
|
+
if config.dtb
|
238
|
+
dtb = REXML::XPath.first(xml_descr, '/domain/os/dtb')
|
239
|
+
if dtb.nil?
|
240
|
+
descr_changed = true
|
241
|
+
dtb = REXML::Element.new('dtb', REXML::XPath.first(xml_descr, '/domain/os'))
|
242
|
+
dtb.text = config.dtb
|
243
|
+
else
|
244
|
+
if dtb.text != config.dtb
|
245
|
+
descr_changed = true
|
246
|
+
dtb.text = config.dtb
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# kernel and initrd
|
252
|
+
if config.kernel
|
253
|
+
kernel = REXML::XPath.first(xml_descr, '/domain/os/kernel')
|
254
|
+
if kernel.nil?
|
255
|
+
descr_changed = true
|
256
|
+
kernel = REXML::Element.new('kernel', REXML::XPath.first(xml_descr, '/domain/os'))
|
257
|
+
kernel.text = config.kernel
|
258
|
+
else
|
259
|
+
if kernel.text != config.kernel
|
260
|
+
descr_changed = true
|
261
|
+
kernel.text = config.kernel
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
if config.initrd
|
266
|
+
initrd = REXML::XPath.first(xml_descr, '/domain/os/initrd')
|
267
|
+
if initrd.nil?
|
268
|
+
descr_changed = true
|
269
|
+
initrd = REXML::Element.new('initrd', REXML::XPath.first(xml_descr, '/domain/os'))
|
270
|
+
initrd.text = config.initrd
|
271
|
+
else
|
272
|
+
if initrd.text != config.initrd
|
273
|
+
descr_changed = true
|
274
|
+
initrd.text = config.initrd
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Apply
|
280
|
+
if descr_changed
|
281
|
+
begin
|
282
|
+
libvirt_domain.undefine
|
283
|
+
new_descr = ''
|
284
|
+
xml_descr.write new_descr
|
285
|
+
server = env[:machine].provider.driver.connection.servers.create(xml: new_descr)
|
286
|
+
rescue Fog::Errors::Error => e
|
287
|
+
server = env[:machine].provider.driver.connection.servers.create(xml: descr)
|
288
|
+
raise Errors::FogCreateServerError, error_message: e.message
|
289
|
+
end
|
290
|
+
end
|
291
|
+
rescue => e
|
292
|
+
env[:ui].error("Error when updating domain settings: #{e.message}")
|
293
|
+
end
|
294
|
+
# Autostart with host if enabled in Vagrantfile
|
295
|
+
libvirt_domain.autostart = config.autostart
|
296
|
+
# Actually start the domain
|
297
|
+
domain.start
|
298
|
+
rescue => e
|
299
|
+
raise Errors::FogError, message: e.message
|
300
|
+
end
|
301
|
+
|
302
|
+
@app.call(env)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|