vagrant-libvirt 0.0.41 → 0.0.42
Sign up to get free protection for your applications and to get access to all the features.
- 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
|