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

« back to all changes in this revision

Viewing changes to .pc/0004-Fix-location-of-Debian-daily-builds.patch/virtinst/OSDistro.py

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2012-07-24 08:52:01 UTC
  • mfrom: (1.6.8 sid)
  • Revision ID: package-import@ubuntu.com-20120724085201-q3h0cbabg4t46gfm
Tags: 0.600.2-1ubuntu1
* Merge from debian unstable. Remaining changes:
  - debian/patches/9003-fix-path-to-hvmloader-in-testsuite.patch: adjust
    testsuite for 0001-fix-path-to-hvmloader.patch and
    0002-Fix-path-to-pygrub.patch.
  - debian/patches/9004_ubuntu_fix_tree_support.patch: Fix tree detection
    for all ISO/HTTP source, to not longer fail with cobbler/koan.
  - debian/patches/0004-Fix-path-to-qemu-dm.patch: fix the path to the
    qemu-dm binary.
  - debian/{control,rules,pyversions}: Build using dh_python2, use
    debhelper v8 instead of cdbs; for some reason the package build an
    empty binary package when using dh_python2.
  - debian/control: added acl package to depends.
  - debian/control: added libvirt-bin to recommends
* Dropped patches:
  - debian/patches/9005_ubuntu_releases.patch: Upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#
2
 
# Represents OS distribution specific install data
3
 
#
4
 
# Copyright 2006-2007  Red Hat, Inc.
5
 
# Daniel P. Berrange <berrange@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
 
import logging
23
 
import os
24
 
import gzip
25
 
import re
26
 
import tempfile
27
 
import socket
28
 
import ConfigParser
29
 
 
30
 
import virtinst
31
 
import osdict
32
 
from virtinst import _util
33
 
from virtinst import _gettext as _
34
 
 
35
 
from ImageFetcher import MountedImageFetcher
36
 
from ImageFetcher import FTPImageFetcher
37
 
from ImageFetcher import HTTPImageFetcher
38
 
from ImageFetcher import DirectImageFetcher
39
 
 
40
 
def safeint(c):
41
 
    try:
42
 
        val = int(c)
43
 
    except:
44
 
        val = 0
45
 
    return val
46
 
 
47
 
def _fetcherForURI(uri, scratchdir=None):
48
 
    if uri.startswith("http://"):
49
 
        fclass = HTTPImageFetcher
50
 
    elif uri.startswith("ftp://"):
51
 
        fclass = FTPImageFetcher
52
 
    elif uri.startswith("nfs://"):
53
 
        fclass = MountedImageFetcher
54
 
    else:
55
 
        if os.path.isdir(uri):
56
 
            fclass = DirectImageFetcher
57
 
        else:
58
 
            fclass = MountedImageFetcher
59
 
    return fclass(uri, scratchdir)
60
 
 
61
 
def _storeForDistro(fetcher, baseuri, typ, progresscb, arch, distro=None,
62
 
                    scratchdir=None):
63
 
    stores = []
64
 
    skip_treeinfo = False
65
 
    logging.debug("Attempting to detect distro:")
66
 
 
67
 
    dist = virtinst.OSDistro.distroFromTreeinfo(fetcher, progresscb, baseuri,
68
 
                                                arch, typ, scratchdir)
69
 
    if dist:
70
 
        return dist
71
 
    skip_treeinfo = True
72
 
 
73
 
    # FIXME: This 'distro ==' doesn't cut it. 'distro' is from our os
74
 
    # dictionary, so would look like 'fedora9' or 'rhel5', so this needs
75
 
    # to be a bit more intelligent
76
 
    if distro == "fedora" or distro is None:
77
 
        stores.append(FedoraDistro)
78
 
    if distro == "rhel" or distro is None:
79
 
        stores.append(RHELDistro)
80
 
    if distro == "centos" or distro is None:
81
 
        stores.append(CentOSDistro)
82
 
    if distro == "sl" or distro is None:
83
 
        stores.append(SLDistro)
84
 
    if distro == "suse" or distro is None:
85
 
        stores.append(SuseDistro)
86
 
    if distro == "debian" or distro is None:
87
 
        stores.append(DebianDistro)
88
 
    if distro == "ubuntu" or distro is None:
89
 
        stores.append(UbuntuDistro)
90
 
    if distro == "mandriva" or distro is None:
91
 
        stores.append(MandrivaDistro)
92
 
    if distro == "mageia" or distro is None:
93
 
        stores.append(MageiaDistro)
94
 
    # XXX: this is really "nevada"
95
 
    if distro == "solaris" or distro is None:
96
 
        stores.append(SolarisDistro)
97
 
    if distro == "solaris" or distro is None:
98
 
        stores.append(OpenSolarisDistro)
99
 
    if distro == "netware" or distro is None:
100
 
        stores.append(NetWareDistro)
101
 
 
102
 
    stores.append(GenericDistro)
103
 
 
104
 
    for sclass in stores:
105
 
        store = sclass(baseuri, arch, typ, scratchdir)
106
 
        if skip_treeinfo:
107
 
            store.uses_treeinfo = False
108
 
        if store.isValidStore(fetcher, progresscb):
109
 
            return store
110
 
 
111
 
    raise ValueError(
112
 
        _("Could not find an installable distribution at '%s'\n"
113
 
          "The location must be the root directory of an install tree." %
114
 
          baseuri))
115
 
 
116
 
def _locationCheckWrapper(guest, baseuri, progresscb,
117
 
                          scratchdir, _type, arch, callback):
118
 
    fetcher = _fetcherForURI(baseuri, scratchdir)
119
 
    if guest:
120
 
        arch = guest.arch
121
 
 
122
 
    try:
123
 
        fetcher.prepareLocation()
124
 
    except ValueError, e:
125
 
        logging.exception("Error preparing install location")
126
 
        raise ValueError(_("Invalid install location: ") + str(e))
127
 
 
128
 
    try:
129
 
        store = _storeForDistro(fetcher=fetcher, baseuri=baseuri, typ=_type,
130
 
                                progresscb=progresscb, scratchdir=scratchdir,
131
 
                                arch=arch)
132
 
 
133
 
        return callback(store, fetcher)
134
 
    finally:
135
 
        fetcher.cleanupLocation()
136
 
 
137
 
def _acquireMedia(iskernel, guest, baseuri, progresscb,
138
 
                  scratchdir="/var/tmp", _type=None):
139
 
 
140
 
    def media_cb(store, fetcher):
141
 
        os_type, os_variant = store.get_osdict_info()
142
 
        media = None
143
 
 
144
 
        if iskernel:
145
 
            media = store.acquireKernel(guest, fetcher, progresscb)
146
 
        else:
147
 
            media = store.acquireBootDisk(guest, fetcher, progresscb)
148
 
 
149
 
        return [store, os_type, os_variant, media]
150
 
 
151
 
    return _locationCheckWrapper(guest, baseuri, progresscb, scratchdir, _type,
152
 
                                 None, media_cb)
153
 
 
154
 
# Helper method to lookup install media distro and fetch an install kernel
155
 
def acquireKernel(guest, baseuri, progresscb, scratchdir, type=None):
156
 
    iskernel = True
157
 
    return _acquireMedia(iskernel, guest, baseuri, progresscb,
158
 
                         scratchdir, type)
159
 
 
160
 
# Helper method to lookup install media distro and fetch a boot iso
161
 
def acquireBootDisk(guest, baseuri, progresscb, scratchdir, type=None):
162
 
    iskernel = False
163
 
    return _acquireMedia(iskernel, guest, baseuri, progresscb,
164
 
                         scratchdir, type)
165
 
 
166
 
def _check_ostype_valid(os_type):
167
 
    return bool(os_type in osdict.sort_helper(osdict.OS_TYPES))
168
 
 
169
 
def _check_osvariant_valid(os_type, os_variant):
170
 
    return bool(_check_ostype_valid(os_type) and
171
 
        os_variant in osdict.sort_helper(osdict.OS_TYPES[os_type]["variants"]))
172
 
 
173
 
# Attempt to detect the os type + variant for the passed location
174
 
def detectMediaDistro(location, arch):
175
 
    import urlgrabber
176
 
    progresscb = urlgrabber.progress.BaseMeter()
177
 
    guest = None
178
 
    baseuri = location
179
 
    scratchdir = "/var/tmp"
180
 
    _type = None
181
 
    def media_cb(store, ignore):
182
 
        return store
183
 
 
184
 
    store = _locationCheckWrapper(guest, baseuri, progresscb, scratchdir,
185
 
                                  _type, arch, media_cb)
186
 
 
187
 
    return store.get_osdict_info()
188
 
 
189
 
 
190
 
def distroFromTreeinfo(fetcher, progresscb, uri, arch, vmtype=None,
191
 
                       scratchdir=None):
192
 
    # Parse treeinfo 'family' field, and return the associated Distro class
193
 
    # None if no treeinfo, GenericDistro if unknown family type.
194
 
    if not fetcher.hasFile(".treeinfo"):
195
 
        return None
196
 
 
197
 
    tmptreeinfo = fetcher.acquireFile(".treeinfo", progresscb)
198
 
    try:
199
 
        treeinfo = ConfigParser.SafeConfigParser()
200
 
        treeinfo.read(tmptreeinfo)
201
 
    finally:
202
 
        os.unlink(tmptreeinfo)
203
 
 
204
 
    try:
205
 
        fam = treeinfo.get("general", "family")
206
 
    except ConfigParser.NoSectionError:
207
 
        return None
208
 
 
209
 
    if re.match(".*Fedora.*", fam):
210
 
        dclass = FedoraDistro
211
 
    elif re.match(".*CentOS.*", fam):
212
 
        dclass = CentOSDistro
213
 
    elif re.match(".*Red Hat Enterprise Linux.*", fam):
214
 
        dclass = RHELDistro
215
 
    elif re.match(".*Scientific Linux.*", fam):
216
 
        dclass = SLDistro
217
 
    else:
218
 
        dclass = GenericDistro
219
 
 
220
 
    ob = dclass(uri, arch, vmtype, scratchdir)
221
 
    ob.treeinfo = treeinfo
222
 
 
223
 
    # Explictly call this, so we populate os_type/variant info
224
 
    ob.isValidStore(fetcher, progresscb)
225
 
 
226
 
    return ob
227
 
 
228
 
 
229
 
# An image store is a base class for retrieving either a bootable
230
 
# ISO image, or a kernel+initrd  pair for a particular OS distribution
231
 
class Distro:
232
 
 
233
 
    name = ""
234
 
 
235
 
    # osdict type and variant values
236
 
    os_type = None
237
 
    os_variant = None
238
 
 
239
 
    _boot_iso_paths = []
240
 
    _hvm_kernel_paths = []
241
 
    _xen_kernel_paths = []
242
 
    uses_treeinfo = False
243
 
 
244
 
    def __init__(self, uri, arch, vmtype=None, scratchdir=None):
245
 
        self.uri = uri
246
 
        self.type = vmtype
247
 
        self.scratchdir = scratchdir
248
 
        self.arch = arch
249
 
        self.treeinfo = None
250
 
 
251
 
    def isValidStore(self, fetcher, progresscb):
252
 
        """Determine if uri points to a tree of the store's distro"""
253
 
        raise NotImplementedError
254
 
 
255
 
    def acquireKernel(self, guest, fetcher, progresscb):
256
 
        kernelpath = None
257
 
        initrdpath = None
258
 
        if self._hasTreeinfo(fetcher, progresscb):
259
 
            kernelpath = self._getTreeinfoMedia("kernel")
260
 
            initrdpath = self._getTreeinfoMedia("initrd")
261
 
        else:
262
 
            # fall back to old code
263
 
            if self.type is None or self.type == "hvm":
264
 
                paths = self._hvm_kernel_paths
265
 
            else:
266
 
                paths = self._xen_kernel_paths
267
 
 
268
 
            for kpath, ipath in paths:
269
 
                if fetcher.hasFile(kpath) and fetcher.hasFile(ipath):
270
 
                    kernelpath = kpath
271
 
                    initrdpath = ipath
272
 
 
273
 
        if not kernelpath or not initrdpath:
274
 
            raise RuntimeError(_("Couldn't find %(type)s kernel for "
275
 
                                 "%(distro)s tree.") % \
276
 
                                 { "distro": self.name, "type" : self.type })
277
 
 
278
 
        return self._kernelFetchHelper(fetcher, guest, progresscb, kernelpath,
279
 
                                       initrdpath)
280
 
 
281
 
    def acquireBootDisk(self, guest, fetcher, progresscb):
282
 
        if self._hasTreeinfo(fetcher, progresscb):
283
 
            return fetcher.acquireFile(self._getTreeinfoMedia("boot.iso"),
284
 
                                       progresscb)
285
 
        else:
286
 
            for path in self._boot_iso_paths:
287
 
                if fetcher.hasFile(path):
288
 
                    return fetcher.acquireFile(path, progresscb)
289
 
            raise RuntimeError(_("Could not find boot.iso in %s tree." % \
290
 
                               self.name))
291
 
 
292
 
    def get_osdict_info(self):
293
 
        """
294
 
        Return (distro, variant) tuple, checking to make sure they are valid
295
 
        osdict entries
296
 
        """
297
 
        if not self.os_type:
298
 
            return (None, None)
299
 
 
300
 
        if not _check_ostype_valid(self.os_type):
301
 
            logging.debug("%s set os_type to %s, which is not in osdict.",
302
 
                          self, self.os_type)
303
 
            return (None, None)
304
 
 
305
 
        if not self.os_variant:
306
 
            return (self.os_type, None)
307
 
 
308
 
        if not _check_osvariant_valid(self.os_type, self.os_variant):
309
 
            logging.debug("%s set os_variant to %s, which is not in osdict"
310
 
                          " for distro %s.",
311
 
                          self, self.os_variant, self.os_type)
312
 
            return (self.os_type, None)
313
 
 
314
 
        return (self.os_type, self.os_variant)
315
 
 
316
 
    def _hasTreeinfo(self, fetcher, progresscb):
317
 
        # all Red Hat based distros should have .treeinfo, perhaps others
318
 
        # will in time
319
 
        if not (self.treeinfo is None):
320
 
            return True
321
 
 
322
 
        if not self.uses_treeinfo or not fetcher.hasFile(".treeinfo"):
323
 
            return False
324
 
 
325
 
        logging.debug("Detected .treeinfo file")
326
 
 
327
 
        tmptreeinfo = fetcher.acquireFile(".treeinfo", progresscb)
328
 
        try:
329
 
            self.treeinfo = ConfigParser.SafeConfigParser()
330
 
            self.treeinfo.read(tmptreeinfo)
331
 
        finally:
332
 
            os.unlink(tmptreeinfo)
333
 
        return True
334
 
 
335
 
    def _getTreeinfoMedia(self, mediaName):
336
 
        if self.type == "xen":
337
 
            t = "xen"
338
 
        else:
339
 
            t = self.treeinfo.get("general", "arch")
340
 
 
341
 
        return self.treeinfo.get("images-%s" % t, mediaName)
342
 
 
343
 
    def _fetchAndMatchRegex(self, fetcher, progresscb, filename, regex):
344
 
        # Fetch 'filename' and return True/False if it matches the regex
345
 
        local_file = None
346
 
        try:
347
 
            try:
348
 
                local_file = fetcher.acquireFile(filename, progresscb)
349
 
            except:
350
 
                return False
351
 
 
352
 
            f = open(local_file, "r")
353
 
            try:
354
 
                while 1:
355
 
                    buf = f.readline()
356
 
                    if not buf:
357
 
                        break
358
 
                    if re.match(regex, buf):
359
 
                        return True
360
 
            finally:
361
 
                f.close()
362
 
        finally:
363
 
            if local_file is not None:
364
 
                os.unlink(local_file)
365
 
 
366
 
        return False
367
 
 
368
 
    def _kernelFetchHelper(self, fetcher, guest, progresscb, kernelpath,
369
 
                           initrdpath):
370
 
        # Simple helper for fetching kernel + initrd and performing
371
 
        # cleanup if neccessary
372
 
        kernel = fetcher.acquireFile(kernelpath, progresscb)
373
 
        args = ''
374
 
 
375
 
        if not fetcher.location.startswith("/"):
376
 
            args += "method=" + fetcher.location
377
 
 
378
 
        if guest.extraargs:
379
 
            args += " " + guest.extraargs
380
 
 
381
 
        try:
382
 
            initrd = fetcher.acquireFile(initrdpath, progresscb)
383
 
            return kernel, initrd, args
384
 
        except:
385
 
            os.unlink(kernel)
386
 
 
387
 
 
388
 
class GenericDistro(Distro):
389
 
    """Generic distro store. Check well known paths for kernel locations
390
 
       as a last resort if we can't recognize any actual distro"""
391
 
 
392
 
    name = "Generic"
393
 
    os_type = "linux"
394
 
    uses_treeinfo = True
395
 
 
396
 
    _xen_paths = [ ("images/xen/vmlinuz",
397
 
                    "images/xen/initrd.img"),           # Fedora
398
 
                 ]
399
 
    _hvm_paths = [ ("images/pxeboot/vmlinuz",
400
 
                    "images/pxeboot/initrd.img"),       # Fedora
401
 
                 ]
402
 
    _iso_paths = [ "images/boot.iso",                   # RH/Fedora
403
 
                   "boot/boot.iso",                     # Suse
404
 
                   "current/images/netboot/mini.iso",   # Debian
405
 
                   "install/images/boot.iso",           # Mandriva
406
 
                 ]
407
 
 
408
 
    # Holds values to use when actually pulling down media
409
 
    _valid_kernel_path = None
410
 
    _valid_iso_path = None
411
 
 
412
 
    def isValidStore(self, fetcher, progresscb):
413
 
        if self._hasTreeinfo(fetcher, progresscb):
414
 
            # Use treeinfo to pull down media paths
415
 
            if self.type == "xen":
416
 
                typ = "xen"
417
 
            else:
418
 
                typ = self.treeinfo.get("general", "arch")
419
 
            kernelSection = "images-%s" % typ
420
 
            isoSection = "images-%s" % self.treeinfo.get("general", "arch")
421
 
 
422
 
            if self.treeinfo.has_section(kernelSection):
423
 
                self._valid_kernel_path = (self._getTreeinfoMedia("kernel"),
424
 
                                           self._getTreeinfoMedia("initrd"))
425
 
            if self.treeinfo.has_section(isoSection):
426
 
                self._valid_iso_path = self.treeinfo.get(isoSection, "boot.iso")
427
 
 
428
 
        if self.type == "xen":
429
 
            kern_list = self._xen_paths
430
 
        else:
431
 
            kern_list = self._hvm_paths
432
 
 
433
 
        # If validated media paths weren't found (no treeinfo), check against
434
 
        # list of media location paths.
435
 
        for kern, init in kern_list:
436
 
            if self._valid_kernel_path == None \
437
 
               and fetcher.hasFile(kern) and fetcher.hasFile(init):
438
 
                self._valid_kernel_path = (kern, init)
439
 
                break
440
 
        for iso in self._iso_paths:
441
 
            if self._valid_iso_path == None \
442
 
               and fetcher.hasFile(iso):
443
 
                self._valid_iso_path = iso
444
 
                break
445
 
 
446
 
        if self._valid_kernel_path or self._valid_iso_path:
447
 
            return True
448
 
        return False
449
 
 
450
 
    def acquireKernel(self, guest, fetcher, progresscb):
451
 
        if self._valid_kernel_path == None:
452
 
            raise ValueError(_("Could not find a kernel path for virt type "
453
 
                               "'%s'" % self.type))
454
 
 
455
 
        return self._kernelFetchHelper(fetcher, guest, progresscb,
456
 
                                       self._valid_kernel_path[0],
457
 
                                       self._valid_kernel_path[1])
458
 
 
459
 
    def acquireBootDisk(self, guest, fetcher, progresscb):
460
 
        if self._valid_iso_path == None:
461
 
            raise ValueError(_("Could not find a boot iso path for this tree."))
462
 
 
463
 
        return fetcher.acquireFile(self._valid_iso_path, progresscb)
464
 
 
465
 
 
466
 
# Base image store for any Red Hat related distros which have
467
 
# a common layout
468
 
class RedHatDistro(Distro):
469
 
 
470
 
    name = "Red Hat"
471
 
    os_type = "linux"
472
 
 
473
 
    uses_treeinfo = True
474
 
    _boot_iso_paths   = [ "images/boot.iso" ]
475
 
    _hvm_kernel_paths = [ ("images/pxeboot/vmlinuz",
476
 
                           "images/pxeboot/initrd.img") ]
477
 
    _xen_kernel_paths = [ ("images/xen/vmlinuz",
478
 
                           "images/xen/initrd.img") ]
479
 
 
480
 
    def isValidStore(self, fetcher, progresscb):
481
 
        raise NotImplementedError
482
 
 
483
 
 
484
 
# Fedora distro check
485
 
class FedoraDistro(RedHatDistro):
486
 
 
487
 
    name = "Fedora"
488
 
 
489
 
    def isValidStore(self, fetcher, progresscb):
490
 
        if self._hasTreeinfo(fetcher, progresscb):
491
 
            m = re.match(".*Fedora.*", self.treeinfo.get("general", "family"))
492
 
            ret = (m != None)
493
 
 
494
 
            if ret:
495
 
                ver = self.treeinfo.get("general", "version")
496
 
                if ver == "development":
497
 
                    self.os_variant = self._latestFedoraVariant()
498
 
                elif ver:
499
 
                    self.os_variant = "fedora" + (str(ver).split("-"))[0]
500
 
 
501
 
            return ret
502
 
        else:
503
 
            if fetcher.hasFile("Fedora"):
504
 
                logging.debug("Detected a Fedora distro")
505
 
                return True
506
 
            return False
507
 
 
508
 
    def _latestFedoraVariant(self):
509
 
        ret = None
510
 
        for var in osdict.sort_helper(osdict.OS_TYPES["linux"]["variants"]):
511
 
            if var.startswith("fedora"):
512
 
                # Last fedora* occurence should be the newest
513
 
                ret = var
514
 
        return ret
515
 
 
516
 
# Red Hat Enterprise Linux distro check
517
 
class RHELDistro(RedHatDistro):
518
 
 
519
 
    name = "Red Hat Enterprise Linux"
520
 
 
521
 
    def isValidStore(self, fetcher, progresscb):
522
 
        if self._hasTreeinfo(fetcher, progresscb):
523
 
            m = re.match(".*Red Hat Enterprise Linux.*",
524
 
                         self.treeinfo.get("general", "family"))
525
 
            ret = (m != None)
526
 
 
527
 
            if ret:
528
 
                self._variantFromVersion()
529
 
            return ret
530
 
        else:
531
 
            # fall back to old code
532
 
            if fetcher.hasFile("Server"):
533
 
                logging.debug("Detected a RHEL 5 Server distro")
534
 
                self.os_variant = "rhel5"
535
 
                return True
536
 
            if fetcher.hasFile("Client"):
537
 
                logging.debug("Detected a RHEL 5 Client distro")
538
 
                self.os_variant = "rhel5"
539
 
                return True
540
 
            if fetcher.hasFile("RedHat"):
541
 
                if fetcher.hasFile("dosutils"):
542
 
                    self.os_variant = "rhel3"
543
 
                else:
544
 
                    self.os_variant = "rhel4"
545
 
 
546
 
                logging.debug("Detected a %s distro", self.os_variant)
547
 
                return True
548
 
            return False
549
 
 
550
 
    def _parseTreeinfoVersion(self, verstr):
551
 
        version = safeint(verstr[0])
552
 
        update = 0
553
 
 
554
 
        updinfo = verstr.split(".")
555
 
        if len(updinfo) > 1:
556
 
            update = safeint(updinfo[1])
557
 
 
558
 
        return version, update
559
 
 
560
 
    def _variantFromVersion(self):
561
 
        ver = self.treeinfo.get("general", "version")
562
 
        if not ver:
563
 
            return
564
 
 
565
 
        version, update = self._parseTreeinfoVersion(ver)
566
 
        self._setRHELVariant(version, update)
567
 
 
568
 
    def _setRHELVariant(self, version, update):
569
 
        if not _check_ostype_valid(self.os_type):
570
 
            return
571
 
 
572
 
        base = "rhel" + str(version)
573
 
        if update < 0:
574
 
            update = 0
575
 
 
576
 
        ret = None
577
 
        while update >= 0:
578
 
            tryvar = base + ".%s" % update
579
 
            if not _check_osvariant_valid(self.os_type, tryvar):
580
 
                update -= 1
581
 
                continue
582
 
 
583
 
            ret = tryvar
584
 
            break
585
 
 
586
 
        if not ret:
587
 
            # Try plain rhel5, rhel6, whatev
588
 
            if _check_osvariant_valid(self.os_type, base):
589
 
                ret = base
590
 
 
591
 
        if ret:
592
 
            self.os_variant = ret
593
 
 
594
 
 
595
 
# CentOS distro check
596
 
class CentOSDistro(RHELDistro):
597
 
 
598
 
    name = "CentOS"
599
 
 
600
 
    def isValidStore(self, fetcher, progresscb):
601
 
        if self._hasTreeinfo(fetcher, progresscb):
602
 
            m = re.match(".*CentOS.*", self.treeinfo.get("general", "family"))
603
 
            ret = (m != None)
604
 
 
605
 
            if ret:
606
 
                self._variantFromVersion()
607
 
            return ret
608
 
        else:
609
 
            # fall back to old code
610
 
            if fetcher.hasFile("CentOS"):
611
 
                logging.debug("Detected a CentOS distro")
612
 
                return True
613
 
            return False
614
 
 
615
 
# Scientific Linux distro check
616
 
class SLDistro(RHELDistro):
617
 
 
618
 
    name = "Scientific Linux"
619
 
 
620
 
    _boot_iso_paths = RHELDistro._boot_iso_paths + [ "images/SL/boot.iso" ]
621
 
    _hvm_kernel_paths = RHELDistro._hvm_kernel_paths + \
622
 
                        [ ("images/SL/pxeboot/vmlinuz",
623
 
                           "images/SL/pxeboot/initrd.img") ]
624
 
 
625
 
    def isValidStore(self, fetcher, progresscb):
626
 
        if self._hasTreeinfo(fetcher, progresscb):
627
 
            m = re.match(".*Scientific Linux.*",
628
 
                         self.treeinfo.get("general", "family"))
629
 
            ret = (m != None)
630
 
 
631
 
            if ret:
632
 
                self._variantFromVersion()
633
 
            return ret
634
 
        else:
635
 
            if fetcher.hasFile("SL"):
636
 
                logging.debug("Detected a Scientific Linux distro")
637
 
                return True
638
 
            return False
639
 
 
640
 
    def _parseTreeinfoVersion(self, verstr):
641
 
        """
642
 
        Overrides method in RHELDistro
643
 
        """
644
 
        version = safeint(verstr[0])
645
 
        update = 0
646
 
 
647
 
        if len(verstr) > 1:
648
 
            update = safeint(verstr[1])
649
 
        return version, update
650
 
 
651
 
 
652
 
# Suse  image store is harder - we fetch the kernel RPM and a helper
653
 
# RPM and then munge bits together to generate a initrd
654
 
class SuseDistro(Distro):
655
 
 
656
 
    name = "SUSE"
657
 
    os_type = "linux"
658
 
    _boot_iso_paths   = [ "boot/boot.iso" ]
659
 
 
660
 
    def __init__(self, uri, arch, vmtype=None, scratchdir=None):
661
 
        Distro.__init__(self, uri, arch, vmtype, scratchdir)
662
 
        if re.match(r'i[4-9]86', arch):
663
 
            self.arch = 'i386'
664
 
 
665
 
        oldkern = "linux"
666
 
        oldinit = "initrd"
667
 
        if arch == "x86_64":
668
 
            oldkern += "64"
669
 
            oldinit += "64"
670
 
 
671
 
        # Tested with Opensuse >= 10.2, 11, and sles 10
672
 
        self._hvm_kernel_paths = [ ("boot/%s/loader/linux" % self.arch,
673
 
                                    "boot/%s/loader/initrd" % self.arch) ]
674
 
        # Tested with Opensuse 10.0
675
 
        self._hvm_kernel_paths.append(("boot/loader/%s" % oldkern,
676
 
                                       "boot/loader/%s" % oldinit))
677
 
 
678
 
        # Matches Opensuse > 10.2 and sles 10
679
 
        self._xen_kernel_paths = [ ("boot/%s/vmlinuz-xen" % self.arch,
680
 
                                    "boot/%s/initrd-xen" % self.arch) ]
681
 
 
682
 
    def isValidStore(self, fetcher, progresscb):
683
 
        # Suse distros always have a 'directory.yast' file in the top
684
 
        # level of install tree, which we use as the magic check
685
 
        if fetcher.hasFile("directory.yast"):
686
 
            logging.debug("Detected a Suse distro.")
687
 
            return True
688
 
        return False
689
 
 
690
 
    def acquireKernel(self, guest, fetcher, progresscb):
691
 
        # If installing a fullvirt guest
692
 
        if self.type is None or self.type == "hvm" or \
693
 
           fetcher.hasFile("boot/%s/vmlinuz-xen" % self.arch):
694
 
            return Distro.acquireKernel(self, guest, fetcher, progresscb)
695
 
 
696
 
        # For Opensuse <= 10.2, we need to perform some heinous stuff
697
 
        logging.debug("Trying Opensuse 10 PV rpm hacking")
698
 
        return self._findXenRPMS(fetcher, progresscb)
699
 
 
700
 
 
701
 
    def _findXenRPMS(self, fetcher, progresscb):
702
 
        kernelrpm = None
703
 
        installinitrdrpm = None
704
 
        filelist = None
705
 
        try:
706
 
            # There is no predictable filename for kernel/install-initrd RPMs
707
 
            # so we have to grok the filelist and find them
708
 
            filelist = fetcher.acquireFile("ls-lR.gz", progresscb)
709
 
            (kernelrpmname, initrdrpmname) = self._extractRPMNames(filelist)
710
 
 
711
 
            # Now fetch the two RPMs we want
712
 
            kernelrpm = fetcher.acquireFile(kernelrpmname, progresscb)
713
 
            installinitrdrpm = fetcher.acquireFile(initrdrpmname, progresscb)
714
 
 
715
 
            # Process the RPMs to extract the kernel & generate an initrd
716
 
            return self._buildKernelInitrd(fetcher, kernelrpm, installinitrdrpm, progresscb)
717
 
        finally:
718
 
            if filelist is not None:
719
 
                os.unlink(filelist)
720
 
            if kernelrpm is not None:
721
 
                os.unlink(kernelrpm)
722
 
            if installinitrdrpm is not None:
723
 
                os.unlink(installinitrdrpm)
724
 
 
725
 
    # We need to parse the ls-lR.gz file, looking for the kernel &
726
 
    # install-initrd RPM entries - capturing the directory they are
727
 
    # in and the version'd filename.
728
 
    def _extractRPMNames(self, filelist):
729
 
        filelistData = gzip.GzipFile(filelist, mode="r")
730
 
        try:
731
 
            arches = [self.arch]
732
 
            # On i686 arch, we also look under i585 and i386 dirs
733
 
            # in case the RPM is built for a lesser arch. We also
734
 
            # need the PAE variant (for Fedora dom0 at least)
735
 
            #
736
 
            # XXX shouldn't hard code that dom0 is PAE
737
 
            if self.arch == "i386":
738
 
                arches.append("i586")
739
 
                arches.append("i686")
740
 
                kernelname = "kernel-xenpae"
741
 
            else:
742
 
                kernelname = "kernel-xen"
743
 
 
744
 
            installinitrdrpm = None
745
 
            kernelrpm = None
746
 
            dirname = None
747
 
            while 1:
748
 
                data = filelistData.readline()
749
 
                if not data:
750
 
                    break
751
 
                if dirname is None:
752
 
                    for arch in arches:
753
 
                        wantdir = "/suse/" + arch
754
 
                        if data == "." + wantdir + ":\n":
755
 
                            dirname = wantdir
756
 
                            break
757
 
                else:
758
 
                    if data == "\n":
759
 
                        dirname = None
760
 
                    else:
761
 
                        if data[:5] != "total":
762
 
                            filename = re.split("\s+", data)[8]
763
 
 
764
 
                            if filename[:14] == "install-initrd":
765
 
                                installinitrdrpm = dirname + "/" + filename
766
 
                            elif filename[:len(kernelname)] == kernelname:
767
 
                                kernelrpm = dirname + "/" + filename
768
 
 
769
 
            if kernelrpm is None:
770
 
                raise Exception(_("Unable to determine kernel RPM path"))
771
 
            if installinitrdrpm is None:
772
 
                raise Exception(_("Unable to determine install-initrd RPM path"))
773
 
            return (kernelrpm, installinitrdrpm)
774
 
        finally:
775
 
            filelistData.close()
776
 
 
777
 
    # We have a kernel RPM and a install-initrd RPM with a generic initrd in it
778
 
    # Now we have to merge the two together to build an initrd capable of
779
 
    # booting the installer.
780
 
    #
781
 
    # Yes, this is crazy ass stuff :-)
782
 
    def _buildKernelInitrd(self, fetcher, kernelrpm, installinitrdrpm, progresscb):
783
 
        progresscb.start(text=_("Building initrd"), size=11)
784
 
        progresscb.update(1)
785
 
        cpiodir = tempfile.mkdtemp(prefix="virtinstcpio.", dir=self.scratchdir)
786
 
        try:
787
 
            # Extract the kernel RPM contents
788
 
            os.mkdir(cpiodir + "/kernel")
789
 
            cmd = "cd " + cpiodir + "/kernel && (rpm2cpio " + kernelrpm + " | cpio --quiet -idm)"
790
 
            logging.debug("Running " + cmd)
791
 
            os.system(cmd)
792
 
            progresscb.update(2)
793
 
 
794
 
            # Determine the raw kernel version
795
 
            kernelinfo = None
796
 
            for f in os.listdir(cpiodir + "/kernel/boot"):
797
 
                if f.startswith("System.map-"):
798
 
                    kernelinfo = re.split("-", f)
799
 
            kernel_override = kernelinfo[1] + "-override-" + kernelinfo[3]
800
 
            kernel_version = kernelinfo[1] + "-" + kernelinfo[2] + "-" + kernelinfo[3]
801
 
            logging.debug("Got kernel version " + str(kernelinfo))
802
 
 
803
 
            # Build a list of all .ko files
804
 
            modpaths = {}
805
 
            for root, dummy, files in os.walk(cpiodir + "/kernel/lib/modules", topdown=False):
806
 
                for name in files:
807
 
                    if name.endswith(".ko"):
808
 
                        modpaths[name] = os.path.join(root, name)
809
 
            progresscb.update(3)
810
 
 
811
 
            # Extract the install-initrd RPM contents
812
 
            os.mkdir(cpiodir + "/installinitrd")
813
 
            cmd = "cd " + cpiodir + "/installinitrd && (rpm2cpio " + installinitrdrpm + " | cpio --quiet -idm)"
814
 
            logging.debug("Running " + cmd)
815
 
            os.system(cmd)
816
 
            progresscb.update(4)
817
 
 
818
 
            # Read in list of mods required for initrd
819
 
            modnames = []
820
 
            fn = open(cpiodir + "/installinitrd/usr/lib/install-initrd/" + kernelinfo[3] + "/module.list", "r")
821
 
            try:
822
 
                while 1:
823
 
                    line = fn.readline()
824
 
                    if not line:
825
 
                        break
826
 
                    line = line[:len(line) - 1]
827
 
                    modnames.append(line)
828
 
            finally:
829
 
                fn.close()
830
 
            progresscb.update(5)
831
 
 
832
 
            # Uncompress the basic initrd
833
 
            cmd = "gunzip -c " + cpiodir + "/installinitrd/usr/lib/install-initrd/initrd-base.gz > " + cpiodir + "/initrd.img"
834
 
            logging.debug("Running " + cmd)
835
 
            os.system(cmd)
836
 
            progresscb.update(6)
837
 
 
838
 
            # Create temp tree to hold stuff we're adding to initrd
839
 
            moddir = cpiodir + "/initrd/lib/modules/" + kernel_override + "/initrd/"
840
 
            moddepdir = cpiodir + "/initrd/lib/modules/" + kernel_version
841
 
            os.makedirs(moddir)
842
 
            os.makedirs(moddepdir)
843
 
            os.symlink("../" + kernel_override, moddepdir + "/updates")
844
 
            os.symlink("lib/modules/" + kernel_override + "/initrd", cpiodir + "/initrd/modules")
845
 
            cmd = "cp " + cpiodir + "/installinitrd/usr/lib/install-initrd/" + kernelinfo[3] + "/module.config" + " " + moddir
846
 
            logging.debug("Running " + cmd)
847
 
            os.system(cmd)
848
 
            progresscb.update(7)
849
 
 
850
 
            # Copy modules we need into initrd staging dir
851
 
            for modname in modnames:
852
 
                if modname in modpaths:
853
 
                    src = modpaths[modname]
854
 
                    dst = moddir + "/" + modname
855
 
                    os.system("cp " + src + " " + dst)
856
 
            progresscb.update(8)
857
 
 
858
 
            # Run depmod across the staging area
859
 
            cmd = "depmod -a -b " + cpiodir + "/initrd -F " + cpiodir + "/kernel/boot/System.map-" + kernel_version + " " + kernel_version
860
 
            logging.debug("Running " + cmd)
861
 
            os.system(cmd)
862
 
            progresscb.update(9)
863
 
 
864
 
            # Add the extra modules to the basic initrd
865
 
            cmd = "cd " + cpiodir + "/initrd && ( find . | cpio --quiet -o -H newc -A -F " + cpiodir + "/initrd.img)"
866
 
            logging.debug("Running " + cmd)
867
 
            os.system(cmd)
868
 
            progresscb.update(10)
869
 
 
870
 
            # Compress the final initrd
871
 
            cmd = "gzip -f9N " + cpiodir + "/initrd.img"
872
 
            logging.debug("Running " + cmd)
873
 
            os.system(cmd)
874
 
            progresscb.end(11)
875
 
 
876
 
            # Save initrd & kernel to temp files for booting...
877
 
            initrdname = fetcher.saveTemp(open(cpiodir + "/initrd.img.gz", "r"), "initrd.img")
878
 
            logging.debug("Saved " + initrdname)
879
 
            try:
880
 
                kernelname = fetcher.saveTemp(open(cpiodir + "/kernel/boot/vmlinuz-" + kernel_version, "r"), "vmlinuz")
881
 
                logging.debug("Saved " + kernelname)
882
 
                return (kernelname, initrdname, "install=" + fetcher.location)
883
 
            except:
884
 
                os.unlink(initrdname)
885
 
        finally:
886
 
            #pass
887
 
            os.system("rm -rf " + cpiodir)
888
 
 
889
 
 
890
 
class DebianDistro(Distro):
891
 
    # ex. http://ftp.egr.msu.edu/debian/dists/sarge/main/installer-i386/
892
 
    # daily builds: http://people.debian.org/~joeyh/d-i/
893
 
 
894
 
    name = "Debian"
895
 
    os_type = "linux"
896
 
 
897
 
    def __init__(self, uri, arch, vmtype=None, scratchdir=None):
898
 
        Distro.__init__(self, uri, arch, vmtype, scratchdir)
899
 
        if uri.count("installer-i386"):
900
 
            self._treeArch = "i386"
901
 
        elif uri.count("installer-amd64"):
902
 
            self._treeArch = "amd64"
903
 
        else:
904
 
            self._treeArch = "i386"
905
 
 
906
 
        if re.match(r'i[4-9]86', arch):
907
 
            self.arch = 'i386'
908
 
 
909
 
        self._installer_name = self.name.lower() + "-" + "installer"
910
 
        self._prefix = 'current/images'
911
 
        self._set_media_paths()
912
 
 
913
 
    def _set_media_paths(self):
914
 
        # Use self._prefix to set media paths
915
 
        self._boot_iso_paths   = [ "%s/netboot/mini.iso" % self._prefix ]
916
 
        hvmroot = "%s/netboot/%s/%s/" % (self._prefix,
917
 
                                         self._installer_name,
918
 
                                         self._treeArch)
919
 
        xenroot = "%s/netboot/xen/" % self._prefix
920
 
        self._hvm_kernel_paths = [ (hvmroot + "linux", hvmroot + "initrd.gz") ]
921
 
        self._xen_kernel_paths = [ (xenroot + "vmlinuz",
922
 
                                    xenroot + "initrd.gz") ]
923
 
 
924
 
    def isValidStore(self, fetcher, progresscb):
925
 
        if fetcher.hasFile("%s/MANIFEST" % self._prefix):
926
 
            # For regular trees
927
 
            pass
928
 
        elif fetcher.hasFile("images/daily/MANIFEST"):
929
 
            # For daily trees
930
 
            self._prefix = "images/daily"
931
 
            self._set_media_paths()
932
 
        else:
933
 
            return False
934
 
 
935
 
        filename = "%s/MANIFEST" % self._prefix
936
 
        regex = ".*%s.*" % self._installer_name
937
 
        if self._fetchAndMatchRegex(fetcher, progresscb, filename, regex):
938
 
            logging.debug("Detected a %s distro", self.name)
939
 
            return True
940
 
 
941
 
        logging.debug("MANIFEST didn't match regex, not a %s distro",
942
 
                      self.name)
943
 
        return False
944
 
 
945
 
 
946
 
class UbuntuDistro(DebianDistro):
947
 
    name = "Ubuntu"
948
 
    # regular tree:
949
 
    # http://archive.ubuntu.com/ubuntu/dists/natty/main/installer-amd64/
950
 
 
951
 
    def isValidStore(self, fetcher, progresscb):
952
 
        if fetcher.hasFile("%s/MANIFEST" % self._prefix):
953
 
            # For regular trees
954
 
            filename = "%s/MANIFEST" % self._prefix
955
 
            regex = ".*%s.*" % self._installer_name
956
 
        elif fetcher.hasFile("install/netboot/version.info"):
957
 
            # For trees based on ISO's
958
 
            self._prefix = "install"
959
 
            self._set_media_paths()
960
 
            filename = "%s/netboot/version.info" % self._prefix
961
 
            regex = "%s*" % self.name
962
 
        else:
963
 
            logging.debug("Doesn't look like an %s Distro.", self.name)
964
 
            return False
965
 
 
966
 
        if self._fetchAndMatchRegex(fetcher, progresscb, filename, regex):
967
 
            logging.debug("Detected an %s distro", self.name)
968
 
            return True
969
 
 
970
 
        logging.debug("Regex didn't match, not an %s distro", self.name)
971
 
        return False
972
 
 
973
 
 
974
 
class MandrivaDistro(Distro):
975
 
    # Ex. ftp://ftp.uwsg.indiana.edu/linux/mandrake/official/2007.1/x86_64/
976
 
 
977
 
    name = "Mandriva"
978
 
    os_type = "linux"
979
 
    _boot_iso_paths = [ "install/images/boot.iso" ]
980
 
    # Kernels for HVM: valid for releases 2007.1, 2008.*, 2009.0
981
 
    _hvm_kernel_paths = [ ("isolinux/alt0/vmlinuz", "isolinux/alt0/all.rdz")]
982
 
    _xen_kernel_paths = []
983
 
 
984
 
    def isValidStore(self, fetcher, progresscb):
985
 
        # Don't support any paravirt installs
986
 
        if self.type is not None and self.type != "hvm":
987
 
            return False
988
 
 
989
 
        # Mandriva websites / media appear to have a VERSION
990
 
        # file in top level which we can use as our 'magic'
991
 
        # check for validity
992
 
        if not fetcher.hasFile("VERSION"):
993
 
            return False
994
 
 
995
 
        if self._fetchAndMatchRegex(fetcher, progresscb, "VERSION",
996
 
                                    ".*%s.*" % self.name):
997
 
            logging.debug("Detected a %s distro", self.name)
998
 
            return True
999
 
 
1000
 
        return False
1001
 
 
1002
 
class MageiaDistro(MandrivaDistro):
1003
 
    name = "Mageia"
1004
 
 
1005
 
# Solaris and OpenSolaris distros
1006
 
class SunDistro(Distro):
1007
 
 
1008
 
    name = "Solaris"
1009
 
    os_type = "solaris"
1010
 
 
1011
 
    def isValidStore(self, fetcher, progresscb):
1012
 
        """Determine if uri points to a tree of the store's distro"""
1013
 
        raise NotImplementedError
1014
 
 
1015
 
    def acquireBootDisk(self, guest, fetcher, progresscb):
1016
 
        return fetcher.acquireFile("images/solarisdvd.iso", progresscb)
1017
 
 
1018
 
    def process_extra_args(self, argstr):
1019
 
        """Collect additional arguments."""
1020
 
        if not argstr:
1021
 
            return (None, None, None, None)
1022
 
 
1023
 
        kopts = ''
1024
 
        kargs = ''
1025
 
        smfargs = ''
1026
 
        Bargs = ''
1027
 
 
1028
 
        args = argstr.split()
1029
 
        i = 0
1030
 
        while i < len(args):
1031
 
            exarg = args[i]
1032
 
            if exarg == '-B':
1033
 
                i += 1
1034
 
                if i == len(args):
1035
 
                    continue
1036
 
 
1037
 
                if not Bargs:
1038
 
                    Bargs = args[i]
1039
 
                else:
1040
 
                    Bargs = ','.join([Bargs, args[i]])
1041
 
 
1042
 
            elif exarg == '-m':
1043
 
                i += 1
1044
 
                if i == len(args):
1045
 
                    continue
1046
 
                smfargs = args[i]
1047
 
            elif exarg.startswith('-'):
1048
 
                if kopts is None:
1049
 
                    kopts = exarg[1:]
1050
 
                else:
1051
 
                    kopts = kopts + exarg[1:]
1052
 
            else:
1053
 
                if kargs is None:
1054
 
                    kargs = exarg
1055
 
                else:
1056
 
                    kargs = kargs + ' ' + exarg
1057
 
            i += 1
1058
 
 
1059
 
        return kopts, kargs, smfargs, Bargs
1060
 
 
1061
 
class SolarisDistro(SunDistro):
1062
 
    kernelpath = 'boot/platform/i86xpv/kernel/unix'
1063
 
    initrdpath = 'boot/x86.miniroot'
1064
 
 
1065
 
    def isValidStore(self, fetcher, progresscb):
1066
 
        if fetcher.hasFile(self.kernelpath):
1067
 
            logging.debug('Detected Solaris')
1068
 
            return True
1069
 
        return False
1070
 
 
1071
 
    def install_args(self, guest):
1072
 
        """Construct kernel cmdline args for the installer, consisting of:
1073
 
           the pathname of the kernel (32/64) to load, kernel options
1074
 
           and args, and '-B' boot properties."""
1075
 
 
1076
 
        # XXX: ignoring smfargs for the time being
1077
 
        (kopts, kargs, ignore_smfargs, kbargs) = \
1078
 
            self.process_extra_args(guest.extraargs)
1079
 
 
1080
 
        args = [ '' ]
1081
 
        if kopts:
1082
 
            args += [ '-%s' % kopts ]
1083
 
        if kbargs:
1084
 
            args += [ '-B', kbargs ]
1085
 
 
1086
 
        netmask = ''
1087
 
        # Yuck. Non-default netmasks require this option to be passed.
1088
 
        # It's distinctly not-trivial to work out the netmask to be used
1089
 
        # automatically.
1090
 
        if kargs:
1091
 
            for karg in kargs.split():
1092
 
                if karg.startswith('subnet-mask'):
1093
 
                    netmask = karg.split('=')[1]
1094
 
                else:
1095
 
                    args += [ kargs ]
1096
 
 
1097
 
        iargs = ''
1098
 
        if not guest.graphics['enabled']:
1099
 
            iargs += 'nowin '
1100
 
 
1101
 
        if guest.location.startswith('nfs:'):
1102
 
            try:
1103
 
                guestIP = socket.gethostbyaddr(guest.name)[2][0]
1104
 
            except:
1105
 
                iargs += ' dhcp'
1106
 
            else:
1107
 
                iserver = guest.location.split(':')[1]
1108
 
                ipath = guest.location.split(':')[2]
1109
 
                iserverIP = socket.gethostbyaddr(iserver)[2][0]
1110
 
                iargs += ' -B install_media=' + iserverIP + ':' + ipath
1111
 
                iargs += ',host-ip=' + guestIP
1112
 
                if netmask:
1113
 
                    iargs += ',subnet-mask=%s' % netmask
1114
 
                droute = _util.default_route(guest.nics[0].bridge)
1115
 
                if droute:
1116
 
                    iargs += ',router-ip=' + droute
1117
 
                if guest.nics[0].macaddr:
1118
 
                    en = guest.nics[0].macaddr.split(':')
1119
 
                    for i in range(len(en)):
1120
 
                        # remove leading '0' from mac address element
1121
 
                        if len(en[i]) > 1 and en[i][0] == '0':
1122
 
                            en[i] = en[i][1]
1123
 
                    boot_mac = ':'.join(en)
1124
 
                    iargs += ',boot-mac=' + boot_mac
1125
 
        else:
1126
 
            iargs += '-B install_media=cdrom'
1127
 
 
1128
 
        args += [ '-', iargs ]
1129
 
        return ' '.join(args)
1130
 
 
1131
 
    def acquireKernel(self, guest, fetcher, progresscb):
1132
 
 
1133
 
        try:
1134
 
            kernel = fetcher.acquireFile(self.kernelpath, progresscb)
1135
 
        except:
1136
 
            raise RuntimeError("Solaris PV kernel not found at %s" %
1137
 
                self.kernelpath)
1138
 
 
1139
 
        # strip boot from the kernel path
1140
 
        kpath = self.kernelpath.split('/')[1:]
1141
 
        args = "/" + "/".join(kpath) + self.install_args(guest)
1142
 
 
1143
 
        try:
1144
 
            initrd = fetcher.acquireFile(self.initrdpath, progresscb)
1145
 
            return (kernel, initrd, args)
1146
 
        except:
1147
 
            os.unlink(kernel)
1148
 
            raise RuntimeError(_("Solaris miniroot not found at %s") %
1149
 
                self.initrdpath)
1150
 
 
1151
 
class OpenSolarisDistro(SunDistro):
1152
 
 
1153
 
    os_variant = "opensolaris"
1154
 
 
1155
 
    kernelpath = "platform/i86xpv/kernel/unix"
1156
 
    initrdpaths = [ "platform/i86pc/boot_archive", "boot/x86.microroot" ]
1157
 
 
1158
 
    def isValidStore(self, fetcher, progresscb):
1159
 
        if fetcher.hasFile(self.kernelpath):
1160
 
            logging.debug("Detected OpenSolaris")
1161
 
            return True
1162
 
        return False
1163
 
 
1164
 
    def install_args(self, guest):
1165
 
        """Construct kernel cmdline args for the installer, consisting of:
1166
 
           the pathname of the kernel (32/64) to load, kernel options
1167
 
           and args, and '-B' boot properties."""
1168
 
 
1169
 
        # XXX: ignoring smfargs and kargs for the time being
1170
 
        (kopts, ignore_kargs, ignore_smfargs, kbargs) = \
1171
 
            self.process_extra_args(guest.extraargs)
1172
 
 
1173
 
        args = ''
1174
 
        if kopts:
1175
 
            args += ' -' + kopts
1176
 
        if kbargs:
1177
 
            args += ' -B ' + kbargs
1178
 
 
1179
 
        return args
1180
 
 
1181
 
    def acquireKernel(self, guest, fetcher, progresscb):
1182
 
 
1183
 
        try:
1184
 
            kernel = fetcher.acquireFile(self.kernelpath, progresscb)
1185
 
        except:
1186
 
            raise RuntimeError(_("OpenSolaris PV kernel not found at %s") %
1187
 
                self.kernelpath)
1188
 
 
1189
 
        args = "/" + self.kernelpath + self.install_args(guest)
1190
 
 
1191
 
        try:
1192
 
            initrd = fetcher.acquireFile(self.initrdpaths[0], progresscb)
1193
 
            return (kernel, initrd, args)
1194
 
        except Exception, e:
1195
 
            try:
1196
 
                initrd = fetcher.acquireFile(self.initrdpaths[1], progresscb)
1197
 
                return (kernel, initrd, args)
1198
 
            except:
1199
 
                os.unlink(kernel)
1200
 
                raise Exception("No OpenSolaris boot archive found: %s\n" % e)
1201
 
 
1202
 
 
1203
 
# NetWare 6 PV
1204
 
class NetWareDistro(Distro):
1205
 
    name = "NetWare"
1206
 
    os_type = "other"
1207
 
    os_variant = "netware6"
1208
 
 
1209
 
    loaderpath = "STARTUP/XNLOADER.SYS"
1210
 
 
1211
 
    def isValidStore(self, fetcher, progresscb):
1212
 
        if fetcher.hasFile(self.loaderpath):
1213
 
            logging.debug("Detected NetWare")
1214
 
            return True
1215
 
        return False
1216
 
 
1217
 
    def acquireKernel(self, guest, fetcher, progresscb):
1218
 
        loader = fetcher.acquireFile(self.loaderpath, progresscb)
1219
 
        return (loader, "", "")