vagrant-libvirt 0.10.6 → 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 +382 -379
- 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/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 +7 -4
- data/spec/unit/plugin_spec.rb +1 -0
- metadata +80 -74
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
require 'log4r'
|
|
4
4
|
|
|
5
5
|
require 'rexml/document'
|
|
6
|
+
require 'rexml/formatters/pretty'
|
|
7
|
+
require 'rexml/xpath'
|
|
6
8
|
|
|
7
9
|
require 'vagrant-libvirt/util/xml'
|
|
8
10
|
|
|
@@ -20,438 +22,439 @@ module VagrantPlugins
|
|
|
20
22
|
def call(env)
|
|
21
23
|
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
|
|
22
24
|
raise Errors::NoDomainError if domain.nil?
|
|
25
|
+
|
|
23
26
|
config = env[:machine].provider_config
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
# update domain settings on change.
|
|
29
|
+
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
|
|
27
30
|
|
|
28
|
-
|
|
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
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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")
|
|
37
58
|
end
|
|
59
|
+
end
|
|
38
60
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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")
|
|
58
|
-
end
|
|
59
|
-
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
|
|
60
69
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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}'"
|
|
65
75
|
descr_changed = true
|
|
66
|
-
|
|
67
|
-
disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
|
|
76
|
+
iface_model.attributes['type'] = config.nic_model_type
|
|
68
77
|
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
69
80
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
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
|
|
80
88
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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}'"
|
|
85
109
|
descr_changed = true
|
|
86
|
-
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
|
|
87
113
|
end
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if cpu.nil?
|
|
92
|
-
@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}'"
|
|
93
117
|
descr_changed = true
|
|
94
|
-
|
|
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
|
|
118
|
+
cpu_model.text = config.cpu_model
|
|
102
119
|
end
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if config.cpu_model.strip != ''
|
|
108
|
-
@logger.debug "cpu_model updated from not set to '#{config.cpu_model}'"
|
|
109
|
-
descr_changed = true
|
|
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
|
|
113
|
-
end
|
|
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}'"
|
|
117
|
-
descr_changed = true
|
|
118
|
-
cpu_model.text = config.cpu_model
|
|
119
|
-
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
|
|
124
|
-
end
|
|
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"
|
|
131
|
-
descr_changed = true
|
|
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'
|
|
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
|
|
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
|
|
163
124
|
end
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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"
|
|
131
|
+
descr_changed = true
|
|
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'
|
|
135
|
+
end
|
|
136
|
+
if svm_feature.nil?
|
|
137
|
+
@logger.debug "nested mode enabled from unset by setting cpu svm feature"
|
|
169
138
|
descr_changed = true
|
|
170
|
-
|
|
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'
|
|
171
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
|
|
172
164
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
clock_timer.each do |attr, value|
|
|
181
|
-
timer.attributes[attr.to_s] = value
|
|
182
|
-
end
|
|
183
|
-
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
|
|
184
172
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
|
191
182
|
end
|
|
183
|
+
end
|
|
192
184
|
|
|
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
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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'
|
|
221
240
|
descr_changed = true
|
|
222
|
-
if config.graphics_passwd.nil?
|
|
223
|
-
graphics.attributes.delete 'passwd'
|
|
224
|
-
else
|
|
225
|
-
graphics.attributes['passwd'] = config.graphics_passwd
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
graphics_gl = REXML::XPath.first(xml_descr, '/domain/devices/graphics/gl')
|
|
229
|
-
if graphics_gl.nil?
|
|
230
|
-
if config.graphics_gl
|
|
231
|
-
graphics_gl = REXML::Element.new('gl', REXML::XPath.first(xml_descr, '/domain/devices/graphics'))
|
|
232
|
-
graphics_gl.attributes['enable'] = 'yes'
|
|
233
|
-
descr_changed = true
|
|
234
|
-
end
|
|
235
|
-
else
|
|
236
|
-
if config.graphics_gl
|
|
237
|
-
if graphics_gl.attributes['enable'] != 'yes'
|
|
238
|
-
graphics_gl.attributes['enable'] = 'yes'
|
|
239
|
-
descr_changed = true
|
|
240
|
-
end
|
|
241
|
-
else
|
|
242
|
-
graphics_gl.parent.delete_element(graphics_gl)
|
|
243
|
-
descr_changed = true
|
|
244
|
-
end
|
|
245
241
|
end
|
|
246
242
|
else
|
|
247
|
-
|
|
248
|
-
|
|
243
|
+
graphics_gl.parent.delete_element(graphics_gl)
|
|
244
|
+
descr_changed = true
|
|
249
245
|
end
|
|
246
|
+
end
|
|
247
|
+
else
|
|
248
|
+
# graphics_type = none, remove entire element
|
|
249
|
+
graphics.parent.delete_element(graphics) unless graphics.nil?
|
|
250
|
+
end
|
|
250
251
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
|
256
257
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
|
273
274
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
275
|
+
unless "'#{newtpm}'".eql? "'#{oldtpm}'"
|
|
276
|
+
@logger.debug "tpm config changed"
|
|
277
|
+
descr_changed = true
|
|
278
|
+
end
|
|
279
|
+
end
|
|
279
280
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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}'"
|
|
285
300
|
descr_changed = true
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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'
|
|
291
316
|
descr_changed = true
|
|
292
|
-
video_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/devices/video'))
|
|
293
|
-
video_model.attributes['type'] = config.video_type
|
|
294
|
-
video_model.attributes['vram'] = config.video_vram
|
|
295
|
-
else
|
|
296
|
-
if video_model.attributes['type'] != config.video_type || video_model.attributes['vram'] != config.video_vram.to_s
|
|
297
|
-
@logger.debug "video type updated from '#{video_model.attributes['type']}' to '#{config.video_type}'"
|
|
298
|
-
@logger.debug "video vram updated from '#{video_model.attributes['vram']}' to '#{config.video_vram}'"
|
|
299
|
-
descr_changed = true
|
|
300
|
-
video_model.attributes['type'] = config.video_type
|
|
301
|
-
video_model.attributes['vram'] = config.video_vram
|
|
302
|
-
end
|
|
303
|
-
end
|
|
304
|
-
video_accel = REXML::XPath.first(xml_descr, '/domain/devices/video/model/acceleration')
|
|
305
|
-
if video_accel.nil?
|
|
306
|
-
if config.video_accel3d
|
|
307
|
-
video_accel = REXML::Element.new('acceleration', REXML::XPath.first(xml_descr, '/domain/devices/video/model'))
|
|
308
|
-
video_accel.attributes['accel3d'] = 'yes'
|
|
309
|
-
descr_changed = true
|
|
310
|
-
end
|
|
311
|
-
else
|
|
312
|
-
if config.video_accel3d
|
|
313
|
-
if video_accel.attributes['accel3d'] != 'yes'
|
|
314
|
-
video_accel.attributes['accel3d'] = 'yes'
|
|
315
|
-
descr_changed = true
|
|
316
|
-
end
|
|
317
|
-
else
|
|
318
|
-
video_accel.parent.delete_element(video_accel)
|
|
319
|
-
descr_changed = true
|
|
320
|
-
end
|
|
321
317
|
end
|
|
318
|
+
else
|
|
319
|
+
video_accel.parent.delete_element(video_accel)
|
|
320
|
+
descr_changed = true
|
|
322
321
|
end
|
|
322
|
+
end
|
|
323
|
+
end
|
|
323
324
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
325
|
+
# Sound device
|
|
326
|
+
if config.sound_type
|
|
327
|
+
sound = REXML::XPath.first(xml_descr,'/domain/devices/sound/model')
|
|
328
|
+
end
|
|
328
329
|
|
|
329
330
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
end
|
|
344
|
-
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
|
|
345
344
|
end
|
|
345
|
+
end
|
|
346
|
+
end
|
|
346
347
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
end
|
|
361
|
-
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
|
|
362
361
|
end
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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
|
|
372
|
+
end
|
|
373
|
+
else
|
|
374
|
+
if (initrd.text or '').strip != config.initrd
|
|
375
|
+
@logger.debug "initrd updated from '#{initrd.text}' to '#{config.initrd}'"
|
|
376
|
+
descr_changed = true
|
|
377
|
+
initrd.text = config.initrd
|
|
379
378
|
end
|
|
379
|
+
end
|
|
380
|
+
end
|
|
380
381
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
descr_changed = true
|
|
391
|
-
loader.text = config.loader
|
|
392
|
-
end
|
|
393
|
-
end
|
|
394
|
-
loader.attributes['type'] = config.nvram ? 'pflash' : 'rom'
|
|
395
|
-
elsif !loader.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
|
|
396
391
|
descr_changed = true
|
|
397
|
-
loader.
|
|
392
|
+
loader.text = config.loader
|
|
398
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
|
|
399
400
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
descr_changed = true
|
|
410
|
-
nvram.text = config.nvram
|
|
411
|
-
end
|
|
412
|
-
end
|
|
413
|
-
elsif !nvram.nil?
|
|
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
|
|
414
410
|
descr_changed = true
|
|
415
|
-
nvram.
|
|
411
|
+
nvram.text = config.nvram
|
|
416
412
|
end
|
|
413
|
+
end
|
|
414
|
+
elsif !nvram.nil?
|
|
415
|
+
descr_changed = true
|
|
416
|
+
nvram.parent.delete_element(nvram)
|
|
417
|
+
end
|
|
417
418
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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
|
|
429
431
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
applied = VagrantPlugins::ProviderLibvirt::Util::Xml.new(libvirt_domain.xml_desc(1))
|
|
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))
|
|
434
435
|
|
|
435
|
-
|
|
436
|
-
|
|
436
|
+
if proposed != applied
|
|
437
|
+
require 'diffy'
|
|
437
438
|
|
|
438
|
-
|
|
439
|
+
diff = Diffy::Diff.new(proposed.to_str, applied.to_str, :context => 3).to_s(:text)
|
|
439
440
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
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."
|
|
443
444
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
end
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
raise
|
|
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
|
|
452
|
+
|
|
453
|
+
#raise Errors::UpdateServerError, error_message: error_msg
|
|
454
454
|
end
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
begin
|
|
455
458
|
# Autostart with host if enabled in Vagrantfile
|
|
456
459
|
libvirt_domain.autostart = config.autostart
|
|
457
460
|
@logger.debug {
|
|
@@ -461,7 +464,7 @@ module VagrantPlugins
|
|
|
461
464
|
env[:ui].info(I18n.t('vagrant_libvirt.starting_domain'))
|
|
462
465
|
domain.start
|
|
463
466
|
rescue Fog::Errors::Error, Errors::VagrantLibvirtError => e
|
|
464
|
-
raise Errors::
|
|
467
|
+
raise Errors::DomainStartError, error_message: e.message
|
|
465
468
|
end
|
|
466
469
|
|
|
467
470
|
@app.call(env)
|