| ... | ... |
@@ -115,10 +115,18 @@ EOF |
| 115 | 115 |
fi |
| 116 | 116 |
fi |
| 117 | 117 |
|
| 118 |
+ # Update the libvirt cpu map with a gate64 cpu model. This enables nova |
|
| 119 |
+ # live migration for 64bit guest OSes on heterogenous cloud "hardware". |
|
| 120 |
+ if [[ -f /usr/share/libvirt/cpu_map.xml ]] ; then |
|
| 121 |
+ sudo $TOP_DIR/tools/cpu_map_update.py /usr/share/libvirt/cpu_map.xml |
|
| 122 |
+ fi |
|
| 123 |
+ |
|
| 118 | 124 |
# libvirt detects various settings on startup, as we potentially changed |
| 119 | 125 |
# the system configuration (modules, filesystems), we need to restart |
| 120 |
- # libvirt to detect those changes. |
|
| 121 |
- restart_service $LIBVIRT_DAEMON |
|
| 126 |
+ # libvirt to detect those changes. Use a stop start as otherwise the new |
|
| 127 |
+ # cpu_map is not loaded properly on some systems (Ubuntu). |
|
| 128 |
+ stop_service $LIBVIRT_DAEMON |
|
| 129 |
+ start_service $LIBVIRT_DAEMON |
|
| 122 | 130 |
} |
| 123 | 131 |
|
| 124 | 132 |
|
| 125 | 133 |
new file mode 100755 |
| ... | ... |
@@ -0,0 +1,89 @@ |
| 0 |
+#!/usr/bin/env python |
|
| 1 |
+# |
|
| 2 |
+# Licensed under the Apache License, Version 2.0 (the "License"); you may |
|
| 3 |
+# not use this file except in compliance with the License. You may obtain |
|
| 4 |
+# a copy of the License at |
|
| 5 |
+# |
|
| 6 |
+# http://www.apache.org/licenses/LICENSE-2.0 |
|
| 7 |
+# |
|
| 8 |
+# Unless required by applicable law or agreed to in writing, software |
|
| 9 |
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
|
| 10 |
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
|
| 11 |
+# License for the specific language governing permissions and limitations |
|
| 12 |
+# under the License. |
|
| 13 |
+ |
|
| 14 |
+# This small script updates the libvirt CPU map to add a gate64 cpu model |
|
| 15 |
+# that can be used to enable a common 64bit capable feature set across |
|
| 16 |
+# devstack nodes so that features like nova live migration work. |
|
| 17 |
+ |
|
| 18 |
+import sys |
|
| 19 |
+import xml.etree.ElementTree as ET |
|
| 20 |
+from xml.dom import minidom |
|
| 21 |
+ |
|
| 22 |
+ |
|
| 23 |
+def update_cpu_map(tree): |
|
| 24 |
+ root = tree.getroot() |
|
| 25 |
+ cpus = root#.find("cpus")
|
|
| 26 |
+ x86 = None |
|
| 27 |
+ for arch in cpus.findall("arch"):
|
|
| 28 |
+ if arch.get("name") == "x86":
|
|
| 29 |
+ x86 = arch |
|
| 30 |
+ break |
|
| 31 |
+ if x86 is not None: |
|
| 32 |
+ # Create a gate64 cpu model that is core2duo less monitor and pse36 |
|
| 33 |
+ gate64 = ET.SubElement(x86, "model") |
|
| 34 |
+ gate64.set("name", "gate64")
|
|
| 35 |
+ ET.SubElement(gate64, "vendor").set("name", "Intel")
|
|
| 36 |
+ ET.SubElement(gate64, "feature").set("name", "fpu")
|
|
| 37 |
+ ET.SubElement(gate64, "feature").set("name", "de")
|
|
| 38 |
+ ET.SubElement(gate64, "feature").set("name", "pse")
|
|
| 39 |
+ ET.SubElement(gate64, "feature").set("name", "tsc")
|
|
| 40 |
+ ET.SubElement(gate64, "feature").set("name", "msr")
|
|
| 41 |
+ ET.SubElement(gate64, "feature").set("name", "pae")
|
|
| 42 |
+ ET.SubElement(gate64, "feature").set("name", "mce")
|
|
| 43 |
+ ET.SubElement(gate64, "feature").set("name", "cx8")
|
|
| 44 |
+ ET.SubElement(gate64, "feature").set("name", "apic")
|
|
| 45 |
+ ET.SubElement(gate64, "feature").set("name", "sep")
|
|
| 46 |
+ ET.SubElement(gate64, "feature").set("name", "pge")
|
|
| 47 |
+ ET.SubElement(gate64, "feature").set("name", "cmov")
|
|
| 48 |
+ ET.SubElement(gate64, "feature").set("name", "pat")
|
|
| 49 |
+ ET.SubElement(gate64, "feature").set("name", "mmx")
|
|
| 50 |
+ ET.SubElement(gate64, "feature").set("name", "fxsr")
|
|
| 51 |
+ ET.SubElement(gate64, "feature").set("name", "sse")
|
|
| 52 |
+ ET.SubElement(gate64, "feature").set("name", "sse2")
|
|
| 53 |
+ ET.SubElement(gate64, "feature").set("name", "vme")
|
|
| 54 |
+ ET.SubElement(gate64, "feature").set("name", "mtrr")
|
|
| 55 |
+ ET.SubElement(gate64, "feature").set("name", "mca")
|
|
| 56 |
+ ET.SubElement(gate64, "feature").set("name", "clflush")
|
|
| 57 |
+ ET.SubElement(gate64, "feature").set("name", "pni")
|
|
| 58 |
+ ET.SubElement(gate64, "feature").set("name", "nx")
|
|
| 59 |
+ ET.SubElement(gate64, "feature").set("name", "ssse3")
|
|
| 60 |
+ ET.SubElement(gate64, "feature").set("name", "syscall")
|
|
| 61 |
+ ET.SubElement(gate64, "feature").set("name", "lm")
|
|
| 62 |
+ |
|
| 63 |
+ |
|
| 64 |
+def format_xml(root): |
|
| 65 |
+ # Adapted from http://pymotw.com/2/xml/etree/ElementTree/create.html |
|
| 66 |
+ # thank you dhellmann |
|
| 67 |
+ rough_string = ET.tostring(root, encoding="UTF-8") |
|
| 68 |
+ dom_parsed = minidom.parseString(rough_string) |
|
| 69 |
+ return dom_parsed.toprettyxml(" ", encoding="UTF-8")
|
|
| 70 |
+ |
|
| 71 |
+ |
|
| 72 |
+def main(): |
|
| 73 |
+ if len(sys.argv) != 2: |
|
| 74 |
+ raise Exception("Must pass path to cpu_map.xml to update")
|
|
| 75 |
+ cpu_map = sys.argv[1] |
|
| 76 |
+ tree = ET.parse(cpu_map) |
|
| 77 |
+ for model in tree.getroot().iter("model"):
|
|
| 78 |
+ if model.get("name") == "gate64":
|
|
| 79 |
+ # gate64 model is already present |
|
| 80 |
+ return |
|
| 81 |
+ update_cpu_map(tree) |
|
| 82 |
+ pretty_xml = format_xml(tree.getroot()) |
|
| 83 |
+ with open(cpu_map, 'w') as f: |
|
| 84 |
+ f.write(pretty_xml) |
|
| 85 |
+ |
|
| 86 |
+ |
|
| 87 |
+if __name__ == "__main__": |
|
| 88 |
+ main() |