lib/vagrant-libvirt/action/start_domain.rb in vagrant-libvirt-0.3.0 vs lib/vagrant-libvirt/action/start_domain.rb in vagrant-libvirt-0.4.0

- old
+ new

@@ -35,110 +35,156 @@ # XML definition manipulation descr = libvirt_domain.xml_desc(1) xml_descr = REXML::Document.new descr descr_changed = false + # For outputting XML for comparison + formatter = REXML::Formatters::Pretty.new + # additional disk bus config.disks.each do |disk| device = disk[:device] bus = disk[:bus] REXML::XPath.each(xml_descr, '/domain/devices/disk[@device="disk"]/target[@dev="' + device + '"]') do |disk_target| next unless disk_target.attributes['bus'] != bus + @logger.debug "disk #{device} bus updated from '#{disk_target.attributes['bus']}' to '#{bus}'" descr_changed = true disk_target.attributes['bus'] = bus disk_target.parent.delete_element("#{disk_target.parent.xpath}/address") end end # disk_bus REXML::XPath.each(xml_descr, '/domain/devices/disk[@device="disk"]/target[@dev="vda"]') do |disk_target| next unless disk_target.attributes['bus'] != config.disk_bus + @logger.debug "domain disk bus updated from '#{disk_target.attributes['bus']}' to '#{bus}'" descr_changed = true disk_target.attributes['bus'] = config.disk_bus disk_target.parent.delete_element("#{disk_target.parent.xpath}/address") end # Iterface type unless config.nic_model_type.nil? REXML::XPath.each(xml_descr, '/domain/devices/interface/model') do |iface_model| if iface_model.attributes['type'] != config.nic_model_type + @logger.debug "network type updated from '#{iface_model.attributes['type']}' to '#{config.nic_model_type}'" descr_changed = true iface_model.attributes['type'] = config.nic_model_type end end end # vCpu count - if config.cpus.to_i != libvirt_domain.num_vcpus(0) + vcpus_count = libvirt_domain.num_vcpus(0) + if config.cpus.to_i != vcpus_count + @logger.debug "cpu count updated from '#{vcpus_count}' to '#{config.cpus}'" descr_changed = true REXML::XPath.first(xml_descr, '/domain/vcpu').text = config.cpus end # cpu_mode cpu = REXML::XPath.first(xml_descr, '/domain/cpu') if cpu.nil? + @logger.debug "cpu_mode updated from not set to '#{config.cpu_mode}'" descr_changed = true cpu = REXML::Element.new('cpu', REXML::XPath.first(xml_descr, '/domain')) cpu.attributes['mode'] = config.cpu_mode else if cpu.attributes['mode'] != config.cpu_mode + @logger.debug "cpu_mode updated from '#{cpu.attributes['mode']}' to '#{config.cpu_mode}'" descr_changed = true cpu.attributes['mode'] = config.cpu_mode end end if config.cpu_mode != 'host-passthrough' cpu_model = REXML::XPath.first(xml_descr, '/domain/cpu/model') if cpu_model.nil? + @logger.debug "cpu_model updated from not set to '#{config.cpu_model}'" descr_changed = true cpu_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/cpu')) cpu_model.attributes['fallback'] = 'allow' cpu_model.text = config.cpu_model else - if cpu_model.text.strip != config.cpu_model.strip + if (cpu_model.text or '').strip != config.cpu_model.strip + @logger.debug "cpu_model text updated from #{cpu_model.text} to '#{config.cpu_model}'" descr_changed = true cpu_model.text = config.cpu_model end if cpu_model.attributes['fallback'] != config.cpu_fallback + @logger.debug "cpu_model fallback attribute updated from #{cpu_model.attributes['fallback']} to '#{config.cpu_fallback}'" descr_changed = true cpu_model.attributes['fallback'] = config.cpu_fallback end end vmx_feature = REXML::XPath.first(xml_descr, '/domain/cpu/feature[@name="vmx"]') svm_feature = REXML::XPath.first(xml_descr, '/domain/cpu/feature[@name="svm"]') if config.nested if vmx_feature.nil? + @logger.debug "nested mode enabled from unset by setting cpu vmx feature" descr_changed = true vmx_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr, '/domain/cpu')) vmx_feature.attributes['policy'] = 'optional' vmx_feature.attributes['name'] = 'vmx' end if svm_feature.nil? + @logger.debug "nested mode enabled from unset by setting cpu svm feature" descr_changed = true svm_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr, '/domain/cpu')) svm_feature.attributes['policy'] = 'optional' svm_feature.attributes['name'] = 'svm' end else unless vmx_feature.nil? + @logger.debug "nested mode disabled for cpu by removing vmx feature" descr_changed = true cpu.delete_element(vmx_feature) end unless svm_feature.nil? + @logger.debug "nested mode disabled for cpu by removing svm feature" descr_changed = true cpu.delete_element(svm_feature) end end elsif config.numa_nodes == nil unless cpu.elements.to_a.empty? + @logger.debug "switching cpu_mode to host-passthrough and removing emulated cpu features" descr_changed = true cpu.elements.each do |elem| cpu.delete_element(elem) end end end + # Clock + clock = REXML::XPath.first(xml_descr, '/domain/clock') + if clock.attributes['offset'] != config.clock_offset + @logger.debug "clock offset changed" + descr_changed = true + clock.attributes['offset'] = config.clock_offset + end + + # clock timers - because timers can be added/removed, just rebuild and then compare + if !config.clock_timers.empty? || clock.has_elements? + oldclock = '' + formatter.write(REXML::XPath.first(xml_descr, '/domain/clock'), oldclock) + clock.delete_element('//timer') + config.clock_timers.each do |clock_timer| + timer = REXML::Element.new('timer', clock) + clock_timer.each do |attr, value| + timer.attributes[attr.to_s] = value + end + end + + newclock = '' + formatter.write(clock, newclock) + unless newclock.eql? oldclock + @logger.debug "clock timers config changed" + descr_changed = true + end + end + # Graphics graphics = REXML::XPath.first(xml_descr, '/domain/devices/graphics') if config.graphics_type != 'none' if graphics.nil? descr_changed = true @@ -176,52 +222,57 @@ # graphics_type = none, remove entire element graphics.parent.delete_element(graphics) unless graphics.nil? end # TPM - if config.tpm_path - raise Errors::FogCreateServerError, 'The TPM Path must be fully qualified' unless config.tpm_path[0].chr == '/' + if [config.tpm_path, config.tpm_version].any? + if config.tpm_path + raise Errors::FogCreateServerError, 'The TPM Path must be fully qualified' unless config.tpm_path[0].chr == '/' + end - tpm = REXML::XPath.first(xml_descr, '/domain/devices/tpm') - if tpm.nil? + # just build the tpm element every time + # check at the end if it is different + oldtpm = REXML::XPath.first(xml_descr, '/domain/devices/tpm') + REXML::XPath.first(xml_descr, '/domain/devices').delete_element("tpm") + newtpm = REXML::Element.new('tpm', REXML::XPath.first(xml_descr, '/domain/devices')) + + newtpm.attributes['model'] = config.tpm_model + backend = newtpm.add_element('backend') + backend.attributes['type'] = config.tpm_type + + case config.tpm_type + when 'emulator' + backend.attributes['version'] = config.tpm_version + when 'passthrough' + backend.add_element('device').attributes['path'] = config.tpm_path + end + + unless "'#{newtpm}'".eql? "'#{oldtpm}'" + @logger.debug "tpm config changed" descr_changed = true - tpm = REXML::Element.new('tpm', REXML::XPath.first(xml_descr, '/domain/devices/tpm/model')) - tpm.attributes['model'] = config.tpm_model - tpm_backend_type = tpm.add_element('backend') - tpm_backend_type.attributes['type'] = config.tpm_type - tpm_device_path = tpm_backend_type.add_element('device') - tpm_device_path.attributes['path'] = config.tpm_path - else - if tpm.attributes['model'] != config.tpm_model - descr_changed = true - tpm.attributes['model'] = config.tpm_model - end - if tpm.elements['backend'].attributes['type'] != config.tpm_type - descr_changed = true - tpm.elements['backend'].attributes['type'] = config.tpm_type - end - if tpm.elements['backend'].elements['device'].attributes['path'] != config.tpm_path - descr_changed = true - tpm.elements['backend'].elements['device'].attributes['path'] = config.tpm_path - end end end # Video device video = REXML::XPath.first(xml_descr, '/domain/devices/video') if !video.nil? && (config.graphics_type == 'none') # graphics_type = none, video devices are removed since there is no possible output + @logger.debug "deleting video elements as config.graphics_type is none" descr_changed = true video.parent.delete_element(video) else video_model = REXML::XPath.first(xml_descr, '/domain/devices/video/model') if video_model.nil? + @logger.debug "video updated from not set to type '#{config.video_type}' and vram '#{config.video_vram}'" + descr_changed = true video_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/devices/video')) video_model.attributes['type'] = config.video_type video_model.attributes['vram'] = config.video_vram else - if video_model.attributes['type'] != config.video_type || video_model.attributes['vram'] != config.video_vram + if video_model.attributes['type'] != config.video_type || video_model.attributes['vram'] != config.video_vram.to_s + @logger.debug "video type updated from '#{video_model.attributes['type']}' to '#{config.video_type}'" + @logger.debug "video vram updated from '#{video_model.attributes['vram']}' to '#{config.video_vram}'" descr_changed = true video_model.attributes['type'] = config.video_type video_model.attributes['vram'] = config.video_vram end end @@ -235,42 +286,48 @@ # dtb if config.dtb dtb = REXML::XPath.first(xml_descr, '/domain/os/dtb') if dtb.nil? + @logger.debug "dtb updated from not set to '#{config.dtb}'" descr_changed = true dtb = REXML::Element.new('dtb', REXML::XPath.first(xml_descr, '/domain/os')) dtb.text = config.dtb else - if dtb.text != config.dtb + if (dtb.text or '') != config.dtb + @logger.debug "dtb updated from '#{dtb.text}' to '#{config.dtb}'" descr_changed = true dtb.text = config.dtb end end end # kernel and initrd if config.kernel kernel = REXML::XPath.first(xml_descr, '/domain/os/kernel') if kernel.nil? + @logger.debug "kernel updated from not set to '#{config.kernel}'" descr_changed = true kernel = REXML::Element.new('kernel', REXML::XPath.first(xml_descr, '/domain/os')) kernel.text = config.kernel else - if kernel.text != config.kernel + if (kernel.text or '').strip != config.kernel + @logger.debug "kernel updated from '#{kernel.text}' to '#{config.kernel}'" descr_changed = true kernel.text = config.kernel end end end if config.initrd initrd = REXML::XPath.first(xml_descr, '/domain/os/initrd') if initrd.nil? + @logger.debug "initrd updated from not set to '#{config.initrd}'" descr_changed = true initrd = REXML::Element.new('initrd', REXML::XPath.first(xml_descr, '/domain/os')) initrd.text = config.initrd else - if initrd.text != config.initrd + if (initrd.text or '').strip != config.initrd + @logger.debug "initrd updated from '#{initrd.text}' to '#{config.initrd}'" descr_changed = true initrd.text = config.initrd end end end