diff options
| author | Will Woods <wwoods@redhat.com> | 2012-02-15 15:37:31 -0500 |
|---|---|---|
| committer | Will Woods <wwoods@redhat.com> | 2012-03-16 12:36:55 -0400 |
| commit | e42db18fda53c97a847ab68a1a1ddf05d4578fab (patch) | |
| tree | 846e8b1ab27de33d8aeb7764bd0aac9e13203517 /dracut/parse-kickstart | |
| parent | 81956dcfddea203629b51f558beb1104285c2399 (diff) | |
| download | anaconda-e42db18fda53c97a847ab68a1a1ddf05d4578fab.tar.gz anaconda-e42db18fda53c97a847ab68a1a1ddf05d4578fab.tar.xz anaconda-e42db18fda53c97a847ab68a1a1ddf05d4578fab.zip | |
Add anaconda dracut module [WIP!]
This adds the dracut directory and anaconda-dracut subpackage.
The 'anaconda' dracut module replaces loader. It should handle all the
tasks that loader used to handle in the first stage of the boot process.
It's a work in progress, but it currently supports repo={http,ftp,nfs}
and most anacaconda network options.
Kickstart parsing is handled using a python interpreter and pykickstart,
which (surprisingly) only adds ~600k to the initramfs.
Driver disks are not yet supported.
Diffstat (limited to 'dracut/parse-kickstart')
| -rwxr-xr-x | dracut/parse-kickstart | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/dracut/parse-kickstart b/dracut/parse-kickstart new file mode 100755 index 000000000..af2229769 --- /dev/null +++ b/dracut/parse-kickstart @@ -0,0 +1,192 @@ +#!/usr/bin/python +#vim: set fileencoding=utf8 +# parse-kickstart - read a kickstart file and emit equivalent dracut boot args. +# +# Copyright © 2012 Red Hat, Inc. +# BLAH BLAH GPL BLAH. +# +# Designed to run inside the dracut initramfs environment. +# Requires python 2.7 or later. +# +# Authors: +# Will Woods <wwoods@redhat.com> + +import sys, os +import logging +from pykickstart.parser import KickstartParser, preprocessKickstart +from pykickstart.version import returnClassForVersion +from pykickstart.errors import KickstartParseError +from pykickstart.constants import * +from pykickstart import commands +from collections import OrderedDict + +# Default logging: none +log = logging.getLogger('parse-kickstart').addHandler(logging.NullHandler()) + +# Here are the kickstart commands we care about: + +class Method(commands.method.F14_Method): + '''install methods: cdrom, harddrive, nfs, url''' + def dracut_args(self, args, lineno, obj): + if self.method == "cdrom": + method="/dev/sr0" + elif self.method == "harddrive": + if self.biospart: + dev = biospart_to_dev(self.biospart, args, lineno) + if dev: + method="hd:%s:%s" % (dev, self.dir) + method="hd:%s:%s" % (self.partition, self.dir) + elif self.method == "nfs": + method="nfs:%s:%s" % (self.server, self.dir) + if self.opts: + method += ":%s" % opts + elif self.method == "url": + # FIXME: self.proxy, self.noverifyssl + method = self.url + return "inst.repo=%s" % method + +class Updates(commands.updates.F7_Updates): + def dracut_args(self, args, lineno, obj): + if self.url == "floppy": + return "inst.updates=/dev/fd0" + elif self.url: + return "inst.updates=%s" % self.url + +class MediaCheck(commands.mediacheck.FC4_MediaCheck): + def dracut_args(self, args, lineno, obj): + if self.mediacheck: + return "rd.live.check" + +class DriverDisk(commands.driverdisk.F14_DriverDisk): + def dracut_args(self, args, lineno, obj): + dd = self.driverdiskList[-1] + if dd.biospart: + location = biospart_to_dev(dd.biospart, args, lineno) + else: + location = dd.partition or dd.source + if location: + return "inst.driverdisk=%s" % location + +class Network(commands.network.F16_Network): + def dracut_args(self, args, lineno, net): + if len(self.network) == 1: # first network line gets special treatment + net.activate = True # activate by default + if not net.device: # --device is optional, defaults to.. + net.device = "ksdev" # whatever the kickstart device was + if not net.device: + log.error("'%s': missing --device", " ".join(args)) + elif net.activate: # we only care about activated devices + return ksnet_to_dracut(args, lineno, net) + +# TODO: keymap, lang... device? upgrade? + +dracutCmds = { + 'cdrom': Method, + 'harddrive': Method, + 'nfs': Method, + 'url': Method, + 'updates': Updates, + 'mediacheck': MediaCheck, + 'driverdisk': DriverDisk, + 'network': Network, +} +handlerclass = returnClassForVersion() +class DracutHandler(handlerclass): + def __init__(self): + handlerclass.__init__(self, commandUpdates=dracutCmds) + self.output = [] + def dispatcher(self, args, lineno): + obj = handlerclass.dispatcher(self, args, lineno) + # and execute any specified dracut_args + cmd = args[0] + command = self.commands[cmd] + if hasattr(command, "dracut_args"): + log.debug("kickstart line %u: handling %s", lineno, cmd) + line = " ".join(args) + self.output.append(command.dracut_args(args, lineno, obj)) + return obj + +# set up logging +class KmsgFormatter(logging.Formatter): + '''Formats log output for /dev/kmsg like dracut does.''' + def format(self, record): + if record.levelno <= logging.INFO: tag = "<30>" + elif record.levelno <= logging.WARNING: tag = "<28>" + else: tag = "<24>" + return tag + logging.Formatter.format(self, record) +def init_logger(): + logfmt = "%(name)s %(levelname)s: %(message)s" + stderr = logging.StreamHandler() + stderr.setFormatter(logging.Formatter(logfmt)) + logger = logging.getLogger('parse-kickstart') + logger.setLevel(logging.WARNING) + logger.addHandler(stderr) + try: + kmsg = logging.FileHandler("/dev/kmsg", "w") + kmsg.setFormatter(KmsgFormatter(logfmt)) + logger.addHandler(kmsg) + except IOError: + pass + return logger + +def biospart_to_dev(biospart, args, lineno): + if not os.path.isdir("/sys/firmware/edd"): + log.error("'%s': --biospart unavailable (no EDD support)", " ".join(args)) + return + log.error("'%s': biospart is not yet supported", " ".join(args), lineno) + +def ksnet_to_dracut(args, lineno, net): + '''Translate the kickstart network data into dracut network data.''' + line = [] + dev = net.device + if net.bootProto == BOOTPROTO_DHCP: + line.append("ip=%s:dhcp" % dev if dev else "ip=dhcp") + elif net.bootProto == BOOTPROTO_IBFT: + line.append("ip=%s:ibft" % dev if dev else "ip=ibft") + elif net.bootProto == BOOTPROTO_BOOTP: # NOTE: no dracut support yet... + line.append("ip=%s:bootp" % dev if dev else "ip=bootp") + elif net.bootProto == BOOTPROTO_QUERY: + log.error("'%s': --bootproto=query is deprecated", " ".join(args)) + elif net.bootProto == BOOTPROTO_STATIC: + req = ("gateway", "netmask", "nameserver", "ip") + missing = ", ".join("--%s" % i for i in req if not hasattr(net, i)) + if missing: + log.warn("line %u: network missing %s", lineno, missing) + else: + line.append("ip={0.ip}::{0.gateway}:{0.netmask}:" \ + "{0.hostname}:{0.device}".format(net)) + for ns in net.nameserver.split(","): + line.append("nameserver=%s" % ns) + if net.ipv6 == "auto": + line.append("ip=%s:auto6" % dev if dev else "ip=auto6") + elif net.ipv6 == "dhcp": + line.append("ip=%s:dhcp6" % dev if dev else "ip=dhcp6") + elif net.ipv6: + line.append("ip=[{0.ipv6}]::{0.gateway}:{0.netmask}:" \ + "{0.hostname}:{0.device}".format(net)) + if net.mtu: + # XXX NOTE: dracut doesn't support mtu= (yet) so this arg might change + mtuarg = "mtu=%s:" % dev if dev else "mtu=" + line.append(mtustr+str(mtu)) + # TODO FIXME: nodns, nodefroute, noipv4, noipv6, dhcpclass, ethtool + if net.essid or net.wepkey or net.wpakey: + # TODO: make dracut support wireless? (do we care?) + log.error("'%s': dracut doesn't support wireless networks", " ".join(args)) + return " ".join(line) + +def process_kickstart(ksfile): + handler = DracutHandler() + parser = KickstartParser(handler) + processed_file = preprocessKickstart(ksfile) + try: + parser.readKickstart(processed_file) + except KickstartParseError as e: + log.error(str(e)) + return handler.output + +if __name__ == '__main__': + log = init_logger() + for path in sys.argv[1:]: + output = process_kickstart(path) + for line in filter(None, output): + print line |
