2
# Copyright 2010 Red Hat, Inc.
3
# Cole Robinson <crobinso@redhat.com>
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
import XMLBuilderDomain
21
from XMLBuilderDomain import _xml_property
25
def _int_or_none(val):
26
return val and int(val) or val
28
class CPUFeature(XMLBuilderDomain.XMLBuilderDomain):
30
Class for generating <cpu> child <feature> XML
33
POLICIES = ["force", "require", "optional", "disable", "forbid"]
35
def __init__(self, conn, parsexml=None, parsexmlnode=None, caps=None):
36
XMLBuilderDomain.XMLBuilderDomain.__init__(self, conn, parsexml,
47
def _set_name(self, val):
49
name = _xml_property(_get_name, _set_name,
52
def _get_policy(self):
54
def _set_policy(self, val):
56
policy = _xml_property(_get_policy, _set_policy,
59
def _get_xml_config(self):
65
xml += " policy='%s'" % self.policy
66
xml += " name='%s'/>" % self.name
71
class CPU(XMLBuilderDomain.XMLBuilderDomain):
73
Class for generating <cpu> XML
76
_dumpxml_xpath = "/domain/cpu"
78
MATCHS = ["minimum", "exact", "strict"]
80
def __init__(self, conn, parsexml=None, parsexmlnode=None, caps=None):
90
XMLBuilderDomain.XMLBuilderDomain.__init__(self, conn, parsexml,
95
def _parsexml(self, xml, node):
96
XMLBuilderDomain.XMLBuilderDomain._parsexml(self, xml, node)
98
for node in self._xml_node.children:
99
if node.name != "feature":
101
feature = CPUFeature(self.conn, parsexmlnode=node)
102
self._features.append(feature)
104
def _get_features(self):
105
return self._features[:]
106
features = _xml_property(_get_features)
108
def add_feature(self, name, policy="require"):
109
feature = CPUFeature(self.conn)
111
feature.policy = policy
114
xml = feature.get_xml_config()
115
node = libxml2.parseDoc(xml).children
116
feature.set_xml_node(node)
117
self._add_child_node("./cpu", node)
119
self._features.append(feature)
121
def remove_feature(self, feature):
122
if self._is_parse() and feature in self._features:
123
xpath = feature.get_xml_node_path()
125
self._remove_child_xpath(xpath)
127
self._features.remove(feature)
130
def _get_model(self):
132
def _set_model(self, val):
133
if val and not self.match:
136
model = _xml_property(_get_model, _set_model,
139
def _get_match(self):
141
def _set_match(self, val):
143
match = _xml_property(_get_match, _set_match,
144
xpath="./cpu/@match")
146
def _get_vendor(self):
148
def _set_vendor(self, val):
150
vendor = _xml_property(_get_vendor, _set_vendor,
151
xpath="./cpu/vendor")
153
# Topology properties
154
def _get_sockets(self):
156
def _set_sockets(self, val):
157
self._sockets = _int_or_none(val)
158
sockets = _xml_property(_get_sockets, _set_sockets,
159
get_converter=lambda s, x: _int_or_none(x),
160
xpath="./cpu/topology/@sockets")
162
def _get_cores(self):
164
def _set_cores(self, val):
165
self._cores = _int_or_none(val)
166
cores = _xml_property(_get_cores, _set_cores,
167
get_converter=lambda s, x: _int_or_none(x),
168
xpath="./cpu/topology/@cores")
170
def _get_threads(self):
172
def _set_threads(self, val):
173
self._threads = _int_or_none(val)
174
threads = _xml_property(_get_threads, _set_threads,
175
get_converter=lambda s, x: _int_or_none(x),
176
xpath="./cpu/topology/@threads")
178
def copy_host_cpu(self):
180
Enact the equivalent of qemu -cpu host, pulling all info
181
from capabilities about the host CPU
183
cpu = self._get_caps().host.cpu
185
raise ValueError(_("No host CPU reported in capabilities"))
188
self.model = cpu.model
189
self.vendor = cpu.vendor
191
for feature in self.features:
192
self.remove_feature(feature)
193
for name in cpu.features.names():
194
self.add_feature(name)
196
def vcpus_from_topology(self):
198
Determine the CPU count represented by topology, or 1 if
201
self.set_topology_defaults()
203
return self.sockets * self.cores * self.threads
206
def set_topology_defaults(self, vcpus=None):
208
Fill in unset topology values, using the passed vcpus count if
211
if (self.sockets is None and
212
self.cores is None and
213
self.threads is None):
217
if self.sockets is None:
219
if self.threads is None:
221
if self.cores is None:
224
vcpus = int(vcpus or 0)
227
self.sockets = vcpus / self.threads
229
self.sockets = vcpus / self.cores
233
self.cores = vcpus / self.sockets
235
self.cores = vcpus / (self.sockets * self.threads)
238
self.threads = vcpus / (self.sockets * self.cores)
242
def _get_topology_xml(self):
245
xml += " sockets='%s'" % self.sockets
247
xml += " cores='%s'" % self.cores
249
xml += " threads='%s'" % self.threads
253
return " <topology%s/>\n" % xml
255
def _get_feature_xml(self):
257
for feature in self._features:
258
xml += feature.get_xml_config() + "\n"
261
def _get_xml_config(self):
262
top_xml = self._get_topology_xml()
263
feature_xml = self._get_feature_xml()
266
match_xml = " match='%s'" % self.match
269
if not (self.model or top_xml or feature_xml):
272
# Simple topology XML mode
273
xml += " <cpu%s>\n" % match_xml
275
xml += " <model>%s</model>\n" % self.model
277
xml += " <vendor>%s</vendor>\n" % self.vendor