~ubuntu-branches/ubuntu/raring/virtinst/raring-proposed

« back to all changes in this revision

Viewing changes to virtinst/util.py

  • Committer: Bazaar Package Importer
  • Author(s): Guido Günther
  • Date: 2008-11-19 09:19:29 UTC
  • mto: (1.4.1 sid)
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20081119091929-vwksujnqzo1utdln
Tags: upstream-0.400.0
Import upstream version 0.400.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
20
# MA 02110-1301 USA.
21
21
 
 
22
import platform
22
23
import random
23
24
import os.path
 
25
import re
 
26
import libxml2
 
27
import logging
24
28
from sys import stderr
25
29
 
26
30
import libvirt
27
31
from virtinst import _virtinst as _
 
32
from virtinst import CapabilitiesParser
 
33
 
 
34
 
 
35
KEYBOARD_DIR = "/etc/sysconfig/keyboard"
28
36
 
29
37
def default_route():
30
38
    route_file = "/proc/net/route"
48
56
# Legacy for compat only.
49
57
def default_bridge():
50
58
    rt = default_route()
51
 
    defn = int(rt[-1])
 
59
    if rt is None:
 
60
        defn = None
 
61
    else:
 
62
        defn = int(rt[-1])
52
63
 
53
64
    if defn is None:
54
65
        return "xenbr0"
55
66
    else:
56
67
        return "xenbr%d"%(defn)
57
68
 
58
 
def default_network():
 
69
def default_network(conn):
59
70
    dev = default_route()
60
71
 
61
 
    if dev is not None:
 
72
    if dev is not None and not is_uri_remote(conn.getURI()):
62
73
        # New style peth0 == phys dev, eth0 == bridge, eth0 == default route
63
74
        if os.path.exists("/sys/class/net/%s/bridge" % dev):
64
75
            return ["bridge", dev]
139
150
# available under the LGPL,
140
151
# Copyright 2004, 2005 Mike Wray <mike.wray@hp.com>
141
152
# Copyright 2005 XenSource Ltd
142
 
def randomMAC():
 
153
def randomMAC(type = "xen"):
143
154
    """Generate a random MAC address.
144
155
 
145
 
    Uses OUI (Organizationally Unique Identifier) 00-16-3E, allocated to
146
 
    Xensource, Inc. The OUI list is available at
147
 
    http://standards.ieee.org/regauth/oui/oui.txt.
 
156
    00-16-3E allocated to xensource
 
157
    54-52-00 used by qemu/kvm
 
158
 
 
159
    The OUI list is available at http://standards.ieee.org/regauth/oui/oui.txt.
148
160
 
149
161
    The remaining 3 fields are random, with the first bit of the first
150
162
    random field set 0.
151
163
 
 
164
    >>> randomMAC().startswith("00:16:36")
 
165
    True
 
166
    >>> randomMAC("foobar").startswith("00:16:36")
 
167
    True
 
168
    >>> randomMAC("xen").startswith("00:16:36")
 
169
    True
 
170
    >>> randomMAC("qemu").startswith("54:52:00")
 
171
    True
 
172
 
152
173
    @return: MAC address string
153
174
    """
154
 
    mac = [ 0x00, 0x16, 0x3e,
 
175
    ouis = { 'xen': [ 0x00, 0x16, 0x36 ], 'qemu': [ 0x54, 0x52, 0x00 ] }
 
176
 
 
177
    try:
 
178
         oui = ouis[type]
 
179
    except KeyError:
 
180
         oui = ouis['xen']
 
181
 
 
182
    mac = oui + [ 
155
183
            random.randint(0x00, 0x7f),
156
184
            random.randint(0x00, 0xff),
157
185
            random.randint(0x00, 0xff) ]
211
239
    pcpus = hostinfo[4] * hostinfo[5] * hostinfo[6] * hostinfo[7]
212
240
    return pcpus
213
241
 
 
242
def system(cmd):
 
243
    st = os.system(cmd)
 
244
    if os.WIFEXITED(st) and os.WEXITSTATUS(st) != 0:
 
245
        raise OSError("Failed to run %s, exited with %d" % 
 
246
                      (cmd, os.WEXITSTATUS(st)))
 
247
 
214
248
def xml_escape(str):
215
249
    """Replaces chars ' " < > & with xml safe counterparts"""
216
250
    str = str.replace("&", "&amp;")
219
253
    str = str.replace("<", "&lt;")
220
254
    str = str.replace(">", "&gt;")
221
255
    return str
 
256
 
 
257
def compareMAC(p, q):
 
258
    """Compare two MAC addresses"""
 
259
    pa = p.split(":")
 
260
    qa = q.split(":")
 
261
 
 
262
    if len(pa) != len(qa):
 
263
        if p > q:
 
264
            return 1
 
265
        else:
 
266
            return -1
 
267
 
 
268
    for i in xrange(len(pa)):
 
269
        n = int(pa[i], 0x10) - int(qa[i], 0x10)
 
270
        if n > 0:
 
271
            return 1
 
272
        elif n < 0:
 
273
            return -1
 
274
    return 0
 
275
 
 
276
def default_keymap():
 
277
    """Look in /etc/sysconfig for the host machine's keymap, and attempt to
 
278
       map it to a keymap supported by qemu"""
 
279
 
 
280
    # Set keymap to same as hosts
 
281
    import keytable
 
282
    keymap = "en-us"
 
283
    try:
 
284
        f = open(KEYBOARD_DIR, "r")
 
285
    except IOError, e:
 
286
        logging.debug('Could not open "/etc/sysconfig/keyboard" ' + str(e))
 
287
    else:
 
288
        while 1:
 
289
            s = f.readline()
 
290
            if s == "":
 
291
                break
 
292
            if re.search("KEYTABLE", s) != None:
 
293
                kt = s.split('"')[1]
 
294
                if keytable.keytable.has_key(kt.lower()):
 
295
                    keymap = keytable.keytable[kt]
 
296
                else:
 
297
                    logging.debug("Didn't find keymap '%s' in keytable!" % kt)
 
298
        f.close()
 
299
    return keymap
 
300
 
 
301
def pygrub_path(conn=None):
 
302
    """
 
303
    Return the pygrub path for the current host, or connection if
 
304
    available.
 
305
    """
 
306
    # FIXME: This should be removed/deprecated when capabilities are
 
307
    #        fixed to provide bootloader info
 
308
    if conn:
 
309
        cap = CapabilitiesParser.parse(conn.getCapabilities())
 
310
        if (cap.host.arch == "i86pc"):
 
311
            return "/usr/lib/xen/bin/pygrub"
 
312
        else:
 
313
            return "/usr/bin/pygrub"
 
314
 
 
315
    if platform.system() == "SunOS":
 
316
        return "/usr/lib/xen/bin/pygrub"
 
317
    return "/usr/bin/pygrub"
 
318
 
 
319
def uri_split(uri):
 
320
    """
 
321
    Parse a libvirt hypervisor uri into it's individual parts
 
322
    @returns: tuple of the form (scheme (ex. 'qemu', 'xen+ssh'), username,
 
323
                                 hostname, path (ex. '/system'), query,
 
324
                                 fragment)
 
325
    """
 
326
    def splitnetloc(url, start=0):
 
327
        for c in '/?#': # the order is important!
 
328
            delim = url.find(c, start)
 
329
            if delim >= 0:
 
330
                break
 
331
        else:
 
332
            delim = len(url)
 
333
        return url[start:delim], url[delim:]
 
334
 
 
335
    username = netloc = query = fragment = ''
 
336
    i = uri.find(":")
 
337
    if i > 0:
 
338
        scheme, uri = uri[:i].lower(), uri[i+1:]
 
339
        if uri[:2] == '//':
 
340
            netloc, uri = splitnetloc(uri, 2)
 
341
            offset = netloc.find("@")
 
342
            if offset > 0:
 
343
                username = netloc[0:offset]
 
344
                netloc = netloc[offset+1:]
 
345
        if '#' in uri:
 
346
            uri, fragment = uri.split('#', 1)
 
347
        if '?' in uri:
 
348
            uri, query = uri.split('?', 1)
 
349
    else:
 
350
        scheme = uri.lower()
 
351
    return scheme, username, netloc, uri, query, fragment
 
352
 
 
353
 
 
354
def is_uri_remote(uri):
 
355
    try:
 
356
        (scheme, username, netloc, path, query, fragment) = uri_split(uri)
 
357
        if netloc == "":
 
358
            return False
 
359
        return True
 
360
    except Exception, e:
 
361
        logging.exception("Error parsing URI in is_remote: %s" % e)
 
362
        return True
 
363
 
 
364
def get_uri_hostname(uri):
 
365
    try:
 
366
        (scheme, username, netloc, path, query, fragment) = uri_split(uri)
 
367
 
 
368
        if netloc != "":
 
369
            return netloc
 
370
    except Exception, e:
 
371
        logging.warning("Cannot parse URI %s: %s" % (uri, str(e)))
 
372
    return "localhost"
 
373
 
 
374
def get_uri_transport(uri):
 
375
    try:
 
376
        (scheme, username, netloc, path, query, fragment) = uri_split(uri)
 
377
        if scheme:
 
378
            offset = scheme.index("+")
 
379
            if offset > 0:
 
380
                return [scheme[offset+1:], username]
 
381
    except:
 
382
        pass
 
383
    return [None, None]
 
384
 
 
385
def get_uri_driver(uri):
 
386
    try:
 
387
        (scheme, username, netloc, path, query, fragment) = uri_split(uri)
 
388
        if scheme:
 
389
            offset = scheme.find("+")
 
390
            if offset > 0:
 
391
                return scheme[:offset]
 
392
            return scheme
 
393
    except Exception, e:
 
394
        pass
 
395
    return "xen"
 
396
 
 
397
def is_storage_capable(conn):
 
398
    """check if virConnectPtr passed has storage API support"""
 
399
    if not conn:
 
400
        return False
 
401
    if not isinstance(conn, libvirt.virConnect):
 
402
        raise ValueError(_("'conn' must be a virConnect instance."))
 
403
    try:
 
404
        if not dir(conn).count("listStoragePools"):
 
405
            return False
 
406
        n = conn.listStoragePools()
 
407
    except libvirt.libvirtError, e:
 
408
        if e.get_error_code() == libvirt.VIR_ERR_RPC or \
 
409
           e.get_error_code() == libvirt.VIR_ERR_NO_SUPPORT:
 
410
            return False
 
411
    return True
 
412
 
 
413
def get_xml_path(xml, path):
 
414
    """return the xpath from the passed xml"""
 
415
    doc = None
 
416
    ctx = None
 
417
    result = None
 
418
    try:
 
419
        doc = libxml2.parseDoc(xml)
 
420
        ctx = doc.xpathNewContext()
 
421
        ret = ctx.xpathEval(path)
 
422
        str = None
 
423
        if ret != None:
 
424
            if type(ret) == list:
 
425
                if len(ret) == 1:
 
426
                    str = ret[0].content
 
427
            else:
 
428
                str = ret
 
429
        result = str
 
430
    finally:
 
431
        if doc:
 
432
            doc.freeDoc()
 
433
        if ctx:
 
434
            ctx.xpathFreeContext()
 
435
    return result
 
436
 
 
437
def lookup_pool_by_path(conn, path):
 
438
    """
 
439
    Return the first pool with matching matching target path.
 
440
    return the first we find, active or inactive. This iterates over
 
441
    all pools and dumps their xml, so it is NOT quick.
 
442
    @return virStoragePool object if found, None otherwise
 
443
    """
 
444
    if not is_storage_capable(conn):
 
445
        return None
 
446
 
 
447
    pool_list = conn.listStoragePools() + conn.listDefinedStoragePools()
 
448
    for name in pool_list:
 
449
        pool = conn.storagePoolLookupByName(name)
 
450
        if get_xml_path(pool.XMLDesc(0), "/pool/target/path") == path:
 
451
            return pool
 
452
    return None
 
453
 
 
454
def _test():
 
455
    import doctest
 
456
    doctest.testmod()
 
457
 
 
458
if __name__ == "__main__":
 
459
    _test()