vagrant-libvirt 0.3.0 → 0.5.2
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/README.md +421 -50
- data/lib/vagrant-libvirt/action.rb +7 -1
- data/lib/vagrant-libvirt/action/clean_machine_folder.rb +30 -0
- data/lib/vagrant-libvirt/action/create_domain.rb +56 -18
- data/lib/vagrant-libvirt/action/create_domain_volume.rb +57 -55
- data/lib/vagrant-libvirt/action/create_network_interfaces.rb +0 -3
- data/lib/vagrant-libvirt/action/create_networks.rb +11 -4
- data/lib/vagrant-libvirt/action/destroy_domain.rb +1 -1
- data/lib/vagrant-libvirt/action/forward_ports.rb +37 -38
- data/lib/vagrant-libvirt/action/halt_domain.rb +25 -9
- data/lib/vagrant-libvirt/action/handle_box_image.rb +163 -74
- data/lib/vagrant-libvirt/action/is_running.rb +1 -3
- data/lib/vagrant-libvirt/action/is_suspended.rb +4 -4
- data/lib/vagrant-libvirt/action/package_domain.rb +2 -1
- data/lib/vagrant-libvirt/action/set_boot_order.rb +6 -2
- data/lib/vagrant-libvirt/action/start_domain.rb +86 -29
- data/lib/vagrant-libvirt/action/wait_till_up.rb +8 -52
- data/lib/vagrant-libvirt/cap/{mount_p9.rb → mount_9p.rb} +2 -2
- data/lib/vagrant-libvirt/cap/mount_virtiofs.rb +37 -0
- data/lib/vagrant-libvirt/cap/{synced_folder.rb → synced_folder_9p.rb} +4 -5
- data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +109 -0
- data/lib/vagrant-libvirt/config.rb +236 -43
- data/lib/vagrant-libvirt/driver.rb +49 -32
- data/lib/vagrant-libvirt/errors.rb +24 -1
- data/lib/vagrant-libvirt/plugin.rb +14 -5
- data/lib/vagrant-libvirt/provider.rb +2 -9
- data/lib/vagrant-libvirt/templates/domain.xml.erb +35 -10
- data/lib/vagrant-libvirt/templates/private_network.xml.erb +1 -1
- data/lib/vagrant-libvirt/util/network_util.rb +21 -3
- data/lib/vagrant-libvirt/version +1 -1
- data/lib/vagrant-libvirt/version.rb +57 -9
- data/locales/en.yml +12 -0
- data/spec/spec_helper.rb +37 -3
- data/spec/support/binding_proc.rb +24 -0
- data/spec/support/libvirt_context.rb +2 -0
- data/spec/support/matchers/have_file_content.rb +63 -0
- data/spec/support/sharedcontext.rb +4 -0
- data/spec/unit/action/clean_machine_folder_spec.rb +58 -0
- data/spec/unit/action/create_domain_spec.rb +121 -36
- data/spec/unit/action/create_domain_spec/additional_disks_domain.xml +54 -0
- data/spec/unit/action/create_domain_spec/default_domain.xml +49 -0
- data/spec/unit/action/create_domain_spec/{default_storage_pool.xml → default_system_storage_pool.xml} +0 -0
- data/spec/unit/action/create_domain_spec/default_user_storage_pool.xml +17 -0
- data/spec/unit/action/create_domain_volume_spec.rb +102 -0
- data/spec/unit/action/create_domain_volume_spec/one_disk_in_storage.xml +21 -0
- data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_0.xml +21 -0
- data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_1.xml +21 -0
- data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_2.xml +21 -0
- data/spec/unit/action/destroy_domain_spec.rb +1 -1
- data/spec/unit/action/forward_ports_spec.rb +202 -0
- data/spec/unit/action/halt_domain_spec.rb +90 -0
- data/spec/unit/action/handle_box_image_spec.rb +363 -0
- data/spec/unit/action/start_domain_spec.rb +183 -1
- data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +50 -0
- data/spec/unit/action/start_domain_spec/default.xml +2 -2
- data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +48 -0
- data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +48 -0
- data/spec/unit/action/wait_till_up_spec.rb +22 -21
- data/spec/unit/config_spec.rb +395 -127
- data/spec/unit/templates/domain_all_settings.xml +14 -3
- data/spec/unit/templates/domain_custom_cpu_model.xml +2 -1
- data/spec/unit/templates/domain_defaults.xml +2 -1
- data/spec/unit/templates/domain_spec.rb +100 -3
- data/spec/unit/templates/tpm/version_1.2.xml +54 -0
- data/spec/unit/templates/tpm/version_2.0.xml +53 -0
- metadata +105 -19
@@ -13,24 +13,40 @@ module VagrantPlugins
|
|
13
13
|
def call(env)
|
14
14
|
env[:ui].info(I18n.t('vagrant_libvirt.halt_domain'))
|
15
15
|
|
16
|
+
timeout = env[:machine].config.vm.graceful_halt_timeout
|
16
17
|
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
|
17
18
|
raise Errors::NoDomainError if domain.nil?
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
@logger.info('Trying Libvirt graceful shutdown.')
|
23
|
-
domain.shutdown
|
20
|
+
if env[:force_halt]
|
21
|
+
domain.poweroff
|
22
|
+
return @app.call(env)
|
24
23
|
end
|
25
24
|
|
26
|
-
|
27
25
|
begin
|
28
|
-
|
29
|
-
|
26
|
+
Timeout.timeout(timeout) do
|
27
|
+
begin
|
28
|
+
env[:machine].guest.capability(:halt)
|
29
|
+
rescue Timeout::Error
|
30
|
+
raise
|
31
|
+
rescue
|
32
|
+
@logger.info('Trying Libvirt graceful shutdown.')
|
33
|
+
# Read domain object again
|
34
|
+
dom = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
|
35
|
+
if dom.state.to_s == 'running'
|
36
|
+
dom.shutdown
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
domain.wait_for(timeout) do
|
41
|
+
!ready?
|
42
|
+
end
|
30
43
|
end
|
31
|
-
rescue
|
44
|
+
rescue Timeout::Error
|
32
45
|
@logger.info('VM is still running. Calling force poweroff.')
|
33
46
|
domain.poweroff
|
47
|
+
rescue
|
48
|
+
@logger.error('Failed to shutdown cleanly. Calling force poweroff.')
|
49
|
+
domain.poweroff
|
34
50
|
end
|
35
51
|
|
36
52
|
@app.call(env)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'log4r'
|
2
|
+
require 'open3'
|
2
3
|
|
3
4
|
module VagrantPlugins
|
4
5
|
module ProviderLibvirt
|
@@ -16,33 +17,69 @@ module VagrantPlugins
|
|
16
17
|
end
|
17
18
|
|
18
19
|
def call(env)
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# Virtual size has to be set for allocating space in storage pool.
|
22
|
-
box_virtual_size = env[:machine].box.metadata['virtual_size']
|
23
|
-
raise Errors::NoBoxVirtualSizeSet if box_virtual_size.nil?
|
20
|
+
# Handle box formats converting between v1 => v2 and ensuring
|
21
|
+
# any obsolete settings are rejected.
|
24
22
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
23
|
+
disks = env[:machine].box.metadata.fetch('disks', [])
|
24
|
+
if disks.empty?
|
25
|
+
# Handle box v1 format
|
26
|
+
|
27
|
+
# Only qcow2 format is supported in v1, but other formats with backing
|
28
|
+
# store capability should be usable.
|
29
|
+
box_format = env[:machine].box.metadata['format']
|
30
|
+
HandleBoxImage.verify_box_format(box_format)
|
31
|
+
|
32
|
+
env[:box_volume_number] = 1
|
33
|
+
env[:box_volumes] = [{
|
34
|
+
:path => HandleBoxImage.get_box_image_path(env[:machine].box, 'box.img'),
|
35
|
+
:name => HandleBoxImage.get_volume_name(env[:machine].box, 'box'),
|
36
|
+
:virtual_size => HandleBoxImage.get_virtual_size(env),
|
37
|
+
:format => box_format,
|
38
|
+
}]
|
39
|
+
else
|
40
|
+
# Handle box v2 format
|
41
|
+
# {
|
42
|
+
# 'path': '<path-of-file-box>',
|
43
|
+
# 'name': '<name-to-use-in-storage>' # optional, will use index
|
44
|
+
# }
|
45
|
+
#
|
46
|
+
env[:box_volume_number] = disks.length()
|
47
|
+
target_volumes = Hash[]
|
48
|
+
env[:box_volumes] = Array.new(env[:box_volume_number]) { |i|
|
49
|
+
raise Errors::BoxFormatMissingAttribute, attribute: "disks[#{i}]['path']" if disks[i]['path'].nil?
|
50
|
+
|
51
|
+
image_path = HandleBoxImage.get_box_image_path(env[:machine].box, disks[i]['path'])
|
52
|
+
format, virtual_size = HandleBoxImage.get_box_disk_settings(image_path)
|
53
|
+
volume_name = HandleBoxImage.get_volume_name(
|
54
|
+
env[:machine].box,
|
55
|
+
disks[i].fetch('name', disks[i]['path'].sub(/#{File.extname(disks[i]['path'])}$/, '')),
|
56
|
+
)
|
57
|
+
|
58
|
+
# allowing name means needing to check that it doesn't cause a clash
|
59
|
+
existing = target_volumes[volume_name]
|
60
|
+
if !existing.nil?
|
61
|
+
raise Errors::BoxFormatDuplicateVolume, volume: volume_name, new_disk: "disks[#{i}]", orig_disk: "disks[#{existing}]"
|
62
|
+
end
|
63
|
+
target_volumes[volume_name] = i
|
64
|
+
|
65
|
+
{
|
66
|
+
:path => image_path,
|
67
|
+
:name => volume_name,
|
68
|
+
:virtual_size => virtual_size.to_i,
|
69
|
+
:format => HandleBoxImage.verify_box_format(format)
|
70
|
+
}
|
71
|
+
}
|
32
72
|
end
|
33
73
|
|
34
74
|
# Get config options
|
35
75
|
config = env[:machine].provider_config
|
36
|
-
|
37
|
-
env[:
|
38
|
-
|
39
|
-
|
40
|
-
env[:machine].box.version.to_s
|
41
|
-
rescue
|
42
|
-
''
|
43
|
-
end}.img"
|
76
|
+
box_image_files = []
|
77
|
+
env[:box_volumes].each do |d|
|
78
|
+
box_image_files.push(d[:path])
|
79
|
+
end
|
44
80
|
|
45
81
|
# Override box_virtual_size
|
82
|
+
box_virtual_size = env[:box_volumes][0][:virtual_size]
|
46
83
|
if config.machine_virtual_size
|
47
84
|
if config.machine_virtual_size < box_virtual_size
|
48
85
|
# Warn that a virtual size less than the box metadata size
|
@@ -57,77 +94,129 @@ module VagrantPlugins
|
|
57
94
|
end
|
58
95
|
end
|
59
96
|
# save for use by later actions
|
60
|
-
env[:
|
97
|
+
env[:box_volumes][0][:virtual_size] = box_virtual_size
|
61
98
|
|
62
99
|
# while inside the synchronize block take care not to call the next
|
63
100
|
# action in the chain, as must exit this block first to prevent
|
64
101
|
# locking all subsequent actions as well.
|
65
102
|
@@lock.synchronize do
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
env[:ui].info(I18n.t('vagrant_libvirt.uploading_volume'))
|
75
|
-
|
76
|
-
# Create new volume in storage pool
|
77
|
-
unless File.exist?(box_image_file)
|
78
|
-
raise Vagrant::Errors::BoxNotFound, name: env[:machine].box.name
|
103
|
+
env[:box_volumes].each_index do |i|
|
104
|
+
# Don't continue if image already exists in storage pool.
|
105
|
+
box_volume = env[:machine].provider.driver.connection.volumes.all(
|
106
|
+
name: env[:box_volumes][i][:name]
|
107
|
+
).first
|
108
|
+
next if box_volume && box_volume.id
|
109
|
+
|
110
|
+
send_box_image(env, config, box_image_files[i], env[:box_volumes][i])
|
79
111
|
end
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
112
|
+
end
|
113
|
+
|
114
|
+
@app.call(env)
|
115
|
+
end
|
84
116
|
|
85
|
-
|
86
|
-
@storage_volume_gid = storage_gid env
|
117
|
+
protected
|
87
118
|
|
119
|
+
def self.get_volume_name(box, name)
|
120
|
+
vol_name = box.name.to_s.dup.gsub('/', '-VAGRANTSLASH-')
|
121
|
+
vol_name << "_vagrant_box_image_#{
|
88
122
|
begin
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
capacity: "#{box_virtual_size}G",
|
93
|
-
format_type: box_format,
|
94
|
-
owner: @storage_volume_uid,
|
95
|
-
group: @storage_volume_gid,
|
96
|
-
pool_name: config.storage_pool_name
|
97
|
-
)
|
98
|
-
rescue Fog::Errors::Error => e
|
99
|
-
raise Errors::FogCreateVolumeError,
|
100
|
-
error_message: e.message
|
123
|
+
box.version.to_s
|
124
|
+
rescue
|
125
|
+
''
|
101
126
|
end
|
127
|
+
}_#{name.dup.gsub('/', '-SLASH-')}.img"
|
128
|
+
end
|
102
129
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
110
|
-
end
|
130
|
+
def self.get_virtual_size(env)
|
131
|
+
# Virtual size has to be set for allocating space in storage pool.
|
132
|
+
box_virtual_size = env[:machine].box.metadata['virtual_size']
|
133
|
+
raise Errors::NoBoxVirtualSizeSet if box_virtual_size.nil?
|
134
|
+
return box_virtual_size
|
135
|
+
end
|
111
136
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
137
|
+
def self.get_box_image_path(box, box_name)
|
138
|
+
return box.directory.join(box_name).to_s
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.verify_box_format(box_format, disk_index=nil)
|
142
|
+
if box_format.nil?
|
143
|
+
raise Errors::NoBoxFormatSet
|
144
|
+
elsif box_format != 'qcow2'
|
145
|
+
if disk_index.nil?
|
146
|
+
raise Errors::WrongBoxFormatSet
|
147
|
+
else
|
148
|
+
raise Errors::WrongDiskFormatSet,
|
149
|
+
disk_index: disk_index
|
124
150
|
end
|
125
151
|
end
|
152
|
+
return box_format
|
153
|
+
end
|
126
154
|
|
127
|
-
|
155
|
+
def self.get_box_disk_settings(image_path)
|
156
|
+
stdout, stderr, status = Open3.capture3('qemu-img', 'info', image_path)
|
157
|
+
if !status.success?
|
158
|
+
raise Errors::BadBoxImage, image: image_path, out: stdout, err: stderr
|
159
|
+
end
|
160
|
+
|
161
|
+
image_info_lines = stdout.split("\n")
|
162
|
+
format = image_info_lines.find { |l| l.start_with?('file format:') }.split(' ')[2]
|
163
|
+
virtual_size = image_info_lines.find { |l| l.start_with?('virtual size:') }.split(' ')[2]
|
164
|
+
|
165
|
+
return format, virtual_size
|
128
166
|
end
|
129
167
|
|
130
|
-
|
168
|
+
def send_box_image(env, config, box_image_file, box_volume)
|
169
|
+
# Box is not available as a storage pool volume. Create and upload
|
170
|
+
# it as a copy of local box image.
|
171
|
+
env[:ui].info(I18n.t('vagrant_libvirt.uploading_volume'))
|
172
|
+
|
173
|
+
# Create new volume in storage pool
|
174
|
+
unless File.exist?(box_image_file)
|
175
|
+
raise Vagrant::Errors::BoxNotFound, name: env[:machine].box.name
|
176
|
+
end
|
177
|
+
box_image_size = File.size(box_image_file) # B
|
178
|
+
message = "Creating volume #{box_volume[:name]}"
|
179
|
+
message << " in storage pool #{config.storage_pool_name}."
|
180
|
+
@logger.info(message)
|
181
|
+
|
182
|
+
begin
|
183
|
+
fog_volume = env[:machine].provider.driver.connection.volumes.create(
|
184
|
+
name: box_volume[:name],
|
185
|
+
allocation: "#{box_image_size / 1024 / 1024}M",
|
186
|
+
capacity: "#{box_volume[:virtual_size]}G",
|
187
|
+
format_type: box_volume[:format],
|
188
|
+
owner: storage_uid(env),
|
189
|
+
group: storage_gid(env),
|
190
|
+
pool_name: config.storage_pool_name
|
191
|
+
)
|
192
|
+
rescue Fog::Errors::Error => e
|
193
|
+
raise Errors::FogCreateVolumeError,
|
194
|
+
error_message: e.message
|
195
|
+
end
|
196
|
+
|
197
|
+
# Upload box image to storage pool
|
198
|
+
ret = upload_image(box_image_file, config.storage_pool_name,
|
199
|
+
box_volume[:name], env) do |progress|
|
200
|
+
rewriting(env[:ui]) do |ui|
|
201
|
+
ui.clear_line
|
202
|
+
ui.report_progress(progress, box_image_size, false)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Clear the line one last time since the progress meter doesn't
|
207
|
+
# disappear immediately.
|
208
|
+
rewriting(env[:ui]) {|ui| ui.clear_line}
|
209
|
+
|
210
|
+
# If upload failed or was interrupted, remove created volume from
|
211
|
+
# storage pool.
|
212
|
+
if env[:interrupted] || !ret
|
213
|
+
begin
|
214
|
+
fog_volume.destroy
|
215
|
+
rescue
|
216
|
+
nil
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
131
220
|
|
132
221
|
# Fog Libvirt currently doesn't support uploading images to storage
|
133
222
|
# pool volumes. Use ruby-libvirt client instead.
|
@@ -9,9 +9,7 @@ module VagrantPlugins
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def call(env)
|
12
|
-
|
13
|
-
raise Errors::NoDomainError if domain.nil?
|
14
|
-
env[:result] = domain.state.to_s == 'running'
|
12
|
+
env[:result] = env[:machine].state.id == :running
|
15
13
|
|
16
14
|
@app.call(env)
|
17
15
|
end
|
@@ -16,9 +16,9 @@ module VagrantPlugins
|
|
16
16
|
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
|
17
17
|
if config.suspend_mode == 'managedsave'
|
18
18
|
if libvirt_domain.has_managed_save?
|
19
|
-
env[:result] =
|
19
|
+
env[:result] = env[:machine].state.id == :shutoff
|
20
20
|
else
|
21
|
-
env[:result] =
|
21
|
+
env[:result] = env[:machine].state.id == :paused
|
22
22
|
if env[:result]
|
23
23
|
env[:ui].warn('One time switching to pause suspend mode, found a paused VM.')
|
24
24
|
config.suspend_mode = 'pause'
|
@@ -27,10 +27,10 @@ module VagrantPlugins
|
|
27
27
|
else
|
28
28
|
if libvirt_domain.has_managed_save?
|
29
29
|
env[:ui].warn('One time switching to managedsave suspend mode, state found.')
|
30
|
-
env[:result] =
|
30
|
+
env[:result] = [:shutoff, :paused].include?(env[:machine].state.id)
|
31
31
|
config.suspend_mode = 'managedsave'
|
32
32
|
else
|
33
|
-
env[:result] =
|
33
|
+
env[:result] = env[:machine].state.id == :paused
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -50,8 +50,9 @@ module VagrantPlugins
|
|
50
50
|
# remove hw association with interface
|
51
51
|
# working for centos with lvs default disks
|
52
52
|
options = ENV.fetch('VAGRANT_LIBVIRT_VIRT_SYSPREP_OPTIONS', '')
|
53
|
-
operations = ENV.fetch('VAGRANT_LIBVIRT_VIRT_SYSPREP_OPERATIONS', 'defaults,-ssh-userdir')
|
53
|
+
operations = ENV.fetch('VAGRANT_LIBVIRT_VIRT_SYSPREP_OPERATIONS', 'defaults,-ssh-userdir,-customize')
|
54
54
|
`virt-sysprep --no-logfile --operations #{operations} -a #{@tmp_img} #{options}`
|
55
|
+
`virt-sparsify --in-place #{@tmp_img}`
|
55
56
|
# add any user provided file
|
56
57
|
extra = ''
|
57
58
|
@tmp_include = @tmp_dir + '/_include'
|
@@ -86,9 +86,13 @@ module VagrantPlugins
|
|
86
86
|
|
87
87
|
def search_network(nets, xml)
|
88
88
|
str = '/domain/devices/interface'
|
89
|
-
str += "[(@type='network' or @type='udp' or @type='bridge')"
|
89
|
+
str += "[(@type='network' or @type='udp' or @type='bridge' or @type='direct')"
|
90
90
|
unless nets.empty?
|
91
|
-
|
91
|
+
net = nets.first
|
92
|
+
network = net['network']
|
93
|
+
dev = net['dev']
|
94
|
+
str += " and source[@network='#{network}']" if network
|
95
|
+
str += " and source[@dev='#{dev}']" if dev
|
92
96
|
end
|
93
97
|
str += ']'
|
94
98
|
@logger.debug(str)
|
@@ -37,12 +37,16 @@ module VagrantPlugins
|
|
37
37
|
xml_descr = REXML::Document.new descr
|
38
38
|
descr_changed = false
|
39
39
|
|
40
|
+
# For outputting XML for comparison
|
41
|
+
formatter = REXML::Formatters::Pretty.new
|
42
|
+
|
40
43
|
# additional disk bus
|
41
44
|
config.disks.each do |disk|
|
42
45
|
device = disk[:device]
|
43
46
|
bus = disk[:bus]
|
44
47
|
REXML::XPath.each(xml_descr, '/domain/devices/disk[@device="disk"]/target[@dev="' + device + '"]') do |disk_target|
|
45
48
|
next unless disk_target.attributes['bus'] != bus
|
49
|
+
@logger.debug "disk #{device} bus updated from '#{disk_target.attributes['bus']}' to '#{bus}'"
|
46
50
|
descr_changed = true
|
47
51
|
disk_target.attributes['bus'] = bus
|
48
52
|
disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
|
@@ -52,6 +56,7 @@ module VagrantPlugins
|
|
52
56
|
# disk_bus
|
53
57
|
REXML::XPath.each(xml_descr, '/domain/devices/disk[@device="disk"]/target[@dev="vda"]') do |disk_target|
|
54
58
|
next unless disk_target.attributes['bus'] != config.disk_bus
|
59
|
+
@logger.debug "domain disk bus updated from '#{disk_target.attributes['bus']}' to '#{bus}'"
|
55
60
|
descr_changed = true
|
56
61
|
disk_target.attributes['bus'] = config.disk_bus
|
57
62
|
disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
|
@@ -61,6 +66,7 @@ module VagrantPlugins
|
|
61
66
|
unless config.nic_model_type.nil?
|
62
67
|
REXML::XPath.each(xml_descr, '/domain/devices/interface/model') do |iface_model|
|
63
68
|
if iface_model.attributes['type'] != config.nic_model_type
|
69
|
+
@logger.debug "network type updated from '#{iface_model.attributes['type']}' to '#{config.nic_model_type}'"
|
64
70
|
descr_changed = true
|
65
71
|
iface_model.attributes['type'] = config.nic_model_type
|
66
72
|
end
|
@@ -68,7 +74,9 @@ module VagrantPlugins
|
|
68
74
|
end
|
69
75
|
|
70
76
|
# vCpu count
|
71
|
-
|
77
|
+
vcpus_count = libvirt_domain.num_vcpus(0)
|
78
|
+
if config.cpus.to_i != vcpus_count
|
79
|
+
@logger.debug "cpu count updated from '#{vcpus_count}' to '#{config.cpus}'"
|
72
80
|
descr_changed = true
|
73
81
|
REXML::XPath.first(xml_descr, '/domain/vcpu').text = config.cpus
|
74
82
|
end
|
@@ -76,11 +84,13 @@ module VagrantPlugins
|
|
76
84
|
# cpu_mode
|
77
85
|
cpu = REXML::XPath.first(xml_descr, '/domain/cpu')
|
78
86
|
if cpu.nil?
|
87
|
+
@logger.debug "cpu_mode updated from not set to '#{config.cpu_mode}'"
|
79
88
|
descr_changed = true
|
80
89
|
cpu = REXML::Element.new('cpu', REXML::XPath.first(xml_descr, '/domain'))
|
81
90
|
cpu.attributes['mode'] = config.cpu_mode
|
82
91
|
else
|
83
92
|
if cpu.attributes['mode'] != config.cpu_mode
|
93
|
+
@logger.debug "cpu_mode updated from '#{cpu.attributes['mode']}' to '#{config.cpu_mode}'"
|
84
94
|
descr_changed = true
|
85
95
|
cpu.attributes['mode'] = config.cpu_mode
|
86
96
|
end
|
@@ -89,16 +99,19 @@ module VagrantPlugins
|
|
89
99
|
if config.cpu_mode != 'host-passthrough'
|
90
100
|
cpu_model = REXML::XPath.first(xml_descr, '/domain/cpu/model')
|
91
101
|
if cpu_model.nil?
|
102
|
+
@logger.debug "cpu_model updated from not set to '#{config.cpu_model}'"
|
92
103
|
descr_changed = true
|
93
104
|
cpu_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/cpu'))
|
94
105
|
cpu_model.attributes['fallback'] = 'allow'
|
95
106
|
cpu_model.text = config.cpu_model
|
96
107
|
else
|
97
|
-
if cpu_model.text.strip != config.cpu_model.strip
|
108
|
+
if (cpu_model.text or '').strip != config.cpu_model.strip
|
109
|
+
@logger.debug "cpu_model text updated from #{cpu_model.text} to '#{config.cpu_model}'"
|
98
110
|
descr_changed = true
|
99
111
|
cpu_model.text = config.cpu_model
|
100
112
|
end
|
101
113
|
if cpu_model.attributes['fallback'] != config.cpu_fallback
|
114
|
+
@logger.debug "cpu_model fallback attribute updated from #{cpu_model.attributes['fallback']} to '#{config.cpu_fallback}'"
|
102
115
|
descr_changed = true
|
103
116
|
cpu_model.attributes['fallback'] = config.cpu_fallback
|
104
117
|
end
|
@@ -107,12 +120,14 @@ module VagrantPlugins
|
|
107
120
|
svm_feature = REXML::XPath.first(xml_descr, '/domain/cpu/feature[@name="svm"]')
|
108
121
|
if config.nested
|
109
122
|
if vmx_feature.nil?
|
123
|
+
@logger.debug "nested mode enabled from unset by setting cpu vmx feature"
|
110
124
|
descr_changed = true
|
111
125
|
vmx_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr, '/domain/cpu'))
|
112
126
|
vmx_feature.attributes['policy'] = 'optional'
|
113
127
|
vmx_feature.attributes['name'] = 'vmx'
|
114
128
|
end
|
115
129
|
if svm_feature.nil?
|
130
|
+
@logger.debug "nested mode enabled from unset by setting cpu svm feature"
|
116
131
|
descr_changed = true
|
117
132
|
svm_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr, '/domain/cpu'))
|
118
133
|
svm_feature.attributes['policy'] = 'optional'
|
@@ -120,16 +135,19 @@ module VagrantPlugins
|
|
120
135
|
end
|
121
136
|
else
|
122
137
|
unless vmx_feature.nil?
|
138
|
+
@logger.debug "nested mode disabled for cpu by removing vmx feature"
|
123
139
|
descr_changed = true
|
124
140
|
cpu.delete_element(vmx_feature)
|
125
141
|
end
|
126
142
|
unless svm_feature.nil?
|
143
|
+
@logger.debug "nested mode disabled for cpu by removing svm feature"
|
127
144
|
descr_changed = true
|
128
145
|
cpu.delete_element(svm_feature)
|
129
146
|
end
|
130
147
|
end
|
131
148
|
elsif config.numa_nodes == nil
|
132
149
|
unless cpu.elements.to_a.empty?
|
150
|
+
@logger.debug "switching cpu_mode to host-passthrough and removing emulated cpu features"
|
133
151
|
descr_changed = true
|
134
152
|
cpu.elements.each do |elem|
|
135
153
|
cpu.delete_element(elem)
|
@@ -137,6 +155,34 @@ module VagrantPlugins
|
|
137
155
|
end
|
138
156
|
end
|
139
157
|
|
158
|
+
# Clock
|
159
|
+
clock = REXML::XPath.first(xml_descr, '/domain/clock')
|
160
|
+
if clock.attributes['offset'] != config.clock_offset
|
161
|
+
@logger.debug "clock offset changed"
|
162
|
+
descr_changed = true
|
163
|
+
clock.attributes['offset'] = config.clock_offset
|
164
|
+
end
|
165
|
+
|
166
|
+
# clock timers - because timers can be added/removed, just rebuild and then compare
|
167
|
+
if !config.clock_timers.empty? || clock.has_elements?
|
168
|
+
oldclock = ''
|
169
|
+
formatter.write(REXML::XPath.first(xml_descr, '/domain/clock'), oldclock)
|
170
|
+
clock.delete_element('//timer')
|
171
|
+
config.clock_timers.each do |clock_timer|
|
172
|
+
timer = REXML::Element.new('timer', clock)
|
173
|
+
clock_timer.each do |attr, value|
|
174
|
+
timer.attributes[attr.to_s] = value
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
newclock = ''
|
179
|
+
formatter.write(clock, newclock)
|
180
|
+
unless newclock.eql? oldclock
|
181
|
+
@logger.debug "clock timers config changed"
|
182
|
+
descr_changed = true
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
140
186
|
# Graphics
|
141
187
|
graphics = REXML::XPath.first(xml_descr, '/domain/devices/graphics')
|
142
188
|
if config.graphics_type != 'none'
|
@@ -178,31 +224,31 @@ module VagrantPlugins
|
|
178
224
|
end
|
179
225
|
|
180
226
|
# TPM
|
181
|
-
if config.tpm_path
|
182
|
-
|
227
|
+
if [config.tpm_path, config.tpm_version].any?
|
228
|
+
if config.tpm_path
|
229
|
+
raise Errors::FogCreateServerError, 'The TPM Path must be fully qualified' unless config.tpm_path[0].chr == '/'
|
230
|
+
end
|
183
231
|
|
184
|
-
tpm
|
185
|
-
if
|
232
|
+
# just build the tpm element every time
|
233
|
+
# check at the end if it is different
|
234
|
+
oldtpm = REXML::XPath.first(xml_descr, '/domain/devices/tpm')
|
235
|
+
REXML::XPath.first(xml_descr, '/domain/devices').delete_element("tpm")
|
236
|
+
newtpm = REXML::Element.new('tpm', REXML::XPath.first(xml_descr, '/domain/devices'))
|
237
|
+
|
238
|
+
newtpm.attributes['model'] = config.tpm_model
|
239
|
+
backend = newtpm.add_element('backend')
|
240
|
+
backend.attributes['type'] = config.tpm_type
|
241
|
+
|
242
|
+
case config.tpm_type
|
243
|
+
when 'emulator'
|
244
|
+
backend.attributes['version'] = config.tpm_version
|
245
|
+
when 'passthrough'
|
246
|
+
backend.add_element('device').attributes['path'] = config.tpm_path
|
247
|
+
end
|
248
|
+
|
249
|
+
unless "'#{newtpm}'".eql? "'#{oldtpm}'"
|
250
|
+
@logger.debug "tpm config changed"
|
186
251
|
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
252
|
end
|
207
253
|
end
|
208
254
|
|
@@ -210,16 +256,21 @@ module VagrantPlugins
|
|
210
256
|
video = REXML::XPath.first(xml_descr, '/domain/devices/video')
|
211
257
|
if !video.nil? && (config.graphics_type == 'none')
|
212
258
|
# graphics_type = none, video devices are removed since there is no possible output
|
259
|
+
@logger.debug "deleting video elements as config.graphics_type is none"
|
213
260
|
descr_changed = true
|
214
261
|
video.parent.delete_element(video)
|
215
262
|
else
|
216
263
|
video_model = REXML::XPath.first(xml_descr, '/domain/devices/video/model')
|
217
264
|
if video_model.nil?
|
265
|
+
@logger.debug "video updated from not set to type '#{config.video_type}' and vram '#{config.video_vram}'"
|
266
|
+
descr_changed = true
|
218
267
|
video_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/devices/video'))
|
219
268
|
video_model.attributes['type'] = config.video_type
|
220
269
|
video_model.attributes['vram'] = config.video_vram
|
221
270
|
else
|
222
|
-
if video_model.attributes['type'] != config.video_type || video_model.attributes['vram'] != config.video_vram
|
271
|
+
if video_model.attributes['type'] != config.video_type || video_model.attributes['vram'] != config.video_vram.to_s
|
272
|
+
@logger.debug "video type updated from '#{video_model.attributes['type']}' to '#{config.video_type}'"
|
273
|
+
@logger.debug "video vram updated from '#{video_model.attributes['vram']}' to '#{config.video_vram}'"
|
223
274
|
descr_changed = true
|
224
275
|
video_model.attributes['type'] = config.video_type
|
225
276
|
video_model.attributes['vram'] = config.video_vram
|
@@ -237,11 +288,13 @@ module VagrantPlugins
|
|
237
288
|
if config.dtb
|
238
289
|
dtb = REXML::XPath.first(xml_descr, '/domain/os/dtb')
|
239
290
|
if dtb.nil?
|
291
|
+
@logger.debug "dtb updated from not set to '#{config.dtb}'"
|
240
292
|
descr_changed = true
|
241
293
|
dtb = REXML::Element.new('dtb', REXML::XPath.first(xml_descr, '/domain/os'))
|
242
294
|
dtb.text = config.dtb
|
243
295
|
else
|
244
|
-
if dtb.text != config.dtb
|
296
|
+
if (dtb.text or '') != config.dtb
|
297
|
+
@logger.debug "dtb updated from '#{dtb.text}' to '#{config.dtb}'"
|
245
298
|
descr_changed = true
|
246
299
|
dtb.text = config.dtb
|
247
300
|
end
|
@@ -252,11 +305,13 @@ module VagrantPlugins
|
|
252
305
|
if config.kernel
|
253
306
|
kernel = REXML::XPath.first(xml_descr, '/domain/os/kernel')
|
254
307
|
if kernel.nil?
|
308
|
+
@logger.debug "kernel updated from not set to '#{config.kernel}'"
|
255
309
|
descr_changed = true
|
256
310
|
kernel = REXML::Element.new('kernel', REXML::XPath.first(xml_descr, '/domain/os'))
|
257
311
|
kernel.text = config.kernel
|
258
312
|
else
|
259
|
-
if kernel.text != config.kernel
|
313
|
+
if (kernel.text or '').strip != config.kernel
|
314
|
+
@logger.debug "kernel updated from '#{kernel.text}' to '#{config.kernel}'"
|
260
315
|
descr_changed = true
|
261
316
|
kernel.text = config.kernel
|
262
317
|
end
|
@@ -265,11 +320,13 @@ module VagrantPlugins
|
|
265
320
|
if config.initrd
|
266
321
|
initrd = REXML::XPath.first(xml_descr, '/domain/os/initrd')
|
267
322
|
if initrd.nil?
|
323
|
+
@logger.debug "initrd updated from not set to '#{config.initrd}'"
|
268
324
|
descr_changed = true
|
269
325
|
initrd = REXML::Element.new('initrd', REXML::XPath.first(xml_descr, '/domain/os'))
|
270
326
|
initrd.text = config.initrd
|
271
327
|
else
|
272
|
-
if initrd.text != config.initrd
|
328
|
+
if (initrd.text or '').strip != config.initrd
|
329
|
+
@logger.debug "initrd updated from '#{initrd.text}' to '#{config.initrd}'"
|
273
330
|
descr_changed = true
|
274
331
|
initrd.text = config.initrd
|
275
332
|
end
|