2
# Represents OS distribution specific install data
4
# Copyright 2006-2007 Red Hat, Inc.
5
# Daniel P. Berrange <berrange@redhat.com>
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.
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.
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,
32
from virtinst import _util
33
from virtinst import _gettext as _
35
from ImageFetcher import MountedImageFetcher
36
from ImageFetcher import FTPImageFetcher
37
from ImageFetcher import HTTPImageFetcher
38
from ImageFetcher import DirectImageFetcher
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
55
if os.path.isdir(uri):
56
fclass = DirectImageFetcher
58
fclass = MountedImageFetcher
59
return fclass(uri, scratchdir)
61
def _storeForDistro(fetcher, baseuri, typ, progresscb, arch, distro=None,
65
logging.debug("Attempting to detect distro:")
67
dist = virtinst.OSDistro.distroFromTreeinfo(fetcher, progresscb, baseuri,
68
arch, typ, scratchdir)
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)
100
stores.append(GenericDistro)
102
for sclass in stores:
103
store = sclass(baseuri, arch, typ, scratchdir)
105
store.uses_treeinfo = False
106
if store.isValidStore(fetcher, progresscb):
110
_("Could not find an installable distribution at '%s'\n"
111
"The location must be the root directory of an install tree." %
114
def _locationCheckWrapper(guest, baseuri, progresscb,
115
scratchdir, _type, arch, callback):
116
fetcher = _fetcherForURI(baseuri, scratchdir)
121
fetcher.prepareLocation()
122
except ValueError, e:
123
logging.exception("Error preparing install location")
124
raise ValueError(_("Invalid install location: ") + str(e))
127
store = _storeForDistro(fetcher=fetcher, baseuri=baseuri, typ=_type,
128
progresscb=progresscb, scratchdir=scratchdir,
131
return callback(store, fetcher)
133
fetcher.cleanupLocation()
135
def _acquireMedia(iskernel, guest, baseuri, progresscb,
136
scratchdir="/var/tmp", _type=None):
138
def media_cb(store, fetcher):
139
os_type, os_variant = store.get_osdict_info()
143
media = store.acquireKernel(guest, fetcher, progresscb)
145
media = store.acquireBootDisk(guest, fetcher, progresscb)
147
return [store, os_type, os_variant, media]
149
return _locationCheckWrapper(guest, baseuri, progresscb, scratchdir, _type,
152
# Helper method to lookup install media distro and fetch an install kernel
153
def acquireKernel(guest, baseuri, progresscb, scratchdir, type=None):
155
return _acquireMedia(iskernel, guest, baseuri, progresscb,
158
# Helper method to lookup install media distro and fetch a boot iso
159
def acquireBootDisk(guest, baseuri, progresscb, scratchdir, type=None):
161
return _acquireMedia(iskernel, guest, baseuri, progresscb,
164
def _check_ostype_valid(os_type):
165
return bool(os_type in osdict.sort_helper(osdict.OS_TYPES))
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"]))
171
# Attempt to detect the os type + variant for the passed location
172
def detectMediaDistro(location, arch):
174
progresscb = urlgrabber.progress.BaseMeter()
177
scratchdir = "/var/tmp"
179
def media_cb(store, ignore):
182
store = _locationCheckWrapper(guest, baseuri, progresscb, scratchdir,
183
_type, arch, media_cb)
185
return store.get_osdict_info()
188
def distroFromTreeinfo(fetcher, progresscb, uri, arch, vmtype=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"):
195
tmptreeinfo = fetcher.acquireFile(".treeinfo", progresscb)
197
treeinfo = ConfigParser.SafeConfigParser()
198
treeinfo.read(tmptreeinfo)
200
os.unlink(tmptreeinfo)
203
fam = treeinfo.get("general", "family")
204
except ConfigParser.NoSectionError:
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):
213
elif re.match(".*Scientific Linux.*", fam):
216
dclass = GenericDistro
218
ob = dclass(uri, arch, vmtype, scratchdir)
219
ob.treeinfo = treeinfo
221
# Explictly call this, so we populate os_type/variant info
222
ob.isValidStore(fetcher, progresscb)
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
233
# osdict type and variant values
238
_hvm_kernel_paths = []
239
_xen_kernel_paths = []
240
uses_treeinfo = False
242
def __init__(self, uri, arch, vmtype=None, scratchdir=None):
245
self.scratchdir = scratchdir
249
def isValidStore(self, fetcher, progresscb):
250
"""Determine if uri points to a tree of the store's distro"""
251
raise NotImplementedError
253
def acquireKernel(self, guest, fetcher, progresscb):
256
if self._hasTreeinfo(fetcher, progresscb):
257
kernelpath = self._getTreeinfoMedia("kernel")
258
initrdpath = self._getTreeinfoMedia("initrd")
260
# fall back to old code
261
if self.type is None or self.type == "hvm":
262
paths = self._hvm_kernel_paths
264
paths = self._xen_kernel_paths
266
for kpath, ipath in paths:
267
if fetcher.hasFile(kpath) and fetcher.hasFile(ipath):
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 })
276
return self._kernelFetchHelper(fetcher, guest, progresscb, kernelpath,
279
def acquireBootDisk(self, guest, fetcher, progresscb):
280
if self._hasTreeinfo(fetcher, progresscb):
281
return fetcher.acquireFile(self._getTreeinfoMedia("boot.iso"),
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." % \
290
def get_osdict_info(self):
292
Return (distro, variant) tuple, checking to make sure they are valid
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))
303
if not self.os_variant:
304
return (self.os_type, None)
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"
309
(self, self.os_variant, self.os_type))
310
return (self.os_type, None)
312
return (self.os_type, self.os_variant)
314
def _hasTreeinfo(self, fetcher, progresscb):
315
# all Red Hat based distros should have .treeinfo, perhaps others
317
if not (self.treeinfo is None):
320
if not self.uses_treeinfo or not fetcher.hasFile(".treeinfo"):
323
logging.debug("Detected .treeinfo file")
325
tmptreeinfo = fetcher.acquireFile(".treeinfo", progresscb)
327
self.treeinfo = ConfigParser.SafeConfigParser()
328
self.treeinfo.read(tmptreeinfo)
330
os.unlink(tmptreeinfo)
333
def _getTreeinfoMedia(self, mediaName):
334
if self.type == "xen":
337
t = self.treeinfo.get("general", "arch")
339
return self.treeinfo.get("images-%s" % t, mediaName)
341
def _fetchAndMatchRegex(self, fetcher, progresscb, filename, regex):
342
# Fetch 'filename' and return True/False if it matches the regex
346
local_file = fetcher.acquireFile(filename, progresscb)
350
f = open(local_file, "r")
356
if re.match(regex, buf):
361
if local_file is not None:
362
os.unlink(local_file)
366
def _kernelFetchHelper(self, fetcher, guest, progresscb, kernelpath,
368
# Simple helper for fetching kernel + initrd and performing
369
# cleanup if neccessary
370
kernel = fetcher.acquireFile(kernelpath, progresscb)
373
if not fetcher.location.startswith("/"):
374
args += "method=" + fetcher.location
377
args += " " + guest.extraargs
380
initrd = fetcher.acquireFile(initrdpath, progresscb)
381
return kernel, initrd, args
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"""
394
_xen_paths = [ ("images/xen/vmlinuz",
395
"images/xen/initrd.img"), # Fedora
397
_hvm_paths = [ ("images/pxeboot/vmlinuz",
398
"images/pxeboot/initrd.img"), # Fedora
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
406
# Holds values to use when actually pulling down media
407
_valid_kernel_path = None
408
_valid_iso_path = None
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":
416
typ = self.treeinfo.get("general", "arch")
417
kernelSection = "images-%s" % typ
418
isoSection = "images-%s" % self.treeinfo.get("general", "arch")
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")
426
if self.type == "xen":
427
kern_list = self._xen_paths
429
kern_list = self._hvm_paths
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)
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
444
if self._valid_kernel_path or self._valid_iso_path:
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 "
453
return self._kernelFetchHelper(fetcher, guest, progresscb,
454
self._valid_kernel_path[0],
455
self._valid_kernel_path[1])
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."))
461
return fetcher.acquireFile(self._valid_iso_path, progresscb)
464
# Base image store for any Red Hat related distros which have
466
class RedHatDistro(Distro):
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") ]
478
def isValidStore(self, fetcher, progresscb):
479
raise NotImplementedError
482
# Fedora distro check
483
class FedoraDistro(RedHatDistro):
487
def isValidStore(self, fetcher, progresscb):
488
if self._hasTreeinfo(fetcher, progresscb):
489
m = re.match(".*Fedora.*", self.treeinfo.get("general", "family"))
493
ver = self.treeinfo.get("general", "version")
494
if ver == "development":
495
self.os_variant = self._latestFedoraVariant()
497
self.os_variant = "fedora" + (str(ver).split("-"))[0]
501
if fetcher.hasFile("Fedora"):
502
logging.debug("Detected a Fedora distro")
506
def _latestFedoraVariant(self):
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
514
# Red Hat Enterprise Linux distro check
515
class RHELDistro(RedHatDistro):
517
name = "Red Hat Enterprise Linux"
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"))
526
self._variantFromVersion()
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"
534
if fetcher.hasFile("Client"):
535
logging.debug("Detected a RHEL 5 Client distro")
536
self.os_variant = "rhel5"
538
if fetcher.hasFile("RedHat"):
539
if fetcher.hasFile("dosutils"):
540
self.os_variant = "rhel3"
542
self.os_variant = "rhel4"
544
logging.debug("Detected a %s distro" % self.os_variant)
548
def _parseTreeinfoVersion(self, verstr):
549
version = safeint(verstr[0])
552
updinfo = verstr.split(".")
554
update = safeint(updinfo[1])
556
return version, update
558
def _variantFromVersion(self):
559
ver = self.treeinfo.get("general", "version")
563
version, update = self._parseTreeinfoVersion(ver)
564
self._setRHELVariant(version, update)
566
def _setRHELVariant(self, version, update):
567
if not _check_ostype_valid(self.os_type):
570
base = "rhel" + str(version)
576
tryvar = base + ".%s" % update
577
if not _check_osvariant_valid(self.os_type, tryvar):
585
# Try plain rhel5, rhel6, whatev
586
if _check_osvariant_valid(self.os_type, base):
590
self.os_variant = ret
593
# CentOS distro check
594
class CentOSDistro(RHELDistro):
598
def isValidStore(self, fetcher, progresscb):
599
if self._hasTreeinfo(fetcher, progresscb):
600
m = re.match(".*CentOS.*", self.treeinfo.get("general", "family"))
604
self._variantFromVersion()
607
# fall back to old code
608
if fetcher.hasFile("CentOS"):
609
logging.debug("Detected a CentOS distro")
613
# Scientific Linux distro check
614
class SLDistro(RHELDistro):
616
name = "Scientific Linux"
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") ]
623
def isValidStore(self, fetcher, progresscb):
624
if self._hasTreeinfo(fetcher, progresscb):
625
m = re.match(".*Scientific Linux.*",
626
self.treeinfo.get("general", "family"))
630
self._variantFromVersion()
633
if fetcher.hasFile("SL"):
634
logging.debug("Detected a Scientific Linux distro")
638
def _parseTreeinfoVersion(self, verstr):
640
Overrides method in RHELDistro
642
version = safeint(verstr[0])
646
update = safeint(verstr[1])
647
return version, update
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):
656
_boot_iso_paths = [ "boot/boot.iso" ]
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):
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))
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) ]
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.")
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)
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)
699
def _findXenRPMS(self, fetcher, progresscb):
701
installinitrdrpm = None
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)
709
# Now fetch the two RPMs we want
710
kernelrpm = fetcher.acquireFile(kernelrpmname, progresscb)
711
installinitrdrpm = fetcher.acquireFile(initrdrpmname, progresscb)
713
# Process the RPMs to extract the kernel & generate an initrd
714
return self._buildKernelInitrd(fetcher, kernelrpm, installinitrdrpm, progresscb)
716
if filelist is not None:
718
if kernelrpm is not None:
720
if installinitrdrpm is not None:
721
os.unlink(installinitrdrpm)
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")
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)
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"
740
kernelname = "kernel-xen"
742
installinitrdrpm = None
746
data = filelistData.readline()
751
wantdir = "/suse/" + arch
752
if data == "." + wantdir + ":\n":
759
if data[:5] != "total":
760
filename = re.split("\s+", data)[8]
762
if filename[:14] == "install-initrd":
763
installinitrdrpm = dirname + "/" + filename
764
elif filename[:len(kernelname)] == kernelname:
765
kernelrpm = dirname + "/" + filename
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)
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.
779
# Yes, this is crazy ass stuff :-)
780
def _buildKernelInitrd(self, fetcher, kernelrpm, installinitrdrpm, progresscb):
781
progresscb.start(text=_("Building initrd"), size=11)
783
cpiodir = tempfile.mkdtemp(prefix="virtinstcpio.", dir=self.scratchdir)
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)
792
# Determine the raw kernel version
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))
801
# Build a list of all .ko files
803
for root, dummy, files in os.walk(cpiodir + "/kernel/lib/modules", topdown=False):
805
if name.endswith(".ko"):
806
modpaths[name] = os.path.join(root, name)
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)
816
# Read in list of mods required for initrd
818
fn = open(cpiodir + "/installinitrd/usr/lib/install-initrd/" + kernelinfo[3] + "/module.list", "r")
824
line = line[:len(line) - 1]
825
modnames.append(line)
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)
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
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)
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)
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)
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)
866
progresscb.update(10)
868
# Compress the final initrd
869
cmd = "gzip -f9N " + cpiodir + "/initrd.img"
870
logging.debug("Running " + cmd)
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)
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)
882
os.unlink(initrdname)
885
os.system("rm -rf " + cpiodir)
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/
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"
902
self._treeArch = "i386"
904
if re.match(r'i[4-9]86', arch):
907
self._installer_name = self.name.lower() + "-" + "installer"
908
self._prefix = 'current/images'
909
self._set_media_paths()
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,
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") ]
922
def isValidStore(self, fetcher, progresscb):
923
if fetcher.hasFile("%s/MANIFEST" % self._prefix):
926
elif fetcher.hasFile("images/daily/MANIFEST"):
928
self._prefix = "images/daily"
929
self._set_media_paths()
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)
939
logging.debug("MANIFEST didn't match regex, not a %s distro" %
944
class UbuntuDistro(DebianDistro):
947
# http://archive.ubuntu.com/ubuntu/dists/natty/main/installer-amd64/
949
def isValidStore(self, fetcher, progresscb):
950
if fetcher.hasFile("%s/MANIFEST" % self._prefix):
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
961
logging.debug("Doesn't look like an %s Distro." % self.name)
964
if self._fetchAndMatchRegex(fetcher, progresscb, filename, regex):
965
logging.debug("Detected an %s distro" % self.name)
968
logging.debug("Regex didn't match, not an %s distro" % self.name)
972
class MandrivaDistro(Distro):
973
# Ex. ftp://ftp.uwsg.indiana.edu/linux/mandrake/official/2007.1/x86_64/
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 = []
982
def isValidStore(self, fetcher, progresscb):
983
# Don't support any paravirt installs
984
if self.type is not None and self.type != "hvm":
987
# Mandriva websites / media appear to have a VERSION
988
# file in top level which we can use as our 'magic'
990
if not fetcher.hasFile("VERSION"):
993
if self._fetchAndMatchRegex(fetcher, progresscb, "VERSION",
995
logging.debug("Detected a Mandriva distro")
1000
# Solaris and OpenSolaris distros
1001
class SunDistro(Distro):
1006
def isValidStore(self, fetcher, progresscb):
1007
"""Determine if uri points to a tree of the store's distro"""
1008
raise NotImplementedError
1010
def acquireBootDisk(self, guest, fetcher, progresscb):
1011
return fetcher.acquireFile("images/solarisdvd.iso", progresscb)
1013
def process_extra_args(self, argstr):
1014
"""Collect additional arguments."""
1016
return (None, None, None, None)
1023
args = argstr.split()
1025
while i < len(args):
1035
Bargs = ','.join([Bargs, args[i]])
1042
elif exarg.startswith('-'):
1046
kopts = kopts + exarg[1:]
1051
kargs = kargs + ' ' + exarg
1054
return kopts, kargs, smfargs, Bargs
1056
class SolarisDistro(SunDistro):
1057
kernelpath = 'boot/platform/i86xpv/kernel/unix'
1058
initrdpath = 'boot/x86.miniroot'
1060
def isValidStore(self, fetcher, progresscb):
1061
if fetcher.hasFile(self.kernelpath):
1062
logging.debug('Detected Solaris')
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."""
1071
# XXX: ignoring smfargs for the time being
1072
(kopts, kargs, ignore_smfargs, kbargs) = \
1073
self.process_extra_args(guest.extraargs)
1077
args += [ '-%s' % kopts ]
1079
args += [ '-B', kbargs ]
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
1086
for karg in kargs.split():
1087
if karg.startswith('subnet-mask'):
1088
netmask = karg.split('=')[1]
1093
if not guest.graphics['enabled']:
1096
if guest.location.startswith('nfs:'):
1098
guestIP = socket.gethostbyaddr(guest.name)[2][0]
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
1108
iargs += ',subnet-mask=%s' % netmask
1109
droute = _util.default_route(guest.nics[0].bridge)
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':
1118
boot_mac = ':'.join(en)
1119
iargs += ',boot-mac=' + boot_mac
1121
iargs += '-B install_media=cdrom'
1123
args += [ '-', iargs ]
1124
return ' '.join(args)
1126
def acquireKernel(self, guest, fetcher, progresscb):
1129
kernel = fetcher.acquireFile(self.kernelpath, progresscb)
1131
raise RuntimeError("Solaris PV kernel not found at %s" %
1134
# strip boot from the kernel path
1135
kpath = self.kernelpath.split('/')[1:]
1136
args = "/" + "/".join(kpath) + self.install_args(guest)
1139
initrd = fetcher.acquireFile(self.initrdpath, progresscb)
1140
return (kernel, initrd, args)
1143
raise RuntimeError(_("Solaris miniroot not found at %s") %
1146
class OpenSolarisDistro(SunDistro):
1148
os_variant = "opensolaris"
1150
kernelpath = "platform/i86xpv/kernel/unix"
1151
initrdpaths = [ "platform/i86pc/boot_archive", "boot/x86.microroot" ]
1153
def isValidStore(self, fetcher, progresscb):
1154
if fetcher.hasFile(self.kernelpath):
1155
logging.debug("Detected OpenSolaris")
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."""
1164
# XXX: ignoring smfargs and kargs for the time being
1165
(kopts, ignore_kargs, ignore_smfargs, kbargs) = \
1166
self.process_extra_args(guest.extraargs)
1170
args += ' -' + kopts
1172
args += ' -B ' + kbargs
1176
def acquireKernel(self, guest, fetcher, progresscb):
1179
kernel = fetcher.acquireFile(self.kernelpath, progresscb)
1181
raise RuntimeError(_("OpenSolaris PV kernel not found at %s") %
1184
args = "/" + self.kernelpath + self.install_args(guest)
1187
initrd = fetcher.acquireFile(self.initrdpaths[0], progresscb)
1188
return (kernel, initrd, args)
1189
except Exception, e:
1191
initrd = fetcher.acquireFile(self.initrdpaths[1], progresscb)
1192
return (kernel, initrd, args)
1195
raise Exception("No OpenSolaris boot archive found: %s\n" % e)
1199
class NetWareDistro(Distro):
1202
os_variant = "netware6"
1204
loaderpath = "STARTUP/XNLOADER.SYS"
1206
def isValidStore(self, fetcher, progresscb):
1207
if fetcher.hasFile(self.loaderpath):
1208
logging.debug("Detected NetWare")
1212
def acquireKernel(self, guest, fetcher, progresscb):
1213
loader = fetcher.acquireFile(self.loaderpath, progresscb)
1214
return (loader, "", "")