~ubuntu-branches/ubuntu/precise/virtinst/precise-updates

« back to all changes in this revision

Viewing changes to .pc/9004_ubuntu_fix_tree_support.patch/virtinst/OSDistro.py

  • Committer: Package Import Robot
  • Author(s): Andres Rodriguez
  • Date: 2012-01-18 16:18:30 UTC
  • Revision ID: package-import@ubuntu.com-20120118161830-jnykb241n1p1lyvd
Tags: 0.600.0-1ubuntu3
debian/patches/9004_ubuntu_fix_tree_support.patch: Fix tree detection
for all ISO/HTTP source, to not longer fail with cobbler/koan (LP: #884765)

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