diff --git a/lib/nova_plugins/functions-libvirt b/lib/nova_plugins/functions-libvirt index 4d617e8b5e..763afaf596 100644 --- a/lib/nova_plugins/functions-libvirt +++ b/lib/nova_plugins/functions-libvirt @@ -110,10 +110,18 @@ EOF fi fi + # Update the libvirt cpu map with a gate64 cpu model. This enables nova + # live migration for 64bit guest OSes on heterogenous cloud "hardware". + if [[ -f /usr/share/libvirt/cpu_map.xml ]] ; then + sudo $TOP_DIR/tools/cpu_map_update.py /usr/share/libvirt/cpu_map.xml + fi + # libvirt detects various settings on startup, as we potentially changed # the system configuration (modules, filesystems), we need to restart - # libvirt to detect those changes. - restart_service $LIBVIRT_DAEMON + # libvirt to detect those changes. Use a stop start as otherwise the new + # cpu_map is not loaded properly on some systems (Ubuntu). + stop_service $LIBVIRT_DAEMON + start_service $LIBVIRT_DAEMON } diff --git a/tools/cpu_map_update.py b/tools/cpu_map_update.py new file mode 100755 index 0000000000..1938793114 --- /dev/null +++ b/tools/cpu_map_update.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# This small script updates the libvirt CPU map to add a gate64 cpu model +# that can be used to enable a common 64bit capable feature set across +# devstack nodes so that features like nova live migration work. + +import sys +import xml.etree.ElementTree as ET +from xml.dom import minidom + + +def update_cpu_map(tree): + root = tree.getroot() + cpus = root#.find("cpus") + x86 = None + for arch in cpus.findall("arch"): + if arch.get("name") == "x86": + x86 = arch + break + if x86 is not None: + # Create a gate64 cpu model that is core2duo less monitor and pse36 + gate64 = ET.SubElement(x86, "model") + gate64.set("name", "gate64") + ET.SubElement(gate64, "vendor").set("name", "Intel") + ET.SubElement(gate64, "feature").set("name", "fpu") + ET.SubElement(gate64, "feature").set("name", "de") + ET.SubElement(gate64, "feature").set("name", "pse") + ET.SubElement(gate64, "feature").set("name", "tsc") + ET.SubElement(gate64, "feature").set("name", "msr") + ET.SubElement(gate64, "feature").set("name", "pae") + ET.SubElement(gate64, "feature").set("name", "mce") + ET.SubElement(gate64, "feature").set("name", "cx8") + ET.SubElement(gate64, "feature").set("name", "apic") + ET.SubElement(gate64, "feature").set("name", "sep") + ET.SubElement(gate64, "feature").set("name", "pge") + ET.SubElement(gate64, "feature").set("name", "cmov") + ET.SubElement(gate64, "feature").set("name", "pat") + ET.SubElement(gate64, "feature").set("name", "mmx") + ET.SubElement(gate64, "feature").set("name", "fxsr") + ET.SubElement(gate64, "feature").set("name", "sse") + ET.SubElement(gate64, "feature").set("name", "sse2") + ET.SubElement(gate64, "feature").set("name", "vme") + ET.SubElement(gate64, "feature").set("name", "mtrr") + ET.SubElement(gate64, "feature").set("name", "mca") + ET.SubElement(gate64, "feature").set("name", "clflush") + ET.SubElement(gate64, "feature").set("name", "pni") + ET.SubElement(gate64, "feature").set("name", "nx") + ET.SubElement(gate64, "feature").set("name", "ssse3") + ET.SubElement(gate64, "feature").set("name", "syscall") + ET.SubElement(gate64, "feature").set("name", "lm") + + +def format_xml(root): + # Adapted from http://pymotw.com/2/xml/etree/ElementTree/create.html + # thank you dhellmann + rough_string = ET.tostring(root, encoding="UTF-8") + dom_parsed = minidom.parseString(rough_string) + return dom_parsed.toprettyxml(" ", encoding="UTF-8") + + +def main(): + if len(sys.argv) != 2: + raise Exception("Must pass path to cpu_map.xml to update") + cpu_map = sys.argv[1] + tree = ET.parse(cpu_map) + for model in tree.getroot().iter("model"): + if model.get("name") == "gate64": + # gate64 model is already present + return + update_cpu_map(tree) + pretty_xml = format_xml(tree.getroot()) + with open(cpu_map, 'w') as f: + f.write(pretty_xml) + + +if __name__ == "__main__": + main()