vagrant-libvirt 0.10.4 → 0.10.7
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 +1 -1
- data/lib/vagrant-libvirt/action/create_domain.rb +2 -0
- data/lib/vagrant-libvirt/action/destroy_domain.rb +4 -5
- data/lib/vagrant-libvirt/action/forward_ports.rb +16 -15
- data/lib/vagrant-libvirt/action/handle_box_image.rb +2 -0
- data/lib/vagrant-libvirt/action/package_domain.rb +1 -0
- data/lib/vagrant-libvirt/action/resolve_disk_settings.rb +2 -5
- data/lib/vagrant-libvirt/action/set_boot_order.rb +44 -42
- data/lib/vagrant-libvirt/action/start_domain.rb +384 -393
- data/lib/vagrant-libvirt/cap/synced_folder_9p.rb +2 -0
- data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +3 -1
- data/lib/vagrant-libvirt/config.rb +1 -2
- data/lib/vagrant-libvirt/errors.rb +4 -0
- data/lib/vagrant-libvirt/util/compat.rb +1 -1
- data/lib/vagrant-libvirt/util/network_util.rb +1 -1
- data/lib/vagrant-libvirt/util/xml.rb +47 -0
- data/lib/vagrant-libvirt/version +1 -1
- data/locales/en.yml +2 -0
- data/spec/spec_helper.rb +13 -6
- data/spec/unit/action/set_boot_order_spec/default.xml +76 -0
- data/spec/unit/action/set_boot_order_spec/explicit_boot_order.xml +77 -0
- data/spec/unit/action/set_boot_order_spec.rb +67 -0
- data/spec/unit/action/start_domain_spec.rb +26 -0
- data/spec/unit/plugin_spec.rb +1 -0
- metadata +92 -85
@@ -2,14 +2,18 @@
|
|
2
2
|
|
3
3
|
require 'log4r'
|
4
4
|
|
5
|
-
require 'equivalent-xml'
|
6
5
|
require 'rexml/document'
|
6
|
+
require 'rexml/formatters/pretty'
|
7
|
+
require 'rexml/xpath'
|
8
|
+
|
9
|
+
require 'vagrant-libvirt/util/xml'
|
7
10
|
|
8
11
|
module VagrantPlugins
|
9
12
|
module ProviderLibvirt
|
10
13
|
module Action
|
11
14
|
# Just start the domain.
|
12
15
|
class StartDomain
|
16
|
+
|
13
17
|
def initialize(app, _env)
|
14
18
|
@logger = Log4r::Logger.new('vagrant_libvirt::action::start_domain')
|
15
19
|
@app = app
|
@@ -18,452 +22,439 @@ module VagrantPlugins
|
|
18
22
|
def call(env)
|
19
23
|
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
|
20
24
|
raise Errors::NoDomainError if domain.nil?
|
25
|
+
|
21
26
|
config = env[:machine].provider_config
|
22
27
|
|
23
|
-
|
24
|
-
|
28
|
+
# update domain settings on change.
|
29
|
+
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
|
25
30
|
|
26
|
-
|
31
|
+
# Libvirt API doesn't support modifying memory on NUMA enabled CPUs
|
32
|
+
# http://libvirt.org/git/?p=libvirt.git;a=commit;h=d174394105cf00ed266bf729ddf461c21637c736
|
33
|
+
if config.numa_nodes == nil
|
34
|
+
if config.memory.to_i * 1024 != libvirt_domain.max_memory
|
35
|
+
libvirt_domain.max_memory = config.memory.to_i * 1024
|
36
|
+
libvirt_domain.memory = libvirt_domain.max_memory
|
37
|
+
end
|
38
|
+
end
|
27
39
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
40
|
+
# XML definition manipulation
|
41
|
+
descr = libvirt_domain.xml_desc(1)
|
42
|
+
xml_descr = REXML::Document.new descr
|
43
|
+
descr_changed = false
|
44
|
+
|
45
|
+
# For outputting XML for comparison
|
46
|
+
formatter = REXML::Formatters::Pretty.new
|
47
|
+
|
48
|
+
# additional disk bus
|
49
|
+
config.disks.each do |disk|
|
50
|
+
device = disk[:device]
|
51
|
+
bus = disk[:bus]
|
52
|
+
REXML::XPath.each(xml_descr, '/domain/devices/disk[@device="disk"]/target[@dev="' + device + '"]') do |disk_target|
|
53
|
+
next unless disk_target.attributes['bus'] != bus
|
54
|
+
@logger.debug "disk #{device} bus updated from '#{disk_target.attributes['bus']}' to '#{bus}'"
|
55
|
+
descr_changed = true
|
56
|
+
disk_target.attributes['bus'] = bus
|
57
|
+
disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
|
35
58
|
end
|
59
|
+
end
|
36
60
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
# additional disk bus
|
47
|
-
config.disks.each do |disk|
|
48
|
-
device = disk[:device]
|
49
|
-
bus = disk[:bus]
|
50
|
-
REXML::XPath.each(xml_descr, '/domain/devices/disk[@device="disk"]/target[@dev="' + device + '"]') do |disk_target|
|
51
|
-
next unless disk_target.attributes['bus'] != bus
|
52
|
-
@logger.debug "disk #{device} bus updated from '#{disk_target.attributes['bus']}' to '#{bus}'"
|
53
|
-
descr_changed = true
|
54
|
-
disk_target.attributes['bus'] = bus
|
55
|
-
disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
|
56
|
-
end
|
57
|
-
end
|
61
|
+
# disk_bus
|
62
|
+
REXML::XPath.each(xml_descr, '/domain/devices/disk[@device="disk"]/target[@dev="vda"]') do |disk_target|
|
63
|
+
next unless disk_target.attributes['bus'] != config.disk_bus
|
64
|
+
@logger.debug "domain disk bus updated from '#{disk_target.attributes['bus']}' to '#{config.disk_bus}'"
|
65
|
+
descr_changed = true
|
66
|
+
disk_target.attributes['bus'] = config.disk_bus
|
67
|
+
disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
|
68
|
+
end
|
58
69
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
70
|
+
# Interface type
|
71
|
+
unless config.nic_model_type.nil?
|
72
|
+
REXML::XPath.each(xml_descr, '/domain/devices/interface/model') do |iface_model|
|
73
|
+
if iface_model.attributes['type'] != config.nic_model_type
|
74
|
+
@logger.debug "network type updated from '#{iface_model.attributes['type']}' to '#{config.nic_model_type}'"
|
63
75
|
descr_changed = true
|
64
|
-
|
65
|
-
disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
|
76
|
+
iface_model.attributes['type'] = config.nic_model_type
|
66
77
|
end
|
78
|
+
end
|
79
|
+
end
|
67
80
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
81
|
+
# vCpu count
|
82
|
+
vcpus_count = libvirt_domain.num_vcpus(0)
|
83
|
+
if config.cpus.to_i != vcpus_count
|
84
|
+
@logger.debug "cpu count updated from '#{vcpus_count}' to '#{config.cpus}'"
|
85
|
+
descr_changed = true
|
86
|
+
REXML::XPath.first(xml_descr, '/domain/vcpu').text = config.cpus
|
87
|
+
end
|
78
88
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
89
|
+
# cpu_mode
|
90
|
+
cpu = REXML::XPath.first(xml_descr, '/domain/cpu')
|
91
|
+
if cpu.nil?
|
92
|
+
@logger.debug "cpu_mode updated from not set to '#{config.cpu_mode}'"
|
93
|
+
descr_changed = true
|
94
|
+
cpu = REXML::Element.new('cpu', REXML::XPath.first(xml_descr, '/domain'))
|
95
|
+
cpu.attributes['mode'] = config.cpu_mode
|
96
|
+
else
|
97
|
+
if cpu.attributes['mode'] != config.cpu_mode
|
98
|
+
@logger.debug "cpu_mode updated from '#{cpu.attributes['mode']}' to '#{config.cpu_mode}'"
|
99
|
+
descr_changed = true
|
100
|
+
cpu.attributes['mode'] = config.cpu_mode
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
if config.cpu_mode != 'host-passthrough'
|
105
|
+
cpu_model = REXML::XPath.first(xml_descr, '/domain/cpu/model')
|
106
|
+
if cpu_model.nil?
|
107
|
+
if config.cpu_model.strip != ''
|
108
|
+
@logger.debug "cpu_model updated from not set to '#{config.cpu_model}'"
|
83
109
|
descr_changed = true
|
84
|
-
REXML::XPath.first(xml_descr, '/domain/
|
110
|
+
cpu_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/cpu'))
|
111
|
+
cpu_model.attributes['fallback'] = 'allow'
|
112
|
+
cpu_model.text = config.cpu_model
|
85
113
|
end
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
if cpu.nil?
|
90
|
-
@logger.debug "cpu_mode updated from not set to '#{config.cpu_mode}'"
|
114
|
+
else
|
115
|
+
if (cpu_model.text or '').strip != config.cpu_model.strip
|
116
|
+
@logger.debug "cpu_model text updated from #{cpu_model.text} to '#{config.cpu_model}'"
|
91
117
|
descr_changed = true
|
92
|
-
|
93
|
-
cpu.attributes['mode'] = config.cpu_mode
|
94
|
-
else
|
95
|
-
if cpu.attributes['mode'] != config.cpu_mode
|
96
|
-
@logger.debug "cpu_mode updated from '#{cpu.attributes['mode']}' to '#{config.cpu_mode}'"
|
97
|
-
descr_changed = true
|
98
|
-
cpu.attributes['mode'] = config.cpu_mode
|
99
|
-
end
|
118
|
+
cpu_model.text = config.cpu_model
|
100
119
|
end
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
if config.cpu_model.strip != ''
|
106
|
-
@logger.debug "cpu_model updated from not set to '#{config.cpu_model}'"
|
107
|
-
descr_changed = true
|
108
|
-
cpu_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/cpu'))
|
109
|
-
cpu_model.attributes['fallback'] = 'allow'
|
110
|
-
cpu_model.text = config.cpu_model
|
111
|
-
end
|
112
|
-
else
|
113
|
-
if (cpu_model.text or '').strip != config.cpu_model.strip
|
114
|
-
@logger.debug "cpu_model text updated from #{cpu_model.text} to '#{config.cpu_model}'"
|
115
|
-
descr_changed = true
|
116
|
-
cpu_model.text = config.cpu_model
|
117
|
-
end
|
118
|
-
if cpu_model.attributes['fallback'] != config.cpu_fallback
|
119
|
-
@logger.debug "cpu_model fallback attribute updated from #{cpu_model.attributes['fallback']} to '#{config.cpu_fallback}'"
|
120
|
-
descr_changed = true
|
121
|
-
cpu_model.attributes['fallback'] = config.cpu_fallback
|
122
|
-
end
|
123
|
-
end
|
124
|
-
vmx_feature = REXML::XPath.first(xml_descr, '/domain/cpu/feature[@name="vmx"]')
|
125
|
-
svm_feature = REXML::XPath.first(xml_descr, '/domain/cpu/feature[@name="svm"]')
|
126
|
-
if config.nested
|
127
|
-
if vmx_feature.nil?
|
128
|
-
@logger.debug "nested mode enabled from unset by setting cpu vmx feature"
|
129
|
-
descr_changed = true
|
130
|
-
vmx_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr, '/domain/cpu'))
|
131
|
-
vmx_feature.attributes['policy'] = 'optional'
|
132
|
-
vmx_feature.attributes['name'] = 'vmx'
|
133
|
-
end
|
134
|
-
if svm_feature.nil?
|
135
|
-
@logger.debug "nested mode enabled from unset by setting cpu svm feature"
|
136
|
-
descr_changed = true
|
137
|
-
svm_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr, '/domain/cpu'))
|
138
|
-
svm_feature.attributes['policy'] = 'optional'
|
139
|
-
svm_feature.attributes['name'] = 'svm'
|
140
|
-
end
|
141
|
-
else
|
142
|
-
unless vmx_feature.nil?
|
143
|
-
@logger.debug "nested mode disabled for cpu by removing vmx feature"
|
144
|
-
descr_changed = true
|
145
|
-
cpu.delete_element(vmx_feature)
|
146
|
-
end
|
147
|
-
unless svm_feature.nil?
|
148
|
-
@logger.debug "nested mode disabled for cpu by removing svm feature"
|
149
|
-
descr_changed = true
|
150
|
-
cpu.delete_element(svm_feature)
|
151
|
-
end
|
152
|
-
end
|
153
|
-
elsif config.numa_nodes == nil
|
154
|
-
unless cpu.elements.to_a.empty?
|
155
|
-
@logger.debug "switching cpu_mode to host-passthrough and removing emulated cpu features"
|
156
|
-
descr_changed = true
|
157
|
-
cpu.elements.each do |elem|
|
158
|
-
cpu.delete_element(elem)
|
159
|
-
end
|
160
|
-
end
|
120
|
+
if cpu_model.attributes['fallback'] != config.cpu_fallback
|
121
|
+
@logger.debug "cpu_model fallback attribute updated from #{cpu_model.attributes['fallback']} to '#{config.cpu_fallback}'"
|
122
|
+
descr_changed = true
|
123
|
+
cpu_model.attributes['fallback'] = config.cpu_fallback
|
161
124
|
end
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
125
|
+
end
|
126
|
+
vmx_feature = REXML::XPath.first(xml_descr, '/domain/cpu/feature[@name="vmx"]')
|
127
|
+
svm_feature = REXML::XPath.first(xml_descr, '/domain/cpu/feature[@name="svm"]')
|
128
|
+
if config.nested
|
129
|
+
if vmx_feature.nil?
|
130
|
+
@logger.debug "nested mode enabled from unset by setting cpu vmx feature"
|
167
131
|
descr_changed = true
|
168
|
-
|
132
|
+
vmx_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr, '/domain/cpu'))
|
133
|
+
vmx_feature.attributes['policy'] = 'optional'
|
134
|
+
vmx_feature.attributes['name'] = 'vmx'
|
169
135
|
end
|
136
|
+
if svm_feature.nil?
|
137
|
+
@logger.debug "nested mode enabled from unset by setting cpu svm feature"
|
138
|
+
descr_changed = true
|
139
|
+
svm_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr, '/domain/cpu'))
|
140
|
+
svm_feature.attributes['policy'] = 'optional'
|
141
|
+
svm_feature.attributes['name'] = 'svm'
|
142
|
+
end
|
143
|
+
else
|
144
|
+
unless vmx_feature.nil?
|
145
|
+
@logger.debug "nested mode disabled for cpu by removing vmx feature"
|
146
|
+
descr_changed = true
|
147
|
+
cpu.delete_element(vmx_feature)
|
148
|
+
end
|
149
|
+
unless svm_feature.nil?
|
150
|
+
@logger.debug "nested mode disabled for cpu by removing svm feature"
|
151
|
+
descr_changed = true
|
152
|
+
cpu.delete_element(svm_feature)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
elsif config.numa_nodes == nil
|
156
|
+
unless cpu.elements.to_a.empty?
|
157
|
+
@logger.debug "switching cpu_mode to host-passthrough and removing emulated cpu features"
|
158
|
+
descr_changed = true
|
159
|
+
cpu.elements.each do |elem|
|
160
|
+
cpu.delete_element(elem)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
170
164
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
clock_timer.each do |attr, value|
|
179
|
-
timer.attributes[attr.to_s] = value
|
180
|
-
end
|
181
|
-
end
|
165
|
+
# Clock
|
166
|
+
clock = REXML::XPath.first(xml_descr, '/domain/clock')
|
167
|
+
if clock.attributes['offset'] != config.clock_offset
|
168
|
+
@logger.debug "clock offset changed"
|
169
|
+
descr_changed = true
|
170
|
+
clock.attributes['offset'] = config.clock_offset
|
171
|
+
end
|
182
172
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
173
|
+
# clock timers - because timers can be added/removed, just rebuild and then compare
|
174
|
+
if !config.clock_timers.empty? || clock.has_elements?
|
175
|
+
oldclock = String.new
|
176
|
+
formatter.write(REXML::XPath.first(xml_descr, '/domain/clock'), oldclock)
|
177
|
+
clock.delete_element('//timer')
|
178
|
+
config.clock_timers.each do |clock_timer|
|
179
|
+
timer = REXML::Element.new('timer', clock)
|
180
|
+
clock_timer.each do |attr, value|
|
181
|
+
timer.attributes[attr.to_s] = value
|
189
182
|
end
|
183
|
+
end
|
190
184
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
185
|
+
newclock = String.new
|
186
|
+
formatter.write(clock, newclock)
|
187
|
+
unless newclock.eql? oldclock
|
188
|
+
@logger.debug "clock timers config changed"
|
189
|
+
descr_changed = true
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Graphics
|
194
|
+
graphics = REXML::XPath.first(xml_descr, '/domain/devices/graphics')
|
195
|
+
if config.graphics_type != 'none'
|
196
|
+
if graphics.nil?
|
197
|
+
descr_changed = true
|
198
|
+
graphics = REXML::Element.new('graphics', REXML::XPath.first(xml_descr, '/domain/devices'))
|
199
|
+
end
|
200
|
+
if graphics.attributes['type'] != config.graphics_type
|
201
|
+
descr_changed = true
|
202
|
+
graphics.attributes['type'] = config.graphics_type
|
203
|
+
end
|
204
|
+
if graphics.attributes['listen'] != config.graphics_ip
|
205
|
+
descr_changed = true
|
206
|
+
graphics.attributes['listen'] = config.graphics_ip
|
207
|
+
graphics.delete_element('//listen')
|
208
|
+
end
|
209
|
+
if graphics.attributes['autoport'] != config.graphics_autoport
|
210
|
+
descr_changed = true
|
211
|
+
graphics.attributes['autoport'] = config.graphics_autoport
|
212
|
+
if config.graphics_autoport == 'no'
|
213
|
+
graphics.attributes.delete('autoport')
|
214
|
+
graphics.attributes['port'] = config.graphics_port
|
215
|
+
end
|
216
|
+
end
|
217
|
+
if graphics.attributes['keymap'] != config.keymap
|
218
|
+
descr_changed = true
|
219
|
+
graphics.attributes['keymap'] = config.keymap
|
220
|
+
end
|
221
|
+
if graphics.attributes['passwd'] != config.graphics_passwd
|
222
|
+
descr_changed = true
|
223
|
+
if config.graphics_passwd.nil?
|
224
|
+
graphics.attributes.delete 'passwd'
|
225
|
+
else
|
226
|
+
graphics.attributes['passwd'] = config.graphics_passwd
|
227
|
+
end
|
228
|
+
end
|
229
|
+
graphics_gl = REXML::XPath.first(xml_descr, '/domain/devices/graphics/gl')
|
230
|
+
if graphics_gl.nil?
|
231
|
+
if config.graphics_gl
|
232
|
+
graphics_gl = REXML::Element.new('gl', REXML::XPath.first(xml_descr, '/domain/devices/graphics'))
|
233
|
+
graphics_gl.attributes['enable'] = 'yes'
|
234
|
+
descr_changed = true
|
235
|
+
end
|
236
|
+
else
|
237
|
+
if config.graphics_gl
|
238
|
+
if graphics_gl.attributes['enable'] != 'yes'
|
239
|
+
graphics_gl.attributes['enable'] = 'yes'
|
219
240
|
descr_changed = true
|
220
|
-
if config.graphics_passwd.nil?
|
221
|
-
graphics.attributes.delete 'passwd'
|
222
|
-
else
|
223
|
-
graphics.attributes['passwd'] = config.graphics_passwd
|
224
|
-
end
|
225
|
-
end
|
226
|
-
graphics_gl = REXML::XPath.first(xml_descr, '/domain/devices/graphics/gl')
|
227
|
-
if graphics_gl.nil?
|
228
|
-
if config.graphics_gl
|
229
|
-
graphics_gl = REXML::Element.new('gl', REXML::XPath.first(xml_descr, '/domain/devices/graphics'))
|
230
|
-
graphics_gl.attributes['enable'] = 'yes'
|
231
|
-
descr_changed = true
|
232
|
-
end
|
233
|
-
else
|
234
|
-
if config.graphics_gl
|
235
|
-
if graphics_gl.attributes['enable'] != 'yes'
|
236
|
-
graphics_gl.attributes['enable'] = 'yes'
|
237
|
-
descr_changed = true
|
238
|
-
end
|
239
|
-
else
|
240
|
-
graphics_gl.parent.delete_element(graphics_gl)
|
241
|
-
descr_changed = true
|
242
|
-
end
|
243
241
|
end
|
244
242
|
else
|
245
|
-
|
246
|
-
|
243
|
+
graphics_gl.parent.delete_element(graphics_gl)
|
244
|
+
descr_changed = true
|
247
245
|
end
|
246
|
+
end
|
247
|
+
else
|
248
|
+
# graphics_type = none, remove entire element
|
249
|
+
graphics.parent.delete_element(graphics) unless graphics.nil?
|
250
|
+
end
|
248
251
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
252
|
+
# TPM
|
253
|
+
if [config.tpm_path, config.tpm_version].any?
|
254
|
+
if config.tpm_path
|
255
|
+
raise Errors::UpdateServerError, 'The TPM Path must be fully qualified' unless config.tpm_path[0].chr == '/'
|
256
|
+
end
|
254
257
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
258
|
+
# just build the tpm element every time
|
259
|
+
# check at the end if it is different
|
260
|
+
oldtpm = REXML::XPath.first(xml_descr, '/domain/devices/tpm')
|
261
|
+
REXML::XPath.first(xml_descr, '/domain/devices').delete_element("tpm")
|
262
|
+
newtpm = REXML::Element.new('tpm', REXML::XPath.first(xml_descr, '/domain/devices'))
|
263
|
+
|
264
|
+
newtpm.attributes['model'] = config.tpm_model
|
265
|
+
backend = newtpm.add_element('backend')
|
266
|
+
backend.attributes['type'] = config.tpm_type
|
267
|
+
|
268
|
+
case config.tpm_type
|
269
|
+
when 'emulator'
|
270
|
+
backend.attributes['version'] = config.tpm_version
|
271
|
+
when 'passthrough'
|
272
|
+
backend.add_element('device').attributes['path'] = config.tpm_path
|
273
|
+
end
|
271
274
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
275
|
+
unless "'#{newtpm}'".eql? "'#{oldtpm}'"
|
276
|
+
@logger.debug "tpm config changed"
|
277
|
+
descr_changed = true
|
278
|
+
end
|
279
|
+
end
|
277
280
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
281
|
+
# Video device
|
282
|
+
video = REXML::XPath.first(xml_descr, '/domain/devices/video')
|
283
|
+
if !video.nil? && (config.graphics_type == 'none')
|
284
|
+
# graphics_type = none, video devices are removed since there is no possible output
|
285
|
+
@logger.debug "deleting video elements as config.graphics_type is none"
|
286
|
+
descr_changed = true
|
287
|
+
video.parent.delete_element(video)
|
288
|
+
else
|
289
|
+
video_model = REXML::XPath.first(xml_descr, '/domain/devices/video/model')
|
290
|
+
if video_model.nil?
|
291
|
+
@logger.debug "video updated from not set to type '#{config.video_type}' and vram '#{config.video_vram}'"
|
292
|
+
descr_changed = true
|
293
|
+
video_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/devices/video'))
|
294
|
+
video_model.attributes['type'] = config.video_type
|
295
|
+
video_model.attributes['vram'] = config.video_vram
|
296
|
+
else
|
297
|
+
if video_model.attributes['type'] != config.video_type || video_model.attributes['vram'] != config.video_vram.to_s
|
298
|
+
@logger.debug "video type updated from '#{video_model.attributes['type']}' to '#{config.video_type}'"
|
299
|
+
@logger.debug "video vram updated from '#{video_model.attributes['vram']}' to '#{config.video_vram}'"
|
283
300
|
descr_changed = true
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
301
|
+
video_model.attributes['type'] = config.video_type
|
302
|
+
video_model.attributes['vram'] = config.video_vram
|
303
|
+
end
|
304
|
+
end
|
305
|
+
video_accel = REXML::XPath.first(xml_descr, '/domain/devices/video/model/acceleration')
|
306
|
+
if video_accel.nil?
|
307
|
+
if config.video_accel3d
|
308
|
+
video_accel = REXML::Element.new('acceleration', REXML::XPath.first(xml_descr, '/domain/devices/video/model'))
|
309
|
+
video_accel.attributes['accel3d'] = 'yes'
|
310
|
+
descr_changed = true
|
311
|
+
end
|
312
|
+
else
|
313
|
+
if config.video_accel3d
|
314
|
+
if video_accel.attributes['accel3d'] != 'yes'
|
315
|
+
video_accel.attributes['accel3d'] = 'yes'
|
289
316
|
descr_changed = true
|
290
|
-
video_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/devices/video'))
|
291
|
-
video_model.attributes['type'] = config.video_type
|
292
|
-
video_model.attributes['vram'] = config.video_vram
|
293
|
-
else
|
294
|
-
if video_model.attributes['type'] != config.video_type || video_model.attributes['vram'] != config.video_vram.to_s
|
295
|
-
@logger.debug "video type updated from '#{video_model.attributes['type']}' to '#{config.video_type}'"
|
296
|
-
@logger.debug "video vram updated from '#{video_model.attributes['vram']}' to '#{config.video_vram}'"
|
297
|
-
descr_changed = true
|
298
|
-
video_model.attributes['type'] = config.video_type
|
299
|
-
video_model.attributes['vram'] = config.video_vram
|
300
|
-
end
|
301
|
-
end
|
302
|
-
video_accel = REXML::XPath.first(xml_descr, '/domain/devices/video/model/acceleration')
|
303
|
-
if video_accel.nil?
|
304
|
-
if config.video_accel3d
|
305
|
-
video_accel = REXML::Element.new('acceleration', REXML::XPath.first(xml_descr, '/domain/devices/video/model'))
|
306
|
-
video_accel.attributes['accel3d'] = 'yes'
|
307
|
-
descr_changed = true
|
308
|
-
end
|
309
|
-
else
|
310
|
-
if config.video_accel3d
|
311
|
-
if video_accel.attributes['accel3d'] != 'yes'
|
312
|
-
video_accel.attributes['accel3d'] = 'yes'
|
313
|
-
descr_changed = true
|
314
|
-
end
|
315
|
-
else
|
316
|
-
video_accel.parent.delete_element(video_accel)
|
317
|
-
descr_changed = true
|
318
|
-
end
|
319
317
|
end
|
318
|
+
else
|
319
|
+
video_accel.parent.delete_element(video_accel)
|
320
|
+
descr_changed = true
|
320
321
|
end
|
322
|
+
end
|
323
|
+
end
|
321
324
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
325
|
+
# Sound device
|
326
|
+
if config.sound_type
|
327
|
+
sound = REXML::XPath.first(xml_descr,'/domain/devices/sound/model')
|
328
|
+
end
|
326
329
|
|
327
330
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
end
|
342
|
-
end
|
331
|
+
# dtb
|
332
|
+
if config.dtb
|
333
|
+
dtb = REXML::XPath.first(xml_descr, '/domain/os/dtb')
|
334
|
+
if dtb.nil?
|
335
|
+
@logger.debug "dtb updated from not set to '#{config.dtb}'"
|
336
|
+
descr_changed = true
|
337
|
+
dtb = REXML::Element.new('dtb', REXML::XPath.first(xml_descr, '/domain/os'))
|
338
|
+
dtb.text = config.dtb
|
339
|
+
else
|
340
|
+
if (dtb.text or '') != config.dtb
|
341
|
+
@logger.debug "dtb updated from '#{dtb.text}' to '#{config.dtb}'"
|
342
|
+
descr_changed = true
|
343
|
+
dtb.text = config.dtb
|
343
344
|
end
|
345
|
+
end
|
346
|
+
end
|
344
347
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
end
|
359
|
-
end
|
348
|
+
# kernel and initrd
|
349
|
+
if config.kernel
|
350
|
+
kernel = REXML::XPath.first(xml_descr, '/domain/os/kernel')
|
351
|
+
if kernel.nil?
|
352
|
+
@logger.debug "kernel updated from not set to '#{config.kernel}'"
|
353
|
+
descr_changed = true
|
354
|
+
kernel = REXML::Element.new('kernel', REXML::XPath.first(xml_descr, '/domain/os'))
|
355
|
+
kernel.text = config.kernel
|
356
|
+
else
|
357
|
+
if (kernel.text or '').strip != config.kernel
|
358
|
+
@logger.debug "kernel updated from '#{kernel.text}' to '#{config.kernel}'"
|
359
|
+
descr_changed = true
|
360
|
+
kernel.text = config.kernel
|
360
361
|
end
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
if (initrd.text or '').strip != config.initrd
|
372
|
-
@logger.debug "initrd updated from '#{initrd.text}' to '#{config.initrd}'"
|
373
|
-
descr_changed = true
|
374
|
-
initrd.text = config.initrd
|
375
|
-
end
|
376
|
-
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
if config.initrd
|
365
|
+
initrd = REXML::XPath.first(xml_descr, '/domain/os/initrd')
|
366
|
+
if initrd.nil?
|
367
|
+
if config.initrd.strip != ''
|
368
|
+
@logger.debug "initrd updated from not set to '#{config.initrd}'"
|
369
|
+
descr_changed = true
|
370
|
+
initrd = REXML::Element.new('initrd', REXML::XPath.first(xml_descr, '/domain/os'))
|
371
|
+
initrd.text = config.initrd
|
377
372
|
end
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
if loader.nil?
|
382
|
-
descr_changed = true
|
383
|
-
loader = REXML::Element.new('loader')
|
384
|
-
REXML::XPath.first(xml_descr, '/domain/os').insert_after('//type', loader)
|
385
|
-
loader.text = config.loader
|
386
|
-
else
|
387
|
-
if (loader.text or '').strip != config.loader
|
388
|
-
descr_changed = true
|
389
|
-
loader.text = config.loader
|
390
|
-
end
|
391
|
-
end
|
392
|
-
loader.attributes['type'] = config.nvram ? 'pflash' : 'rom'
|
393
|
-
elsif !loader.nil?
|
373
|
+
else
|
374
|
+
if (initrd.text or '').strip != config.initrd
|
375
|
+
@logger.debug "initrd updated from '#{initrd.text}' to '#{config.initrd}'"
|
394
376
|
descr_changed = true
|
395
|
-
|
377
|
+
initrd.text = config.initrd
|
396
378
|
end
|
379
|
+
end
|
380
|
+
end
|
397
381
|
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
descr_changed = true
|
408
|
-
nvram.text = config.nvram
|
409
|
-
end
|
410
|
-
end
|
411
|
-
elsif !nvram.nil?
|
382
|
+
loader = REXML::XPath.first(xml_descr, '/domain/os/loader')
|
383
|
+
if config.loader
|
384
|
+
if loader.nil?
|
385
|
+
descr_changed = true
|
386
|
+
loader = REXML::Element.new('loader')
|
387
|
+
REXML::XPath.first(xml_descr, '/domain/os').insert_after('//type', loader)
|
388
|
+
loader.text = config.loader
|
389
|
+
else
|
390
|
+
if (loader.text or '').strip != config.loader
|
412
391
|
descr_changed = true
|
413
|
-
|
392
|
+
loader.text = config.loader
|
414
393
|
end
|
394
|
+
end
|
395
|
+
loader.attributes['type'] = config.nvram ? 'pflash' : 'rom'
|
396
|
+
elsif !loader.nil?
|
397
|
+
descr_changed = true
|
398
|
+
loader.parent.delete_element(loader)
|
399
|
+
end
|
415
400
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
401
|
+
nvram = REXML::XPath.first(xml_descr, '/domain/os/nvram')
|
402
|
+
if config.nvram
|
403
|
+
if nvram.nil?
|
404
|
+
descr_changed = true
|
405
|
+
nvram = REXML::Element.new('nvram')
|
406
|
+
REXML::XPath.first(xml_descr, '/domain/os').insert_after(loader, nvram)
|
407
|
+
nvram.text = config.nvram
|
408
|
+
else
|
409
|
+
if (nvram.text or '').strip != config.nvram
|
410
|
+
descr_changed = true
|
411
|
+
nvram.text = config.nvram
|
412
|
+
end
|
413
|
+
end
|
414
|
+
elsif !nvram.nil?
|
415
|
+
descr_changed = true
|
416
|
+
nvram.parent.delete_element(nvram)
|
417
|
+
end
|
430
418
|
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
419
|
+
# Apply
|
420
|
+
if descr_changed
|
421
|
+
env[:ui].info(I18n.t('vagrant_libvirt.updating_domain'))
|
422
|
+
new_xml = String.new
|
423
|
+
xml_descr.write(new_xml)
|
424
|
+
begin
|
425
|
+
# providing XML for the same name and UUID will update the existing domain
|
426
|
+
libvirt_domain = env[:machine].provider.driver.connection.define_domain(new_xml)
|
427
|
+
rescue ::Libvirt::Error => e
|
428
|
+
env[:ui].error("Error when updating domain settings: #{e.message}")
|
429
|
+
raise Errors::UpdateServerError, error_message: e.message
|
430
|
+
end
|
436
431
|
|
437
|
-
|
438
|
-
|
432
|
+
# need to check whether the updated XML contains all the changes requested
|
433
|
+
proposed = VagrantPlugins::ProviderLibvirt::Util::Xml.new(new_xml)
|
434
|
+
applied = VagrantPlugins::ProviderLibvirt::Util::Xml.new(libvirt_domain.xml_desc(1))
|
439
435
|
|
440
|
-
|
441
|
-
|
436
|
+
if proposed != applied
|
437
|
+
require 'diffy'
|
442
438
|
|
443
|
-
|
444
|
-
# the output with diffy appears to be clearer
|
445
|
-
pretty_proposed = StringIO.new
|
446
|
-
pretty_applied = StringIO.new
|
447
|
-
proposed.write_xml_to(pretty_proposed, indent: 2)
|
448
|
-
applied.write_xml_to(pretty_applied, indent: 2)
|
439
|
+
diff = Diffy::Diff.new(proposed.to_str, applied.to_str, :context => 3).to_s(:text)
|
449
440
|
|
450
|
-
|
441
|
+
error_msg = "Libvirt failed to fully update the domain with the specified XML. Result differs from requested:\n" +
|
442
|
+
"--- requested\n+++ result\n#{diff}\n" +
|
443
|
+
"Typically this means there is a bug in the XML being sent, please log an issue as this will halt machine start in the future."
|
451
444
|
|
452
|
-
|
453
|
-
|
454
|
-
|
445
|
+
env[:ui].warn(error_msg)
|
446
|
+
#env[:ui].error("Updated domain settings did not fully apply, attempting restore to previous definition: #{error_msg}")
|
447
|
+
#begin
|
448
|
+
# env[:machine].provider.driver.connection.define_domain(descr)
|
449
|
+
#rescue Fog::Errors::Error => e
|
450
|
+
# env[:ui].error("Failed to restore previous domain definition: #{e.message}")
|
451
|
+
#end
|
455
452
|
|
456
|
-
|
457
|
-
end
|
458
|
-
rescue Exception => e
|
459
|
-
env[:machine].provider.driver.connection.define_domain(descr)
|
460
|
-
raise
|
461
|
-
end
|
462
|
-
end
|
463
|
-
rescue Errors::VagrantLibvirtError => e
|
464
|
-
env[:ui].error("Error when updating domain settings: #{e.message}")
|
465
|
-
raise
|
453
|
+
#raise Errors::UpdateServerError, error_message: error_msg
|
466
454
|
end
|
455
|
+
end
|
456
|
+
|
457
|
+
begin
|
467
458
|
# Autostart with host if enabled in Vagrantfile
|
468
459
|
libvirt_domain.autostart = config.autostart
|
469
460
|
@logger.debug {
|
@@ -473,7 +464,7 @@ module VagrantPlugins
|
|
473
464
|
env[:ui].info(I18n.t('vagrant_libvirt.starting_domain'))
|
474
465
|
domain.start
|
475
466
|
rescue Fog::Errors::Error, Errors::VagrantLibvirtError => e
|
476
|
-
raise Errors::
|
467
|
+
raise Errors::DomainStartError, error_message: e.message
|
477
468
|
end
|
478
469
|
|
479
470
|
@app.call(env)
|