Package pyanaconda :: Module kickstart
[hide private]
[frames] | no frames]

Source Code for Module pyanaconda.kickstart

   1  # 
   2  # kickstart.py: kickstart install support 
   3  # 
   4  # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 
   5  # Red Hat, Inc.  All rights reserved. 
   6  # 
   7  # This program is free software; you can redistribute it and/or modify 
   8  # it under the terms of the GNU General Public License as published by 
   9  # the Free Software Foundation; either version 2 of the License, or 
  10  # (at your option) any later version. 
  11  # 
  12  # This program is distributed in the hope that it will be useful, 
  13  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  15  # GNU General Public License for more details. 
  16  # 
  17  # You should have received a copy of the GNU General Public License 
  18  # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  19  # 
  20   
  21  from storage.deviceaction import * 
  22  from storage.devices import LUKSDevice 
  23  from storage.devicelibs.lvm import getPossiblePhysicalExtents 
  24  from storage.devicelibs.mpath import MultipathConfigWriter, MultipathTopology 
  25  from storage.formats import getFormat 
  26  from storage.partitioning import clearPartitions 
  27  from storage.partitioning import shouldClear 
  28  import storage.iscsi 
  29  import storage.fcoe 
  30  import storage.zfcp 
  31   
  32  from yuminstall import NoSuchGroup 
  33  import iutil 
  34  import isys 
  35  import os 
  36  import os.path 
  37  import tempfile 
  38  from flags import flags 
  39  from constants import * 
  40  import sys 
  41  import string 
  42  import urlgrabber 
  43  import network 
  44  import upgrade 
  45  import pykickstart.commands as commands 
  46  from storage.devices import * 
  47  from scdate.core import zonetab 
  48   
  49  from pykickstart.base import KickstartCommand, BaseData 
  50  from pykickstart.constants import * 
  51  from pykickstart.errors import formatErrorMsg, KickstartError, KickstartValueError, KickstartParseError 
  52  from pykickstart.parser import Group, KickstartParser, Packages, Script 
  53  from pykickstart.sections import * 
  54  from pykickstart.version import returnClassForVersion 
  55   
  56  import gettext 
  57  _ = lambda x: gettext.ldgettext("anaconda", x) 
  58   
  59  import logging 
  60  log = logging.getLogger("anaconda") 
  61  stderrLog = logging.getLogger("anaconda.stderr") 
  62  storage_log = logging.getLogger("storage") 
  63  stdoutLog = logging.getLogger("anaconda.stdout") 
  64  from anaconda_log import logger, logLevelMap, setHandlersLevel,\ 
  65      DEFAULT_TTY_LEVEL 
  66   
  67  packagesSeen = False 
  68   
  69  # deviceMatches is called early, before any multipaths can possibly be coalesced 
  70  # so it needs to know about them in some additional way: have the topology ready. 
  71  topology = None 
  72   
73 -class AnacondaKSScript(Script):
74 - def run(self, chroot, serial, intf = None):
75 if self.inChroot: 76 scriptRoot = chroot 77 else: 78 scriptRoot = "/" 79 80 (fd, path) = tempfile.mkstemp("", "ks-script-", scriptRoot + "/tmp") 81 82 os.write(fd, self.script) 83 os.close(fd) 84 os.chmod(path, 0700) 85 86 # Always log stdout/stderr from scripts. Using --logfile just lets you 87 # pick where it goes. The script will also be logged to program.log 88 # because of execWithRedirect, and to anaconda.log if the script fails. 89 if self.logfile: 90 if self.inChroot: 91 messages = "%s/%s" % (scriptRoot, self.logfile) 92 else: 93 messages = self.logfile 94 95 d = os.path.dirname(messages) 96 if not os.path.exists(d): 97 os.makedirs(d) 98 else: 99 messages = "%s.log" % path 100 101 if intf: 102 intf.suspend() 103 rc = iutil.execWithRedirect(self.interp, ["/tmp/%s" % os.path.basename(path)], 104 stdin = messages, stdout = messages, stderr = messages, 105 root = scriptRoot) 106 if intf: 107 intf.resume() 108 109 # Always log an error. Only fail if we have a handle on the 110 # windowing system and the kickstart file included --erroronfail. 111 if rc != 0: 112 log.error("Error code %s running the kickstart script at line %s" % (rc, self.lineno)) 113 114 try: 115 f = open(messages, "r") 116 except IOError as e: 117 err = None 118 else: 119 err = f.readlines() 120 f.close() 121 for l in err: 122 log.error("\t%s" % l) 123 124 if self.errorOnFail: 125 if intf != None: 126 msg = _("There was an error running the kickstart " 127 "script at line %(lineno)s. You may examine the " 128 "output in %(msgs)s. This is a fatal error and " 129 "installation will be aborted. Press the " 130 "OK button to exit the installer.") \ 131 % {'lineno': self.lineno, 'msgs': messages} 132 133 if err: 134 intf.detailedMessageWindow(_("Scriptlet Failure"), msg, err) 135 else: 136 intf.messageWindow(_("Scriptlet Failure"), msg) 137 138 sys.exit(0) 139 140 if serial or self.logfile is not None: 141 os.chmod("%s" % messages, 0600)
142
143 -def getEscrowCertificate(anaconda, url):
144 if not url: 145 return None 146 147 if url in anaconda.storage.escrowCertificates: 148 return anaconda.storage.escrowCertificates[url] 149 150 needs_net = not url.startswith("/") and not url.startswith("file:") 151 if needs_net and not network.hasActiveNetDev(): 152 msg = _("Escrow certificate with url %s requires network to be enabled " 153 "in loader or configured in kickstart file." % url) 154 if anaconda.intf: 155 anaconda.intf.kickstartErrorWindow(msg) 156 sys.exit(1) 157 else: 158 stderrLog.critical(msg) 159 sys.exit(1) 160 161 log.info("escrow: downloading %s" % (url,)) 162 163 try: 164 f = urlgrabber.urlopen(url) 165 except urlgrabber.grabber.URLGrabError as e: 166 msg = _("The following error was encountered while downloading the escrow certificate:\n\n%s" % e) 167 if anaconda.intf: 168 anaconda.intf.kickstartErrorWindow(msg) 169 sys.exit(1) 170 else: 171 stderrLog.critical(msg) 172 sys.exit(1) 173 174 try: 175 anaconda.storage.escrowCertificates[url] = f.read() 176 finally: 177 f.close() 178 179 return anaconda.storage.escrowCertificates[url]
180
181 -def detect_multipaths():
182 global topology 183 mcw = MultipathConfigWriter() 184 cfg = mcw.write(friendly_names=True) 185 with open("/etc/multipath.conf", "w+") as mpath_cfg: 186 mpath_cfg.write(cfg) 187 devices = udev_get_block_devices() 188 topology = MultipathTopology(devices)
189
190 -def deviceMatches(spec):
191 full_spec = spec 192 if not full_spec.startswith("/dev/"): 193 full_spec = os.path.normpath("/dev/" + full_spec) 194 195 # the regular case 196 matches = udev_resolve_glob(full_spec) 197 dev = udev_resolve_devspec(full_spec) 198 # udev_resolve_devspec returns None if there's no match, but we don't 199 # want that ending up in the list. 200 if dev and dev not in matches: 201 matches.append(dev) 202 203 # now see if any mpaths and mpath members match 204 for members in topology.multipaths_iter(): 205 mpath_name = udev_device_get_multipath_name(members[0]) 206 member_names = map(udev_device_get_name, members) 207 if mpath_name == spec or (dev in member_names): 208 # append the entire mpath 209 matches.append(mpath_name) 210 matches.extend(member_names) 211 212 return matches
213 214 # Remove any existing formatting on a device, but do not remove the partition 215 # itself. This sets up an existing device to be used in a --onpart option.
216 -def removeExistingFormat(device, storage):
217 deps = storage.deviceDeps(device) 218 while deps: 219 leaves = [d for d in deps if d.isleaf] 220 for leaf in leaves: 221 storage.destroyDevice(leaf) 222 deps.remove(leaf) 223 224 storage.devicetree.registerAction(ActionDestroyFormat(device))
225 226 ### 227 ### SUBCLASSES OF PYKICKSTART COMMAND HANDLERS 228 ### 229
230 -class Authconfig(commands.authconfig.FC3_Authconfig):
231 - def execute(self):
232 self.anaconda.security.auth = self.authconfig
233
234 -class AutoPart(commands.autopart.F17_AutoPart):
235 - def execute(self):
236 # sets up default autopartitioning. use clearpart separately 237 # if you want it 238 self.anaconda.instClass.setDefaultPartitioning(self.anaconda.storage, self.anaconda.platform) 239 self.anaconda.storage.doAutoPart = True 240 241 if self.encrypted: 242 self.anaconda.storage.encryptedAutoPart = True 243 self.anaconda.storage.encryptionPassphrase = self.passphrase 244 self.anaconda.storage.autoPartEscrowCert = \ 245 getEscrowCertificate(self.anaconda, self.escrowcert) 246 self.anaconda.storage.autoPartAddBackupPassphrase = \ 247 self.backuppassphrase 248 249 if self.type is not None: 250 self.anaconda.storage.autoPartType = self.type 251 252 self.anaconda.dispatch.skip_steps("partition", "parttype")
253
254 -class AutoStep(commands.autostep.FC3_AutoStep):
255 - def execute(self):
256 flags.autostep = 1 257 flags.autoscreenshot = self.autoscreenshot
258
259 -class Bootloader(commands.bootloader.F17_Bootloader):
260 - def execute(self):
261 if self.location == "none": 262 location = None 263 elif self.location == "partition": 264 location = "boot" 265 else: 266 location = self.location 267 268 if self.upgrade and not self.anaconda.upgrade: 269 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Selected upgrade mode for bootloader but not doing an upgrade") 270 271 if self.upgrade and self.anaconda.bootloader.can_update: 272 self.anaconda.bootloader.update_only = True 273 274 if location is None: 275 self.anaconda.dispatch.skip_steps("instbootloader") 276 else: 277 if self.appendLine: 278 args = self.appendLine.split() 279 self.anaconda.bootloader.boot_args.update(args) 280 281 if self.password: 282 if self.isCrypted: 283 self.anaconda.bootloader.encrypted_password = self.password 284 else: 285 self.anaconda.bootloader.password = self.password 286 287 if location != None: 288 self.anaconda.bootloader.set_preferred_stage1_type(location) 289 290 if self.timeout is not None: 291 self.anaconda.bootloader.timeout = self.timeout 292 293 # Throw out drives specified that don't exist. 294 disk_names = [d.name for d in self.anaconda.storage.disks] 295 for drive in self.driveorder[:]: 296 if drive not in disk_names: 297 log.warning("requested drive %s in boot drive order doesn't exist" % drive) 298 self.driveorder.remove(drive) 299 300 self.anaconda.bootloader.drive_order = self.driveorder 301 302 if self.bootDrive: 303 spec = udev_resolve_devspec(self.bootDrive) 304 drive = self.anaconda.storage.devicetree.getDeviceByName(spec) 305 self.anaconda.bootloader.stage1_drive = drive 306 307 self.anaconda.dispatch.skip_steps("upgbootloader", "bootloader")
308
309 -class BTRFSData(commands.btrfs.F17_BTRFSData):
310 - def execute(self):
311 storage = self.anaconda.storage 312 devicetree = storage.devicetree 313 314 storage.doAutoPart = False 315 316 members = [] 317 318 # Get a list of all the devices that make up this volume. 319 for member in self.devices: 320 # if using --onpart, use original device 321 member_name = self.anaconda.ksdata.onPart.get(member, member) 322 if member_name: 323 dev = devicetree.getDeviceByName(member_name) 324 if not dev: 325 dev = devicetree.resolveDevice(member) 326 327 if dev and dev.format.type == "luks": 328 try: 329 dev = devicetree.getChildren(dev)[0] 330 except IndexError: 331 dev = None 332 if not dev: 333 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Tried to use undefined partition %s in BTRFS volume specification" % member) 334 335 members.append(dev) 336 337 if self.subvol: 338 name = self.name 339 elif self.label: 340 name = self.label 341 else: 342 name = None 343 344 if len(members) == 0 and not self.preexist: 345 raise KickstartValueError, formatErrorMsg(self.lineno, msg="BTRFS volume defined without any member devices. Either specify member devices or use --useexisting.") 346 347 # allow creating btrfs vols/subvols without specifying mountpoint 348 if self.mountpoint in ("none", "None"): 349 self.mountpoint = "" 350 351 # Sanity check mountpoint 352 if self.mountpoint != "" and self.mountpoint[0] != '/': 353 raise KickstartValueError, formatErrorMsg(self.lineno, msg="The mount point \"%s\" is not valid." % (self.mountpoint,)) 354 355 if self.preexist: 356 device = devicetree.getDeviceByName(self.name) 357 if not device: 358 device = udev_resolve_devspec(self.name) 359 360 if not device: 361 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent BTRFS volume %s in btrfs command" % self.name) 362 else: 363 # If a previous device has claimed this mount point, delete the 364 # old one. 365 try: 366 if self.mountpoint: 367 device = storage.mountpoints[self.mountpoint] 368 storage.destroyDevice(device) 369 except KeyError: 370 pass 371 372 request = storage.newBTRFS(name=name, 373 subvol=self.subvol, 374 mountpoint=self.mountpoint, 375 metaDataLevel=self.metaDataLevel, 376 dataLevel=self.dataLevel, 377 parents=members) 378 379 storage.createDevice(request) 380 381 self.anaconda.dispatch.skip_steps("partition", "parttype")
382
383 -class ClearPart(commands.clearpart.FC3_ClearPart):
384 - def parse(self, args):
385 retval = commands.clearpart.FC3_ClearPart.parse(self, args) 386 387 if self.type is None: 388 self.type = CLEARPART_TYPE_NONE 389 390 # Do any glob expansion now, since we need to have the real list of 391 # disks available before the execute methods run. 392 drives = [] 393 for spec in self.drives: 394 matched = deviceMatches(spec) 395 if matched: 396 drives.extend(matched) 397 else: 398 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent disk %s in clearpart command" % spec) 399 400 self.drives = drives 401 402 return retval
403
404 - def execute(self):
405 self.anaconda.storage.config.clearPartType = self.type 406 self.anaconda.storage.config.clearPartDisks = self.drives 407 if self.initAll: 408 self.anaconda.storage.config.reinitializeDisks = self.initAll 409 410 clearPartitions(self.anaconda.storage) 411 self.anaconda.dispatch.skip_steps("cleardiskssel")
412
413 -class Fcoe(commands.fcoe.F13_Fcoe):
414 - def parse(self, args):
415 fc = commands.fcoe.F13_Fcoe.parse(self, args) 416 417 if fc.nic not in isys.getDeviceProperties(): 418 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent nic %s in fcoe command" % fc.nic) 419 420 storage.fcoe.fcoe().addSan(nic=fc.nic, dcb=fc.dcb) 421 422 return fc
423
424 -class Firewall(commands.firewall.F14_Firewall):
425 - def execute(self):
426 self.anaconda.firewall.enabled = self.enabled 427 self.anaconda.firewall.trustdevs = self.trusts 428 429 for port in self.ports: 430 self.anaconda.firewall.portlist.append (port) 431 432 for svc in self.services: 433 self.anaconda.firewall.servicelist.append (svc)
434
435 -class IgnoreDisk(commands.ignoredisk.RHEL6_IgnoreDisk):
436 - def parse(self, args):
437 retval = commands.ignoredisk.RHEL6_IgnoreDisk.parse(self, args) 438 439 # See comment in ClearPart.parse 440 drives = [] 441 for spec in self.ignoredisk: 442 matched = deviceMatches(spec) 443 if matched: 444 drives.extend(matched) 445 else: 446 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent disk %s in ignoredisk command" % spec) 447 448 self.ignoredisk = drives 449 450 drives = [] 451 for spec in self.onlyuse: 452 matched = deviceMatches(spec) 453 if matched: 454 drives.extend(matched) 455 else: 456 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent disk %s in ignoredisk command" % spec) 457 458 self.onlyuse = drives 459 460 return retval
461
462 -class Iscsi(commands.iscsi.F10_Iscsi):
463 - def parse(self, args):
464 tg = commands.iscsi.F10_Iscsi.parse(self, args) 465 466 try: 467 storage.iscsi.iscsi().addTarget(tg.ipaddr, tg.port, tg.user, 468 tg.password, tg.user_in, 469 tg.password_in, 470 target=tg.target) 471 log.info("added iscsi target: %s" %(tg.ipaddr,)) 472 except (IOError, ValueError) as e: 473 raise KickstartValueError, formatErrorMsg(self.lineno, 474 msg=str(e)) 475 476 return tg
477
478 -class IscsiName(commands.iscsiname.FC6_IscsiName):
479 - def parse(self, args):
480 retval = commands.iscsiname.FC6_IscsiName.parse(self, args) 481 482 storage.iscsi.iscsi().initiator = self.iscsiname 483 return retval
484
485 -class Keyboard(commands.keyboard.FC3_Keyboard):
486 - def execute(self):
487 self.anaconda.keyboard.set(self.keyboard) 488 self.anaconda.keyboard.beenset = 1 489 self.anaconda.dispatch.skip_steps("keyboard")
490
491 -class Lang(commands.lang.FC3_Lang):
492 - def execute(self):
493 self.anaconda.instLanguage.instLang = self.lang 494 self.anaconda.instLanguage.systemLang = self.lang 495 self.anaconda.instLanguage.buildLocale() 496 self.anaconda.dispatch.skip_steps("language")
497
498 -class LogVolData(commands.logvol.F15_LogVolData):
499 - def execute(self):
500 storage = self.anaconda.storage 501 devicetree = storage.devicetree 502 503 storage.doAutoPart = False 504 505 if self.mountpoint == "swap": 506 type = "swap" 507 self.mountpoint = "" 508 if self.recommended: 509 (self.size, self.maxSizeMB) = iutil.swapSuggestion() 510 self.grow = True 511 else: 512 if self.fstype != "": 513 type = self.fstype 514 else: 515 type = storage.defaultFSType 516 517 # Sanity check mountpoint 518 if self.mountpoint != "" and self.mountpoint[0] != '/': 519 raise KickstartValueError, formatErrorMsg(self.lineno, msg="The mount point \"%s\" is not valid." % (self.mountpoint,)) 520 521 # Check that the VG this LV is a member of has already been specified. 522 vg = devicetree.getDeviceByName(self.vgname) 523 if not vg: 524 raise KickstartValueError, formatErrorMsg(self.lineno, msg="No volume group exists with the name \"%s\". Specify volume groups before logical volumes." % self.vgname) 525 526 # If this specifies an existing request that we should not format, 527 # quit here after setting up enough information to mount it later. 528 if not self.format: 529 if not self.name: 530 raise KickstartValueError, formatErrorMsg(self.lineno, msg="--noformat used without --name") 531 532 dev = devicetree.getDeviceByName("%s-%s" % (vg.name, self.name)) 533 if not dev: 534 raise KickstartValueError, formatErrorMsg(self.lineno, msg="No preexisting logical volume with the name \"%s\" was found." % self.name) 535 536 dev.format.mountpoint = self.mountpoint 537 dev.format.mountopts = self.fsopts 538 self.anaconda.dispatch.skip_steps("partition", "parttype") 539 return 540 541 # Make sure this LV name is not already used in the requested VG. 542 if not self.preexist: 543 tmp = devicetree.getDeviceByName("%s-%s" % (vg.name, self.name)) 544 if tmp: 545 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Logical volume name already used in volume group %s" % vg.name) 546 547 # Size specification checks 548 if not self.percent: 549 if not self.size: 550 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Size required") 551 elif not self.grow and self.size*1024 < vg.peSize: 552 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Logical volume size must be larger than the volume group physical extent size.") 553 elif self.percent <= 0 or self.percent > 100: 554 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Percentage must be between 0 and 100") 555 556 # Now get a format to hold a lot of these extra values. 557 format = getFormat(type, 558 mountpoint=self.mountpoint, 559 label=self.label, 560 fsprofile=self.fsprofile, 561 mountopts=self.fsopts) 562 if not format.type: 563 raise KickstartValueError, formatErrorMsg(self.lineno, msg="The \"%s\" filesystem type is not supported." % type) 564 565 # If we were given a pre-existing LV to create a filesystem on, we need 566 # to verify it and its VG exists and then schedule a new format action 567 # to take place there. Also, we only support a subset of all the 568 # options on pre-existing LVs. 569 if self.preexist: 570 device = devicetree.getDeviceByName("%s-%s" % (vg.name, self.name)) 571 if not device: 572 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent LV %s in logvol command" % self.name) 573 574 removeExistingFormat(device, storage) 575 devicetree.registerAction(ActionCreateFormat(device, format)) 576 else: 577 # If a previous device has claimed this mount point, delete the 578 # old one. 579 try: 580 if self.mountpoint: 581 device = storage.mountpoints[self.mountpoint] 582 storage.destroyDevice(device) 583 except KeyError: 584 pass 585 586 request = storage.newLV(format=format, 587 name=self.name, 588 vg=vg, 589 size=self.size, 590 grow=self.grow, 591 maxsize=self.maxSizeMB, 592 percent=self.percent) 593 594 storage.createDevice(request) 595 596 if self.encrypted: 597 if self.passphrase and not storage.encryptionPassphrase: 598 storage.encryptionPassphrase = self.passphrase 599 600 cert = getEscrowCertificate(self.anaconda, self.escrowcert) 601 if self.preexist: 602 luksformat = format 603 device.format = getFormat("luks", passphrase=self.passphrase, device=device.path, 604 escrow_cert=cert, 605 add_backup_passphrase=self.backuppassphrase) 606 luksdev = LUKSDevice("luks%d" % storage.nextID, 607 format=luksformat, 608 parents=device) 609 else: 610 luksformat = request.format 611 request.format = getFormat("luks", passphrase=self.passphrase, 612 escrow_cert=cert, 613 add_backup_passphrase=self.backuppassphrase) 614 luksdev = LUKSDevice("luks%d" % storage.nextID, 615 format=luksformat, 616 parents=request) 617 storage.createDevice(luksdev) 618 619 self.anaconda.dispatch.skip_steps("partition", "parttype")
620
621 -class Logging(commands.logging.FC6_Logging):
622 - def execute(self):
623 if logger.tty_loglevel == DEFAULT_TTY_LEVEL: 624 # not set from the command line 625 level = logLevelMap[self.level] 626 logger.tty_loglevel = level 627 setHandlersLevel(log, level) 628 setHandlersLevel(storage_log, level) 629 630 if logger.remote_syslog == None and len(self.host) > 0: 631 # not set from the command line, ok to use kickstart 632 remote_server = self.host 633 if self.port: 634 remote_server = "%s:%s" %(self.host, self.port) 635 logger.updateRemote(remote_server)
636
637 -class NetworkData(commands.network.F16_NetworkData):
638 - def execute(self):
639 if flags.imageInstall: 640 if self.hostname != "": 641 self.anaconda.network.setHostname(self.hostname) 642 643 # Only set hostname 644 return 645 646 # we can ignore this here (already activated in stage 1) 647 # only set hostname 648 if self.essid: 649 if self.hostname != "": 650 self.anaconda.network.setHostname(self.hostname) 651 return 652 653 devices = self.anaconda.network.netdevices 654 655 if not self.device: 656 if self.anaconda.network.ksdevice: 657 msg = "ksdevice boot parameter" 658 device = self.anaconda.network.ksdevice 659 elif network.hasActiveNetDev(): 660 # device activated in stage 1 by network kickstart command 661 msg = "first active device" 662 device = network.getActiveNetDevs()[0] 663 else: 664 msg = "first device found" 665 device = min(devices.keys()) 666 log.info("unspecified network --device in kickstart, using %s (%s)" % 667 (device, msg)) 668 else: 669 if self.device.lower() == "ibft": 670 return 671 if self.device.lower() == "link": 672 for dev in sorted(devices): 673 if isys.getLinkStatus(dev): 674 device = dev 675 break 676 else: 677 raise KickstartValueError, formatErrorMsg(self.lineno, msg="No device with link found") 678 679 elif self.device.lower() == "bootif": 680 if "BOOTIF" in flags.cmdline: 681 # MAC address like 01-aa-bb-cc-dd-ee-ff 682 device = flags.cmdline["BOOTIF"][3:] 683 device = device.replace("-",":") 684 else: 685 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Using --device=bootif without BOOTIF= boot option supplied") 686 else: device = self.device 687 688 # If we were given a network device name, grab the device object. 689 # If we were given a MAC address, resolve that to a device name 690 # and then grab the device object. Otherwise, errors. 691 dev = None 692 693 if devices.has_key(device): 694 dev = devices[device] 695 else: 696 for (key, val) in devices.iteritems(): 697 if val.get("HWADDR").lower() == device.lower(): 698 dev = val 699 break 700 701 if self.hostname != "": 702 self.anaconda.network.setHostname(self.hostname) 703 if not dev: 704 # Only set hostname 705 return 706 else: 707 if not dev: 708 raise KickstartValueError, formatErrorMsg(self.lineno, msg="The provided network interface %s does not exist" % device) 709 710 711 # ipv4 settings 712 if not self.noipv4: 713 dev.set(("BOOTPROTO", self.bootProto)) 714 dev.set(("DHCPCLASS", self.dhcpclass)) 715 716 if self.bootProto == "static": 717 if (self.ip): 718 dev.set(("IPADDR", self.ip)) 719 if (self.netmask): 720 dev.set(("NETMASK", self.netmask)) 721 722 if self.bootProto == "dhcp" and self.hostname: 723 dev.set(("DHCP_HOSTNAME", self.hostname)) 724 725 726 # ipv6 settings 727 if self.noipv6: 728 dev.set(("IPV6INIT", "no")) 729 else: 730 dev.set(("IPV6INIT", "yes")) 731 if self.ipv6 == "auto": 732 dev.set(("IPV6_AUTOCONF", "yes")) 733 elif self.ipv6 == "dhcp": 734 dev.set(("IPV6_AUTOCONF", "no")) 735 dev.set(("DHCPV6C", "yes")) 736 elif self.ipv6: 737 dev.set(("IPV6_AUTOCONF", "no")) 738 dev.set(("IPV6ADDR", "%s" % self.ipv6)) 739 # settings common for ipv4 and ipv6 740 if not self.noipv6 or not self.noipv4: 741 if self.onboot: 742 dev.set (("ONBOOT", "yes")) 743 else: 744 dev.set (("ONBOOT", "no")) 745 746 if self.mtu: 747 dev.set(("MTU", self.mtu)) 748 749 if self.ethtool: 750 dev.set(("ETHTOOL_OPTS", self.ethtool)) 751 752 if self.nameserver != "": 753 self.anaconda.network.setDNS(self.nameserver, dev.iface) 754 755 if self.gateway != "": 756 self.anaconda.network.setGateway(self.gateway, dev.iface) 757 758 if self.nodefroute: 759 dev.set (("DEFROUTE", "no"))
760
761 -class MultiPath(commands.multipath.FC6_MultiPath):
762 - def parse(self, args):
763 raise NotImplementedError("The multipath kickstart command is not currently supported")
764
765 -class DmRaid(commands.dmraid.FC6_DmRaid):
766 - def parse(self, args):
767 raise NotImplementedError("The dmraid kickstart command is not currently supported")
768
769 -class PartitionData(commands.partition.F12_PartData):
770 - def execute(self):
771 storage = self.anaconda.storage 772 devicetree = storage.devicetree 773 kwargs = {} 774 775 storage.doAutoPart = False 776 777 if self.onbiosdisk != "": 778 for (disk, biosdisk) in storage.eddDict.iteritems(): 779 if str(biosdisk) == self.onbiosdisk: 780 self.disk = disk 781 break 782 783 if self.disk == "": 784 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified BIOS disk %s cannot be determined" % self.onbiosdisk) 785 786 if self.mountpoint == "swap": 787 type = "swap" 788 self.mountpoint = "" 789 if self.recommended: 790 (self.size, self.maxSizeMB) = iutil.swapSuggestion() 791 self.grow = True 792 # if people want to specify no mountpoint for some reason, let them 793 # this is really needed for pSeries boot partitions :( 794 elif self.mountpoint == "None": 795 self.mountpoint = "" 796 if self.fstype: 797 type = self.fstype 798 else: 799 type = storage.defaultFSType 800 elif self.mountpoint == 'appleboot': 801 type = "appleboot" 802 self.mountpoint = "" 803 elif self.mountpoint == 'prepboot': 804 type = "prepboot" 805 self.mountpoint = "" 806 elif self.mountpoint == 'biosboot': 807 type = "biosboot" 808 self.mountpoint = "" 809 elif self.mountpoint.startswith("raid."): 810 type = "mdmember" 811 kwargs["name"] = self.mountpoint 812 813 if devicetree.getDeviceByName(kwargs["name"]): 814 raise KickstartValueError, formatErrorMsg(self.lineno, msg="RAID partition defined multiple times") 815 816 # store "raid." alias for other ks partitioning commands 817 if self.onPart: 818 self.anaconda.ksdata.onPart[kwargs["name"]] = self.onPart 819 self.mountpoint = "" 820 elif self.mountpoint.startswith("pv."): 821 type = "lvmpv" 822 kwargs["name"] = self.mountpoint 823 824 if devicetree.getDeviceByName(kwargs["name"]): 825 raise KickstartValueError, formatErrorMsg(self.lineno, msg="PV partition defined multiple times") 826 827 # store "pv." alias for other ks partitioning commands 828 if self.onPart: 829 self.anaconda.ksdata.onPart[kwargs["name"]] = self.onPart 830 self.mountpoint = "" 831 elif self.mountpoint.startswith("btrfs."): 832 type = "btrfs" 833 kwargs["name"] = self.mountpoint 834 835 if devicetree.getDeviceByName(kwargs["name"]): 836 raise KickstartValueError, formatErrorMsg(self.lineno, msg="BTRFS partition defined multiple times") 837 838 # store "btrfs." alias for other ks partitioning commands 839 if self.onPart: 840 self.anaconda.ksdata.onPart[kwargs["name"]] = self.onPart 841 self.mountpoint = "" 842 elif self.mountpoint == "/boot/efi": 843 if iutil.isMactel(): 844 type = "hfs+" 845 else: 846 type = "EFI System Partition" 847 self.fsopts = "defaults,uid=0,gid=0,umask=0077,shortname=winnt" 848 else: 849 if self.fstype != "": 850 type = self.fstype 851 elif self.mountpoint == "/boot": 852 type = storage.defaultBootFSType 853 else: 854 type = storage.defaultFSType 855 856 # If this specified an existing request that we should not format, 857 # quit here after setting up enough information to mount it later. 858 if not self.format: 859 if not self.onPart: 860 raise KickstartValueError, formatErrorMsg(self.lineno, msg="--noformat used without --onpart") 861 862 dev = devicetree.getDeviceByName(udev_resolve_devspec(self.onPart)) 863 if not dev: 864 raise KickstartValueError, formatErrorMsg(self.lineno, msg="No preexisting partition with the name \"%s\" was found." % self.onPart) 865 866 dev.format.mountpoint = self.mountpoint 867 dev.format.mountopts = self.fsopts 868 self.anaconda.dispatch.skip_steps("partition", "parttype") 869 return 870 871 # Now get a format to hold a lot of these extra values. 872 kwargs["format"] = getFormat(type, 873 mountpoint=self.mountpoint, 874 label=self.label, 875 fsprofile=self.fsprofile, 876 mountopts=self.fsopts) 877 if not kwargs["format"].type: 878 raise KickstartValueError, formatErrorMsg(self.lineno, msg="The \"%s\" filesystem type is not supported." % type) 879 880 # If we were given a specific disk to create the partition on, verify 881 # that it exists first. If it doesn't exist, see if it exists with 882 # mapper/ on the front. If that doesn't exist either, it's an error. 883 if self.disk: 884 names = [self.disk, "mapper/" + self.disk] 885 for n in names: 886 disk = devicetree.getDeviceByName(udev_resolve_devspec(n)) 887 # if this is a multipath member promote it to the real mpath 888 if disk and disk.format.type == "multipath_member": 889 mpath_device = storage.devicetree.getChildren(disk)[0] 890 storage_log.info("kickstart: part: promoting %s to %s" 891 % (disk.name, mpath_device.name)) 892 disk = mpath_device 893 if not disk: 894 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent disk %s in partition command" % n) 895 if not disk.partitionable: 896 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Cannot install to read-only media %s." % n) 897 898 should_clear = shouldClear(disk, 899 storage.config.clearPartType, 900 storage.config.clearPartDisks) 901 if disk and (disk.partitioned or should_clear): 902 kwargs["disks"] = [disk] 903 break 904 elif disk: 905 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified unpartitioned disk %s in partition command" % self.disk) 906 907 if not kwargs["disks"]: 908 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent disk %s in partition command" % self.disk) 909 910 kwargs["grow"] = self.grow 911 kwargs["size"] = self.size 912 kwargs["maxsize"] = self.maxSizeMB 913 kwargs["primary"] = self.primOnly 914 915 # If we were given a pre-existing partition to create a filesystem on, 916 # we need to verify it exists and then schedule a new format action to 917 # take place there. Also, we only support a subset of all the options 918 # on pre-existing partitions. 919 if self.onPart: 920 device = devicetree.getDeviceByName(udev_resolve_devspec(self.onPart)) 921 if not device: 922 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent partition %s in partition command" % self.onPart) 923 924 removeExistingFormat(device, storage) 925 devicetree.registerAction(ActionCreateFormat(device, kwargs["format"])) 926 else: 927 # If a previous device has claimed this mount point, delete the 928 # old one. 929 try: 930 if self.mountpoint: 931 device = storage.mountpoints[self.mountpoint] 932 storage.destroyDevice(device) 933 except KeyError: 934 pass 935 936 if "format" in kwargs: 937 # set weight based on fstype and mountpoint 938 mpt = getattr(kwargs["format"], "mountpoint", None) 939 fstype = kwargs["format"].type 940 kwargs["weight"] = self.anaconda.platform.weight(fstype=fstype, 941 mountpoint=mpt) 942 943 request = storage.newPartition(**kwargs) 944 945 storage.createDevice(request) 946 947 if self.encrypted: 948 if self.passphrase and not storage.encryptionPassphrase: 949 storage.encryptionPassphrase = self.passphrase 950 951 cert = getEscrowCertificate(self.anaconda, self.escrowcert) 952 if self.onPart: 953 luksformat = format 954 device.format = getFormat("luks", passphrase=self.passphrase, device=device.path, 955 escrow_cert=cert, 956 add_backup_passphrase=self.backuppassphrase) 957 luksdev = LUKSDevice("luks%d" % storage.nextID, 958 format=luksformat, 959 parents=device) 960 else: 961 luksformat = request.format 962 request.format = getFormat("luks", passphrase=self.passphrase, 963 escrow_cert=cert, 964 add_backup_passphrase=self.backuppassphrase) 965 luksdev = LUKSDevice("luks%d" % storage.nextID, 966 format=luksformat, 967 parents=request) 968 storage.createDevice(luksdev) 969 970 self.anaconda.dispatch.skip_steps("partition", "parttype")
971
972 -class Reboot(commands.reboot.FC6_Reboot):
973 - def execute(self):
974 self.anaconda.dispatch.skip_steps("complete")
975
976 -class RaidData(commands.raid.F15_RaidData):
977 - def execute(self):
978 raidmems = [] 979 devicename = "md%d" % self.device 980 981 storage = self.anaconda.storage 982 devicetree = storage.devicetree 983 kwargs = {} 984 985 storage.doAutoPart = False 986 987 if self.mountpoint == "swap": 988 type = "swap" 989 self.mountpoint = "" 990 elif self.mountpoint.startswith("pv."): 991 type = "lvmpv" 992 kwargs["name"] = self.mountpoint 993 self.anaconda.ksdata.onPart[kwargs["name"]] = devicename 994 995 if devicetree.getDeviceByName(kwargs["name"]): 996 raise KickstartValueError, formatErrorMsg(self.lineno, msg="PV partition defined multiple times") 997 998 self.mountpoint = "" 999 elif self.mountpoint.startswith("btrfs."): 1000 type = "btrfs" 1001 kwargs["name"] = self.mountpoint 1002 self.anaconda.ksdata.onPart[kwargs["name"]] = devicename 1003 1004 if devicetree.getDeviceByName(kwargs["name"]): 1005 raise KickstartValueError, formatErrorMsg(self.lineno, msg="BTRFS partition defined multiple times") 1006 1007 self.mountpoint = "" 1008 else: 1009 if self.fstype != "": 1010 type = self.fstype 1011 elif self.mountpoint == "/boot" and \ 1012 "mdarray" in self.anaconda.bootloader.stage2_device_types: 1013 type = storage.defaultBootFSType 1014 else: 1015 type = storage.defaultFSType 1016 1017 # Sanity check mountpoint 1018 if self.mountpoint != "" and self.mountpoint[0] != '/': 1019 raise KickstartValueError, formatErrorMsg(self.lineno, msg="The mount point is not valid.") 1020 1021 # If this specifies an existing request that we should not format, 1022 # quit here after setting up enough information to mount it later. 1023 if not self.format: 1024 if not devicename: 1025 raise KickstartValueError, formatErrorMsg(self.lineno, msg="--noformat used without --device") 1026 1027 dev = devicetree.getDeviceByName(devicename) 1028 if not dev: 1029 raise KickstartValueError, formatErrorMsg(self.lineno, msg="No preexisting RAID device with the name \"%s\" was found." % devicename) 1030 1031 dev.format.mountpoint = self.mountpoint 1032 dev.format.mountopts = self.fsopts 1033 self.anaconda.dispatch.skip_steps("partition", "parttype") 1034 return 1035 1036 # Get a list of all the RAID members. 1037 for member in self.members: 1038 # if member is using --onpart, use original device 1039 member = self.anaconda.ksdata.onPart.get(member, member) 1040 dev = devicetree.getDeviceByName(member) 1041 if dev and dev.format.type == "luks": 1042 try: 1043 dev = devicetree.getChildren(dev)[0] 1044 except IndexError: 1045 dev = None 1046 if not dev: 1047 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Tried to use undefined partition %s in RAID specification" % member) 1048 1049 raidmems.append(dev) 1050 1051 # Now get a format to hold a lot of these extra values. 1052 kwargs["format"] = getFormat(type, 1053 label=self.label, 1054 fsprofile=self.fsprofile, 1055 mountpoint=self.mountpoint, 1056 mountopts=self.fsopts) 1057 if not kwargs["format"].type: 1058 raise KickstartValueError, formatErrorMsg(self.lineno, msg="The \"%s\" filesystem type is not supported." % type) 1059 1060 kwargs["name"] = devicename 1061 kwargs["level"] = self.level 1062 kwargs["parents"] = raidmems 1063 kwargs["memberDevices"] = len(raidmems) - self.spares 1064 kwargs["totalDevices"] = len(raidmems) 1065 1066 # If we were given a pre-existing RAID to create a filesystem on, 1067 # we need to verify it exists and then schedule a new format action 1068 # to take place there. Also, we only support a subset of all the 1069 # options on pre-existing RAIDs. 1070 if self.preexist: 1071 device = devicetree.getDeviceByName(devicename) 1072 if not device: 1073 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specifeid nonexistent RAID %s in raid command" % devicename) 1074 1075 removeExistingFormat(device, storage) 1076 devicetree.registerAction(ActionCreateFormat(device, kwargs["format"])) 1077 else: 1078 if devicename and devicename in [a.name for a in storage.mdarrays]: 1079 raise KickstartValueError(formatErrorMsg(self.lineno, msg="The Software RAID array name \"%s\" is already in use." % devicename)) 1080 1081 # If a previous device has claimed this mount point, delete the 1082 # old one. 1083 try: 1084 if self.mountpoint: 1085 device = storage.mountpoints[self.mountpoint] 1086 storage.destroyDevice(device) 1087 except KeyError: 1088 pass 1089 1090 try: 1091 request = storage.newMDArray(**kwargs) 1092 except ValueError as e: 1093 raise KickstartValueError, formatErrorMsg(self.lineno, msg=str(e)) 1094 1095 storage.createDevice(request) 1096 1097 if self.encrypted: 1098 if self.passphrase and not storage.encryptionPassphrase: 1099 storage.encryptionPassphrase = self.passphrase 1100 1101 cert = getEscrowCertificate(self.anaconda, self.escrowcert) 1102 if self.preexist: 1103 luksformat = format 1104 device.format = getFormat("luks", passphrase=self.passphrase, device=device.path, 1105 escrow_cert=cert, 1106 add_backup_passphrase=self.backuppassphrase) 1107 luksdev = LUKSDevice("luks%d" % storage.nextID, 1108 format=luksformat, 1109 parents=device) 1110 else: 1111 luksformat = request.format 1112 request.format = getFormat("luks", passphrase=self.passphrase, 1113 escrow_cert=cert, 1114 add_backup_passphrase=self.backuppassphrase) 1115 luksdev = LUKSDevice("luks%d" % storage.nextID, 1116 format=luksformat, 1117 parents=request) 1118 storage.createDevice(luksdev) 1119 1120 self.anaconda.dispatch.skip_steps("partition", "parttype")
1121
1122 -class RootPw(commands.rootpw.F8_RootPw):
1123 - def execute(self):
1124 self.anaconda.users.rootPassword["password"] = self.password 1125 self.anaconda.users.rootPassword["isCrypted"] = self.isCrypted 1126 self.anaconda.users.rootPassword["lock"] = self.lock 1127 self.anaconda.dispatch.skip_steps("accounts")
1128
1129 -class SELinux(commands.selinux.FC3_SELinux):
1130 - def execute(self):
1131 self.anaconda.security.setSELinux(self.selinux)
1132
1133 -class SkipX(commands.skipx.FC3_SkipX):
1134 - def execute(self):
1135 if self.anaconda.desktop is not None: 1136 self.anaconda.desktop.setDefaultRunLevel(3)
1137
1138 -class Timezone(commands.timezone.FC6_Timezone):
1139 - def execute(self):
1140 # check validity 1141 tab = zonetab.ZoneTab() 1142 if self.timezone not in (entry.tz.replace(' ','_') for entry in 1143 tab.getEntries()): 1144 log.warning("Timezone %s set in kickstart is not valid." % (self.timezone,)) 1145 1146 self.anaconda.timezone.setTimezoneInfo(self.timezone, self.isUtc) 1147 self.anaconda.dispatch.skip_steps("timezone")
1148
1149 -class Upgrade(commands.upgrade.F11_Upgrade):
1150 - def execute(self):
1151 self.anaconda.upgrade = self.upgrade
1152
1153 -class VolGroupData(commands.volgroup.FC16_VolGroupData):
1154 - def execute(self):
1155 pvs = [] 1156 1157 storage = self.anaconda.storage 1158 devicetree = storage.devicetree 1159 1160 storage.doAutoPart = False 1161 1162 # Get a list of all the physical volume devices that make up this VG. 1163 for pv in self.physvols: 1164 # if pv is using --onpart, use original device 1165 pv = self.anaconda.ksdata.onPart.get(pv, pv) 1166 dev = devicetree.getDeviceByName(pv) 1167 if dev and dev.format.type == "luks": 1168 try: 1169 dev = devicetree.getChildren(dev)[0] 1170 except IndexError: 1171 dev = None 1172 if not dev: 1173 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Tried to use undefined partition %s in Volume Group specification" % pv) 1174 1175 pvs.append(dev) 1176 1177 if len(pvs) == 0 and not self.preexist: 1178 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Volume group defined without any physical volumes. Either specify physical volumes or use --useexisting.") 1179 1180 if self.pesize not in getPossiblePhysicalExtents(floor=1024): 1181 raise KickstartValueError, formatErrorMsg(self.lineno, msg="Volume group specified invalid pesize") 1182 1183 # If --noformat or --useexisting was given, there's really nothing to do. 1184 if not self.format or self.preexist: 1185 if not self.vgname: 1186 raise KickstartValueError, formatErrorMsg(self.lineno, msg="--noformat or --useexisting used without giving a name") 1187 1188 dev = devicetree.getDeviceByName(self.vgname) 1189 if not dev: 1190 raise KickstartValueError, formatErrorMsg(self.lineno, msg="No preexisting VG with the name \"%s\" was found." % self.vgname) 1191 elif self.vgname in [vg.name for vg in storage.vgs]: 1192 raise KickstartValueError(formatErrorMsg(self.lineno, msg="The volume group name \"%s\" is already in use." % self.vgname)) 1193 else: 1194 request = storage.newVG(pvs=pvs, 1195 name=self.vgname, 1196 peSize=self.pesize/1024.0) 1197 1198 storage.createDevice(request) 1199 if self.reserved_space: 1200 request.reserved_space = self.reserved_space 1201 elif self.reserved_percent: 1202 request.reserved_percent = self.reserved_percent
1203
1204 -class XConfig(commands.xconfig.F14_XConfig):
1205 - def execute(self):
1206 if self.startX: 1207 self.anaconda.desktop.setDefaultRunLevel(5) 1208 1209 if self.defaultdesktop: 1210 self.anaconda.desktop.setDefaultDesktop(self.defaultdesktop)
1211
1212 -class ZFCP(commands.zfcp.F14_ZFCP):
1213 - def parse(self, args):
1214 fcp = commands.zfcp.F14_ZFCP.parse(self, args) 1215 try: 1216 storage.zfcp.ZFCP().addFCP(fcp.devnum, fcp.wwpn, fcp.fcplun) 1217 except ValueError as e: 1218 log.warning(str(e)) 1219 1220 return fcp
1221 1222 ### 1223 ### HANDLERS 1224 ### 1225 1226 # This is just the latest entry from pykickstart.handlers.control with all the 1227 # classes we're overriding in place of the defaults. 1228 commandMap = { 1229 "auth": Authconfig, 1230 "authconfig": Authconfig, 1231 "autopart": AutoPart, 1232 "autostep": AutoStep, 1233 "bootloader": Bootloader, 1234 "clearpart": ClearPart, 1235 "dmraid": DmRaid, 1236 "fcoe": Fcoe, 1237 "firewall": Firewall, 1238 "halt": Reboot, 1239 "ignoredisk": IgnoreDisk, 1240 "install": Upgrade, 1241 "iscsi": Iscsi, 1242 "iscsiname": IscsiName, 1243 "keyboard": Keyboard, 1244 "lang": Lang, 1245 "logging": Logging, 1246 "multipath": MultiPath, 1247 "poweroff": Reboot, 1248 "reboot": Reboot, 1249 "rootpw": RootPw, 1250 "selinux": SELinux, 1251 "shutdown": Reboot, 1252 "skipx": SkipX, 1253 "timezone": Timezone, 1254 "upgrade": Upgrade, 1255 "xconfig": XConfig, 1256 "zfcp": ZFCP, 1257 } 1258 1259 dataMap = { 1260 "BTRFSData": BTRFSData, 1261 "LogVolData": LogVolData, 1262 "NetworkData": NetworkData, 1263 "PartData": PartitionData, 1264 "RaidData": RaidData, 1265 "VolGroupData": VolGroupData, 1266 } 1267 1268 superclass = returnClassForVersion() 1269
1270 -class AnacondaKSHandler(superclass):
1271 - def __init__ (self, anaconda):
1272 superclass.__init__(self, commandUpdates=commandMap, dataUpdates=dataMap) 1273 1274 self.anaconda = anaconda 1275 self.onPart = {} 1276 1277 # All the KickstartCommand and KickstartData objects that 1278 # handleCommand returns, so we can later iterate over them and run 1279 # the execute methods. These really should be stored in the order 1280 # they're seen in the kickstart file. 1281 self._dataObjs = []
1282
1283 - def add(self, obj):
1284 if isinstance(obj, KickstartCommand): 1285 # Commands can only be run once, and the latest one seen takes 1286 # precedence over any earlier ones. 1287 i = 0 1288 while i < len(self._dataObjs): 1289 if self._dataObjs[i].__class__ == obj.__class__: 1290 self._dataObjs.pop(i) 1291 break 1292 1293 i += 1 1294 1295 self._dataObjs.append(obj) 1296 else: 1297 # Data objects can be seen over and over again. 1298 self._dataObjs.append(obj)
1299
1300 - def dispatcher(self, args, lineno):
1301 cmd = args[0] 1302 1303 if self.commands.has_key(cmd): 1304 self.commands[cmd].anaconda = self.anaconda 1305 1306 return superclass.dispatcher(self, args, lineno)
1307
1308 - def execute(self):
1309 try: 1310 for obj in filter(lambda o: hasattr(o, "execute"), self._dataObjs): 1311 obj.anaconda = self.anaconda 1312 obj.execute() 1313 except KickstartError as e: 1314 if self.anaconda.intf: 1315 self.anaconda.intf.kickstartErrorWindow(e.__str__()) 1316 self.anaconda.intf.shutdown() 1317 sys.exit(0) 1318 else: 1319 stderrLog.critical(_("The following error was found while parsing the kickstart " 1320 "configuration file:\n\n%s") % e) 1321 sys.exit(1)
1322
1323 -class AnacondaPreParser(KickstartParser):
1324 # A subclass of KickstartParser that only looks for %pre scripts and 1325 # sets them up to be run. All other scripts and commands are ignored.
1326 - def __init__ (self, handler, followIncludes=True, errorsAreFatal=True, 1327 missingIncludeIsFatal=True):
1328 KickstartParser.__init__(self, handler, missingIncludeIsFatal=False)
1329
1330 - def handleCommand (self, lineno, args):
1331 pass
1332
1333 - def setupSections(self):
1334 self.registerSection(PreScriptSection(self.handler, dataObj=AnacondaKSScript)) 1335 self.registerSection(NullSection(self.handler, sectionOpen="%post")) 1336 self.registerSection(NullSection(self.handler, sectionOpen="%traceback")) 1337 self.registerSection(NullSection(self.handler, sectionOpen="%packages"))
1338
1339 -class AnacondaKSParser(KickstartParser):
1340 - def __init__ (self, handler, followIncludes=True, errorsAreFatal=True, 1341 missingIncludeIsFatal=True):
1342 KickstartParser.__init__(self, handler)
1343
1344 - def handleCommand (self, lineno, args):
1345 if not self.handler: 1346 return 1347 1348 retval = KickstartParser.handleCommand(self, lineno, args) 1349 self.handler.add(retval) 1350 return retval
1351
1352 - def setupSections(self):
1353 self.registerSection(PreScriptSection(self.handler, dataObj=AnacondaKSScript)) 1354 self.registerSection(PostScriptSection(self.handler, dataObj=AnacondaKSScript)) 1355 self.registerSection(TracebackScriptSection(self.handler, dataObj=AnacondaKSScript)) 1356 self.registerSection(PackageSection(self.handler))
1357
1358 -def doKickstart(anaconda):
1359 storage.storageInitialize(anaconda) 1360 # Having initialized storage, we can apply all the other kickstart commands. 1361 # This gives us the ability to check that storage commands are correctly 1362 # formed and refer to actual devices. 1363 anaconda.ksdata.execute()
1364
1365 -def preScriptPass(anaconda, file):
1366 # The first pass through kickstart file processing - look for %pre scripts 1367 # and run them. This must come in a separate pass in case a script 1368 # generates an included file that has commands for later. 1369 ksparser = AnacondaPreParser(AnacondaKSHandler(anaconda)) 1370 1371 try: 1372 ksparser.readKickstart(file) 1373 except (KickstartValueError, KickstartParseError) as e: 1374 if anaconda.intf: 1375 anaconda.intf.kickstartErrorWindow(e.__str__()) 1376 sys.exit(1) 1377 else: 1378 stderrLog.critical(_("The following error was found while parsing the kickstart " 1379 "configuration file:\n\n%s") % e) 1380 sys.exit(1) 1381 except KickstartError as e: 1382 if anaconda.intf: 1383 anaconda.intf.kickstartErrorWindow("Could not open kickstart file or included file named %s" % file) 1384 sys.exit(1) 1385 else: 1386 stderrLog.critical(_("The following error was found while parsing the kickstart " 1387 "configuration file:\n\n%s") % e) 1388 sys.exit(1) 1389 1390 # run %pre scripts 1391 runPreScripts(anaconda, ksparser.handler.scripts)
1392
1393 -def parseKickstart(anaconda, file):
1394 # preprocessing the kickstart file has already been handled by loader. 1395 1396 handler = AnacondaKSHandler(anaconda) 1397 ksparser = AnacondaKSParser(handler) 1398 1399 # We need this so all the /dev/disk/* stuff is set up before parsing. 1400 udev_trigger(subsystem="block", action="change") 1401 # So that drives onlined by these can be used in the ks file 1402 storage.iscsi.iscsi().startup() 1403 storage.fcoe.fcoe().startup() 1404 storage.zfcp.ZFCP().startup() 1405 # Note we do NOT call dasd.startup() here, that does not online drives, but 1406 # only checks if they need formatting, which requires zerombr to be known 1407 detect_multipaths() 1408 1409 try: 1410 ksparser.readKickstart(file) 1411 except (KickstartValueError, KickstartParseError) as e: 1412 if anaconda.intf: 1413 anaconda.intf.kickstartErrorWindow(e.__str__()) 1414 sys.exit(1) 1415 else: 1416 stderrLog.critical(_("The following error was found while parsing the kickstart " 1417 "configuration file:\n\n%s") % e) 1418 sys.exit(1) 1419 except KickstartError as e: 1420 # We may not have an intf now, but we can do better than just raising 1421 # the exception. 1422 if anaconda.intf: 1423 anaconda.intf.kickstartErrorWindow("Could not open kickstart file or included file named %s" % file) 1424 sys.exit(1) 1425 else: 1426 stderrLog.critical(_("The following error was found while parsing the kickstart " 1427 "configuration file:\n\n%s") % e) 1428 sys.exit(1) 1429 1430 global packagesSeen 1431 packagesSeen = ksparser.getSection("%packages").timesSeen > 0 1432 return handler
1433
1434 -def runPostScripts(anaconda):
1435 if not anaconda.ksdata: 1436 return 1437 1438 postScripts = filter (lambda s: s.type == KS_SCRIPT_POST, 1439 anaconda.ksdata.scripts) 1440 1441 if len(postScripts) == 0: 1442 return 1443 1444 # Remove environment variables that cause problems for %post scripts. 1445 for var in ["LIBUSER_CONF"]: 1446 if os.environ.has_key(var): 1447 del(os.environ[var]) 1448 1449 log.info("Running kickstart %%post script(s)") 1450 if anaconda.intf is not None: 1451 w = anaconda.intf.waitWindow(_("Post-Installation"), 1452 _("Running post-installation scripts")) 1453 1454 map (lambda s: s.run(ROOT_PATH, flags.serial, anaconda.intf), postScripts) 1455 1456 log.info("All kickstart %%post script(s) have been run") 1457 if anaconda.intf is not None: 1458 w.pop()
1459
1460 -def runPreScripts(anaconda, scripts):
1461 preScripts = filter (lambda s: s.type == KS_SCRIPT_PRE, scripts) 1462 1463 if len(preScripts) == 0: 1464 return 1465 1466 log.info("Running kickstart %%pre script(s)") 1467 stdoutLog.info(_("Running pre-installation scripts")) 1468 1469 map (lambda s: s.run("/", flags.serial, anaconda.intf), preScripts) 1470 1471 log.info("All kickstart %%pre script(s) have been run")
1472
1473 -def runTracebackScripts(anaconda):
1474 log.info("Running kickstart %%traceback script(s)") 1475 for script in filter (lambda s: s.type == KS_SCRIPT_TRACEBACK, 1476 anaconda.ksdata.scripts): 1477 script.run("/", flags.serial) 1478 log.info("All kickstart %%traceback script(s) have been run")
1479
1480 -def selectPackages(anaconda):
1481 ksdata = anaconda.ksdata 1482 ignoreAll = False 1483 1484 # If no %packages header was seen, use the installclass's default group 1485 # selections. This can also be explicitly specified with %packages 1486 # --default. Otherwise, select whatever was given (even if it's nothing). 1487 if not packagesSeen or ksdata.packages.default: 1488 anaconda.instClass.setGroupSelection(anaconda) 1489 if not packagesSeen: 1490 return 1491 1492 for pkg in ksdata.packages.packageList: 1493 num = anaconda.backend.selectPackage(pkg) 1494 if ksdata.packages.handleMissing == KS_MISSING_IGNORE or ignoreAll: 1495 continue 1496 if num > 0: 1497 continue 1498 rc = anaconda.intf.messageWindow(_("Missing Package"), 1499 _("You have specified that the " 1500 "package '%s' should be installed. " 1501 "This package does not exist. " 1502 "Would you like to continue or " 1503 "abort this installation?") %(pkg,), 1504 type="custom", 1505 custom_buttons=[_("_Abort"), 1506 _("_Ignore All"), 1507 _("_Continue")]) 1508 if rc == 0: 1509 sys.exit(1) 1510 elif rc == 1: 1511 ignoreAll = True 1512 1513 ksdata.packages.groupList.insert(0, Group("Core")) 1514 1515 if ksdata.packages.addBase: 1516 ksdata.packages.groupList.insert(1, Group("Base")) 1517 else: 1518 log.warning("not adding Base group") 1519 1520 for grp in ksdata.packages.groupList: 1521 default = False 1522 optional = False 1523 1524 if grp.include == GROUP_DEFAULT: 1525 default = True 1526 elif grp.include == GROUP_ALL: 1527 default = True 1528 optional = True 1529 1530 try: 1531 anaconda.backend.selectGroup(grp.name, (default, optional)) 1532 except NoSuchGroup as e: 1533 if ksdata.packages.handleMissing == KS_MISSING_IGNORE or ignoreAll: 1534 pass 1535 else: 1536 rc = anaconda.intf.messageWindow(_("Missing Group"), 1537 _("You have specified that the " 1538 "group '%s' should be installed. " 1539 "This group does not exist. " 1540 "Would you like to continue or " 1541 "abort this installation?") 1542 %(grp.name,), 1543 type="custom", 1544 custom_buttons=[_("_Abort"), 1545 _("_Ignore All"), 1546 _("_Continue")]) 1547 if rc == 0: 1548 sys.exit(1) 1549 elif rc == 1: 1550 ignoreAll = True 1551 1552 map(anaconda.backend.deselectPackage, ksdata.packages.excludedList) 1553 map(lambda g: anaconda.backend.deselectGroup(g.name), 1554 ksdata.packages.excludedGroupList)
1555
1556 -def setSteps(anaconda):
1557 def havePackages(packages): 1558 return len(packages.groupList) > 0 or len(packages.packageList) > 0 or \ 1559 len(packages.excludedList) > 0 or len(packages.excludedGroupList) > 0
1560 1561 dispatch = anaconda.dispatch 1562 ksdata = anaconda.ksdata 1563 1564 if ksdata.upgrade.upgrade: 1565 upgrade.setSteps(anaconda) 1566 1567 # we have no way to specify migrating yet 1568 dispatch.skip_steps("upgrademigfind") 1569 dispatch.skip_steps("upgrademigratefs") 1570 dispatch.skip_steps("upgradecontinue") 1571 dispatch.skip_steps("findinstall") 1572 dispatch.skip_steps("language") 1573 dispatch.skip_steps("keyboard") 1574 dispatch.skip_steps("betanag") 1575 else: 1576 anaconda.instClass.setSteps(anaconda) 1577 dispatch.skip_steps("findrootparts") 1578 dispatch.request_steps("kickstart") 1579 1580 dispatch.skip_steps("betanag") 1581 dispatch.skip_steps("network") 1582 1583 # Storage is initialized for us right when kickstart processing starts. 1584 dispatch.skip_steps("storageinit") 1585 1586 # Make sure to automatically reboot if told to. 1587 if ksdata.reboot.action in [KS_REBOOT, KS_SHUTDOWN]: 1588 dispatch.skip_steps("complete") 1589 1590 # If the package section included anything, skip group selection. 1591 if ksdata.upgrade.upgrade: 1592 dispatch.skip_steps("tasksel", "group-selection") 1593 1594 # Special check for this, since it doesn't make any sense. 1595 if packagesSeen: 1596 log.warning("Ignoring contents of %packages section due to upgrade.") 1597 elif havePackages(ksdata.packages): 1598 dispatch.skip_steps("tasksel", "group-selection") 1599 else: 1600 if packagesSeen: 1601 dispatch.skip_steps("tasksel", "group-selection") 1602 else: 1603 dispatch.request_steps("tasksel") 1604 1605 if ksdata.ignoredisk.interactive: 1606 dispatch.request_steps("filtertype", "filter") 1607 else: 1608 # Since ignoredisk is optional and not specifying it means you want to 1609 # consider all possible disks, we should not stop on the filter steps 1610 # unless we've been told to. 1611 dispatch.skip_steps("filtertype", "filter") 1612 1613 # Text mode doesn't have all the steps that graphical mode does, so we 1614 # can't stop and prompt for missing information. Make sure we've got 1615 # everything that would be provided by a missing section now and error 1616 # out if we don't. 1617 if anaconda.displayMode == "t": 1618 missingSteps = [("bootloader", "Bootloader configuration"), 1619 ("filter", "Disks to use in installation"), 1620 ("cleardiskssel", "Disks to clear"), 1621 ("group-selection", "Package selection")] 1622 errors = [] 1623 1624 for (step, msg) in missingSteps: 1625 if dispatch.step_enabled(step): 1626 errors.append(msg) 1627 1628 if len(errors) > 0: 1629 anaconda.intf.kickstartErrorWindow(_("The kickstart configuration " 1630 "file is missing required information that anaconda cannot " 1631 "prompt for. Please add the following sections and try " 1632 "again:\n%s") % ", ".join(errors)) 1633 sys.exit(0) 1634