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
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)
102
stores.append(GenericDistro)
104
for sclass in stores:
105
store = sclass(baseuri, arch, typ, scratchdir)
107
store.uses_treeinfo = False
108
if store.isValidStore(fetcher, progresscb):
112
_("Could not find an installable distribution at '%s'\n"
113
"The location must be the root directory of an install tree." %
116
def _locationCheckWrapper(guest, baseuri, progresscb,
117
scratchdir, _type, arch, callback):
118
fetcher = _fetcherForURI(baseuri, scratchdir)
123
fetcher.prepareLocation()
124
except ValueError, e:
125
logging.exception("Error preparing install location")
126
raise ValueError(_("Invalid install location: ") + str(e))
129
store = _storeForDistro(fetcher=fetcher, baseuri=baseuri, typ=_type,
130
progresscb=progresscb, scratchdir=scratchdir,
133
return callback(store, fetcher)
135
fetcher.cleanupLocation()
137
def _acquireMedia(iskernel, guest, baseuri, progresscb,
138
scratchdir="/var/tmp", _type=None):
140
def media_cb(store, fetcher):
141
os_type, os_variant = store.get_osdict_info()
145
media = store.acquireKernel(guest, fetcher, progresscb)
147
media = store.acquireBootDisk(guest, fetcher, progresscb)
149
return [store, os_type, os_variant, media]
151
return _locationCheckWrapper(guest, baseuri, progresscb, scratchdir, _type,
154
# Helper method to lookup install media distro and fetch an install kernel
155
def acquireKernel(guest, baseuri, progresscb, scratchdir, type=None):
157
return _acquireMedia(iskernel, guest, baseuri, progresscb,
160
# Helper method to lookup install media distro and fetch a boot iso
161
def acquireBootDisk(guest, baseuri, progresscb, scratchdir, type=None):
163
return _acquireMedia(iskernel, guest, baseuri, progresscb,
166
def _check_ostype_valid(os_type):
167
return bool(os_type in osdict.sort_helper(osdict.OS_TYPES))
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"]))
173
# Attempt to detect the os type + variant for the passed location
174
def detectMediaDistro(location, arch):
176
progresscb = urlgrabber.progress.BaseMeter()
179
scratchdir = "/var/tmp"
181
def media_cb(store, ignore):
184
store = _locationCheckWrapper(guest, baseuri, progresscb, scratchdir,
185
_type, arch, media_cb)
187
return store.get_osdict_info()
190
def distroFromTreeinfo(fetcher, progresscb, uri, arch, vmtype=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"):
197
tmptreeinfo = fetcher.acquireFile(".treeinfo", progresscb)
199
treeinfo = ConfigParser.SafeConfigParser()
200
treeinfo.read(tmptreeinfo)
202
os.unlink(tmptreeinfo)
205
fam = treeinfo.get("general", "family")
206
except ConfigParser.NoSectionError:
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):
215
elif re.match(".*Scientific Linux.*", fam):
218
dclass = GenericDistro
220
ob = dclass(uri, arch, vmtype, scratchdir)
221
ob.treeinfo = treeinfo
223
# Explictly call this, so we populate os_type/variant info
224
ob.isValidStore(fetcher, progresscb)
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
235
# osdict type and variant values
240
_hvm_kernel_paths = []
241
_xen_kernel_paths = []
242
uses_treeinfo = False
244
def __init__(self, uri, arch, vmtype=None, scratchdir=None):
247
self.scratchdir = scratchdir
251
def isValidStore(self, fetcher, progresscb):
252
"""Determine if uri points to a tree of the store's distro"""
253
raise NotImplementedError
255
def acquireKernel(self, guest, fetcher, progresscb):
258
if self._hasTreeinfo(fetcher, progresscb):
259
kernelpath = self._getTreeinfoMedia("kernel")
260
initrdpath = self._getTreeinfoMedia("initrd")
262
# fall back to old code
263
if self.type is None or self.type == "hvm":
264
paths = self._hvm_kernel_paths
266
paths = self._xen_kernel_paths
268
for kpath, ipath in paths:
269
if fetcher.hasFile(kpath) and fetcher.hasFile(ipath):
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 })
278
return self._kernelFetchHelper(fetcher, guest, progresscb, kernelpath,
281
def acquireBootDisk(self, guest, fetcher, progresscb):
282
if self._hasTreeinfo(fetcher, progresscb):
283
return fetcher.acquireFile(self._getTreeinfoMedia("boot.iso"),
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." % \
292
def get_osdict_info(self):
294
Return (distro, variant) tuple, checking to make sure they are valid
300
if not _check_ostype_valid(self.os_type):
301
logging.debug("%s set os_type to %s, which is not in osdict.",
305
if not self.os_variant:
306
return (self.os_type, None)
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"
311
self, self.os_variant, self.os_type)
312
return (self.os_type, None)
314
return (self.os_type, self.os_variant)
316
def _hasTreeinfo(self, fetcher, progresscb):
317
# all Red Hat based distros should have .treeinfo, perhaps others
319
if not (self.treeinfo is None):
322
if not self.uses_treeinfo or not fetcher.hasFile(".treeinfo"):
325
logging.debug("Detected .treeinfo file")
327
tmptreeinfo = fetcher.acquireFile(".treeinfo", progresscb)
329
self.treeinfo = ConfigParser.SafeConfigParser()
330
self.treeinfo.read(tmptreeinfo)
332
os.unlink(tmptreeinfo)
335
def _getTreeinfoMedia(self, mediaName):
336
if self.type == "xen":
339
t = self.treeinfo.get("general", "arch")
341
return self.treeinfo.get("images-%s" % t, mediaName)
343
def _fetchAndMatchRegex(self, fetcher, progresscb, filename, regex):
344
# Fetch 'filename' and return True/False if it matches the regex
348
local_file = fetcher.acquireFile(filename, progresscb)
352
f = open(local_file, "r")
358
if re.match(regex, buf):
363
if local_file is not None:
364
os.unlink(local_file)
368
def _kernelFetchHelper(self, fetcher, guest, progresscb, kernelpath,
370
# Simple helper for fetching kernel + initrd and performing
371
# cleanup if neccessary
372
kernel = fetcher.acquireFile(kernelpath, progresscb)
375
if not fetcher.location.startswith("/"):
376
args += "method=" + fetcher.location
379
args += " " + guest.extraargs
382
initrd = fetcher.acquireFile(initrdpath, progresscb)
383
return kernel, initrd, args
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"""
396
_xen_paths = [ ("images/xen/vmlinuz",
397
"images/xen/initrd.img"), # Fedora
399
_hvm_paths = [ ("images/pxeboot/vmlinuz",
400
"images/pxeboot/initrd.img"), # Fedora
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
408
# Holds values to use when actually pulling down media
409
_valid_kernel_path = None
410
_valid_iso_path = None
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":
418
typ = self.treeinfo.get("general", "arch")
419
kernelSection = "images-%s" % typ
420
isoSection = "images-%s" % self.treeinfo.get("general", "arch")
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")
428
if self.type == "xen":
429
kern_list = self._xen_paths
431
kern_list = self._hvm_paths
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)
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
446
if self._valid_kernel_path or self._valid_iso_path:
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 "
455
return self._kernelFetchHelper(fetcher, guest, progresscb,
456
self._valid_kernel_path[0],
457
self._valid_kernel_path[1])
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."))
463
return fetcher.acquireFile(self._valid_iso_path, progresscb)
466
# Base image store for any Red Hat related distros which have
468
class RedHatDistro(Distro):
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") ]
480
def isValidStore(self, fetcher, progresscb):
481
raise NotImplementedError
484
# Fedora distro check
485
class FedoraDistro(RedHatDistro):
489
def isValidStore(self, fetcher, progresscb):
490
if self._hasTreeinfo(fetcher, progresscb):
491
m = re.match(".*Fedora.*", self.treeinfo.get("general", "family"))
495
ver = self.treeinfo.get("general", "version")
496
if ver == "development":
497
self.os_variant = self._latestFedoraVariant()
499
self.os_variant = "fedora" + (str(ver).split("-"))[0]
503
if fetcher.hasFile("Fedora"):
504
logging.debug("Detected a Fedora distro")
508
def _latestFedoraVariant(self):
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
516
# Red Hat Enterprise Linux distro check
517
class RHELDistro(RedHatDistro):
519
name = "Red Hat Enterprise Linux"
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"))
528
self._variantFromVersion()
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"
536
if fetcher.hasFile("Client"):
537
logging.debug("Detected a RHEL 5 Client distro")
538
self.os_variant = "rhel5"
540
if fetcher.hasFile("RedHat"):
541
if fetcher.hasFile("dosutils"):
542
self.os_variant = "rhel3"
544
self.os_variant = "rhel4"
546
logging.debug("Detected a %s distro", self.os_variant)
550
def _parseTreeinfoVersion(self, verstr):
551
version = safeint(verstr[0])
554
updinfo = verstr.split(".")
556
update = safeint(updinfo[1])
558
return version, update
560
def _variantFromVersion(self):
561
ver = self.treeinfo.get("general", "version")
565
version, update = self._parseTreeinfoVersion(ver)
566
self._setRHELVariant(version, update)
568
def _setRHELVariant(self, version, update):
569
if not _check_ostype_valid(self.os_type):
572
base = "rhel" + str(version)
578
tryvar = base + ".%s" % update
579
if not _check_osvariant_valid(self.os_type, tryvar):
587
# Try plain rhel5, rhel6, whatev
588
if _check_osvariant_valid(self.os_type, base):
592
self.os_variant = ret
595
# CentOS distro check
596
class CentOSDistro(RHELDistro):
600
def isValidStore(self, fetcher, progresscb):
601
if self._hasTreeinfo(fetcher, progresscb):
602
m = re.match(".*CentOS.*", self.treeinfo.get("general", "family"))
606
self._variantFromVersion()
609
# fall back to old code
610
if fetcher.hasFile("CentOS"):
611
logging.debug("Detected a CentOS distro")
615
# Scientific Linux distro check
616
class SLDistro(RHELDistro):
618
name = "Scientific Linux"
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") ]
625
def isValidStore(self, fetcher, progresscb):
626
if self._hasTreeinfo(fetcher, progresscb):
627
m = re.match(".*Scientific Linux.*",
628
self.treeinfo.get("general", "family"))
632
self._variantFromVersion()
635
if fetcher.hasFile("SL"):
636
logging.debug("Detected a Scientific Linux distro")
640
def _parseTreeinfoVersion(self, verstr):
642
Overrides method in RHELDistro
644
version = safeint(verstr[0])
648
update = safeint(verstr[1])
649
return version, update
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):
658
_boot_iso_paths = [ "boot/boot.iso" ]
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):
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))
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) ]
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.")
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)
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)
701
def _findXenRPMS(self, fetcher, progresscb):
703
installinitrdrpm = None
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)
711
# Now fetch the two RPMs we want
712
kernelrpm = fetcher.acquireFile(kernelrpmname, progresscb)
713
installinitrdrpm = fetcher.acquireFile(initrdrpmname, progresscb)
715
# Process the RPMs to extract the kernel & generate an initrd
716
return self._buildKernelInitrd(fetcher, kernelrpm, installinitrdrpm, progresscb)
718
if filelist is not None:
720
if kernelrpm is not None:
722
if installinitrdrpm is not None:
723
os.unlink(installinitrdrpm)
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")
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)
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"
742
kernelname = "kernel-xen"
744
installinitrdrpm = None
748
data = filelistData.readline()
753
wantdir = "/suse/" + arch
754
if data == "." + wantdir + ":\n":
761
if data[:5] != "total":
762
filename = re.split("\s+", data)[8]
764
if filename[:14] == "install-initrd":
765
installinitrdrpm = dirname + "/" + filename
766
elif filename[:len(kernelname)] == kernelname:
767
kernelrpm = dirname + "/" + filename
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)
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.
781
# Yes, this is crazy ass stuff :-)
782
def _buildKernelInitrd(self, fetcher, kernelrpm, installinitrdrpm, progresscb):
783
progresscb.start(text=_("Building initrd"), size=11)
785
cpiodir = tempfile.mkdtemp(prefix="virtinstcpio.", dir=self.scratchdir)
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)
794
# Determine the raw kernel version
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))
803
# Build a list of all .ko files
805
for root, dummy, files in os.walk(cpiodir + "/kernel/lib/modules", topdown=False):
807
if name.endswith(".ko"):
808
modpaths[name] = os.path.join(root, name)
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)
818
# Read in list of mods required for initrd
820
fn = open(cpiodir + "/installinitrd/usr/lib/install-initrd/" + kernelinfo[3] + "/module.list", "r")
826
line = line[:len(line) - 1]
827
modnames.append(line)
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)
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
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)
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)
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)
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)
868
progresscb.update(10)
870
# Compress the final initrd
871
cmd = "gzip -f9N " + cpiodir + "/initrd.img"
872
logging.debug("Running " + cmd)
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)
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)
884
os.unlink(initrdname)
887
os.system("rm -rf " + cpiodir)
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/
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"
904
self._treeArch = "i386"
906
if re.match(r'i[4-9]86', arch):
909
self._installer_name = self.name.lower() + "-" + "installer"
910
self._prefix = 'current/images'
911
self._set_media_paths()
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,
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") ]
924
def isValidStore(self, fetcher, progresscb):
925
if fetcher.hasFile("%s/MANIFEST" % self._prefix):
928
elif fetcher.hasFile("images/daily/MANIFEST"):
930
self._prefix = "images/daily"
931
self._set_media_paths()
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)
941
logging.debug("MANIFEST didn't match regex, not a %s distro",
946
class UbuntuDistro(DebianDistro):
949
# http://archive.ubuntu.com/ubuntu/dists/natty/main/installer-amd64/
951
def isValidStore(self, fetcher, progresscb):
952
if fetcher.hasFile("%s/MANIFEST" % self._prefix):
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
963
logging.debug("Doesn't look like an %s Distro.", self.name)
966
if self._fetchAndMatchRegex(fetcher, progresscb, filename, regex):
967
logging.debug("Detected an %s distro", self.name)
970
logging.debug("Regex didn't match, not an %s distro", self.name)
974
class MandrivaDistro(Distro):
975
# Ex. ftp://ftp.uwsg.indiana.edu/linux/mandrake/official/2007.1/x86_64/
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 = []
984
def isValidStore(self, fetcher, progresscb):
985
# Don't support any paravirt installs
986
if self.type is not None and self.type != "hvm":
989
# Mandriva websites / media appear to have a VERSION
990
# file in top level which we can use as our 'magic'
992
if not fetcher.hasFile("VERSION"):
995
if self._fetchAndMatchRegex(fetcher, progresscb, "VERSION",
996
".*%s.*" % self.name):
997
logging.debug("Detected a %s distro", self.name)
1002
class MageiaDistro(MandrivaDistro):
1005
# Solaris and OpenSolaris distros
1006
class SunDistro(Distro):
1011
def isValidStore(self, fetcher, progresscb):
1012
"""Determine if uri points to a tree of the store's distro"""
1013
raise NotImplementedError
1015
def acquireBootDisk(self, guest, fetcher, progresscb):
1016
return fetcher.acquireFile("images/solarisdvd.iso", progresscb)
1018
def process_extra_args(self, argstr):
1019
"""Collect additional arguments."""
1021
return (None, None, None, None)
1028
args = argstr.split()
1030
while i < len(args):
1040
Bargs = ','.join([Bargs, args[i]])
1047
elif exarg.startswith('-'):
1051
kopts = kopts + exarg[1:]
1056
kargs = kargs + ' ' + exarg
1059
return kopts, kargs, smfargs, Bargs
1061
class SolarisDistro(SunDistro):
1062
kernelpath = 'boot/platform/i86xpv/kernel/unix'
1063
initrdpath = 'boot/x86.miniroot'
1065
def isValidStore(self, fetcher, progresscb):
1066
if fetcher.hasFile(self.kernelpath):
1067
logging.debug('Detected Solaris')
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."""
1076
# XXX: ignoring smfargs for the time being
1077
(kopts, kargs, ignore_smfargs, kbargs) = \
1078
self.process_extra_args(guest.extraargs)
1082
args += [ '-%s' % kopts ]
1084
args += [ '-B', kbargs ]
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
1091
for karg in kargs.split():
1092
if karg.startswith('subnet-mask'):
1093
netmask = karg.split('=')[1]
1098
if not guest.graphics['enabled']:
1101
if guest.location.startswith('nfs:'):
1103
guestIP = socket.gethostbyaddr(guest.name)[2][0]
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
1113
iargs += ',subnet-mask=%s' % netmask
1114
droute = _util.default_route(guest.nics[0].bridge)
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':
1123
boot_mac = ':'.join(en)
1124
iargs += ',boot-mac=' + boot_mac
1126
iargs += '-B install_media=cdrom'
1128
args += [ '-', iargs ]
1129
return ' '.join(args)
1131
def acquireKernel(self, guest, fetcher, progresscb):
1134
kernel = fetcher.acquireFile(self.kernelpath, progresscb)
1136
raise RuntimeError("Solaris PV kernel not found at %s" %
1139
# strip boot from the kernel path
1140
kpath = self.kernelpath.split('/')[1:]
1141
args = "/" + "/".join(kpath) + self.install_args(guest)
1144
initrd = fetcher.acquireFile(self.initrdpath, progresscb)
1145
return (kernel, initrd, args)
1148
raise RuntimeError(_("Solaris miniroot not found at %s") %
1151
class OpenSolarisDistro(SunDistro):
1153
os_variant = "opensolaris"
1155
kernelpath = "platform/i86xpv/kernel/unix"
1156
initrdpaths = [ "platform/i86pc/boot_archive", "boot/x86.microroot" ]
1158
def isValidStore(self, fetcher, progresscb):
1159
if fetcher.hasFile(self.kernelpath):
1160
logging.debug("Detected OpenSolaris")
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."""
1169
# XXX: ignoring smfargs and kargs for the time being
1170
(kopts, ignore_kargs, ignore_smfargs, kbargs) = \
1171
self.process_extra_args(guest.extraargs)
1175
args += ' -' + kopts
1177
args += ' -B ' + kbargs
1181
def acquireKernel(self, guest, fetcher, progresscb):
1184
kernel = fetcher.acquireFile(self.kernelpath, progresscb)
1186
raise RuntimeError(_("OpenSolaris PV kernel not found at %s") %
1189
args = "/" + self.kernelpath + self.install_args(guest)
1192
initrd = fetcher.acquireFile(self.initrdpaths[0], progresscb)
1193
return (kernel, initrd, args)
1194
except Exception, e:
1196
initrd = fetcher.acquireFile(self.initrdpaths[1], progresscb)
1197
return (kernel, initrd, args)
1200
raise Exception("No OpenSolaris boot archive found: %s\n" % e)
1204
class NetWareDistro(Distro):
1207
os_variant = "netware6"
1209
loaderpath = "STARTUP/XNLOADER.SYS"
1211
def isValidStore(self, fetcher, progresscb):
1212
if fetcher.hasFile(self.loaderpath):
1213
logging.debug("Detected NetWare")
1217
def acquireKernel(self, guest, fetcher, progresscb):
1218
loader = fetcher.acquireFile(self.loaderpath, progresscb)
1219
return (loader, "", "")