aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwiktor w brodlo <wiktor@brodlo.net>2011-06-15 16:59:54 +0000
committerwiktor w brodlo <wiktor@brodlo.net>2011-06-15 16:59:54 +0000
commit2590d96369d0217e31dc2812690dde61dac417b5 (patch)
tree82276f787b08a28548e342c7921486f1acefab9f /kickstart.py
parentfirst commit (diff)
downloadanaconda-2590d96369d0217e31dc2812690dde61dac417b5.tar.gz
anaconda-2590d96369d0217e31dc2812690dde61dac417b5.tar.bz2
anaconda-2590d96369d0217e31dc2812690dde61dac417b5.zip
Initial import from Sabayon (ver 0.9.9.56)
Diffstat (limited to 'kickstart.py')
-rw-r--r--kickstart.py1499
1 files changed, 1499 insertions, 0 deletions
diff --git a/kickstart.py b/kickstart.py
new file mode 100644
index 0000000..7c47933
--- /dev/null
+++ b/kickstart.py
@@ -0,0 +1,1499 @@
+#
+# kickstart.py: kickstart install support
+#
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+# Red Hat, Inc. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from storage.deviceaction import *
+from storage.devices import LUKSDevice
+from storage.devicelibs.lvm import getPossiblePhysicalExtents
+from storage.formats import getFormat
+from storage.partitioning import clearPartitions
+from storage.partitioning import shouldClear
+import storage.iscsi
+import storage.fcoe
+import storage.zfcp
+
+from errors import *
+import iutil
+import isys
+import os
+import os.path
+import tempfile
+from flags import flags
+from constants import *
+import sys
+import string
+import urlgrabber
+import warnings
+import network
+import upgrade
+import pykickstart.commands as commands
+from storage.devices import *
+from scdate.core import zonetab
+from pykickstart.base import KickstartCommand, BaseData
+from pykickstart.constants import *
+from pykickstart.errors import *
+from pykickstart.parser import *
+from pykickstart.version import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("anaconda", x)
+
+import logging
+log = logging.getLogger("anaconda")
+stderrLog = logging.getLogger("anaconda.stderr")
+from anaconda_log import logger, logLevelMap, setHandlersLevel,\
+ DEFAULT_TTY_LEVEL
+
+class AnacondaKSScript(Script):
+ def run(self, chroot, serial, intf = None):
+ if self.inChroot:
+ scriptRoot = chroot
+ else:
+ scriptRoot = "/"
+
+ (fd, path) = tempfile.mkstemp("", "ks-script-", scriptRoot + "/tmp")
+
+ os.write(fd, self.script)
+ os.close(fd)
+ os.chmod(path, 0700)
+
+ # Always log stdout/stderr from scripts. Using --logfile just lets you
+ # pick where it goes. The script will also be logged to program.log
+ # because of execWithRedirect, and to anaconda.log if the script fails.
+ if self.logfile:
+ if self.inChroot:
+ messages = "%s/%s" % (scriptRoot, self.logfile)
+ else:
+ messages = self.logfile
+
+ d = os.path.basename(messages)
+ if not os.path.exists(d):
+ os.makedirs(d)
+ else:
+ messages = "%s.log" % path
+
+ if intf:
+ intf.suspend()
+ rc = iutil.execWithRedirect(self.interp, ["/tmp/%s" % os.path.basename(path)],
+ stdin = messages, stdout = messages, stderr = messages,
+ root = scriptRoot)
+ if intf:
+ intf.resume()
+
+ # Always log an error. Only fail if we have a handle on the
+ # windowing system and the kickstart file included --erroronfail.
+ if rc != 0:
+ log.error("Error code %s running the kickstart script at line %s" % (rc, self.lineno))
+
+ try:
+ f = open(messages, "r")
+ err = f.readlines()
+ f.close()
+ for l in err:
+ log.error("\t%s" % l)
+ except:
+ err = None
+
+ if self.errorOnFail:
+ if intf != None:
+ msg = _("There was an error running the kickstart "
+ "script at line %(lineno)s. You may examine the "
+ "output in %(msgs)s. This is a fatal error and "
+ "installation will be aborted. Press the "
+ "OK button to exit the installer.") \
+ % {'lineno': self.lineno, 'msgs': messages}
+
+ if err:
+ intf.detailedMessageWindow(_("Scriptlet Failure"), msg, err)
+ else:
+ intf.messageWindow(_("Scriptlet Failure"), msg)
+
+ sys.exit(0)
+
+ if serial or self.logfile is not None:
+ os.chmod("%s" % messages, 0600)
+
+class AnacondaKSPackages(Packages):
+ def __init__(self):
+ Packages.__init__(self)
+
+ # Has the %packages section been seen at all?
+ self.seen = False
+
+
+def getEscrowCertificate(anaconda, url):
+ if not url:
+ return None
+
+ if url in anaconda.storage.escrowCertificates:
+ return anaconda.storage.escrowCertificates[url]
+
+ needs_net = not url.startswith("/") and not url.startswith("file:")
+ if needs_net and not network.hasActiveNetDev():
+ if not anaconda.intf.enableNetwork(anaconda):
+ anaconda.intf.messageWindow(_("No Network Available"),
+ _("Encryption key escrow requires "
+ "networking, but there was an error "
+ "enabling the network on your "
+ "system."), type="custom",
+ custom_icon="error",
+ custom_buttons=[_("_Exit installer")])
+ sys.exit(1)
+
+ log.info("escrow: downloading %s" % (url,))
+
+ try:
+ f = urlgrabber.urlopen(url)
+ except urlgrabber.grabber.URLGrabError as e:
+ msg = _("The following error was encountered while downloading the escrow certificate:\n\n%s" % e)
+ if anaconda.intf:
+ anaconda.intf.kickstartErrorWindow(msg)
+ sys.exit(1)
+ else:
+ stderrLog.critical(msg)
+ sys.exit(1)
+
+ try:
+ anaconda.storage.escrowCertificates[url] = f.read()
+ finally:
+ f.close()
+
+ return anaconda.storage.escrowCertificates[url]
+
+def deviceMatches(spec):
+ if not spec.startswith("/dev/"):
+ spec = os.path.normpath("/dev/" + spec)
+
+ matches = udev_resolve_glob(spec)
+ dev = udev_resolve_devspec(spec)
+
+ # udev_resolve_devspec returns None if there's no match, but we don't
+ # want that ending up in the list.
+ if dev and dev not in matches:
+ matches.append(dev)
+
+ return matches
+
+# Remove any existing formatting on a device, but do not remove the partition
+# itself. This sets up an existing device to be used in a --onpart option.
+def removeExistingFormat(device, devicetree):
+ deps = storage.deviceDeps(device)
+ while deps:
+ leaves = [d for d in deps if d.isleaf]
+ for leaf in leaves:
+ storage.destroyDevice(leaf)
+ deps.remove(leaf)
+
+ devicetree.registerAction(ActionDestroyFormat(device))
+
+###
+### SUBCLASSES OF PYKICKSTART COMMAND HANDLERS
+###
+
+class Authconfig(commands.authconfig.FC3_Authconfig):
+ def execute(self, anaconda):
+ anaconda.security.auth = self.authconfig
+
+class AutoPart(commands.autopart.F12_AutoPart):
+ def execute(self, anaconda):
+ # sets up default autopartitioning. use clearpart separately
+ # if you want it
+ anaconda.instClass.setDefaultPartitioning(anaconda.storage, anaconda.platform)
+ anaconda.storage.doAutoPart = True
+
+ if self.encrypted:
+ anaconda.storage.encryptedAutoPart = True
+ anaconda.storage.encryptionPassphrase = self.passphrase
+ anaconda.storage.autoPartEscrowCert = \
+ getEscrowCertificate(anaconda, self.escrowcert)
+ anaconda.storage.autoPartAddBackupPassphrase = \
+ self.backuppassphrase
+
+ anaconda.ksdata.skipSteps.extend(["partition", "zfcpconfig", "parttype"])
+
+class AutoStep(commands.autostep.FC3_AutoStep):
+ def execute(self, anaconda):
+ flags.autostep = 1
+ flags.autoscreenshot = self.autoscreenshot
+
+class Bootloader(commands.bootloader.F12_Bootloader):
+ def execute(self, anaconda):
+ if self.location == "none":
+ location = None
+ elif self.location == "partition":
+ location = "boot"
+ else:
+ location = self.location
+
+ if self.upgrade and not anaconda.upgrade:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Selected upgrade mode for bootloader but not doing an upgrade")
+
+ if self.upgrade:
+ anaconda.bootloader.kickstart = 1
+ anaconda.bootloader.doUpgradeOnly = 1
+
+ if location is None:
+ anaconda.ksdata.permanentSkipSteps.extend(["bootloadersetup", "instbootloader"])
+ else:
+ anaconda.ksdata.showSteps.append("bootloader")
+
+ if self.appendLine:
+ anaconda.bootloader.args.append(self.appendLine)
+
+ if self.password:
+ anaconda.bootloader.setPassword(self.password, isCrypted = 0)
+
+ if self.md5pass:
+ anaconda.bootloader.setPassword(self.md5pass)
+
+ if location != None:
+ anaconda.bootloader.defaultDevice = location
+ else:
+ anaconda.bootloader.defaultDevice = -1
+
+ if self.timeout:
+ anaconda.bootloader.timeout = self.timeout
+
+ # add unpartitioned devices that will get partitioned into
+ # bootloader.drivelist
+ disks = anaconda.storage.disks
+ partitioned = anaconda.storage.partitioned
+ for disk in [d for d in disks if not d.partitioned]:
+ if shouldClear(disk, anaconda.storage.clearPartType,
+ anaconda.storage.clearPartDisks):
+ # add newly partitioned disks to the drivelist
+ anaconda.bootloader.drivelist.append(disk.name)
+ elif disk.name in anaconda.bootloader.drivelist:
+ # remove unpartitioned disks from the drivelist
+ anaconda.bootloader.drivelist.remove(disk.name)
+ anaconda.bootloader.drivelist.sort(
+ cmp=anaconda.storage.compareDisks)
+
+ # Throw out drives specified that don't exist.
+ if self.driveorder and len(self.driveorder) > 0:
+ new = []
+ for drive in self.driveorder:
+ if drive in anaconda.bootloader.drivelist:
+ new.append(drive)
+ else:
+ log.warning("requested drive %s in boot drive order "
+ "doesn't exist" %(drive,))
+
+ anaconda.bootloader.updateDriveList(new)
+
+ anaconda.ksdata.permanentSkipSteps.extend(["upgbootloader", "bootloader"])
+
+class ClearPart(commands.clearpart.FC3_ClearPart):
+ def parse(self, args):
+ retval = commands.clearpart.FC3_ClearPart.parse(self, args)
+
+ if self.type is None:
+ self.type = CLEARPART_TYPE_NONE
+
+ # Do any glob expansion now, since we need to have the real list of
+ # disks available before the execute methods run.
+ drives = []
+ for spec in self.drives:
+ matched = deviceMatches(spec)
+ if matched:
+ drives.extend(matched)
+ else:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent disk %s in clearpart command" % spec)
+
+ self.drives = drives
+
+ return retval
+
+ def execute(self, anaconda):
+ anaconda.storage.clearPartType = self.type
+ anaconda.storage.clearPartDisks = self.drives
+ if self.initAll:
+ anaconda.storage.reinitializeDisks = self.initAll
+
+ clearPartitions(anaconda.storage)
+ anaconda.ksdata.skipSteps.append("cleardiskssel")
+
+class Fcoe(commands.fcoe.F13_Fcoe):
+ def parse(self, args):
+ fc = commands.fcoe.F13_Fcoe.parse(self, args)
+
+ if fc.nic not in isys.getDeviceProperties():
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent nic %s in fcoe command" % fc.nic)
+
+ storage.fcoe.fcoe().addSan(nic=fc.nic, dcb=fc.dcb)
+
+ return fc
+
+class Firewall(commands.firewall.F10_Firewall):
+ def execute(self, anaconda):
+ anaconda.firewall.enabled = self.enabled
+ anaconda.firewall.trustdevs = self.trusts
+
+ for port in self.ports:
+ anaconda.firewall.portlist.append (port)
+
+ for svc in self.services:
+ anaconda.firewall.servicelist.append (svc)
+
+class IgnoreDisk(commands.ignoredisk.F8_IgnoreDisk):
+ def parse(self, args):
+ retval = commands.ignoredisk.F8_IgnoreDisk.parse(self, args)
+
+ # See comment in ClearPart.parse
+ drives = []
+ for spec in self.ignoredisk:
+ matched = deviceMatches(spec)
+ if matched:
+ drives.extend(matched)
+ else:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent disk %s in ignoredisk command" % spec)
+
+ self.ignoredisk = drives
+
+ drives = []
+ for spec in self.onlyuse:
+ matched = deviceMatches(spec)
+ if matched:
+ drives.extend(matched)
+ else:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent disk %s in ignoredisk command" % spec)
+
+ self.onlyuse = drives
+
+ return retval
+
+ def execute(self, anaconda):
+ anaconda.storage.ignoredDisks = self.ignoredisk
+ anaconda.storage.exclusiveDisks = self.onlyuse
+ anaconda.ksdata.skipSteps.extend(["filter", "filtertype"])
+
+class Iscsi(commands.iscsi.F10_Iscsi):
+ def parse(self, args):
+ tg = commands.iscsi.F10_Iscsi.parse(self, args)
+
+ try:
+ storage.iscsi.iscsi().addTarget(tg.ipaddr, tg.port,
+ tg.user, tg.password, tg.user_in, tg.password_in)
+ log.info("added iscsi target: %s" %(tg.ipaddr,))
+ except (IOError, ValueError), e:
+ raise KickstartValueError, formatErrorMsg(self.lineno,
+ msg=str(e))
+ return tg
+
+class IscsiName(commands.iscsiname.FC6_IscsiName):
+ def parse(self, args):
+ retval = commands.iscsiname.FC6_IscsiName.parse(self, args)
+
+ storage.iscsi.iscsi().initiator = self.iscsiname
+ return retval
+
+class Keyboard(commands.keyboard.FC3_Keyboard):
+ def execute(self, anaconda):
+ anaconda.keyboard.set(self.keyboard)
+ anaconda.keyboard.beenset = 1
+ anaconda.ksdata.skipSteps.append("keyboard")
+
+class Lang(commands.lang.FC3_Lang):
+ def execute(self, anaconda):
+ anaconda.instLanguage.instLang = self.lang
+ anaconda.instLanguage.systemLang = self.lang
+ anaconda.ksdata.skipSteps.append("language")
+
+class LogVolData(commands.logvol.F12_LogVolData):
+ def execute(self, anaconda):
+ storage = anaconda.storage
+ devicetree = storage.devicetree
+
+ storage.doAutoPart = False
+
+ if self.mountpoint == "swap":
+ type = "swap"
+ self.mountpoint = ""
+ if self.recommended:
+ (self.size, self.maxSizeMB) = iutil.swapSuggestion()
+ self.grow = True
+ else:
+ if self.fstype != "":
+ type = self.fstype
+ else:
+ type = storage.defaultFSType
+
+ # Sanity check mountpoint
+ if self.mountpoint != "" and self.mountpoint[0] != '/':
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="The mount point \"%s\" is not valid." % (self.mountpoint,))
+
+ # Check that the VG this LV is a member of has already been specified.
+ vg = devicetree.getDeviceByName(self.vgname)
+ if not vg:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="No volume group exists with the name \"%s\". Specify volume groups before logical volumes." % self.vgname)
+
+ # If this specifies an existing request that we should not format,
+ # quit here after setting up enough information to mount it later.
+ if not self.format:
+ if not self.name:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="--noformat used without --name")
+
+ dev = devicetree.getDeviceByName("%s-%s" % (vg.name, self.name))
+ if not dev:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="No preexisting logical volume with the name \"%s\" was found." % self.name)
+
+ dev.format.mountpoint = self.mountpoint
+ dev.format.mountopts = self.fsopts
+ anaconda.ksdata.skipSteps.extend(["partition", "zfcpconfig", "parttype"])
+ return
+
+ # Make sure this LV name is not already used in the requested VG.
+ if not self.preexist:
+ tmp = devicetree.getDeviceByName("%s-%s" % (vg.name, self.name))
+ if tmp:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Logical volume name already used in volume group %s" % vg.name)
+
+ # Size specification checks
+ if not self.percent:
+ if not self.size:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Size required")
+ elif not self.grow and self.size*1024 < vg.peSize:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Logical volume size must be larger than the volume group physical extent size.")
+ elif self.percent <= 0 or self.percent > 100:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Percentage must be between 0 and 100")
+
+ # Now get a format to hold a lot of these extra values.
+ format = getFormat(type,
+ mountpoint=self.mountpoint,
+ mountopts=self.fsopts)
+ if not format:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="The \"%s\" filesystem type is not supported." % type)
+
+ # If we were given a pre-existing LV to create a filesystem on, we need
+ # to verify it and its VG exists and then schedule a new format action
+ # to take place there. Also, we only support a subset of all the
+ # options on pre-existing LVs.
+ if self.preexist:
+ device = devicetree.getDeviceByName("%s-%s" % (vg.name, self.name))
+ if not device:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent LV %s in logvol command" % self.name)
+
+ removeExistingFormat(device, devicetree)
+ devicetree.registerAction(ActionCreateFormat(device, format))
+ else:
+ # If a previous device has claimed this mount point, delete the
+ # old one.
+ try:
+ if self.mountpoint:
+ device = storage.mountpoints[self.mountpoint]
+ storage.destroyDevice(device)
+ except KeyError:
+ pass
+
+ request = storage.newLV(format=format,
+ name=self.name,
+ vg=vg,
+ size=self.size,
+ grow=self.grow,
+ maxsize=self.maxSizeMB,
+ percent=self.percent)
+
+ if self.fsprofile and hasattr(request.format, "fsprofile"):
+ request.format.fsprofile = self.fsprofile
+
+ storage.createDevice(request)
+
+ if self.encrypted:
+ if self.passphrase and not storage.encryptionPassphrase:
+ storage.encryptionPassphrase = self.passphrase
+
+ cert = getEscrowCertificate(anaconda, self.escrowcert)
+ if self.preexist:
+ luksformat = format
+ device.format = getFormat("luks", passphrase=self.passphrase, device=device.path,
+ escrow_cert=cert,
+ add_backup_passphrase=self.backuppassphrase)
+ luksdev = LUKSDevice("luks%d" % storage.nextID,
+ format=luksformat,
+ parents=device)
+ else:
+ luksformat = request.format
+ request.format = getFormat("luks", passphrase=self.passphrase,
+ escrow_cert=cert,
+ add_backup_passphrase=self.backuppassphrase)
+ luksdev = LUKSDevice("luks%d" % storage.nextID,
+ format=luksformat,
+ parents=request)
+ storage.createDevice(luksdev)
+
+ anaconda.ksdata.skipSteps.extend(["partition", "zfcpconfig", "parttype"])
+
+class Logging(commands.logging.FC6_Logging):
+ def execute(self, anaconda):
+ if logger.tty_loglevel == DEFAULT_TTY_LEVEL:
+ # not set from the command line
+ level = logLevelMap[self.level]
+ logger.tty_loglevel = level
+ storage_log = logging.getLogger("storage")
+ setHandlersLevel(log, level)
+ setHandlersLevel(storage_log, level)
+
+ if logger.remote_syslog == None and len(self.host) > 0:
+ # not set from the command line, ok to use kickstart
+ remote_server = self.host
+ if self.port:
+ remote_server = "%s:%s" %(self.host, self.port)
+ logger.updateRemote(remote_server)
+
+class NetworkData(commands.network.F8_NetworkData):
+ def execute(self, anaconda):
+ if self.bootProto:
+ devices = anaconda.network.netdevices
+ if (devices and self.bootProto):
+ if not self.device:
+ list = devices.keys ()
+ list.sort()
+ device = list[0]
+ else:
+ device = self.device
+
+ try:
+ dev = devices[device]
+ except KeyError:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="The provided network interface %s does not exist" % device)
+
+ dev.set (("bootproto", self.bootProto))
+ dev.set (("dhcpclass", self.dhcpclass))
+
+ if self.onboot:
+ dev.set (("onboot", "yes"))
+ else:
+ dev.set (("onboot", "no"))
+
+ if self.bootProto == "static":
+ if (self.ip):
+ dev.set (("ipaddr", self.ip))
+ if (self.netmask):
+ dev.set (("netmask", self.netmask))
+
+ if self.ethtool:
+ dev.set (("ethtool_opts", self.ethtool))
+
+ if isys.isWireless(device):
+ if self.essid:
+ dev.set(("essid", self.essid))
+ if self.wepkey:
+ dev.set(("wepkey", self.wepkey))
+
+ if self.hostname != "":
+ anaconda.network.setHostname(self.hostname)
+ anaconda.network.overrideDHCPhostname = True
+
+ if self.nameserver != "":
+ anaconda.network.setDNS(self.nameserver, device)
+
+ if self.gateway != "":
+ anaconda.network.setGateway(self.gateway, device)
+
+ needs_net = (anaconda.methodstr and
+ (anaconda.methodstr.startswith("http:") or
+ anaconda.methodstr.startswith("ftp:") or
+ anaconda.methodstr.startswith("nfs:")))
+ if needs_net and not network.hasActiveNetDev():
+ log.info("Bringing up network in stage2 kickstart ...")
+ rc = anaconda.network.bringUp()
+ log.info("Network setup %s" % (rc and 'succeeded' or 'failed',))
+
+class MultiPath(commands.multipath.FC6_MultiPath):
+ def parse(self, args):
+ raise NotImplementedError("The multipath kickstart command is not currently supported")
+
+class DmRaid(commands.dmraid.FC6_DmRaid):
+ def parse(self, args):
+ raise NotImplementedError("The dmraid kickstart command is not currently supported")
+
+class PartitionData(commands.partition.F12_PartData):
+ def execute(self, anaconda):
+ storage = anaconda.storage
+ devicetree = storage.devicetree
+ kwargs = {}
+
+ storage.doAutoPart = False
+
+ if self.onbiosdisk != "":
+ for (disk, biosdisk) in storage.eddDict.iteritems():
+ if str(biosdisk) == self.onbiosdisk:
+ self.disk = disk
+ break
+
+ if self.disk == "":
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified BIOS disk %s cannot be determined" % self.onbiosdisk)
+
+ if self.mountpoint == "swap":
+ type = "swap"
+ self.mountpoint = ""
+ if self.recommended:
+ (self.size, self.maxSizeMB) = iutil.swapSuggestion()
+ self.grow = True
+ # if people want to specify no mountpoint for some reason, let them
+ # this is really needed for pSeries boot partitions :(
+ elif self.mountpoint == "None":
+ self.mountpoint = ""
+ if self.fstype:
+ type = self.fstype
+ else:
+ type = storage.defaultFSType
+ elif self.mountpoint == 'appleboot':
+ type = "Apple Bootstrap"
+ self.mountpoint = ""
+ kwargs["weight"] = anaconda.platform.weight(fstype="appleboot")
+ elif self.mountpoint == 'prepboot':
+ type = "PPC PReP Boot"
+ self.mountpoint = ""
+ kwargs["weight"] = anaconda.platform.weight(fstype="prepboot")
+ elif self.mountpoint.startswith("raid."):
+ type = "mdmember"
+ kwargs["name"] = self.mountpoint
+
+ if devicetree.getDeviceByName(kwargs["name"]):
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="RAID partition defined multiple times")
+
+ # store "raid." alias for other ks partitioning commands
+ if self.onPart:
+ anaconda.ksdata.onPart[kwargs["name"]] = self.onPart
+ self.mountpoint = ""
+ elif self.mountpoint.startswith("pv."):
+ type = "lvmpv"
+ kwargs["name"] = self.mountpoint
+
+ if devicetree.getDeviceByName(kwargs["name"]):
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="PV partition defined multiple times")
+
+ # store "pv." alias for other ks partitioning commands
+ if self.onPart:
+ anaconda.ksdata.onPart[kwargs["name"]] = self.onPart
+ self.mountpoint = ""
+ elif self.mountpoint == "/boot/efi":
+ type = "EFI System Partition"
+ self.fsopts = "defaults,uid=0,gid=0,umask=0077,shortname=winnt"
+ kwargs["weight"] = anaconda.platform.weight(fstype="efi")
+ else:
+ if self.fstype != "":
+ type = self.fstype
+ elif self.mountpoint == "/boot":
+ type = anaconda.platform.defaultBootFSType
+ else:
+ type = storage.defaultFSType
+
+ # If this specified an existing request that we should not format,
+ # quit here after setting up enough information to mount it later.
+ if not self.format:
+ if not self.onPart:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="--noformat used without --onpart")
+
+ dev = devicetree.getDeviceByName(udev_resolve_devspec(self.onPart))
+ if not dev:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="No preexisting partition with the name \"%s\" was found." % self.onPart)
+
+ dev.format.mountpoint = self.mountpoint
+ dev.format.mountopts = self.fsopts
+ anaconda.ksdata.skipSteps.extend(["partition", "zfcpconfig", "parttype"])
+ return
+
+ # Size specification checks.
+ if not self.size and not self.onPart:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Partition requires a size specification")
+
+ # Now get a format to hold a lot of these extra values.
+ kwargs["format"] = getFormat(type,
+ mountpoint=self.mountpoint,
+ label=self.label,
+ mountopts=self.fsopts)
+ if not kwargs["format"]:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="The \"%s\" filesystem type is not supported." % type)
+
+ # If we were given a specific disk to create the partition on, verify
+ # that it exists first. If it doesn't exist, see if it exists with
+ # mapper/ on the front. If that doesn't exist either, it's an error.
+ if self.disk:
+ names = [self.disk, "mapper/" + self.disk]
+ for n in names:
+ disk = devicetree.getDeviceByName(udev_resolve_devspec(n))
+ if not disk:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent disk %s in partition command" % n)
+
+ should_clear = shouldClear(disk,
+ storage.clearPartType,
+ storage.clearPartDisks)
+ if disk and (disk.partitioned or should_clear):
+ kwargs["disks"] = [disk]
+ break
+ elif disk:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified unpartitioned disk %s in partition command" % self.disk)
+
+ if not kwargs["disks"]:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent disk %s in partition command" % self.disk)
+
+ kwargs["grow"] = self.grow
+ kwargs["size"] = self.size
+ kwargs["maxsize"] = self.maxSizeMB
+ kwargs["primary"] = self.primOnly
+
+ # If we were given a pre-existing partition to create a filesystem on,
+ # we need to verify it exists and then schedule a new format action to
+ # take place there. Also, we only support a subset of all the options
+ # on pre-existing partitions.
+ if self.onPart:
+ device = devicetree.getDeviceByName(udev_resolve_devspec(self.onPart))
+ if not device:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent partition %s in partition command" % self.onPart)
+
+ removeExistingFormat(device, devicetree)
+ devicetree.registerAction(ActionCreateFormat(device, kwargs["format"]))
+ else:
+ # If a previous device has claimed this mount point, delete the
+ # old one.
+ try:
+ if self.mountpoint:
+ device = storage.mountpoints[self.mountpoint]
+ storage.destroyDevice(device)
+ except KeyError:
+ pass
+
+ request = storage.newPartition(**kwargs)
+
+ if self.fsprofile and hasattr(request.format, "fsprofile"):
+ request.format.fsprofile = self.fsprofile
+
+ storage.createDevice(request)
+
+ if self.encrypted:
+ if self.passphrase and not storage.encryptionPassphrase:
+ storage.encryptionPassphrase = self.passphrase
+
+ cert = getEscrowCertificate(anaconda, self.escrowcert)
+ if self.onPart:
+ luksformat = format
+ device.format = getFormat("luks", passphrase=self.passphrase, device=device.path,
+ escrow_cert=cert,
+ add_backup_passphrase=self.backuppassphrase)
+ luksdev = LUKSDevice("luks%d" % storage.nextID,
+ format=luksformat,
+ parents=device)
+ else:
+ luksformat = request.format
+ request.format = getFormat("luks", passphrase=self.passphrase,
+ escrow_cert=cert,
+ add_backup_passphrase=self.backuppassphrase)
+ luksdev = LUKSDevice("luks%d" % storage.nextID,
+ format=luksformat,
+ parents=request)
+ storage.createDevice(luksdev)
+
+ anaconda.ksdata.skipSteps.extend(["partition", "zfcpconfig", "parttype"])
+
+class Reboot(commands.reboot.FC6_Reboot):
+ def execute(self, anaconda):
+ anaconda.ksdata.skipSteps.append("complete")
+
+class RaidData(commands.raid.F12_RaidData):
+ def execute(self, anaconda):
+ raidmems = []
+ devicename = "md%d" % self.device
+
+ storage = anaconda.storage
+ devicetree = storage.devicetree
+ kwargs = {}
+
+ storage.doAutoPart = False
+
+ if self.mountpoint == "swap":
+ type = "swap"
+ self.mountpoint = ""
+ elif self.mountpoint.startswith("pv."):
+ type = "lvmpv"
+ kwargs["name"] = self.mountpoint
+ anaconda.ksdata.onPart[kwargs["name"]] = devicename
+
+ if devicetree.getDeviceByName(kwargs["name"]):
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="PV partition defined multiple times")
+
+ self.mountpoint = ""
+ else:
+ if self.fstype != "":
+ type = self.fstype
+ elif self.mountpoint == "/boot" and anaconda.platform.supportsMdRaidBoot:
+ type = anaconda.platform.defaultBootFSType
+ else:
+ type = storage.defaultFSType
+
+ # Sanity check mountpoint
+ if self.mountpoint != "" and self.mountpoint[0] != '/':
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="The mount point is not valid.")
+
+ # If this specifies an existing request that we should not format,
+ # quit here after setting up enough information to mount it later.
+ if not self.format:
+ if not devicename:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="--noformat used without --device")
+
+ dev = devicetree.getDeviceByName(devicename)
+ if not dev:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="No preexisting RAID device with the name \"%s\" was found." % devicename)
+
+ dev.format.mountpoint = self.mountpoint
+ dev.format.mountopts = self.fsopts
+ anaconda.ksdata.skipSteps.extend(["partition", "zfcpconfig", "parttype"])
+ return
+
+ # Get a list of all the RAID members.
+ for member in self.members:
+ # if member is using --onpart, use original device
+ member = anaconda.ksdata.onPart.get(member, member)
+ dev = devicetree.getDeviceByName(member)
+ if dev and dev.format.type == "luks":
+ try:
+ dev = devicetree.getChildren(dev)[0]
+ except IndexError:
+ dev = None
+ if not dev:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Tried to use undefined partition %s in RAID specification" % member)
+
+ raidmems.append(dev)
+
+ if not self.preexist:
+ if len(raidmems) == 0:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="RAID Partition defined without any RAID members")
+
+ if self.level == "":
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="RAID Partition defined without RAID level")
+
+ # Now get a format to hold a lot of these extra values.
+ kwargs["format"] = getFormat(type,
+ mountpoint=self.mountpoint,
+ mountopts=self.fsopts)
+ if not kwargs["format"]:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="The \"%s\" filesystem type is not supported." % type)
+
+ kwargs["name"] = devicename
+ kwargs["level"] = self.level
+ kwargs["parents"] = raidmems
+ kwargs["memberDevices"] = len(raidmems)
+ kwargs["totalDevices"] = kwargs["memberDevices"]+self.spares
+
+ # If we were given a pre-existing RAID to create a filesystem on,
+ # we need to verify it exists and then schedule a new format action
+ # to take place there. Also, we only support a subset of all the
+ # options on pre-existing RAIDs.
+ if self.preexist:
+ device = devicetree.getDeviceByName(devicename)
+ if not device:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specifeid nonexistent RAID %s in raid command" % devicename)
+
+ removeExistingFormat(device, devicetree)
+ devicetree.registerAction(ActionCreateFormat(device, kwargs["format"]))
+ else:
+ # If a previous device has claimed this mount point, delete the
+ # old one.
+ try:
+ if self.mountpoint:
+ device = storage.mountpoints[self.mountpoint]
+ storage.destroyDevice(device)
+ except KeyError:
+ pass
+
+ try:
+ request = storage.newMDArray(**kwargs)
+ except ValueError, e:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg=str(e))
+
+ if self.fsprofile and hasattr(request.format, "fsprofile"):
+ request.format.fsprofile = self.fsprofile
+
+ storage.createDevice(request)
+
+ if self.encrypted:
+ if self.passphrase and not storage.encryptionPassphrase:
+ storage.encryptionPassphrase = self.passphrase
+
+ cert = getEscrowCertificate(anaconda, self.escrowcert)
+ if self.preexist:
+ luksformat = format
+ device.format = getFormat("luks", passphrase=self.passphrase, device=device.path,
+ escrow_cert=cert,
+ add_backup_passphrase=self.backuppassphrase)
+ luksdev = LUKSDevice("luks%d" % storage.nextID,
+ format=luksformat,
+ parents=device)
+ else:
+ luksformat = request.format
+ request.format = getFormat("luks", passphrase=self.passphrase,
+ escrow_cert=cert,
+ add_backup_passphrase=self.backuppassphrase)
+ luksdev = LUKSDevice("luks%d" % storage.nextID,
+ format=luksformat,
+ parents=request)
+ storage.createDevice(luksdev)
+
+ anaconda.ksdata.skipSteps.extend(["partition", "zfcpconfig", "parttype"])
+
+class RootPw(commands.rootpw.F8_RootPw):
+ def execute(self, anaconda):
+ anaconda.users.rootPassword["password"] = self.password
+ anaconda.users.rootPassword["isCrypted"] = self.isCrypted
+ anaconda.users.rootPassword["lock"] = self.lock
+ anaconda.ksdata.skipSteps.append("accounts")
+
+class SELinux(commands.selinux.FC3_SELinux):
+ def execute(self, anaconda):
+ anaconda.security.setSELinux(self.selinux)
+
+class SkipX(commands.skipx.FC3_SkipX):
+ def execute(self, anaconda):
+ anaconda.ksdata.skipSteps.extend(["setsanex", "videocard", "xcustom"])
+
+ if anaconda.desktop is not None:
+ anaconda.desktop.setDefaultRunLevel(3)
+
+class Timezone(commands.timezone.FC6_Timezone):
+ def execute(self, anaconda):
+ # check validity
+ tab = zonetab.ZoneTab()
+ if self.timezone not in (entry.tz.replace(' ','_') for entry in
+ tab.getEntries()):
+ log.warning("Timezone %s set in kickstart is not valid." % (self.timezone,))
+
+ anaconda.timezone.setTimezoneInfo(self.timezone, self.isUtc)
+ anaconda.ksdata.skipSteps.append("timezone")
+
+class Upgrade(commands.upgrade.F11_Upgrade):
+ def execute(self, anaconda):
+ anaconda.upgrade = self.upgrade
+
+class VolGroupData(commands.volgroup.FC3_VolGroupData):
+ def execute(self, anaconda):
+ pvs = []
+
+ storage = anaconda.storage
+ devicetree = storage.devicetree
+
+ storage.doAutoPart = False
+
+ # Get a list of all the physical volume devices that make up this VG.
+ for pv in self.physvols:
+ # if pv is using --onpart, use original device
+ pv = anaconda.ksdata.onPart.get(pv, pv)
+ dev = devicetree.getDeviceByName(pv)
+ if dev and dev.format.type == "luks":
+ try:
+ dev = devicetree.getChildren(dev)[0]
+ except IndexError:
+ dev = None
+ if not dev:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Tried to use undefined partition %s in Volume Group specification" % pv)
+
+ pvs.append(dev)
+
+ if len(pvs) == 0 and not self.preexist:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Volume group defined without any physical volumes. Either specify physical volumes or use --useexisting.")
+
+ if self.pesize not in getPossiblePhysicalExtents(floor=1024):
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="Volume group specified invalid pesize")
+
+ # If --noformat or --useexisting was given, there's really nothing to do.
+ if not self.format or self.preexist:
+ if not self.vgname:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="--noformat or --useexisting used without giving a name")
+
+ dev = devicetree.getDeviceByName(self.vgname)
+ if not dev:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg="No preexisting VG with the name \"%s\" was found." % self.vgname)
+ else:
+ request = storage.newVG(pvs=pvs,
+ name=self.vgname,
+ peSize=self.pesize/1024.0)
+
+ storage.createDevice(request)
+
+class XConfig(commands.xconfig.F10_XConfig):
+ def execute(self, anaconda):
+ if self.startX:
+ anaconda.desktop.setDefaultRunLevel(5)
+
+ if self.defaultdesktop:
+ anaconda.desktop.setDefaultDesktop(self.defaultdesktop)
+
+class ZeroMbr(commands.zerombr.FC3_ZeroMbr):
+ def execute(self, anaconda):
+ anaconda.storage.zeroMbr = 1
+
+class ZFCP(commands.zfcp.FC3_ZFCP):
+ def parse(self, args):
+ fcp = commands.zfcp.FC3_ZFCP.parse(self, args)
+ try:
+ storage.zfcp.ZFCP().addFCP(fcp.devnum, fcp.wwpn, fcp.fcplun)
+ except ValueError, e:
+ log.warning(str(e))
+
+ return fcp
+
+###
+### HANDLERS
+###
+
+# This is just the latest entry from pykickstart.handlers.control with all the
+# classes we're overriding in place of the defaults.
+commandMap = {
+ "auth": Authconfig,
+ "authconfig": Authconfig,
+ "autopart": AutoPart,
+ "autostep": AutoStep,
+ "bootloader": Bootloader,
+ "clearpart": ClearPart,
+ "dmraid": DmRaid,
+ "fcoe": Fcoe,
+ "firewall": Firewall,
+ "halt": Reboot,
+ "ignoredisk": IgnoreDisk,
+ "install": Upgrade,
+ "iscsi": Iscsi,
+ "iscsiname": IscsiName,
+ "keyboard": Keyboard,
+ "lang": Lang,
+ "logging": Logging,
+ "multipath": MultiPath,
+ "poweroff": Reboot,
+ "reboot": Reboot,
+ "rootpw": RootPw,
+ "selinux": SELinux,
+ "shutdown": Reboot,
+ "skipx": SkipX,
+ "timezone": Timezone,
+ "upgrade": Upgrade,
+ "xconfig": XConfig,
+ "zerombr": ZeroMbr,
+ "zfcp": ZFCP,
+}
+
+dataMap = {
+ "LogVolData": LogVolData,
+ "NetworkData": NetworkData,
+ "PartData": PartitionData,
+ "RaidData": RaidData,
+ "VolGroupData": VolGroupData,
+}
+
+superclass = returnClassForVersion()
+
+class AnacondaKSHandler(superclass):
+ def __init__ (self, anaconda):
+ superclass.__init__(self, commandUpdates=commandMap, dataUpdates=dataMap)
+ self.packages = AnacondaKSPackages()
+
+ self.permanentSkipSteps = []
+ self.skipSteps = []
+ self.showSteps = []
+ self.anaconda = anaconda
+ self.id = self.anaconda.id
+ self.onPart = {}
+
+ # All the KickstartCommand and KickstartData objects that
+ # handleCommand returns, so we can later iterate over them and run
+ # the execute methods. These really should be stored in the order
+ # they're seen in the kickstart file.
+ self._dataObjs = []
+
+ def add(self, obj):
+ if isinstance(obj, KickstartCommand):
+ # Commands can only be run once, and the latest one seen takes
+ # precedence over any earlier ones.
+ i = 0
+ while i < len(self._dataObjs):
+ if self._dataObjs[i].__class__ == obj.__class__:
+ self._dataObjs.pop(i)
+ break
+
+ i += 1
+
+ self._dataObjs.append(obj)
+ else:
+ # Data objects can be seen over and over again.
+ self._dataObjs.append(obj)
+
+ def execute(self):
+ for obj in filter(lambda o: hasattr(o, "execute"), self._dataObjs):
+ obj.execute(self.anaconda)
+
+class AnacondaPreParser(KickstartParser):
+ # A subclass of KickstartParser that only looks for %pre scripts and
+ # sets them up to be run. All other scripts and commands are ignored.
+ def __init__ (self, handler, followIncludes=True, errorsAreFatal=True,
+ missingIncludeIsFatal=True):
+ KickstartParser.__init__(self, handler, missingIncludeIsFatal=False)
+
+ def addScript (self):
+ if self._script["type"] != KS_SCRIPT_PRE:
+ return
+
+ s = AnacondaKSScript (self._script["body"], type=self._script["type"],
+ interp=self._script["interp"],
+ lineno=self._script["lineno"],
+ inChroot=self._script["chroot"],
+ logfile=self._script["log"],
+ errorOnFail=self._script["errorOnFail"])
+ self.handler.scripts.append(s)
+
+ def addPackages (self, line):
+ pass
+
+ def handleCommand (self, lineno, args):
+ pass
+
+ def handlePackageHdr (self, lineno, args):
+ pass
+
+ def handleScriptHdr (self, lineno, args):
+ if not args[0] == "%pre":
+ return
+
+ KickstartParser.handleScriptHdr(self, lineno, args)
+
+class AnacondaKSParser(KickstartParser):
+ def __init__ (self, handler, followIncludes=True, errorsAreFatal=True,
+ missingIncludeIsFatal=True):
+ KickstartParser.__init__(self, handler)
+
+ def addScript (self):
+ if string.join(self._script["body"]).strip() == "":
+ return
+
+ s = AnacondaKSScript (self._script["body"], type=self._script["type"],
+ interp=self._script["interp"],
+ lineno=self._script["lineno"],
+ inChroot=self._script["chroot"],
+ logfile=self._script["log"],
+ errorOnFail=self._script["errorOnFail"])
+ self.handler.scripts.append(s)
+
+ def handlePackageHdr (self, lineno, args):
+ KickstartParser.handlePackageHdr (self, lineno, args)
+ self.handler.packages.seen = True
+
+ def handleCommand (self, lineno, args):
+ if not self.handler:
+ return
+
+ retval = KickstartParser.handleCommand(self, lineno, args)
+ self.handler.add(retval)
+ return retval
+
+def preScriptPass(anaconda, file):
+ # The first pass through kickstart file processing - look for %pre scripts
+ # and run them. This must come in a separate pass in case a script
+ # generates an included file that has commands for later.
+ ksparser = AnacondaPreParser(AnacondaKSHandler(anaconda))
+
+ try:
+ ksparser.readKickstart(file)
+ except IOError, e:
+ if anaconda.intf:
+ anaconda.intf.kickstartErrorWindow("Could not open kickstart file or included file named %s" % e.filename)
+ sys.exit(1)
+ else:
+ stderrLog.critical(_("The following error was found while parsing the kickstart "
+ "configuration file:\n\n%s") % e)
+ sys.exit(1)
+ except KickstartError, e:
+ if anaconda.intf:
+ anaconda.intf.kickstartErrorWindow(e.__str__())
+ sys.exit(1)
+ else:
+ stderrLog.critical(_("The following error was found while parsing the kickstart "
+ "configuration file:\n\n%s") % e)
+ sys.exit(1)
+
+ # run %pre scripts
+ runPreScripts(anaconda, ksparser.handler.scripts)
+
+def parseKickstart(anaconda, file):
+ try:
+ file = preprocessKickstart(file)
+ except KickstartError, msg:
+ stderrLog.critical(_("Error processing %%ksappend lines: %s") % msg)
+ sys.exit(1)
+ except Exception, e:
+ stderrLog.critical(_("Unknown error processing %%ksappend lines: %s") % e)
+ sys.exit(1)
+
+ handler = AnacondaKSHandler(anaconda)
+ ksparser = AnacondaKSParser(handler)
+
+ # We need this so all the /dev/disk/* stuff is set up before parsing.
+ udev_trigger(subsystem="block", action="change")
+ # So that drives onlined by these can be used in the ks file
+ storage.iscsi.iscsi().startup()
+ storage.fcoe.fcoe().startup()
+ storage.zfcp.ZFCP().startup()
+ # Note we do NOT call dasd.startup() here, that does not online drives, but
+ # only checks if they need formatting, which requires zerombr to be known
+
+ try:
+ ksparser.readKickstart(file)
+ except IOError, e:
+ # We may not have an intf now, but we can do better than just raising
+ # the exception.
+ if anaconda.intf:
+ anaconda.intf.kickstartErrorWindow("Could not open kickstart file or included file named %s" % e.filename)
+ sys.exit(1)
+ else:
+ stderrLog.critical(_("The following error was found while parsing the kickstart "
+ "configuration file:\n\n%s") % e)
+ sys.exit(1)
+ except KickstartError, e:
+ if anaconda.intf:
+ anaconda.intf.kickstartErrorWindow(e.__str__())
+ sys.exit(1)
+ else:
+ stderrLog.critical(_("The following error was found while parsing the kickstart "
+ "configuration file:\n\n%s") % e)
+ sys.exit(1)
+
+ return handler
+
+def runPostScripts(anaconda):
+ if not anaconda.ksdata:
+ return
+
+ postScripts = filter (lambda s: s.type == KS_SCRIPT_POST,
+ anaconda.ksdata.scripts)
+
+ if len(postScripts) == 0:
+ return
+
+ # Remove environment variables that cause problems for %post scripts.
+ for var in ["LIBUSER_CONF"]:
+ if os.environ.has_key(var):
+ del(os.environ[var])
+
+ log.info("Running kickstart %%post script(s)")
+ if anaconda.intf is not None:
+ w = anaconda.intf.waitWindow(_("Post-Installation"),
+ _("Running post-installation scripts"))
+
+ map (lambda s: s.run(anaconda.rootPath, flags.serial, anaconda.intf), postScripts)
+
+ log.info("All kickstart %%post script(s) have been run")
+ if anaconda.intf is not None:
+ w.pop()
+
+def runPreScripts(anaconda, scripts):
+ preScripts = filter (lambda s: s.type == KS_SCRIPT_PRE, scripts)
+
+ if len(preScripts) == 0:
+ return
+
+ log.info("Running kickstart %%pre script(s)")
+ if anaconda.intf is not None:
+ w = anaconda.intf.waitWindow(_("Pre-Installation"),
+ _("Running pre-installation scripts"))
+
+ map (lambda s: s.run("/", flags.serial, anaconda.intf), preScripts)
+
+ log.info("All kickstart %%pre script(s) have been run")
+ if anaconda.intf is not None:
+ w.pop()
+
+def runTracebackScripts(anaconda):
+ log.info("Running kickstart %%traceback script(s)")
+ for script in filter (lambda s: s.type == KS_SCRIPT_TRACEBACK,
+ anaconda.ksdata.scripts):
+ script.run("/", flags.serial)
+ log.info("All kickstart %%traceback script(s) have been run")
+
+def selectPackages(anaconda):
+ ksdata = anaconda.ksdata
+ ignoreAll = False
+
+ # If no %packages header was seen, use the installclass's default group
+ # selections. This can also be explicitly specified with %packages
+ # --default. Otherwise, select whatever was given (even if it's nothing).
+ if not ksdata.packages.seen or ksdata.packages.default:
+ anaconda.instClass.setGroupSelection(anaconda)
+ return
+
+ for pkg in ksdata.packages.packageList:
+ num = anaconda.backend.selectPackage(pkg)
+ if ksdata.packages.handleMissing == KS_MISSING_IGNORE or ignoreAll:
+ continue
+ if num > 0:
+ continue
+ rc = anaconda.intf.messageWindow(_("Missing Package"),
+ _("You have specified that the "
+ "package '%s' should be installed. "
+ "This package does not exist. "
+ "Would you like to continue or "
+ "abort this installation?") %(pkg,),
+ type="custom",
+ custom_buttons=[_("_Abort"),
+ _("_Ignore All"),
+ _("_Continue")])
+ if rc == 0:
+ sys.exit(1)
+ elif rc == 1:
+ ignoreAll = True
+
+ ksdata.packages.groupList.insert(0, Group("Core"))
+
+ if ksdata.packages.addBase:
+ ksdata.packages.groupList.insert(1, Group("Base"))
+ else:
+ log.warning("not adding Base group")
+
+ for grp in ksdata.packages.groupList:
+ default = False
+ optional = False
+
+ if grp.include == GROUP_DEFAULT:
+ default = True
+ elif grp.include == GROUP_ALL:
+ default = True
+ optional = True
+
+ try:
+ anaconda.backend.selectGroup(grp.name, (default, optional))
+ except NoSuchGroup, e:
+ if ksdata.packages.handleMissing == KS_MISSING_IGNORE or ignoreAll:
+ pass
+ else:
+ rc = anaconda.intf.messageWindow(_("Missing Group"),
+ _("You have specified that the "
+ "group '%s' should be installed. "
+ "This group does not exist. "
+ "Would you like to continue or "
+ "abort this installation?")
+ %(grp.name,),
+ type="custom",
+ custom_buttons=[_("_Abort"),
+ _("_Ignore All"),
+ _("_Continue")])
+ if rc == 0:
+ sys.exit(1)
+ elif rc == 1:
+ ignoreAll = True
+
+ map(anaconda.backend.deselectPackage, ksdata.packages.excludedList)
+ map(lambda g: anaconda.backend.deselectGroup(g.name),
+ ksdata.packages.excludedGroupList)
+
+def setSteps(anaconda):
+ def havePackages(packages):
+ return len(packages.groupList) > 0 or len(packages.packageList) > 0 or \
+ len(packages.excludedList) > 0 or len(packages.excludedGroupList) > 0
+
+ dispatch = anaconda.dispatch
+ ksdata = anaconda.ksdata
+ interactive = ksdata.interactive.interactive
+
+ if ksdata.upgrade.upgrade:
+ upgrade.setSteps(anaconda)
+
+ # we have no way to specify migrating yet
+ dispatch.skipStep("upgrademigfind")
+ dispatch.skipStep("upgrademigratefs")
+ dispatch.skipStep("upgradecontinue")
+ dispatch.skipStep("findinstall", permanent = 1)
+ dispatch.skipStep("language")
+ dispatch.skipStep("keyboard")
+ dispatch.skipStep("betanag")
+ dispatch.skipStep("installtype")
+ else:
+ anaconda.instClass.setSteps(anaconda)
+ dispatch.skipStep("findrootparts")
+
+ if interactive or flags.autostep:
+ dispatch.skipStep("installtype")
+ dispatch.skipStep("bootdisk")
+
+ dispatch.skipStep("bootdisk")
+ dispatch.skipStep("betanag")
+ dispatch.skipStep("installtype")
+ dispatch.skipStep("network")
+
+ # Storage is initialized for us right when kickstart processing starts.
+ dispatch.skipStep("storageinit")
+
+ if not interactive:
+ # Don't show confirmation screens on non-interactive installs.
+ dispatch.skipStep("confirminstall")
+ dispatch.skipStep("confirmupgrade")
+ dispatch.skipStep("welcome")
+
+ # Since ignoredisk is optional and not specifying it means you want to
+ # consider all possible disks, we should not stop on the filter steps
+ # unless it's an interactive install.
+ dispatch.skipStep("filter")
+ dispatch.skipStep("filtertype")
+
+ # Make sure to automatically reboot even in interactive if told to.
+ if interactive and ksdata.reboot.action in [KS_REBOOT, KS_SHUTDOWN]:
+ dispatch.skipStep("complete")
+
+ # If the package section included anything, skip group selection unless
+ # they're in interactive.
+ if ksdata.upgrade.upgrade:
+ ksdata.skipSteps.extend(["tasksel", "group-selection"])
+
+ # Special check for this, since it doesn't make any sense.
+ if ksdata.packages.seen:
+ warnings.warn("Ignoring contents of %packages section due to upgrade.")
+ elif havePackages(ksdata.packages):
+ if interactive:
+ ksdata.showSteps.extend(["tasksel", "group-selection"])
+ else:
+ ksdata.skipSteps.extend(["tasksel", "group-selection"])
+ else:
+ if ksdata.packages.seen:
+ ksdata.skipSteps.extend(["tasksel", "group-selection"])
+ else:
+ ksdata.showSteps.extend(["tasksel", "group-selection"])
+
+ if not interactive:
+ for n in ksdata.skipSteps:
+ dispatch.skipStep(n)
+ for n in ksdata.permanentSkipSteps:
+ dispatch.skipStep(n, permanent=1)
+ for n in ksdata.showSteps:
+ dispatch.skipStep(n, skip = 0)
+
+ # Text mode doesn't have all the steps that graphical mode does, so we
+ # can't stop and prompt for missing information. Make sure we've got
+ # everything that would be provided by a missing section now and error
+ # out if we don't.
+ if anaconda.displayMode == "t":
+ missingSteps = [("bootloader", "Bootloader configuration"),
+ ("filter", "Disks to use in installation"),
+ ("cleardiskssel", "Disks to clear"),
+ ("group-selection", "Package selection")]
+ errors = []
+
+ for (step, msg) in missingSteps:
+ if not dispatch.stepInSkipList(step):
+ errors.append(msg)
+
+ if len(errors) > 0:
+ anaconda.intf.kickstartErrorWindow(_("The kickstart configuration "
+ "file is missing required information that anaconda cannot "
+ "prompt for. Please add the following sections and try "
+ "again:\n%s") % ", ".join(errors))
+ sys.exit(0)