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

« back to all changes in this revision

Viewing changes to .pc/0003-Fix-path-to-keyboard-configuration.patch/virtinst/util.py

  • Committer: Bazaar Package Importer
  • Author(s): Laurent Léonard
  • Date: 2010-03-25 18:13:28 UTC
  • mfrom: (1.2.7 upstream)
  • mto: (1.6.1 sid)
  • mto: This revision was merged to the branch mainline in revision 26.
  • Revision ID: james.westby@ubuntu.com-20100325181328-ah0izdq4cdza60xd
Tags: 0.500.3-1
* [6e8ccf1] Imported Upstream version 0.500.3
* [140e8ed] Drop patches.
* [801ac3f] Switch to new source format 3.0 (quilt).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# Utility functions used for guest installation
 
3
#
 
4
# Copyright 2006  Red Hat, Inc.
 
5
# Jeremy Katz <katzj@redhat.com>
 
6
#
 
7
# This program is free software; you can redistribute it and/or modify
 
8
# it under the terms of the GNU General Public License as published by
 
9
# the Free  Software Foundation; either version 2 of the License, or
 
10
# (at your option)  any later version.
 
11
#
 
12
# This program is distributed in the hope that it will be useful,
 
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
# GNU General Public License for more details.
 
16
#
 
17
# You should have received a copy of the GNU General Public License
 
18
# along with this program; if not, write to the Free Software
 
19
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
20
# MA 02110-1301 USA.
 
21
 
 
22
#
 
23
# WARNING: the contents of this file, somewhat unfortunately, are legacy
 
24
# API. No incompatible changes are allowed to this file, and no new
 
25
# code should be added here (utility functions live in _util.py).
 
26
# Clients of virtinst shouldn't use these functions: if you think you
 
27
# need to, tell us why.
 
28
#
 
29
 
 
30
import platform
 
31
import random
 
32
import os.path
 
33
import re
 
34
import libxml2
 
35
import logging
 
36
import subprocess
 
37
from sys import stderr
 
38
 
 
39
import libvirt
 
40
from virtinst import _virtinst as _
 
41
import virtinst
 
42
import CapabilitiesParser
 
43
import User
 
44
import support
 
45
 
 
46
KEYBOARD_DIR = "/etc/sysconfig/keyboard"
 
47
XORG_CONF = "/etc/X11/xorg.conf"
 
48
CONSOLE_SETUP_CONF = "/etc/default/console-setup"
 
49
 
 
50
def default_route(nic = None):
 
51
    if platform.system() == 'SunOS':
 
52
        cmd = [ '/usr/bin/netstat', '-rn' ]
 
53
        if nic:
 
54
            cmd += [ '-I', nic ]
 
55
        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
 
56
            stderr=subprocess.PIPE)
 
57
        for line in proc.stdout.readlines():
 
58
            vals = line.split()
 
59
            if len(vals) > 1 and vals[0] == 'default':
 
60
                return vals[1]
 
61
        return None
 
62
 
 
63
    route_file = "/proc/net/route"
 
64
    d = file(route_file)
 
65
 
 
66
    defn = 0
 
67
    for line in d.xreadlines():
 
68
        info = line.split()
 
69
        if (len(info) != 11): # 11 = typical num of fields in the file
 
70
            print >> stderr, _("Invalid line length while parsing %s.") %(route_file)
 
71
            print >> stderr, _("Defaulting bridge to xenbr%d") % (defn)
 
72
            break
 
73
        try:
 
74
            route = int(info[1],16)
 
75
            if route == 0:
 
76
                return info[0]
 
77
        except ValueError:
 
78
            continue
 
79
    return None
 
80
 
 
81
 
 
82
def default_bridge():
 
83
    ret = virtinst._util.default_bridge2(None)
 
84
    if not ret:
 
85
        # Maintain this behavior for back compat
 
86
        ret = "xenbr0"
 
87
    else:
 
88
        ret = ret[1]
 
89
 
 
90
    return ret
 
91
 
 
92
def default_network(conn):
 
93
    ret = virtinst._util.default_bridge2(conn)
 
94
    if not ret:
 
95
        # FIXME: Check that this exists
 
96
        ret = ["network", "default"]
 
97
 
 
98
    return ret
 
99
 
 
100
def default_connection():
 
101
    if os.path.exists('/var/lib/xend'):
 
102
        if os.path.exists('/dev/xen/evtchn'):
 
103
            return 'xen' 
 
104
        if os.path.exists("/proc/xen"):
 
105
            return 'xen' 
 
106
 
 
107
    if os.path.exists("/usr/bin/qemu") or \
 
108
        os.path.exists("/usr/bin/qemu-kvm") or \
 
109
        os.path.exists("/usr/bin/kvm") or \
 
110
        os.path.exists("/usr/bin/xenner"):
 
111
        if User.User.current().has_priv(User.User.PRIV_QEMU_SYSTEM):
 
112
            return "qemu:///system"
 
113
        else:
 
114
            return "qemu:///session"
 
115
    return None
 
116
 
 
117
def get_cpu_flags():
 
118
    if platform.system() == 'SunOS':
 
119
        raise OSError('CPU flags not available')
 
120
 
 
121
    f = open("/proc/cpuinfo")
 
122
    lines = f.readlines()
 
123
    f.close()
 
124
    for line in lines:
 
125
        if not line.startswith("flags"):
 
126
            continue
 
127
        # get the actual flags
 
128
        flags = line[:-1].split(":", 1)[1]
 
129
        # and split them
 
130
        flst = flags.split(" ")
 
131
        return flst
 
132
    return []
 
133
 
 
134
def is_pae_capable(conn = None):
 
135
    """Determine if a machine is PAE capable or not."""
 
136
    if not conn:
 
137
        conn = libvirt.open('')
 
138
    return "pae" in conn.getCapabilities()
 
139
 
 
140
def is_hvm_capable():
 
141
    """Determine if a machine is HVM capable or not."""
 
142
    if platform.system() == 'SunOS':
 
143
        raise OSError('HVM capability not determinible')
 
144
 
 
145
    caps = ""
 
146
    if os.path.exists("/sys/hypervisor/properties/capabilities"):
 
147
        caps = open("/sys/hypervisor/properties/capabilities").read()
 
148
    if caps.find("hvm") != -1:
 
149
        return True
 
150
    return False
 
151
 
 
152
def is_kqemu_capable():
 
153
    return os.path.exists("/dev/kqemu")
 
154
 
 
155
def is_kvm_capable():
 
156
    return os.path.exists("/dev/kvm")
 
157
 
 
158
def is_blktap_capable():
 
159
    if platform.system() == 'SunOS':
 
160
        return False
 
161
 
 
162
    #return os.path.exists("/dev/xen/blktapctrl")
 
163
    f = open("/proc/modules")
 
164
    lines = f.readlines()
 
165
    f.close()
 
166
    for line in lines:
 
167
        if line.startswith("blktap ") or line.startswith("xenblktap "):
 
168
            return True
 
169
    return False
 
170
 
 
171
def get_default_arch():
 
172
    arch = os.uname()[4]
 
173
    if arch == "x86_64":
 
174
        return "x86_64"
 
175
    return "i686"
 
176
 
 
177
# this function is directly from xend/server/netif.py and is thus
 
178
# available under the LGPL,
 
179
# Copyright 2004, 2005 Mike Wray <mike.wray@hp.com>
 
180
# Copyright 2005 XenSource Ltd
 
181
def randomMAC(type = "xen"):
 
182
    """Generate a random MAC address.
 
183
 
 
184
    00-16-3E allocated to xensource
 
185
    52-54-00 used by qemu/kvm
 
186
 
 
187
    The OUI list is available at http://standards.ieee.org/regauth/oui/oui.txt.
 
188
 
 
189
    The remaining 3 fields are random, with the first bit of the first
 
190
    random field set 0.
 
191
 
 
192
    >>> randomMAC().startswith("00:16:36")
 
193
    True
 
194
    >>> randomMAC("foobar").startswith("00:16:36")
 
195
    True
 
196
    >>> randomMAC("xen").startswith("00:16:36")
 
197
    True
 
198
    >>> randomMAC("qemu").startswith("52:54:00")
 
199
    True
 
200
 
 
201
    @return: MAC address string
 
202
    """
 
203
    ouis = { 'xen': [ 0x00, 0x16, 0x36 ], 'qemu': [ 0x52, 0x54, 0x00 ] }
 
204
 
 
205
    try:
 
206
        oui = ouis[type]
 
207
    except KeyError:
 
208
        oui = ouis['xen']
 
209
 
 
210
    mac = oui + [
 
211
            random.randint(0x00, 0xff),
 
212
            random.randint(0x00, 0xff),
 
213
            random.randint(0x00, 0xff) ]
 
214
    return ':'.join(map(lambda x: "%02x" % x, mac))
 
215
 
 
216
# the following three functions are from xend/uuid.py and are thus
 
217
# available under the LGPL,
 
218
# Copyright 2005 Mike Wray <mike.wray@hp.com>
 
219
# Copyright 2005 XenSource Ltd
 
220
def randomUUID():
 
221
    """Generate a random UUID."""
 
222
 
 
223
    return [ random.randint(0, 255) for dummy in range(0, 16) ]
 
224
 
 
225
def uuidToString(u):
 
226
    return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2,
 
227
                     "%02x" * 6]) % tuple(u)
 
228
 
 
229
def uuidFromString(s):
 
230
    s = s.replace('-', '')
 
231
    return [ int(s[i : i + 2], 16) for i in range(0, 32, 2) ]
 
232
 
 
233
# the following function quotes from python2.5/uuid.py
 
234
def get_host_network_devices():
 
235
    device = []
 
236
    for dirname in ['', '/sbin/', '/usr/sbin']:
 
237
        executable = os.path.join(dirname, "ifconfig")
 
238
        if not os.path.exists(executable):
 
239
            continue
 
240
        try:
 
241
            cmd = 'LC_ALL=C %s -a 2>/dev/null' % (executable)
 
242
            pipe = os.popen(cmd)
 
243
        except IOError:
 
244
            continue
 
245
        for line in pipe:
 
246
            if line.find("encap:Ethernet") > 0:
 
247
                words = line.lower().split()
 
248
                for i in range(len(words)):
 
249
                    if words[i] == "hwaddr":
 
250
                        device.append(words)
 
251
    return device
 
252
 
 
253
def get_max_vcpus(conn, type=None):
 
254
    """@conn libvirt connection to poll for max possible vcpus
 
255
       @type optional guest type (kvm, etc.)"""
 
256
    if type is None:
 
257
        type = conn.getType()
 
258
    try:
 
259
        m = conn.getMaxVcpus(type.lower())
 
260
    except libvirt.libvirtError:
 
261
        m = 32
 
262
    return m
 
263
 
 
264
def get_phy_cpus(conn):
 
265
    """Get number of physical CPUs."""
 
266
    hostinfo = conn.getInfo()
 
267
    pcpus = hostinfo[4] * hostinfo[5] * hostinfo[6] * hostinfo[7]
 
268
    return pcpus
 
269
 
 
270
def system(cmd):
 
271
    st = os.system(cmd)
 
272
    if os.WIFEXITED(st) and os.WEXITSTATUS(st) != 0:
 
273
        raise OSError("Failed to run %s, exited with %d" % 
 
274
                      (cmd, os.WEXITSTATUS(st)))
 
275
 
 
276
def xml_escape(str):
 
277
    """Replaces chars ' " < > & with xml safe counterparts"""
 
278
    str = str.replace("&", "&amp;")
 
279
    str = str.replace("'", "&apos;")
 
280
    str = str.replace("\"", "&quot;")
 
281
    str = str.replace("<", "&lt;")
 
282
    str = str.replace(">", "&gt;")
 
283
    return str
 
284
 
 
285
def compareMAC(p, q):
 
286
    """Compare two MAC addresses"""
 
287
    pa = p.split(":")
 
288
    qa = q.split(":")
 
289
 
 
290
    if len(pa) != len(qa):
 
291
        if p > q:
 
292
            return 1
 
293
        else:
 
294
            return -1
 
295
 
 
296
    for i in xrange(len(pa)):
 
297
        n = int(pa[i], 0x10) - int(qa[i], 0x10)
 
298
        if n > 0:
 
299
            return 1
 
300
        elif n < 0:
 
301
            return -1
 
302
    return 0
 
303
 
 
304
def _xorg_keymap():
 
305
    """Look in /etc/X11/xorg.conf for the host machine's keymap, and attempt to
 
306
       map it to a keymap supported by qemu"""
 
307
 
 
308
    kt = None
 
309
    try:
 
310
        f = open(XORG_CONF, "r")
 
311
    except IOError, e:
 
312
        logging.debug('Could not open "%s": %s ' % (XORG_CONF, str(e)))
 
313
    else:
 
314
        keymap_re = re.compile(r'\s*Option\s+"XkbLayout"\s+"(?P<kt>[a-z-]+)"')
 
315
        for line in f:
 
316
            m = keymap_re.match(line)
 
317
            if m:
 
318
                kt = m.group('kt')
 
319
                break
 
320
        else:
 
321
            logging.debug("Didn't find keymap in '%s'!" % XORG_CONF)
 
322
        f.close()
 
323
    return kt
 
324
 
 
325
def _console_setup_keymap():
 
326
    """Look in /etc/default/console-setup for the host machine's keymap, and attempt to
 
327
       map it to a keymap supported by qemu"""
 
328
 
 
329
    kt = None
 
330
    try:
 
331
        f = open(CONSOLE_SETUP_CONF, "r")
 
332
    except IOError, e:
 
333
        logging.debug('Could not open "%s": %s ' % (CONSOLE_SETUP_CONF, str(e)))
 
334
    else:
 
335
        keymap_re = re.compile(r'\s*XKBLAYOUT="(?P<kt>[a-z-]+)"')
 
336
        for line in f:
 
337
            m = keymap_re.match(line)
 
338
            if m:
 
339
                kt = m.group('kt')
 
340
                break
 
341
        else:
 
342
            logging.debug("Didn't find keymap in '%s'!" % XORG_CONF)
 
343
        f.close()
 
344
    return kt
 
345
 
 
346
def default_keymap():
 
347
    """Look in /etc/sysconfig for the host machine's keymap, and attempt to
 
348
       map it to a keymap supported by qemu"""
 
349
 
 
350
    # Set keymap to same as hosts
 
351
    default = "en-us"
 
352
    keymap = None
 
353
 
 
354
    kt = None
 
355
    try:
 
356
        f = open(KEYBOARD_DIR, "r")
 
357
    except IOError, e:
 
358
        logging.debug('Could not open "/etc/sysconfig/keyboard" ' + str(e))
 
359
        kt = _xorg_keymap()
 
360
        if not kt:
 
361
            kt = _console_setup_keymap()
 
362
    else:
 
363
        while 1:
 
364
            s = f.readline()
 
365
            if s == "":
 
366
                break
 
367
            if re.search("KEYTABLE", s) != None or \
 
368
               (re.search("KEYBOARD", s) != None and
 
369
                re.search("KEYBOARDTYPE", s) == None):
 
370
                if s.count('"'):
 
371
                    delim = '"'
 
372
                elif s.count('='):
 
373
                    delim = '='
 
374
                else:
 
375
                    continue
 
376
                kt = s.split(delim)[1].strip()
 
377
        f.close()
 
378
 
 
379
    if kt == None:
 
380
        logging.debug("Did not parse any usable keymapping.")
 
381
        return default
 
382
 
 
383
    kt = kt.lower()
 
384
 
 
385
    keymap = check_keytable(kt)
 
386
 
 
387
    if not keymap:
 
388
        logging.debug("Didn't match keymap '%s' in keytable!" % kt)
 
389
        return default
 
390
 
 
391
    return keymap
 
392
 
 
393
def pygrub_path(conn=None):
 
394
    """
 
395
    Return the pygrub path for the current host, or connection if
 
396
    available.
 
397
    """
 
398
    # FIXME: This should be removed/deprecated when capabilities are
 
399
    #        fixed to provide bootloader info
 
400
    if conn:
 
401
        cap = CapabilitiesParser.parse(conn.getCapabilities())
 
402
        if (cap.host.arch == "i86pc"):
 
403
            return "/usr/lib/xen/bin/pygrub"
 
404
        else:
 
405
            return "/usr/lib/xen-default/bin/pygrub"
 
406
 
 
407
    if platform.system() == "SunOS":
 
408
        return "/usr/lib/xen/bin/pygrub"
 
409
    return "/usr/lib/xen-default/bin/pygrub"
 
410
 
 
411
def uri_split(uri):
 
412
    """
 
413
    Parse a libvirt hypervisor uri into it's individual parts
 
414
    @returns: tuple of the form (scheme (ex. 'qemu', 'xen+ssh'), username,
 
415
                                 hostname, path (ex. '/system'), query,
 
416
                                 fragment)
 
417
    """
 
418
    def splitnetloc(url, start=0):
 
419
        for c in '/?#': # the order is important!
 
420
            delim = url.find(c, start)
 
421
            if delim >= 0:
 
422
                break
 
423
        else:
 
424
            delim = len(url)
 
425
        return url[start:delim], url[delim:]
 
426
 
 
427
    username = netloc = query = fragment = ''
 
428
    i = uri.find(":")
 
429
    if i > 0:
 
430
        scheme, uri = uri[:i].lower(), uri[i+1:]
 
431
        if uri[:2] == '//':
 
432
            netloc, uri = splitnetloc(uri, 2)
 
433
            offset = netloc.find("@")
 
434
            if offset > 0:
 
435
                username = netloc[0:offset]
 
436
                netloc = netloc[offset+1:]
 
437
        if '#' in uri:
 
438
            uri, fragment = uri.split('#', 1)
 
439
        if '?' in uri:
 
440
            uri, query = uri.split('?', 1)
 
441
    else:
 
442
        scheme = uri.lower()
 
443
    return scheme, username, netloc, uri, query, fragment
 
444
 
 
445
 
 
446
def is_uri_remote(uri):
 
447
    try:
 
448
        split_uri = uri_split(uri)
 
449
        netloc = split_uri[2]
 
450
 
 
451
        if netloc == "":
 
452
            return False
 
453
        return True
 
454
    except Exception, e:
 
455
        logging.exception("Error parsing URI in is_remote: %s" % e)
 
456
        return True
 
457
 
 
458
def get_uri_hostname(uri):
 
459
    try:
 
460
        split_uri = uri_split(uri)
 
461
        netloc = split_uri[2]
 
462
 
 
463
        if netloc != "":
 
464
            return netloc
 
465
    except Exception, e:
 
466
        logging.warning("Cannot parse URI %s: %s" % (uri, str(e)))
 
467
    return "localhost"
 
468
 
 
469
def get_uri_transport(uri):
 
470
    try:
 
471
        split_uri = uri_split(uri)
 
472
        scheme = split_uri[0]
 
473
        username = split_uri[1]
 
474
 
 
475
        if scheme:
 
476
            offset = scheme.index("+")
 
477
            if offset > 0:
 
478
                return [scheme[offset+1:], username]
 
479
    except:
 
480
        pass
 
481
    return [None, None]
 
482
 
 
483
def get_uri_driver(uri):
 
484
    try:
 
485
        split_uri = uri_split(uri)
 
486
        scheme = split_uri[0]
 
487
 
 
488
        if scheme:
 
489
            offset = scheme.find("+")
 
490
            if offset > 0:
 
491
                return scheme[:offset]
 
492
            return scheme
 
493
    except Exception:
 
494
        pass
 
495
    return "xen"
 
496
 
 
497
def is_storage_capable(conn):
 
498
    """check if virConnectPtr passed has storage API support"""
 
499
    return support.check_conn_support(conn, support.SUPPORT_CONN_STORAGE)
 
500
 
 
501
def get_xml_path(xml, path=None, func=None):
 
502
    """
 
503
    Return the content from the passed xml xpath, or return the result
 
504
    of a passed function (receives xpathContext as its only arg)
 
505
    """
 
506
    doc = None
 
507
    ctx = None
 
508
    result = None
 
509
 
 
510
    try:
 
511
        doc = libxml2.parseDoc(xml)
 
512
        ctx = doc.xpathNewContext()
 
513
 
 
514
        if path:
 
515
            ret = ctx.xpathEval(path)
 
516
            if ret != None:
 
517
                if type(ret) == list:
 
518
                    if len(ret) >= 1:
 
519
                        result = ret[0].content
 
520
                else:
 
521
                    result = ret
 
522
 
 
523
        elif func:
 
524
            result = func(ctx)
 
525
 
 
526
        else:
 
527
            raise ValueError(_("'path' or 'func' is required."))
 
528
    finally:
 
529
        if doc:
 
530
            doc.freeDoc()
 
531
        if ctx:
 
532
            ctx.xpathFreeContext()
 
533
    return result
 
534
 
 
535
def lookup_pool_by_path(conn, path):
 
536
    """
 
537
    Return the first pool with matching matching target path.
 
538
    return the first we find, active or inactive. This iterates over
 
539
    all pools and dumps their xml, so it is NOT quick.
 
540
    Favor running pools over inactive pools.
 
541
    @return virStoragePool object if found, None otherwise
 
542
    """
 
543
    if not is_storage_capable(conn):
 
544
        return None
 
545
 
 
546
    def check_pool(poolname, path):
 
547
        pool = conn.storagePoolLookupByName(poolname)
 
548
        xml_path = get_xml_path(pool.XMLDesc(0), "/pool/target/path")
 
549
        if os.path.abspath(xml_path) == path:
 
550
            return pool
 
551
 
 
552
    running_list = conn.listStoragePools()
 
553
    inactive_list = conn.listDefinedStoragePools()
 
554
    for plist in [running_list, inactive_list]:
 
555
        for name in plist:
 
556
            p = check_pool(name, path)
 
557
            if p:
 
558
                return p
 
559
    return None
 
560
 
 
561
def check_keytable(kt):
 
562
    import keytable
 
563
    keymap = None
 
564
    # Try a simple lookup in the keytable
 
565
    if keytable.keytable.has_key(kt.lower()):
 
566
        return keytable.keytable[kt]
 
567
    else:
 
568
        # Try a more intelligent lookup: strip out all '-' and '_', sort
 
569
        # the keytable keys putting the longest first, then compare
 
570
        # by string prefix
 
571
        def len_cmp(a, b):
 
572
            return len(b) - len(a)
 
573
 
 
574
        clean_kt = kt.replace("-", "").replace("_", "")
 
575
        sorted_keys = sorted(keytable.keytable.keys(), len_cmp)
 
576
 
 
577
        for key in sorted_keys:
 
578
            origkey = key
 
579
            key = key.replace("-", "").replace("_","")
 
580
 
 
581
            if clean_kt.startswith(key):
 
582
                return keytable.keytable[origkey]
 
583
 
 
584
    return keymap
 
585
 
 
586
def _test():
 
587
    import doctest
 
588
    doctest.testmod()
 
589
 
 
590
if __name__ == "__main__":
 
591
    _test()