summaryrefslogtreecommitdiffstats
path: root/dracut/parse-kickstart
diff options
context:
space:
mode:
authorWill Woods <wwoods@redhat.com>2012-02-15 15:37:31 -0500
committerWill Woods <wwoods@redhat.com>2012-03-16 12:36:55 -0400
commite42db18fda53c97a847ab68a1a1ddf05d4578fab (patch)
tree846e8b1ab27de33d8aeb7764bd0aac9e13203517 /dracut/parse-kickstart
parent81956dcfddea203629b51f558beb1104285c2399 (diff)
downloadanaconda-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-xdracut/parse-kickstart192
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