2 # parser.py: Kickstart file parser.
4 # Chris Lumens <clumens@redhat.com>
6 # Copyright 2005 Red Hat, Inc.
8 # This software may be freely redistributed under the terms of the GNU
9 # general public license.
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 from optparse
import OptionParser
, Option
22 from constants
import *
37 class KickstartError(Exception):
38 def __init__(self
, val
= ""):
44 class KickstartParseError(KickstartError
):
45 def __init__(self
, line
= ""):
46 self
.value
= "There was a problem reading the following line from the kickstart file. This could be due to an error on the line or using a keyword that no longer exists.\n\n%s" % line
51 class KickstartValueError(KickstartError
):
52 def __init__(self
, val
= ""):
62 # Specialized OptionParser, mainly to handle the MappableOption and to turn
64 class KSOptionParser(OptionParser
):
65 def exit(self
, status
=0, msg
=None):
69 raise KickstartParseError
, msg
74 for opt
in self
.option_list
:
76 retval
.append(opt
.dest
)
80 def _init_parsing_state (self
):
81 OptionParser
._init
_parsing
_state
(self
)
84 def check_values (self
, values
, args
):
85 for option
in self
.option_list
:
86 if (isinstance(option
, Option
) and option
.required
and \
87 not self
.option_seen
.has_key(option
)):
88 raise KickstartError
, "Option %s is required" % option
89 elif isinstance(option
, Option
) and option
.deprecated
and \
90 self
.option_seen
.has_key(option
):
91 warnings
.warn("Ignoring deprecated option: %s" % option
,
96 def __init__(self
, map={}):
98 OptionParser
.__init
__(self
, option_class
=DeprecatedOption
,
99 add_help_option
=False)
101 # Creates a new Option type that supports a "required" option attribute. Any
102 # option with this attribute must be supplied or an exception is thrown.
103 class RequiredOption (Option
):
104 ATTRS
= Option
.ATTRS
+ ['required']
106 def _check_required (self
):
107 if self
.required
and not self
.takes_value():
108 raise OptionError("Required flag set for option that doesn't take a value", self
)
110 # Make sure _check_required() is called from the constructor!
111 CHECK_METHODS
= Option
.CHECK_METHODS
+ [_check_required
]
113 def process (self
, opt
, value
, values
, parser
):
114 Option
.process(self
, opt
, value
, values
, parser
)
115 parser
.option_seen
[self
] = 1
117 # Additional OptionParser actions. "map" allows you to define a opt -> val
118 # mapping such that dest gets val when opt is seen. "map_extend" allows you
119 # to define an opt -> [val1, ... valn] mapping such that dest gets a list of
120 # vals build up when opt is seen.
121 class MappableOption(RequiredOption
):
122 ACTIONS
= RequiredOption
.ACTIONS
+ ("map", "map_extend",)
123 STORE_ACTIONS
= RequiredOption
.STORE_ACTIONS
+ ("map", "map_extend",)
125 def take_action(self
, action
, dest
, opt
, value
, values
, parser
):
127 values
.ensure_value(dest
, parser
.map[opt
.lstrip('-')])
128 elif action
== "map_extend":
129 values
.ensure_value(dest
, []).extend(parser
.map[opt
.lstrip('-')])
131 RequiredOption
.take_action(self
, action
, dest
, opt
, value
, values
, parser
)
133 # Creates a new Option type that supports a "deprecated" option attribute.
134 # Any option with this attribute will cause a DeprecationWarning to be
135 # thrown if the option is used.
136 class DeprecatedOption(MappableOption
):
137 ATTRS
= MappableOption
.ATTRS
+ ['deprecated']
139 def process (self
, opt
, value
, values
, parser
):
140 MappableOption
.process(self
, opt
, value
, values
, parser
)
141 parser
.option_seen
[self
] = 1
147 # You may make a subclass of Script if you need additional script handling
148 # besides just a data representation. For instance, anaconda may subclass
149 # this to add a run method.
152 str = ("(s: '%s' i: %s c: %d)") % \
153 (self
.script
, self
.interp
, self
.inChroot
)
154 return string
.replace(str, "\n", "|")
156 def __init__(self
, script
, interp
= "/bin/sh", inChroot
= False,
157 logfile
= None, errorOnFail
= False, type = KS_SCRIPT_PRE
):
158 self
.script
= string
.join(script
, "")
160 self
.inChroot
= inChroot
161 self
.logfile
= logfile
162 self
.errorOnFail
= errorOnFail
165 # Produce a string representation of the script suitable for writing
166 # to a kickstart file. Add this to the end of the %whatever header.
169 if self
.interp
!= "/bin/sh" and self
.interp
!= "":
170 str = str + " --interp %s" % self
.interp
171 if self
.type == KS_SCRIPT_POST
and not self
.inChroot
:
172 str = str + " --nochroot"
173 if self
.logfile
!= None:
174 str = str + " --logfile %s" % self
.logfile
176 str = str + " --erroronfail"
178 str = str + "\n%s\n" % self
.script
185 # You may make a subclass of KickstartHandlers if you need to do something
186 # besides just build up the data store. If you need to do additional processing
187 # just make a subclass, define handlers for each command in your subclass, and
188 # make sure to call the same handler in the super class before whatever you
189 # want to do. Also if you need to make a new parser that only takes action
190 # for a subset of commands, make a subclass and define all the handlers to
191 # None except the ones you care about.
192 class KickstartHandlers
:
193 def __init__ (self
, ksdata
):
196 self
.handlers
= { "auth" : self
.doAuthconfig
,
197 "authconfig" : self
.doAuthconfig
,
198 "autopart" : self
.doAutoPart
,
199 "autostep" : self
.doAutoStep
,
200 "bootloader" : self
.doBootloader
,
201 "cdrom" : self
.doMethod
,
202 "clearpart" : self
.doClearPart
,
203 "cmdline" : self
.doDisplayMode
,
204 "device" : self
.doDevice
,
205 "deviceprobe" : self
.doDeviceProbe
,
206 "driverdisk" : self
.doDriverDisk
,
207 "firewall" : self
.doFirewall
,
208 "firstboot" : self
.doFirstboot
,
209 "graphical" : self
.doDisplayMode
,
210 "halt" : self
.doReboot
,
211 "harddrive" : self
.doMethod
,
212 "ignoredisk" : self
.doIgnoreDisk
,
213 # implied by lack of "upgrade" command
215 "interactive" : self
.doInteractive
,
216 "keyboard" : self
.doKeyboard
,
217 "lang" : self
.doLang
,
218 "langsupport" : self
.doLangSupport
,
219 "logvol" : self
.doLogicalVolume
,
220 "mediacheck" : self
.doMediaCheck
,
221 "monitor" : self
.doMonitor
,
222 "mouse" : self
.doMouse
,
223 "network" : self
.doNetwork
,
224 "nfs" : self
.doMethod
,
225 "part" : self
.doPartition
,
226 "partition" : self
.doPartition
,
227 "poweroff" : self
.doReboot
,
228 "raid" : self
.doRaid
,
229 "reboot" : self
.doReboot
,
230 "rootpw" : self
.doRootPw
,
231 "selinux" : self
.doSELinux
,
232 "shutdown" : self
.doReboot
,
233 "skipx" : self
.doSkipX
,
234 "text" : self
.doDisplayMode
,
235 "timezone" : self
.doTimezone
,
236 "url" : self
.doMethod
,
237 "upgrade" : self
.doUpgrade
,
239 "volgroup" : self
.doVolumeGroup
,
240 "xconfig" : self
.doXConfig
,
241 "zerombr" : self
.doZeroMbr
,
242 "zfcp" : self
.doZFCP
,
245 def resetHandlers (self
):
246 for key
in self
.handlers
.keys():
247 self
.handlers
[key
] = None
249 def deprecatedCommand(self
, cmd
):
250 warnings
.warn("The %s command has been deprecated and no longer has any effect. It may be removed from future releases, which will result in a fatal error from kickstart. Please modify your kickstart file to remove this command." % cmd
, DeprecationWarning)
252 def doAuthconfig(self
, args
):
253 self
.ksdata
.authconfig
= string
.join(args
)
255 def doAutoPart(self
, args
):
256 self
.ksdata
.autopart
= True
258 def doAutoStep(self
, args
):
259 op
= KSOptionParser()
260 op
.add_option("--autoscreenshot", dest
="autoscreenshot",
261 action
="store_true", default
=False)
263 (opts
, extra
) = op
.parse_args(args
=args
)
264 self
.ksdata
.autostep
["autoscreenshot"] = opts
.autoscreenshot
266 def doBootloader(self
, args
):
267 def driveorder_cb (option
, opt_str
, value
, parser
):
268 for d
in value
.split(','):
269 parser
.values
.ensure_value(option
.dest
, []).append(d
)
271 op
= KSOptionParser()
272 op
.add_option("--append", dest
="appendLine")
273 op
.add_option("--location", dest
="location", type="choice",
275 choices
=["mbr", "partition", "none", "boot"])
276 op
.add_option("--lba32", dest
="forceLBA", action
="store_true",
278 op
.add_option("--password", dest
="password", default
="")
279 op
.add_option("--md5pass", dest
="md5pass", default
="")
280 op
.add_option("--upgrade", dest
="upgrade", action
="store_true",
282 op
.add_option("--driveorder", dest
="driveorder", action
="callback",
283 callback
=driveorder_cb
, nargs
=1, type="string")
285 (opts
, extra
) = op
.parse_args(args
=args
)
287 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
288 self
.ksdata
.bootloader
[key
] = getattr(opts
, key
)
290 def doClearPart(self
, args
):
291 def drive_cb (option
, opt_str
, value
, parser
):
292 for d
in value
.split(','):
293 parser
.values
.ensure_value(option
.dest
, []).append(d
)
295 op
= KSOptionParser()
296 op
.add_option("--all", dest
="type", action
="store_const",
297 const
=CLEARPART_TYPE_ALL
)
298 op
.add_option("--drives", dest
="drives", action
="callback",
299 callback
=drive_cb
, nargs
=1, type="string")
300 op
.add_option("--initlabel", dest
="initAll", action
="store_true",
302 op
.add_option("--linux", dest
="type", action
="store_const",
303 const
=CLEARPART_TYPE_LINUX
)
304 op
.add_option("--none", dest
="type", action
="store_const",
305 const
=CLEARPART_TYPE_NONE
)
307 (opts
, extra
) = op
.parse_args(args
=args
)
309 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
310 self
.ksdata
.clearpart
[key
] = getattr(opts
, key
)
312 def doDevice(self
, args
):
313 self
.ksdata
.device
= string
.join(args
)
315 def doDeviceProbe(self
, args
):
316 self
.ksdata
.deviceprobe
= string
.join(args
)
318 def doDisplayMode(self
, args
):
319 if self
.currentCmd
== "cmdline":
320 self
.ksdata
.displayMode
= DISPLAY_MODE_CMDLINE
321 elif self
.currentCmd
== "graphical":
322 self
.ksdata
.displayMode
= DISPLAY_MODE_GRAPHICAL
323 elif self
.currentCmd
== "text":
324 self
.ksdata
.displayMode
= DISPLAY_MODE_TEXT
326 def doDriverDisk(self
, args
):
327 self
.ksdata
.driverdisk
= string
.join(args
)
329 def doFirewall(self
, args
):
330 def firewall_port_cb (option
, opt_str
, value
, parser
):
331 for p
in value
.split(","):
333 if p
.find(":") == -1:
335 parser
.values
.ensure_value(option
.dest
, []).append(p
)
337 op
= KSOptionParser({"ssh":["22:tcp"], "telnet":["23:tcp"],
338 "smtp":["25:tcp"], "http":["80:tcp", "443:tcp"],
341 op
.add_option("--disable", "--disabled", dest
="enabled",
342 action
="store_false")
343 op
.add_option("--enable", "--enabled", dest
="enabled",
344 action
="store_true", default
=True)
345 op
.add_option("--ftp", "--http", "--smtp", "--ssh", "--telnet",
346 dest
="ports", action
="map_extend")
347 op
.add_option("--port", dest
="ports", action
="callback",
348 callback
=firewall_port_cb
, nargs
=1, type="string")
349 op
.add_option("--trust", dest
="trusts", action
="append")
351 (opts
, extra
) = op
.parse_args(args
=args
)
353 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
354 self
.ksdata
.firewall
[key
] = getattr(opts
, key
)
356 def doFirstboot(self
, args
):
357 op
= KSOptionParser()
358 op
.add_option("--disable", "--disabled", dest
="firstboot",
359 action
="store_const", const
=FIRSTBOOT_SKIP
)
360 op
.add_option("--enable", "--enabled", dest
="firstboot",
361 action
="store_const", const
=FIRSTBOOT_DEFAULT
)
362 op
.add_option("--reconfig", dest
="firstboot", action
="store_const",
363 const
=FIRSTBOOT_RECONFIG
)
365 (opts
, extra
) = op
.parse_args(args
=args
)
366 self
.ksdata
.firstboot
= opts
.firstboot
368 def doIgnoreDisk(self
, args
):
369 def drive_cb (option
, opt_str
, value
, parser
):
370 for d
in value
.split(','):
371 parser
.values
.ensure_value(option
.dest
, []).append(d
)
373 op
= KSOptionParser()
374 op
.add_option("--drives", dest
="drives", action
=callback
,
375 callback
=drive_cb
, nargs
=1, type="string")
377 (opts
, extra
) = op
.parse_args(args
=args
)
379 self
.ksdata
.ignoredisk
= opt
.ignoredisk
381 def doInteractive(self
, args
):
382 self
.ksdata
.interactive
= True
384 def doKeyboard(self
, args
):
385 self
.ksdata
.keyboard
= args
[0]
387 def doLang(self
, args
):
388 self
.ksdata
.lang
= args
[0]
390 def doLangSupport(self
, args
):
391 self
.deprecatedCommand("langsupport")
393 def doLogicalVolume(self
, args
):
394 def lv_cb (option
, opt_str
, value
, parser
):
395 parser
.values
.ensure_value(option
.dest
, False)
396 parser
.values
.ensure_value("preexist", True)
398 op
= KSOptionParser()
399 op
.add_option("--bytes-per-inode", dest
="bytesPerInode", action
="store",
401 op
.add_option("--fsoptions", dest
="fsopts")
402 op
.add_option("--fstype", dest
="fstype")
403 op
.add_option("--grow", dest
="grow", action
="store_true",
405 op
.add_option("--maxsize", dest
="maxSizeMB", action
="store", type="int",
407 op
.add_option("--name", dest
="name", required
=1)
408 op
.add_option("--noformat", action
="callback", callback
=lv_cb
,
409 dest
="format", default
=True, nargs
=0)
410 op
.add_option("--percent", dest
="percent", action
="store", type="int",
412 op
.add_option("--recommended", dest
="recommended", action
="store_true",
414 op
.add_option("--size", dest
="size", action
="store", type="int",
416 op
.add_option("--useexisting", dest
="preexist", action
="store_true",
418 op
.add_option("--vgname", dest
="vgname", required
=1)
420 (opts
, extra
) = op
.parse_args(args
=args
)
423 raise KickstartValueError
, "Mount point required on line:\n\nlogvol %s" % string
.join (args
)
425 lvd
= KickstartLogVolData()
426 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
427 setattr(lvd
, key
, getattr(opts
, key
))
429 lvd
.mountpoint
= extra
[0]
430 self
.ksdata
.lvList
.append(lvd
)
432 def doMediaCheck(self
, args
):
433 self
.ksdata
.mediacheck
= True
435 def doMethod(self
, args
):
436 op
= KSOptionParser()
438 self
.ksdata
.method
["method"] = self
.currentCmd
440 if self
.currentCmd
== "cdrom":
442 elif self
.currentCmd
== "harddrive":
443 op
.add_option("--partition", dest
="partition", required
=1)
444 op
.add_option("--dir", dest
="dir", required
=1)
446 (opts
, extra
) = op
.parse_args(args
=args
)
447 self
.ksdata
.method
["partition"] = opts
.partition
448 self
.ksdata
.method
["dir"] = opts
.dir
449 elif self
.currentCmd
== "nfs":
450 op
.add_option("--server", dest
="server", required
=1)
451 op
.add_option("--dir", dest
="dir", required
=1)
453 (opts
, extra
) = op
.parse_args(args
=args
)
454 self
.ksdata
.method
["server"] = opts
.server
455 self
.ksdata
.method
["dir"] = opts
.dir
456 elif self
.currentCmd
== "url":
457 op
.add_option("--url", dest
="url", required
=1)
459 (opts
, extra
) = op
.parse_args(args
=args
)
460 self
.ksdata
.method
["url"] = opts
.url
462 def doMonitor(self
, args
):
463 op
= KSOptionParser()
464 op
.add_option("--hsync", dest
="hsync")
465 op
.add_option("--monitor", dest
="monitor")
466 op
.add_option("--vsync", dest
="vsync")
468 (opts
, extra
) = op
.parse_args(args
=args
)
471 raise KickstartValueError
, "Unexpected arguments to monitor: %s" % string
.join(args
)
473 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
474 self
.ksdata
.monitor
[key
] = getattr(opts
, key
)
476 def doMouse(self
, args
):
477 self
.deprecatedCommand("mouse")
479 def doNetwork(self
, args
):
480 def onboot_cb (option
, opt_str
, value
, parser
):
482 parser
.values
.ensure_value(option
.dest
, False)
484 parser
.values
.ensure_value(option
.dest
, True)
486 op
= KSOptionParser()
487 op
.add_option("--bootproto", dest
="bootProto", default
="dhcp")
488 op
.add_option("--class", dest
="dhcpclass")
489 op
.add_option("--device", dest
="device")
490 op
.add_option("--essid", dest
="essid")
491 op
.add_option("--ethtool", dest
="ethtool")
492 op
.add_option("--gateway", dest
="gateway")
493 op
.add_option("--hostname", dest
="hostname")
494 op
.add_option("--ip", dest
="ip")
495 op
.add_option("--nameserver", dest
="nameserver")
496 op
.add_option("--netmask", dest
="netmask")
497 op
.add_option("--nodns", dest
="nodns", action
="store_true",
499 op
.add_option("--notksdevice", dest
="notksdevice", action
="store_true",
501 op
.add_option("--onboot", dest
="onboot", action
="callback",
502 callback
=onboot_cb
, nargs
=1, type="string")
503 op
.add_option("--wepkey", dest
="wepkey")
505 (opts
, extra
) = op
.parse_args(args
=args
)
507 nd
= KickstartNetworkData()
508 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
509 setattr(nd
, key
, getattr(opts
, key
))
511 self
.ksdata
.network
.append(nd
)
513 def doPartition(self
, args
):
514 def part_cb (option
, opt_str
, value
, parser
):
515 if value
.startswith("/dev/"):
516 parser
.values
.ensure_value(option
.dest
, value
[5:])
518 parser
.values
.ensure_value(option
.dest
, value
)
520 op
= KSOptionParser()
521 op
.add_option("--active", dest
="active", action
="store_true",
523 op
.add_option("--asprimary", dest
="primOnly", action
="store_true",
525 op
.add_option("--bytes-per-inode", dest
="bytesPerInode", action
="store",
527 op
.add_option("--end", dest
="end", action
="store", type="int",
529 op
.add_option("--fsoptions", dest
="fsopts")
530 op
.add_option("--fstype", "--type", dest
="fstype")
531 op
.add_option("--grow", dest
="grow", action
="store_true", default
=False)
532 op
.add_option("--label", dest
="label")
533 op
.add_option("--maxsize", dest
="maxSizeMB", action
="store", type="int",
535 op
.add_option("--noformat", dest
="format", action
="store_false",
537 op
.add_option("--onbiosdisk", dest
="onbiosdisk")
538 op
.add_option("--ondisk", "--ondrive", dest
="disk")
539 op
.add_option("--onpart", "--usepart", dest
="onPart", action
="callback",
540 callback
=part_cb
, nargs
=1, type="string")
541 op
.add_option("--recommended", dest
="recommended", action
="store_true",
543 op
.add_option("--size", dest
="size", action
="store", type="int",
545 op
.add_option("--start", dest
="start", action
="store", type="int",
548 (opts
, extra
) = op
.parse_args(args
=args
)
551 raise KickstartValueError
, "Mount point required on line:\n\npartition %s" % string
.join (args
)
553 pd
= KickstartPartData()
554 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
555 setattr(pd
, key
, getattr(opts
, key
))
557 pd
.mountpoint
= extra
[0]
558 self
.ksdata
.partitions
.append(pd
)
560 def doReboot(self
, args
):
561 self
.ksdata
.reboot
= True
563 def doRaid(self
, args
):
564 def raid_cb (option
, opt_str
, value
, parser
):
565 parser
.values
.ensure_value(option
.dest
, False)
566 parser
.values
.ensure_value("preexist", True)
568 def device_cb (option
, opt_str
, value
, parser
):
569 if value
[0:2] == "md":
570 parser
.values
.ensure_value(option
.dest
, value
[2:])
572 parser
.values
.ensure_value(option
.dest
, value
)
574 def level_cb (option
, opt_str
, value
, parser
):
575 if value
== "RAID0" or value
== "0":
576 parser
.values
.ensure_value(option
.dest
, "RAID0")
577 elif value
== "RAID1" or value
== "1":
578 parser
.values
.ensure_value(option
.dest
, "RAID1")
579 elif value
== "RAID5" or value
== "5":
580 parser
.values
.ensure_value(option
.dest
, "RAID5")
581 elif value
== "RAID6" or value
== "6":
582 parser
.values
.ensure_value(option
.dest
, "RAID6")
584 op
= KSOptionParser()
585 op
.add_option("--device", action
="callback", callback
=device_cb
,
586 dest
="device", type="string", nargs
=1, required
=1)
587 op
.add_option("--fsoptions", dest
="fsopts")
588 op
.add_option("--fstype", dest
="fstype")
589 op
.add_option("--level", dest
="level", action
="callback",
590 callback
=level_cb
, type="string", nargs
=1, required
=1)
591 op
.add_option("--noformat", action
="callback", callback
=raid_cb
,
592 dest
="format", default
=True, nargs
=0)
593 op
.add_option("--spares", dest
="spares", action
="store", type="int",
595 op
.add_option("--useexisting", dest
="preexist", action
="store_true",
598 (opts
, extra
) = op
.parse_args(args
=args
)
601 raise KickstartValueError
, "Mount point required on line:\n\nraid %s" % string
.join (args
)
603 rd
= KickstartRaidData()
604 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
605 setattr(rd
, key
, getattr(opts
, key
))
607 rd
.mountpoint
= extra
[0]
608 rd
.members
= extra
[1:]
609 self
.ksdata
.raidList
.append(rd
)
611 def doRootPw(self
, args
):
612 op
= KSOptionParser()
613 op
.add_option("--iscrypted", dest
="isCrypted", action
="store_true",
616 (opts
, extra
) = op
.parse_args(args
=args
)
617 self
.ksdata
.rootpw
["isCrypted"] = opts
.isCrypted
620 raise KickstartValueError
, "A single argument is expected for rootpw"
622 self
.ksdata
.rootpw
["password"] = extra
[0]
624 def doSELinux(self
, args
):
625 op
= KSOptionParser()
626 op
.add_option("--disabled", dest
="sel", action
="store_const",
627 const
=SELINUX_DISABLED
)
628 op
.add_option("--enforcing", dest
="sel", action
="store_const",
629 const
=SELINUX_ENFORCING
)
630 op
.add_option("--permissive", dest
="sel", action
="store_const",
631 const
=SELINUX_PERMISSIVE
)
633 (opts
, extra
) = op
.parse_args(args
=args
)
634 self
.ksdata
.selinux
= opts
.sel
636 def doSkipX(self
, args
):
637 self
.ksdata
.skipx
= True
639 def doTimezone(self
, args
):
640 op
= KSOptionParser()
641 op
.add_option("--utc", dest
="isUtc", action
="store_true", default
=False)
643 (opts
, extra
) = op
.parse_args(args
=args
)
644 self
.ksdata
.timezone
["isUtc"] = opts
.isUtc
647 raise KickstartValueError
, "A single argument is expected for timezone"
649 self
.ksdata
.timezone
["timezone"] = extra
[0]
651 def doUpgrade(self
, args
):
652 self
.ksdata
.upgrade
= True
654 def doVnc(self
, args
):
655 def connect_cb (option
, opt_str
, value
, parser
):
656 cargs
= opt_str
.split(":")
657 parser
.values
.ensure_value("host", cargs
[0])
660 parser
.values
.ensure_value("port", cargs
[1])
662 op
= KSOptionParser()
663 op
.add_option("--connect", action
="callback", callback
=connect_cb
,
664 nargs
=1, type="string", required
=1)
665 op
.add_option("--password", dest
="password")
667 (opts
, extra
) = op
.parse_args(args
=args
)
669 self
.ksdata
.vnc
["enabled"] = True
671 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
672 self
.ksdata
.vnc
[key
] = getattr(opts
, key
)
674 def doVolumeGroup(self
, args
):
675 # Have to be a little more complicated to set two values.
676 def vg_cb (option
, opt_str
, value
, parser
):
677 parser
.values
.ensure_value(option
.dest
, False)
678 parser
.values
.ensure_value("preexist", True)
680 op
= KSOptionParser()
681 op
.add_option("--noformat", action
="callback", callback
=vg_cb
,
682 dest
="format", default
=True, nargs
=0)
683 op
.add_option("--pesize", dest
="pesize", type="int", nargs
=1,
685 op
.add_option("--useexisting", dest
="preexist", action
="store_true",
688 (opts
, extra
) = op
.parse_args(args
=args
)
690 vgd
= KickstartVolGroupData()
691 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
692 setattr(vgd
, key
, getattr(opts
, key
))
694 vgd
.vgname
= extra
[0]
695 vgd
.physvols
= extra
[1:]
696 self
.ksdata
.vgList
.append(vgd
)
698 def doXConfig(self
, args
):
699 op
= KSOptionParser()
700 op
.add_option("--card", deprecated
=1)
701 op
.add_option("--driver", dest
="driver")
702 op
.add_option("--defaultdesktop", dest
="defaultdesktop")
703 op
.add_option("--depth", dest
="depth", action
="store", type="int",
705 op
.add_option("--hsync", dest
="hsync")
706 op
.add_option("--monitor", dest
="monitor")
707 op
.add_option("--noprobe", dest
="probe", action
="store_false",
709 op
.add_option("--resolution", dest
="resolution")
710 op
.add_option("--startxonboot", dest
="startX", action
="store_true",
712 op
.add_option("--videoram", dest
="videoRam")
713 op
.add_option("--vsync", dest
="vsync")
715 (opts
, extra
) = op
.parse_args(args
=args
)
717 raise KickstartValueError
, "Unexpected arguments to xconfig: %s" % string
.join (args
)
719 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
720 self
.ksdata
.xconfig
[key
] = getattr(opts
, key
)
722 def doZeroMbr(self
, args
):
723 self
.ksdata
.zerombr
= True
725 def doZFCP(self
, args
):
726 op
= KSOptionParser()
727 op
.add_option("--devnum", dest
="devnum", required
=1)
728 op
.add_option("--fcplun", dest
="fcplun", required
=1)
729 op
.add_option("--scsiid", dest
="scsiid", required
=1)
730 op
.add_option("--scsilun", dest
="scsilun", required
=1)
731 op
.add_option("--wwpn", dest
="wwpn", required
=1)
733 (opts
, extra
) = op
.parse_args(args
=args
)
735 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
736 self
.ksdata
.zfcp
[key
] = getattr(opts
, key
)
742 # The kickstart file parser. This only transitions between states and calls
743 # handlers at certain points. To create a specialized parser, make a subclass
744 # of this and override the methods you care about. Methods that don't need to
745 # do anything may just pass.
747 # Passing None for kshandlers is valid just in case you don't care about
748 # handling any commands.
749 class KickstartParser
:
750 def __init__ (self
, ksdata
, kshandlers
):
751 self
.handler
= kshandlers
753 self
.followIncludes
= True
754 self
.state
= STATE_COMMANDS
756 self
.includeDepth
= 0
758 # Functions to be called when we are at certain points in the
759 # kickstart file parsing. Override these if you need special
761 def addScript (self
):
762 if string
.join(self
.script
["body"]).strip() == "":
765 s
= Script (self
.script
["body"], self
.script
["interp"],
766 self
.script
["chroot"], self
.script
["log"],
767 self
.script
["errorOnFail"], self
.script
["type"])
769 self
.ksdata
.scripts
.append(s
)
771 def addPackages (self
, line
):
774 self
.ksdata
.groupList
.append(line
.lstrip())
777 self
.ksdata
.excludedList
.append(line
.lstrip())
779 self
.ksdata
.packageList
.append(line
.lstrip())
781 def handleCommand (self
, cmd
, args
):
785 if not self
.handler
.handlers
.has_key(cmd
):
786 raise KickstartParseError
, (cmd
+ " " + string
.join (args
))
788 if self
.handler
.handlers
[cmd
] != None:
789 setattr(self
.handler
, "currentCmd", cmd
)
790 self
.handler
.handlers
[cmd
](args
)
792 def handlePackageHdr (self
, args
):
793 op
= KSOptionParser()
794 op
.add_option("--excludedocs", dest
="excludedocs", action
="store_true",
796 op
.add_option("--ignoremissing", dest
="ignoremissing",
797 action
="store_true", default
=False)
798 op
.add_option("--nobase", dest
="nobase", action
="store_true",
801 (opts
, extra
) = op
.parse_args(args
=args
[1:])
803 self
.ksdata
.excludeDocs
= opts
.excludedocs
804 self
.ksdata
.addBase
= not opts
.nobase
805 if opts
.ignoremissing
:
806 self
.ksdata
.handleMissing
= KS_MISSING_IGNORE
808 self
.ksdata
.handleMissing
= KS_MISSING_PROMPT
810 def handleScriptHdr (self
, args
):
811 op
= KSOptionParser()
812 op
.add_option("--erroronfail", dest
="errorOnFail", action
="store_true",
814 op
.add_option("--interpreter", dest
="interpreter", default
="/bin/sh")
815 op
.add_option("--log", "--logfile", dest
="log")
817 if args
[0] == "%pre" or args
[0] == "%traceback":
818 self
.script
["chroot"] = False
819 elif args
[0] == "%post":
820 self
.script
["chroot"] = True
821 op
.add_option("--nochroot", dest
="nochroot", action
="store_true",
824 (opts
, extra
) = op
.parse_args(args
=args
[1:])
826 self
.script
["interp"] = opts
.interpreter
827 self
.script
["log"] = opts
.log
828 self
.script
["errorOnFail"] = opts
.errorOnFail
829 if hasattr(opts
, "nochroot"):
830 self
.script
["chroot"] = not opts
.nochroot
832 def readKickstart (self
, file):
835 excludedPackages
= []
845 if line
== "" and self
.includeDepth
> 0:
849 # Don't eliminate whitespace or comments from scripts.
850 if line
.isspace() or (line
!= "" and line
[0] == '#'):
851 # Save the platform for s-c-kickstart, though.
852 if line
[:10] == "#platform=" and self
.state
== STATE_COMMANDS
:
853 self
.ksdata
.platform
= line
[11:]
855 if self
.state
in [STATE_PRE
, STATE_POST
, STATE_TRACEBACK
]:
856 self
.script
["body"].append(line
)
861 args
= shlex
.split(line
)
863 if args
and args
[0] == "%include" and self
.followIncludes
:
865 raise KickstartParseError
, line
867 self
.includeDepth
+= 1
868 self
.readKickstart (args
[1])
869 self
.includeDepth
-= 1
873 if self
.state
== STATE_COMMANDS
:
874 if not args
and self
.includeDepth
== 0:
875 self
.state
= STATE_END
876 elif args
[0] in ["%pre", "%post", "%traceback"]:
877 self
.state
= STATE_SCRIPT_HDR
878 elif args
[0] == "%packages":
879 self
.state
= STATE_PACKAGES
880 elif args
[0][0] == '%':
881 raise KickstartParseError
, line
884 self
.handleCommand(args
[0], args
[1:])
886 elif self
.state
== STATE_PACKAGES
:
887 if not args
and self
.includeDepth
== 0:
888 self
.state
= STATE_END
889 elif args
[0] in ["%pre", "%post", "%traceback"]:
890 self
.state
= STATE_SCRIPT_HDR
891 elif args
[0] == "%packages":
893 self
.handlePackageHdr (args
)
894 elif args
[0][0] == '%':
895 raise KickstartParseError
, line
898 self
.addPackages (string
.rstrip(line
))
900 elif self
.state
== STATE_SCRIPT_HDR
:
902 self
.script
= {"body": [], "interp": "/bin/sh", "log": None,
903 "errorOnFail": False}
905 if not args
and self
.includeDepth
== 0:
906 self
.state
= STATE_END
907 elif args
[0] == "%pre":
908 self
.state
= STATE_PRE
909 self
.script
["type"] = KS_SCRIPT_PRE
910 elif args
[0] == "%post":
911 self
.state
= STATE_POST
912 self
.script
["type"] = KS_SCRIPT_POST
913 elif args
[0] == "%traceback":
914 self
.state
= STATE_TRACEBACK
915 self
.script
["type"] = KS_SCRIPT_TRACEBACK
916 elif args
[0][0] == '%':
917 raise KickstartParseError
, line
919 self
.handleScriptHdr (args
)
921 elif self
.state
in [STATE_PRE
, STATE_POST
, STATE_TRACEBACK
]:
922 # If this is part of a script, append to it.
923 if not args
and self
.includeDepth
== 0:
925 self
.state
= STATE_END
926 elif args
[0] in ["%pre", "%post", "%traceback", "%packages"]:
927 # Otherwise, figure out what kind of a script we just
928 # finished reading, add it to the list, and switch to
931 self
.state
= STATE_COMMANDS
933 self
.script
["body"].append(line
)
936 elif self
.state
== STATE_END
: