# # Copyright 2010 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from virtinst.xmlbuilder import XMLBuilder, XMLProperty import libxml2 def _int_or_none(val): if val is None: return None return int(val) class CPUFeature(XMLBuilder): """ Class for generating child XML """ POLICIES = ["force", "require", "optional", "disable", "forbid"] def __init__(self, conn, parsexml=None, parsexmlnode=None): XMLBuilder.__init__(self, conn, parsexml, parsexmlnode) self._name = None self._policy = None if self._is_parse(): return def _get_name(self): return self._name def _set_name(self, val): self._name = val name = XMLProperty(_get_name, _set_name, xpath="./@name") def _get_policy(self): return self._policy def _set_policy(self, val): self._policy = val policy = XMLProperty(_get_policy, _set_policy, xpath="./@policy") def _get_xml_config(self): if not self.name: return "" xml = " XML """ _dumpxml_xpath = "/domain/cpu" MATCHS = ["minimum", "exact", "strict"] def __init__(self, conn, parsexml=None, parsexmlnode=None): self._model = None self._match = None self._vendor = None self._mode = None self._features = [] self._sockets = None self._cores = None self._threads = None XMLBuilder.__init__(self, conn, parsexml, parsexmlnode) if self._is_parse(): return def _parsexml(self, xml, node): XMLBuilder._parsexml(self, xml, node) for node in self._xml_node.children: if node.name != "feature": continue feature = CPUFeature(self.conn, parsexmlnode=node) self._features.append(feature) def _get_features(self): return self._features[:] features = property(_get_features) def add_feature(self, name, policy="require"): feature = CPUFeature(self.conn) feature.name = name feature.policy = policy if self._is_parse(): xml = feature.get_xml_config() node = libxml2.parseDoc(xml).children feature.set_xml_node(node) self._add_child_node("./cpu", node) self._features.append(feature) def remove_feature(self, feature): if self._is_parse() and feature in self._features: xpath = feature.get_xml_node_path() if xpath: self._remove_child_xpath(xpath) self._features.remove(feature) def _get_model(self): return self._model def _set_model(self, val): if val: self.mode = "custom" if val and not self.match: self.match = "exact" self._model = val model = XMLProperty(_get_model, _set_model, xpath="./cpu/model") def _get_match(self): return self._match def _set_match(self, val): self._match = val match = XMLProperty(_get_match, _set_match, xpath="./cpu/@match") def _get_vendor(self): return self._vendor def _set_vendor(self, val): self._vendor = val vendor = XMLProperty(_get_vendor, _set_vendor, xpath="./cpu/vendor") def _get_mode(self): return self._mode def _set_mode(self, val): self._mode = val mode = XMLProperty(_get_mode, _set_mode, xpath="./cpu/@mode") # Topology properties def _get_sockets(self): return self._sockets def _set_sockets(self, val): self._sockets = _int_or_none(val) sockets = XMLProperty(_get_sockets, _set_sockets, is_int=True, xpath="./cpu/topology/@sockets") def _get_cores(self): return self._cores def _set_cores(self, val): self._cores = _int_or_none(val) cores = XMLProperty(_get_cores, _set_cores, is_int=True, xpath="./cpu/topology/@cores") def _get_threads(self): return self._threads def _set_threads(self, val): self._threads = _int_or_none(val) threads = XMLProperty(_get_threads, _set_threads, is_int=True, xpath="./cpu/topology/@threads") def clear_attrs(self): self.match = None self.mode = None self.vendor = None self.model = None for feature in self.features: self.remove_feature(feature) def copy_host_cpu(self): """ Enact the equivalent of qemu -cpu host, pulling all info from capabilities about the host CPU """ cpu = self.conn.caps.host.cpu if not cpu.model: raise ValueError(_("No host CPU reported in capabilities")) self.mode = "custom" self.match = "exact" self.model = cpu.model self.vendor = cpu.vendor for feature in self.features: self.remove_feature(feature) for name in cpu.features.names(): self.add_feature(name) def vcpus_from_topology(self): """ Determine the CPU count represented by topology, or 1 if no topology is set """ self.set_topology_defaults() if self.sockets: return self.sockets * self.cores * self.threads return 1 def set_topology_defaults(self, vcpus=None): """ Fill in unset topology values, using the passed vcpus count if required """ if (self.sockets is None and self.cores is None and self.threads is None): return if vcpus is None: if self.sockets is None: self.sockets = 1 if self.threads is None: self.threads = 1 if self.cores is None: self.cores = 1 vcpus = int(vcpus or 0) if not self.sockets: if not self.cores: self.sockets = vcpus / self.threads else: self.sockets = vcpus / self.cores if not self.cores: if not self.threads: self.cores = vcpus / self.sockets else: self.cores = vcpus / (self.sockets * self.threads) if not self.threads: self.threads = vcpus / (self.sockets * self.cores) return def _get_topology_xml(self): xml = "" if self.sockets: xml += " sockets='%s'" % self.sockets if self.cores: xml += " cores='%s'" % self.cores if self.threads: xml += " threads='%s'" % self.threads if not xml: return "" return " \n" % xml def _get_feature_xml(self): xml = "" for feature in self._features: xml += feature.get_xml_config() + "\n" return xml def _get_xml_config(self): top_xml = self._get_topology_xml() feature_xml = self._get_feature_xml() mode_xml = "" match_xml = "" if self.match: match_xml = " match='%s'" % self.match xml = "" if self.model == "host-passthrough": self.mode = "host-passthrough" mode_xml = " mode='%s'" % self.mode xml += " " % mode_xml return xml else: self.mode = "custom" mode_xml = " mode='%s'" % self.mode if not (self.model or top_xml or feature_xml): return "" # Simple topology XML mode xml += " \n" % (mode_xml, match_xml) if self.model: xml += " %s\n" % self.model if self.vendor: xml += " %s\n" % self.vendor if top_xml: xml += top_xml if feature_xml: xml += feature_xml xml += " " return xml