~ubuntu-branches/ubuntu/quantal/virtinst/quantal-proposed

« back to all changes in this revision

Viewing changes to virtinst/CapabilitiesParser.py

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen
  • Date: 2007-11-20 13:40:28 UTC
  • Revision ID: james.westby@ubuntu.com-20071120134028-rg0pjby0jc4mycks
Tags: upstream-0.300.1+hg20071120
ImportĀ upstreamĀ versionĀ 0.300.1+hg20071120

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python -tt
 
2
 
 
3
# Some code for parsing libvirt's capabilities XML
 
4
#
 
5
# Copyright 2007  Red Hat, Inc.
 
6
# Mark McLoughlin <markmc@redhat.com>
 
7
#
 
8
# This program is free software; you can redistribute it and/or modify
 
9
# it under the terms of the GNU General Public License as published by
 
10
# the Free  Software Foundation; either version 2 of the License, or
 
11
# (at your option)  any later version.
 
12
#
 
13
# This program is distributed in the hope that it will be useful,
 
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
# GNU General Public License for more details.
 
17
#
 
18
# You should have received a copy of the GNU General Public License
 
19
# along with this program; if not, write to the Free Software
 
20
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
21
# MA 02110-1301 USA.
 
22
 
 
23
import libxml2
 
24
from virtinst import _virtinst as _
 
25
 
 
26
class CapabilitiesParserException(Exception):
 
27
    def __init__(self, msg):
 
28
        Exception.__init__(self, msg)
 
29
 
 
30
# Whether a guest can be created with a certain feature on resp. off
 
31
FEATURE_ON      = 0x01
 
32
FEATURE_OFF     = 0x02
 
33
 
 
34
class Features(object):
 
35
    """Represent a set of features. For each feature, store a bit mask of
 
36
       FEATURE_ON and FEATURE_OFF to indicate whether the feature can
 
37
       be turned on or off. For features for which toggling doesn't make sense
 
38
       (e.g., 'vmx') store FEATURE_ON when the feature is present."""
 
39
 
 
40
    def __init__(self, node = None):
 
41
        self.features = {}
 
42
        if node is not None:
 
43
            self.parseXML(node)
 
44
 
 
45
    def __getitem__(self, feature):
 
46
        if self.features.has_key(feature):
 
47
            return self.features[feature]
 
48
        return 0
 
49
 
 
50
    def names(self):
 
51
        return self.features.keys()
 
52
 
 
53
    def parseXML(self, node):
 
54
        d = self.features
 
55
        for n in node.xpathEval("*"):
 
56
            feature = n.name
 
57
            if not d.has_key(feature):
 
58
                d[feature] = 0
 
59
 
 
60
            self._extractFeature(feature, d, n)
 
61
 
 
62
    def _extractFeature(self, feature, dict, node):
 
63
        """Extract the value of FEATURE from NODE and set DICT[FEATURE] to
 
64
        its value. Abstract method, must be overridden"""
 
65
        raise NotImplementedError("Abstract base class")
 
66
 
 
67
class CapabilityFeatures(Features):
 
68
    def __init__(self, node = None):
 
69
        Features.__init__(self, node)
 
70
 
 
71
    def _extractFeature(self, feature, d, n):
 
72
        default = xpathString(n, "@default")
 
73
        toggle = xpathString(n, "@toggle")
 
74
 
 
75
        if default is not None:
 
76
            if default == "on":
 
77
                d[feature] = FEATURE_ON
 
78
            elif default == "off":
 
79
                d[feature] = FEATURE_OFF
 
80
            else:
 
81
                raise CapabilitiesParserException("Feature %s: value of default must be 'on' or 'off', but is '%s'" % (feature, default))
 
82
            if toggle == "yes":
 
83
                d[feature] |= d[feature] ^ (FEATURE_ON|FEATURE_OFF)
 
84
        else:
 
85
            if feature == "nonpae":
 
86
                d["pae"] |= FEATURE_OFF
 
87
            else:
 
88
                d[feature] |= FEATURE_ON
 
89
 
 
90
class Host(object):
 
91
    def __init__(self, node = None):
 
92
        # e.g. "i686" or "x86_64"
 
93
        self.arch = None
 
94
 
 
95
        self.features = CapabilityFeatures()
 
96
 
 
97
        if not node is None:
 
98
            self.parseXML(node)
 
99
 
 
100
    def parseXML(self, node):
 
101
        child = node.children
 
102
        while child:
 
103
            if child.name != "cpu":
 
104
                child = child.next
 
105
                continue
 
106
 
 
107
            n = child.children
 
108
            while n:
 
109
                if n.name == "arch":
 
110
                    self.arch = n.content
 
111
                elif n.name == "features":
 
112
                    self.features = CapabilityFeatures(n)
 
113
                n = n.next
 
114
 
 
115
            child = child.next
 
116
 
 
117
class Guest(object):
 
118
    def __init__(self, node = None):
 
119
        # e.g. "xen" or "hvm"
 
120
        self.os_type = None
 
121
 
 
122
        # e.g. "xen", "qemu", "kqemu" or "kvm"
 
123
        self.hypervisor_type = None
 
124
 
 
125
        # e.g. "i686" or "x86_64"
 
126
        self.arch = None
 
127
 
 
128
        self.features = CapabilityFeatures()
 
129
 
 
130
        if not node is None:
 
131
            self.parseXML(node)
 
132
 
 
133
    def parseXML(self, node):
 
134
        child = node.children
 
135
        while child:
 
136
            if child.name == "os_type":
 
137
                self.os_type = child.content
 
138
            elif child.name == "features":
 
139
                self.features = CapabilityFeatures(child)
 
140
            elif child.name == "arch":
 
141
                self.arch = child.prop("name")
 
142
                n = child.children
 
143
                while n:
 
144
                    # NB. for now, ignoring the rest of arch e.g. wordsize etc.
 
145
                    if n.name == "domain":
 
146
                        self.hypervisor_type = n.prop("type")
 
147
                    n = n.next
 
148
 
 
149
            child = child.next
 
150
 
 
151
class Capabilities(object):
 
152
    def __init__(self, node = None):
 
153
        self.host = None
 
154
        self.guests = []
 
155
 
 
156
        if not node is None:
 
157
            self.parseXML(node)
 
158
 
 
159
    def parseXML(self, node):
 
160
        child = node.children
 
161
        while child:
 
162
            if child.name == "host":
 
163
                self.host = Host(child)
 
164
            elif child.name == "guest":
 
165
                self.guests.append(Guest(child))
 
166
            child = child.next
 
167
 
 
168
def parse(xml):
 
169
    class ErrorHandler:
 
170
        def __init__(self):
 
171
            self.msg = ""
 
172
        def handler(self, ctx, str):
 
173
            self.msg += str
 
174
    error = ErrorHandler()
 
175
    libxml2.registerErrorHandler(error.handler, None)
 
176
 
 
177
    try:
 
178
        # try/except/finally is only available in python-2.5
 
179
        try:
 
180
            doc = libxml2.readMemory(xml, len(xml),
 
181
                                     None, None,
 
182
                                     libxml2.XML_PARSE_NOBLANKS)
 
183
        except (libxml2.parserError, libxml2.treeError), e:
 
184
            raise CapabilitiesParserException("%s\n%s" % (e, error.msg))
 
185
    finally:
 
186
        libxml2.registerErrorHandler(None, None)
 
187
 
 
188
    try:
 
189
        root = doc.getRootElement()
 
190
        if root.name != "capabilities":
 
191
            raise CapabilitiesParserException("Root element is not 'capabilities'")
 
192
 
 
193
        capabilities = Capabilities(root)
 
194
    finally:
 
195
        doc.freeDoc()
 
196
 
 
197
    return capabilities
 
198
 
 
199
def xpathString(node, path, default = None):
 
200
    result = node.xpathEval("string(%s)" % path)
 
201
    if len(result) == 0:
 
202
        result = default
 
203
    return result