2 # parser.py: Kickstart file parser.
4 # Chris Lumens <clumens@redhat.com>
6 # Copyright 2005, 2006 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.
21 from optparse
import *
23 from constants
import *
26 from rhpl
.translate
import _
27 import rhpl
.translate
as translate
29 translate
.textdomain("pykickstart")
43 def formatErrorMsg(lineno
, msg
=""):
45 return _("The following problem occurred on line %s of the kickstart file:\n\n%s\n") % (lineno
, msg
)
47 return _("There was a problem reading from line %s of the kickstart file") % lineno
49 class KickstartError(Exception):
50 def __init__(self
, val
= ""):
51 Exception.__init
__(self
)
57 class KickstartParseError(KickstartError
):
58 def __init__(self
, msg
):
59 KickstartError
.__init
__(self
, msg
)
64 class KickstartValueError(KickstartError
):
65 def __init__(self
, msg
):
66 KickstartError
.__init
__(self
, msg
)
75 # Specialized OptionParser, mainly to handle the MappableOption and to turn
77 class KSOptionParser(OptionParser
):
78 def exit(self
, status
=0, msg
=None):
82 if self
.lineno
!= None:
83 raise KickstartParseError
, formatErrorMsg(self
.lineno
, msg
=msg
)
85 raise KickstartParseError
, msg
90 for opt
in self
.option_list
:
92 retval
.append(opt
.dest
)
96 def _init_parsing_state (self
):
97 OptionParser
._init
_parsing
_state
(self
)
100 def check_values (self
, values
, args
):
101 for option
in self
.option_list
:
102 if (isinstance(option
, Option
) and option
.required
and \
103 not self
.option_seen
.has_key(option
)):
104 raise KickstartValueError
, formatErrorMsg(self
.lineno
, _("Option %s is required") % option
)
105 elif isinstance(option
, Option
) and option
.deprecated
and \
106 self
.option_seen
.has_key(option
):
107 warnings
.warn(_("Ignoring deprecated option on line %s: The %s option 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 option.") % (self
.lineno
, option
), DeprecationWarning)
109 return (values
, args
)
111 def __init__(self
, map={}, lineno
=None):
114 OptionParser
.__init
__(self
, option_class
=KSOption
,
115 add_help_option
=False)
117 # Creates a new Option class that supports two new attributes:
118 # - required: any option with this attribute must be supplied or an exception
120 # - deprecated: any option with this attribute will cause a DeprecationWarning
121 # to be thrown if the option is used
122 # Also creates a new type:
123 # - ksboolean: support various kinds of boolean values on an option
124 # And two new actions:
125 # - map : allows you to define an opt -> val mapping such that dest gets val
127 # - map_extend: allows you to define an opt -> [val1, ... valn] mapping such
128 # that dest gets a list of vals built up when opt is seen
129 class KSOption (Option
):
130 ATTRS
= Option
.ATTRS
+ ['deprecated', 'required']
131 ACTIONS
= Option
.ACTIONS
+ ("map", "map_extend",)
132 STORE_ACTIONS
= Option
.STORE_ACTIONS
+ ("map", "map_extend",)
134 TYPES
= Option
.TYPES
+ ("ksboolean",)
135 TYPE_CHECKER
= copy(Option
.TYPE_CHECKER
)
137 def _check_required(self
):
138 if self
.required
and not self
.takes_value():
139 raise OptionError(_("Required flag set for option that doesn't take a value"), self
)
141 def _check_ksboolean(option
, opt
, value
):
142 if value
.lower() in ("on", "yes", "true", "1"):
144 elif value
.lower() in ("off", "no", "false", "0"):
147 raise OptionValueError(_("Option %s: invalid boolean value: %r") % (opt
, value
))
149 # Make sure _check_required() is called from the constructor!
150 CHECK_METHODS
= Option
.CHECK_METHODS
+ [_check_required
]
151 TYPE_CHECKER
["ksboolean"] = _check_ksboolean
153 def process (self
, opt
, value
, values
, parser
):
154 Option
.process(self
, opt
, value
, values
, parser
)
155 parser
.option_seen
[self
] = 1
157 # Override default take_action method to handle our custom actions.
158 def take_action(self
, action
, dest
, opt
, value
, values
, parser
):
160 values
.ensure_value(dest
, parser
.map[opt
.lstrip('-')])
161 elif action
== "map_extend":
162 values
.ensure_value(dest
, []).extend(parser
.map[opt
.lstrip('-')])
164 Option
.take_action(self
, action
, dest
, opt
, value
, values
, parser
)
170 # You may make a subclass of Script if you need additional script handling
171 # besides just a data representation. For instance, anaconda may subclass
172 # this to add a run method.
175 retval
= ("(s: '%s' i: %s c: %d)") % \
176 (self
.script
, self
.interp
, self
.inChroot
)
177 return string
.replace(retval
, "\n", "|")
179 def __init__(self
, script
, interp
= "/bin/sh", inChroot
= False,
180 logfile
= None, errorOnFail
= False, type = KS_SCRIPT_PRE
):
181 self
.script
= string
.join(script
, "")
183 self
.inChroot
= inChroot
184 self
.logfile
= logfile
185 self
.errorOnFail
= errorOnFail
188 # Produce a string representation of the script suitable for writing
189 # to a kickstart file. Add this to the end of the %whatever header.
192 if self
.interp
!= "/bin/sh" and self
.interp
!= "":
193 retval
= retval
+ " --interp %s" % self
.interp
194 if self
.type == KS_SCRIPT_POST
and not self
.inChroot
:
195 retval
= retval
+ " --nochroot"
196 if self
.logfile
!= None:
197 retval
= retval
+ " --logfile %s" % self
.logfile
199 retval
= retval
+ " --erroronfail"
201 retval
= retval
+ "\n%s\n" % self
.script
208 # You may make a subclass of KickstartHandlers if you need to do something
209 # besides just build up the data store. If you need to do additional processing
210 # just make a subclass, define handlers for each command in your subclass, and
211 # make sure to call the same handler in the super class before whatever you
212 # want to do. Also if you need to make a new parser that only takes action
213 # for a subset of commands, make a subclass and define all the handlers to
214 # None except the ones you care about.
215 class KickstartHandlers
:
216 def __init__ (self
, ksdata
):
219 # These will get set by the handleCommand method in the parser.
223 self
.handlers
= { "auth" : self
.doAuthconfig
,
224 "authconfig" : self
.doAuthconfig
,
225 "autopart" : self
.doAutoPart
,
226 "autostep" : self
.doAutoStep
,
227 "bootloader" : self
.doBootloader
,
228 "cdrom" : self
.doMethod
,
229 "clearpart" : self
.doClearPart
,
230 "cmdline" : self
.doDisplayMode
,
231 "device" : self
.doDevice
,
232 "deviceprobe" : self
.doDeviceProbe
,
233 "driverdisk" : self
.doDriverDisk
,
234 "firewall" : self
.doFirewall
,
235 "firstboot" : self
.doFirstboot
,
236 "graphical" : self
.doDisplayMode
,
237 "halt" : self
.doReboot
,
238 "harddrive" : self
.doMethod
,
239 "ignoredisk" : self
.doIgnoreDisk
,
240 # implied by lack of "upgrade" command
242 "interactive" : self
.doInteractive
,
243 "keyboard" : self
.doKeyboard
,
244 "lang" : self
.doLang
,
245 "langsupport" : self
.doLangSupport
,
246 "logvol" : self
.doLogicalVolume
,
247 "logging" : self
.doLogging
,
248 "mediacheck" : self
.doMediaCheck
,
249 "monitor" : self
.doMonitor
,
250 "mouse" : self
.doMouse
,
251 "network" : self
.doNetwork
,
252 "nfs" : self
.doMethod
,
253 "dmraid" : self
.doDmRaid
,
254 "part" : self
.doPartition
,
255 "partition" : self
.doPartition
,
256 "poweroff" : self
.doReboot
,
257 "raid" : self
.doRaid
,
258 "reboot" : self
.doReboot
,
259 "repo" : self
.doRepo
,
260 "rootpw" : self
.doRootPw
,
261 "selinux" : self
.doSELinux
,
262 "shutdown" : self
.doReboot
,
263 "skipx" : self
.doSkipX
,
264 "text" : self
.doDisplayMode
,
265 "timezone" : self
.doTimezone
,
266 "url" : self
.doMethod
,
267 "upgrade" : self
.doUpgrade
,
269 "volgroup" : self
.doVolumeGroup
,
270 "xconfig" : self
.doXConfig
,
271 "zerombr" : self
.doZeroMbr
,
272 "zfcp" : self
.doZFCP
,
275 def resetHandlers (self
):
276 for key
in self
.handlers
.keys():
277 self
.handlers
[key
] = None
279 def deprecatedCommand(self
, cmd
):
280 warnings
.warn(_("Ignoring deprecated command on line %s: 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.") % (self
.lineno
, cmd
), DeprecationWarning)
282 def doAuthconfig(self
, args
):
283 self
.ksdata
.authconfig
= string
.join(args
)
285 def doAutoPart(self
, args
):
287 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Command %s does not take any arguments") % "autopart")
289 self
.ksdata
.autopart
= True
291 def doAutoStep(self
, args
):
292 op
= KSOptionParser(lineno
=self
.lineno
)
293 op
.add_option("--autoscreenshot", dest
="autoscreenshot",
294 action
="store_true", default
=False)
296 (opts
, extra
) = op
.parse_args(args
=args
)
297 self
.ksdata
.autostep
["autoscreenshot"] = opts
.autoscreenshot
299 def doBootloader(self
, args
):
300 def driveorder_cb (option
, opt_str
, value
, parser
):
301 for d
in value
.split(','):
302 parser
.values
.ensure_value(option
.dest
, []).append(d
)
304 op
= KSOptionParser(lineno
=self
.lineno
)
305 op
.add_option("--append", dest
="appendLine")
306 op
.add_option("--location", dest
="location", type="choice",
308 choices
=["mbr", "partition", "none", "boot"])
309 op
.add_option("--lba32", dest
="forceLBA", action
="store_true",
311 op
.add_option("--password", dest
="password", default
="")
312 op
.add_option("--md5pass", dest
="md5pass", default
="")
313 op
.add_option("--upgrade", dest
="upgrade", action
="store_true",
315 op
.add_option("--driveorder", dest
="driveorder", action
="callback",
316 callback
=driveorder_cb
, nargs
=1, type="string")
318 (opts
, extra
) = op
.parse_args(args
=args
)
320 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
321 self
.ksdata
.bootloader
[key
] = getattr(opts
, key
)
323 def doClearPart(self
, args
):
324 def drive_cb (option
, opt_str
, value
, parser
):
325 for d
in value
.split(','):
326 parser
.values
.ensure_value(option
.dest
, []).append(d
)
328 op
= KSOptionParser(lineno
=self
.lineno
)
329 op
.add_option("--all", dest
="type", action
="store_const",
330 const
=CLEARPART_TYPE_ALL
)
331 op
.add_option("--drives", dest
="drives", action
="callback",
332 callback
=drive_cb
, nargs
=1, type="string")
333 op
.add_option("--initlabel", dest
="initAll", action
="store_true",
335 op
.add_option("--linux", dest
="type", action
="store_const",
336 const
=CLEARPART_TYPE_LINUX
)
337 op
.add_option("--none", dest
="type", action
="store_const",
338 const
=CLEARPART_TYPE_NONE
)
340 (opts
, extra
) = op
.parse_args(args
=args
)
342 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
343 self
.ksdata
.clearpart
[key
] = getattr(opts
, key
)
345 def doDevice(self
, args
):
346 self
.ksdata
.device
= string
.join(args
)
348 def doDeviceProbe(self
, args
):
349 self
.ksdata
.deviceprobe
= string
.join(args
)
351 def doDisplayMode(self
, args
):
352 if self
.currentCmd
== "cmdline":
353 self
.ksdata
.displayMode
= DISPLAY_MODE_CMDLINE
354 elif self
.currentCmd
== "graphical":
355 self
.ksdata
.displayMode
= DISPLAY_MODE_GRAPHICAL
356 elif self
.currentCmd
== "text":
357 self
.ksdata
.displayMode
= DISPLAY_MODE_TEXT
359 def doDriverDisk(self
, args
):
360 self
.ksdata
.driverdisk
= string
.join(args
)
362 def doFirewall(self
, args
):
363 def firewall_port_cb (option
, opt_str
, value
, parser
):
364 for p
in value
.split(","):
366 if p
.find(":") == -1:
368 parser
.values
.ensure_value(option
.dest
, []).append(p
)
370 op
= KSOptionParser(map={"ssh":["22:tcp"], "telnet":["23:tcp"],
371 "smtp":["25:tcp"], "http":["80:tcp", "443:tcp"],
372 "ftp":["21:tcp"]}, lineno
=self
.lineno
)
374 op
.add_option("--disable", "--disabled", dest
="enabled",
375 action
="store_false")
376 op
.add_option("--enable", "--enabled", dest
="enabled",
377 action
="store_true", default
=True)
378 op
.add_option("--ftp", "--http", "--smtp", "--ssh", "--telnet",
379 dest
="ports", action
="map_extend")
380 op
.add_option("--port", dest
="ports", action
="callback",
381 callback
=firewall_port_cb
, nargs
=1, type="string")
382 op
.add_option("--trust", dest
="trusts", action
="append")
384 (opts
, extra
) = op
.parse_args(args
=args
)
386 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
387 self
.ksdata
.firewall
[key
] = getattr(opts
, key
)
389 def doFirstboot(self
, args
):
390 op
= KSOptionParser(lineno
=self
.lineno
)
391 op
.add_option("--disable", "--disabled", dest
="firstboot",
392 action
="store_const", const
=FIRSTBOOT_SKIP
)
393 op
.add_option("--enable", "--enabled", dest
="firstboot",
394 action
="store_const", const
=FIRSTBOOT_DEFAULT
)
395 op
.add_option("--reconfig", dest
="firstboot", action
="store_const",
396 const
=FIRSTBOOT_RECONFIG
)
398 (opts
, extra
) = op
.parse_args(args
=args
)
399 self
.ksdata
.firstboot
= opts
.firstboot
401 def doIgnoreDisk(self
, args
):
402 def drive_cb (option
, opt_str
, value
, parser
):
403 for d
in value
.split(','):
404 parser
.values
.ensure_value(option
.dest
, []).append(d
)
406 op
= KSOptionParser(lineno
=self
.lineno
)
407 op
.add_option("--drives", dest
="drives", action
="callback",
408 callback
=drive_cb
, nargs
=1, type="string")
410 (opts
, extra
) = op
.parse_args(args
=args
)
412 self
.ksdata
.ignoredisk
= opts
.drives
414 def doInteractive(self
, args
):
416 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Command %s does not take any arguments") % "interactive")
418 self
.ksdata
.interactive
= True
420 def doKeyboard(self
, args
):
422 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Command %s only takes one argument") % "keyboard")
424 self
.ksdata
.keyboard
= args
[0]
426 def doLang(self
, args
):
428 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Command %s only takes one argument") % "lang")
430 self
.ksdata
.lang
= args
[0]
432 def doLangSupport(self
, args
):
433 self
.deprecatedCommand("langsupport")
435 def doLogicalVolume(self
, args
):
436 def lv_cb (option
, opt_str
, value
, parser
):
437 parser
.values
.format
= False
438 parser
.values
.preexist
= True
440 op
= KSOptionParser(lineno
=self
.lineno
)
441 op
.add_option("--bytes-per-inode", dest
="bytesPerInode", action
="store",
443 op
.add_option("--fsoptions", dest
="fsopts")
444 op
.add_option("--fstype", dest
="fstype")
445 op
.add_option("--grow", dest
="grow", action
="store_true",
447 op
.add_option("--maxsize", dest
="maxSizeMB", action
="store", type="int",
449 op
.add_option("--name", dest
="name", required
=1)
450 op
.add_option("--noformat", action
="callback", callback
=lv_cb
,
451 dest
="format", default
=True, nargs
=0)
452 op
.add_option("--percent", dest
="percent", action
="store", type="int",
454 op
.add_option("--recommended", dest
="recommended", action
="store_true",
456 op
.add_option("--size", dest
="size", action
="store", type="int",
458 op
.add_option("--useexisting", dest
="preexist", action
="store_true",
460 op
.add_option("--vgname", dest
="vgname", required
=1)
462 (opts
, extra
) = op
.parse_args(args
=args
)
465 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Mount point required for %s") % "logvol")
467 lvd
= KickstartLogVolData()
468 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
469 setattr(lvd
, key
, getattr(opts
, key
))
471 lvd
.mountpoint
= extra
[0]
472 self
.ksdata
.lvList
.append(lvd
)
474 def doLogging(self
, args
):
475 op
= KSOptionParser(lineno
=self
.lineno
)
476 op
.add_option("--host")
477 op
.add_option("--level", type="choice",
478 choices
=["debug", "info", "warning", "error", "critical"])
479 op
.add_option("--port")
481 (opts
, extra
) = op
.parse_args(args
=args
)
483 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
484 self
.ksdata
.logging
[key
] = getattr(opts
, key
)
486 def doMediaCheck(self
, args
):
488 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Command %s does not take any arguments") % "mediacheck")
490 self
.ksdata
.mediacheck
= True
492 def doMethod(self
, args
):
493 op
= KSOptionParser(lineno
=self
.lineno
)
495 self
.ksdata
.method
["method"] = self
.currentCmd
497 if self
.currentCmd
== "cdrom":
499 elif self
.currentCmd
== "harddrive":
500 op
.add_option("--partition", dest
="partition", required
=1)
501 op
.add_option("--dir", dest
="dir", required
=1)
503 (opts
, extra
) = op
.parse_args(args
=args
)
504 self
.ksdata
.method
["partition"] = opts
.partition
505 self
.ksdata
.method
["dir"] = opts
.dir
506 elif self
.currentCmd
== "nfs":
507 op
.add_option("--server", dest
="server", required
=1)
508 op
.add_option("--dir", dest
="dir", required
=1)
510 (opts
, extra
) = op
.parse_args(args
=args
)
511 self
.ksdata
.method
["server"] = opts
.server
512 self
.ksdata
.method
["dir"] = opts
.dir
513 elif self
.currentCmd
== "url":
514 op
.add_option("--url", dest
="url", required
=1)
516 (opts
, extra
) = op
.parse_args(args
=args
)
517 self
.ksdata
.method
["url"] = opts
.url
519 def doMonitor(self
, args
):
520 op
= KSOptionParser(lineno
=self
.lineno
)
521 op
.add_option("--hsync", dest
="hsync")
522 op
.add_option("--monitor", dest
="monitor")
523 op
.add_option("--noprobe", dest
="probe", action
="store_false",
525 op
.add_option("--vsync", dest
="vsync")
527 (opts
, extra
) = op
.parse_args(args
=args
)
530 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Unexpected arguments to %s command: %s") % ("monitor", extra
))
532 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
533 self
.ksdata
.monitor
[key
] = getattr(opts
, key
)
535 def doMouse(self
, args
):
536 self
.deprecatedCommand("mouse")
538 def doNetwork(self
, args
):
539 op
= KSOptionParser(lineno
=self
.lineno
)
540 op
.add_option("--bootproto", dest
="bootProto", default
="dhcp")
541 op
.add_option("--class", dest
="dhcpclass")
542 op
.add_option("--device", dest
="device")
543 op
.add_option("--essid", dest
="essid")
544 op
.add_option("--ethtool", dest
="ethtool")
545 op
.add_option("--gateway", dest
="gateway")
546 op
.add_option("--hostname", dest
="hostname")
547 op
.add_option("--ip", dest
="ip")
548 op
.add_option("--nameserver", dest
="nameserver")
549 op
.add_option("--netmask", dest
="netmask")
550 op
.add_option("--nodns", dest
="nodns", action
="store_true",
552 op
.add_option("--notksdevice", dest
="notksdevice", action
="store_true",
554 op
.add_option("--onboot", dest
="onboot", action
="store",
556 op
.add_option("--wepkey", dest
="wepkey")
558 (opts
, extra
) = op
.parse_args(args
=args
)
560 nd
= KickstartNetworkData()
561 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
562 setattr(nd
, key
, getattr(opts
, key
))
564 self
.ksdata
.network
.append(nd
)
566 def doDmRaid(self
, args
):
567 op
= KSOptionParser(lineno
=self
.lineno
)
568 op
.add_option("--name", dest
="name", action
="store", type="string",
570 op
.add_option("--dev", dest
="devices", action
="append", type="string",
573 (opts
, extra
) = op
.parse_args(args
=args
)
575 dd
= KickstartDmRaidData()
576 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
577 setattr(dd
, key
, getattr(opts
, key
))
578 dd
.name
= dd
.name
.split('/')[-1]
580 self
.ksdata
.dmraids
.append(dd
)
582 def doPartition(self
, args
):
583 def part_cb (option
, opt_str
, value
, parser
):
584 if value
.startswith("/dev/"):
585 parser
.values
.ensure_value(option
.dest
, value
[5:])
587 parser
.values
.ensure_value(option
.dest
, value
)
589 op
= KSOptionParser(lineno
=self
.lineno
)
590 op
.add_option("--active", dest
="active", action
="store_true",
592 op
.add_option("--asprimary", dest
="primOnly", action
="store_true",
594 op
.add_option("--bytes-per-inode", dest
="bytesPerInode", action
="store",
596 op
.add_option("--end", dest
="end", action
="store", type="int",
598 op
.add_option("--fsoptions", dest
="fsopts")
599 op
.add_option("--fstype", "--type", dest
="fstype")
600 op
.add_option("--grow", dest
="grow", action
="store_true", default
=False)
601 op
.add_option("--label", dest
="label")
602 op
.add_option("--maxsize", dest
="maxSizeMB", action
="store", type="int",
604 op
.add_option("--noformat", dest
="format", action
="store_false",
606 op
.add_option("--onbiosdisk", dest
="onbiosdisk")
607 op
.add_option("--ondisk", "--ondrive", dest
="disk")
608 op
.add_option("--onpart", "--usepart", dest
="onPart", action
="callback",
609 callback
=part_cb
, nargs
=1, type="string")
610 op
.add_option("--recommended", dest
="recommended", action
="store_true",
612 op
.add_option("--size", dest
="size", action
="store", type="int",
614 op
.add_option("--start", dest
="start", action
="store", type="int",
617 (opts
, extra
) = op
.parse_args(args
=args
)
620 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Mount point required for %s") % "partition")
622 pd
= KickstartPartData()
623 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
624 setattr(pd
, key
, getattr(opts
, key
))
626 pd
.mountpoint
= extra
[0]
627 self
.ksdata
.partitions
.append(pd
)
629 def doReboot(self
, args
):
630 if self
.currentCmd
== "reboot":
631 self
.ksdata
.reboot
["action"] = KS_REBOOT
633 self
.ksdata
.reboot
["action"] = KS_SHUTDOWN
635 op
= KSOptionParser(lineno
=self
.lineno
)
636 op
.add_option("--eject", dest
="eject", action
="store_true",
639 (opts
, extra
) = op
.parse_args(args
=args
)
640 self
.ksdata
.reboot
["eject"] = opts
.eject
642 def doRepo(self
, args
):
643 op
= KSOptionParser(lineno
=self
.lineno
)
644 op
.add_option("--name", dest
="name", required
=1)
645 op
.add_option("--baseurl")
646 op
.add_option("--mirrorlist")
648 (opts
, extra
) = op
.parse_args(args
=args
)
650 # This is lame, but I can't think of a better way to make sure only
651 # one of these two is specified.
652 if opts
.baseurl
and opts
.mirrorlist
:
653 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Only one of --baseurl and --mirrorlist may be specified for repo command."))
655 if not opts
.baseurl
and not opts
.mirrorlist
:
656 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("One of --baseurl or --mirrorlist must be specified for repo command."))
658 rd
= KickstartRepoData()
659 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
660 setattr(rd
, key
, getattr(opts
, key
))
662 self
.ksdata
.repoList
.append(rd
)
664 def doRaid(self
, args
):
665 def raid_cb (option
, opt_str
, value
, parser
):
666 parser
.values
.format
= False
667 parser
.values
.preexist
= True
669 def device_cb (option
, opt_str
, value
, parser
):
670 if value
[0:2] == "md":
671 parser
.values
.ensure_value(option
.dest
, value
[2:])
673 parser
.values
.ensure_value(option
.dest
, value
)
675 def level_cb (option
, opt_str
, value
, parser
):
676 if value
== "RAID0" or value
== "0":
677 parser
.values
.ensure_value(option
.dest
, "RAID0")
678 elif value
== "RAID1" or value
== "1":
679 parser
.values
.ensure_value(option
.dest
, "RAID1")
680 elif value
== "RAID5" or value
== "5":
681 parser
.values
.ensure_value(option
.dest
, "RAID5")
682 elif value
== "RAID6" or value
== "6":
683 parser
.values
.ensure_value(option
.dest
, "RAID6")
685 op
= KSOptionParser(lineno
=self
.lineno
)
686 op
.add_option("--bytes-per-inode", dest
="bytesPerInode", action
="store",
688 op
.add_option("--device", action
="callback", callback
=device_cb
,
689 dest
="device", type="string", nargs
=1, required
=1)
690 op
.add_option("--fsoptions", dest
="fsopts")
691 op
.add_option("--fstype", dest
="fstype")
692 op
.add_option("--level", dest
="level", action
="callback",
693 callback
=level_cb
, type="string", nargs
=1)
694 op
.add_option("--noformat", action
="callback", callback
=raid_cb
,
695 dest
="format", default
=True, nargs
=0)
696 op
.add_option("--spares", dest
="spares", action
="store", type="int",
698 op
.add_option("--useexisting", dest
="preexist", action
="store_true",
701 (opts
, extra
) = op
.parse_args(args
=args
)
704 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Mount point required for %s") % "raid")
706 rd
= KickstartRaidData()
707 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
708 setattr(rd
, key
, getattr(opts
, key
))
710 rd
.mountpoint
= extra
[0]
711 rd
.members
= extra
[1:]
712 self
.ksdata
.raidList
.append(rd
)
714 def doRootPw(self
, args
):
715 op
= KSOptionParser(lineno
=self
.lineno
)
716 op
.add_option("--iscrypted", dest
="isCrypted", action
="store_true",
719 (opts
, extra
) = op
.parse_args(args
=args
)
720 self
.ksdata
.rootpw
["isCrypted"] = opts
.isCrypted
723 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("A single argument is expected for the %s command") % "rootpw")
725 self
.ksdata
.rootpw
["password"] = extra
[0]
727 def doSELinux(self
, args
):
728 op
= KSOptionParser(lineno
=self
.lineno
)
729 op
.add_option("--disabled", dest
="sel", action
="store_const",
730 const
=SELINUX_DISABLED
)
731 op
.add_option("--enforcing", dest
="sel", action
="store_const",
732 const
=SELINUX_ENFORCING
)
733 op
.add_option("--permissive", dest
="sel", action
="store_const",
734 const
=SELINUX_PERMISSIVE
)
736 (opts
, extra
) = op
.parse_args(args
=args
)
737 self
.ksdata
.selinux
= opts
.sel
739 def doSkipX(self
, args
):
741 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Command %s does not take any arguments") % "skipx")
743 self
.ksdata
.skipx
= True
745 def doTimezone(self
, args
):
746 op
= KSOptionParser(lineno
=self
.lineno
)
747 op
.add_option("--utc", dest
="isUtc", action
="store_true", default
=False)
749 (opts
, extra
) = op
.parse_args(args
=args
)
750 self
.ksdata
.timezone
["isUtc"] = opts
.isUtc
753 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("A single argument is expected for the %s command") % "timezone")
755 self
.ksdata
.timezone
["timezone"] = extra
[0]
757 def doUpgrade(self
, args
):
759 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Command %s does not take any arguments") % "upgrade")
761 self
.ksdata
.upgrade
= True
763 def doVnc(self
, args
):
764 def connect_cb (option
, opt_str
, value
, parser
):
765 cargs
= value
.split(":")
766 parser
.values
.ensure_value("host", cargs
[0])
769 parser
.values
.ensure_value("port", cargs
[1])
771 op
= KSOptionParser(lineno
=self
.lineno
)
772 op
.add_option("--connect", action
="callback", callback
=connect_cb
,
773 nargs
=1, type="string", deprecated
=1)
774 op
.add_option("--password", dest
="password")
775 op
.add_option("--host", dest
="host")
776 op
.add_option("--port", dest
="port")
778 (opts
, extra
) = op
.parse_args(args
=args
)
780 self
.ksdata
.vnc
["enabled"] = True
782 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
783 self
.ksdata
.vnc
[key
] = getattr(opts
, key
)
785 def doVolumeGroup(self
, args
):
786 # Have to be a little more complicated to set two values.
787 def vg_cb (option
, opt_str
, value
, parser
):
788 parser
.values
.format
= False
789 parser
.values
.preexist
= True
791 op
= KSOptionParser(lineno
=self
.lineno
)
792 op
.add_option("--noformat", action
="callback", callback
=vg_cb
,
793 dest
="format", default
=True, nargs
=0)
794 op
.add_option("--pesize", dest
="pesize", type="int", nargs
=1,
796 op
.add_option("--useexisting", dest
="preexist", action
="store_true",
799 (opts
, extra
) = op
.parse_args(args
=args
)
801 vgd
= KickstartVolGroupData()
802 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
803 setattr(vgd
, key
, getattr(opts
, key
))
805 vgd
.vgname
= extra
[0]
806 vgd
.physvols
= extra
[1:]
807 self
.ksdata
.vgList
.append(vgd
)
809 def doXConfig(self
, args
):
810 op
= KSOptionParser(lineno
=self
.lineno
)
811 op
.add_option("--card", deprecated
=1)
812 op
.add_option("--driver", dest
="driver")
813 op
.add_option("--defaultdesktop", dest
="defaultdesktop")
814 op
.add_option("--depth", dest
="depth", action
="store", type="int",
816 op
.add_option("--hsync", deprecated
=1)
817 op
.add_option("--monitor", deprecated
=1)
818 op
.add_option("--noprobe", deprecated
=1)
819 op
.add_option("--resolution", dest
="resolution")
820 op
.add_option("--startxonboot", dest
="startX", action
="store_true",
822 op
.add_option("--videoram", dest
="videoRam")
823 op
.add_option("--vsync", deprecated
=1)
825 (opts
, extra
) = op
.parse_args(args
=args
)
827 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
=_("Unexpected arguments to %s command: %s" % ("xconfig", extra
)))
829 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
830 self
.ksdata
.xconfig
[key
] = getattr(opts
, key
)
832 def doZeroMbr(self
, args
):
834 warnings
.warn(_("Ignoring deprecated option on line %s: The zerombr command no longer takes any options. In future releases, this will result in a fatal error from kickstart. Please modify your kickstart file to remove any options.") % self
.lineno
, DeprecationWarning)
836 self
.ksdata
.zerombr
= True
838 def doZFCP(self
, args
):
839 op
= KSOptionParser(lineno
=self
.lineno
)
840 op
.add_option("--devnum", dest
="devnum", required
=1)
841 op
.add_option("--fcplun", dest
="fcplun", required
=1)
842 op
.add_option("--scsiid", dest
="scsiid", required
=1)
843 op
.add_option("--scsilun", dest
="scsilun", required
=1)
844 op
.add_option("--wwpn", dest
="wwpn", required
=1)
846 (opts
, extra
) = op
.parse_args(args
=args
)
848 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
849 self
.ksdata
.zfcp
[key
] = getattr(opts
, key
)
855 # The kickstart file parser. This only transitions between states and calls
856 # handlers at certain points. To create a specialized parser, make a subclass
857 # of this and override the methods you care about. Methods that don't need to
858 # do anything may just pass.
860 # Passing None for kshandlers is valid just in case you don't care about
861 # handling any commands.
862 class KickstartParser
:
863 def __init__ (self
, ksdata
, kshandlers
, followIncludes
=True,
864 errorsAreFatal
=True, missingIncludeIsFatal
=True):
865 self
.handler
= kshandlers
867 self
.followIncludes
= followIncludes
868 self
.missingIncludeIsFatal
= missingIncludeIsFatal
869 self
.state
= STATE_COMMANDS
871 self
.includeDepth
= 0
872 self
.errorsAreFatal
= errorsAreFatal
874 # Functions to be called when we are at certain points in the
875 # kickstart file parsing. Override these if you need special
877 def addScript (self
):
878 if string
.join(self
.script
["body"]).strip() == "":
881 s
= Script (self
.script
["body"], self
.script
["interp"],
882 self
.script
["chroot"], self
.script
["log"],
883 self
.script
["errorOnFail"], self
.script
["type"])
885 self
.ksdata
.scripts
.append(s
)
887 def addPackages (self
, line
):
888 stripped
= line
.strip()
890 if stripped
[0] == '@':
891 self
.ksdata
.groupList
.append(stripped
[1:].lstrip())
892 elif stripped
[0] == '-':
893 self
.ksdata
.excludedList
.append(stripped
[1:].lstrip())
895 self
.ksdata
.packageList
.append(stripped
)
897 def handleCommand (self
, lineno
, args
):
904 if not self
.handler
.handlers
.has_key(cmd
):
905 raise KickstartParseError
, formatErrorMsg(lineno
)
907 if self
.handler
.handlers
[cmd
] != None:
908 self
.handler
.currentCmd
= cmd
909 self
.handler
.lineno
= lineno
910 self
.handler
.handlers
[cmd
](cmdArgs
)
912 def handlePackageHdr (self
, lineno
, args
):
913 op
= KSOptionParser(lineno
=lineno
)
914 op
.add_option("--excludedocs", dest
="excludedocs", action
="store_true",
916 op
.add_option("--ignoremissing", dest
="ignoremissing",
917 action
="store_true", default
=False)
918 op
.add_option("--nobase", dest
="nobase", action
="store_true",
920 op
.add_option("--ignoredeps", dest
="resolveDeps", action
="store_false",
922 op
.add_option("--resolvedeps", dest
="resolveDeps", action
="store_true",
925 (opts
, extra
) = op
.parse_args(args
=args
[1:])
927 self
.ksdata
.excludeDocs
= opts
.excludedocs
928 self
.ksdata
.addBase
= not opts
.nobase
929 if opts
.ignoremissing
:
930 self
.ksdata
.handleMissing
= KS_MISSING_IGNORE
932 self
.ksdata
.handleMissing
= KS_MISSING_PROMPT
934 def handleScriptHdr (self
, lineno
, args
):
935 op
= KSOptionParser(lineno
=lineno
)
936 op
.add_option("--erroronfail", dest
="errorOnFail", action
="store_true",
938 op
.add_option("--interpreter", dest
="interpreter", default
="/bin/sh")
939 op
.add_option("--log", "--logfile", dest
="log")
941 if args
[0] == "%pre" or args
[0] == "%traceback":
942 self
.script
["chroot"] = False
943 elif args
[0] == "%post":
944 self
.script
["chroot"] = True
945 op
.add_option("--nochroot", dest
="nochroot", action
="store_true",
948 (opts
, extra
) = op
.parse_args(args
=args
[1:])
950 self
.script
["interp"] = opts
.interpreter
951 self
.script
["log"] = opts
.log
952 self
.script
["errorOnFail"] = opts
.errorOnFail
953 if hasattr(opts
, "nochroot"):
954 self
.script
["chroot"] = not opts
.nochroot
956 # Parser state machine. Don't override this in a subclass.
957 def readKickstart (self
, file):
958 # For error reporting.
970 # At the end of an included file
971 if line
== "" and self
.includeDepth
> 0:
975 # Don't eliminate whitespace or comments from scripts.
976 if line
.isspace() or (line
!= "" and line
.lstrip()[0] == '#'):
977 # Save the platform for s-c-kickstart, though.
978 if line
[:10] == "#platform=" and self
.state
== STATE_COMMANDS
:
979 self
.ksdata
.platform
= line
[11:]
981 if self
.state
in [STATE_PRE
, STATE_POST
, STATE_TRACEBACK
]:
982 self
.script
["body"].append(line
)
987 # We only want to split the line if we're outside of a script,
988 # as inside the script might involve some pretty weird quoting
989 # that shlex doesn't understand.
990 if self
.state
in [STATE_PRE
, STATE_POST
, STATE_TRACEBACK
]:
991 # Have we found a state transition? If so, we still want
992 # to split. Otherwise, args won't be set but we'll fall through
993 # all the way to the last case.
994 if line
!= "" and string
.split(line
.lstrip())[0] in \
995 ["%post", "%pre", "%traceback", "%include", "%packages"]:
996 args
= shlex
.split(line
)
1000 args
= shlex
.split(line
)
1002 if args
and args
[0] == "%include":
1003 # This case comes up primarily in ksvalidator.
1004 if not self
.followIncludes
:
1009 raise KickstartParseError
, formatErrorMsg(lineno
)
1011 self
.includeDepth
+= 1
1014 self
.readKickstart (args
[1])
1016 # Handle the include file being provided over the
1017 # network in a %pre script. This case comes up in the
1018 # early parsing in anaconda.
1019 if self
.missingIncludeIsFatal
:
1022 self
.includeDepth
-= 1
1026 if self
.state
== STATE_COMMANDS
:
1027 if not args
and self
.includeDepth
== 0:
1028 self
.state
= STATE_END
1029 elif args
[0] in ["%pre", "%post", "%traceback"]:
1030 self
.state
= STATE_SCRIPT_HDR
1031 elif args
[0] == "%packages":
1032 self
.state
= STATE_PACKAGES
1033 elif args
[0][0] == '%':
1034 # This error is too difficult to continue from, without
1035 # lots of resync code. So just print this one and quit.
1036 raise KickstartParseError
, formatErrorMsg(lineno
)
1040 if self
.errorsAreFatal
:
1041 self
.handleCommand(lineno
, args
)
1044 self
.handleCommand(lineno
, args
)
1045 except Exception, msg
:
1048 elif self
.state
== STATE_PACKAGES
:
1049 if not args
and self
.includeDepth
== 0:
1050 self
.state
= STATE_END
1051 elif args
[0] in ["%pre", "%post", "%traceback"]:
1052 self
.state
= STATE_SCRIPT_HDR
1053 elif args
[0] == "%packages":
1056 if self
.errorsAreFatal
:
1057 self
.handlePackageHdr (lineno
, args
)
1060 self
.handlePackageHdr (lineno
, args
)
1061 except Exception, msg
:
1063 elif args
[0][0] == '%':
1064 # This error is too difficult to continue from, without
1065 # lots of resync code. So just print this one and quit.
1066 raise KickstartParseError
, formatErrorMsg(lineno
)
1069 self
.addPackages (string
.rstrip(line
))
1071 elif self
.state
== STATE_SCRIPT_HDR
:
1073 self
.script
= {"body": [], "interp": "/bin/sh", "log": None,
1074 "errorOnFail": False}
1076 if not args
and self
.includeDepth
== 0:
1077 self
.state
= STATE_END
1078 elif args
[0] == "%pre":
1079 self
.state
= STATE_PRE
1080 self
.script
["type"] = KS_SCRIPT_PRE
1081 elif args
[0] == "%post":
1082 self
.state
= STATE_POST
1083 self
.script
["type"] = KS_SCRIPT_POST
1084 elif args
[0] == "%traceback":
1085 self
.state
= STATE_TRACEBACK
1086 self
.script
["type"] = KS_SCRIPT_TRACEBACK
1087 elif args
[0][0] == '%':
1088 # This error is too difficult to continue from, without
1089 # lots of resync code. So just print this one and quit.
1090 raise KickstartParseError
, formatErrorMsg(lineno
)
1092 if self
.errorsAreFatal
:
1093 self
.handleScriptHdr (lineno
, args
)
1096 self
.handleScriptHdr (lineno
, args
)
1097 except Exception, msg
:
1100 elif self
.state
in [STATE_PRE
, STATE_POST
, STATE_TRACEBACK
]:
1101 if line
== "" and self
.includeDepth
== 0:
1102 # If we're at the end of the kickstart file, add the script.
1104 self
.state
= STATE_END
1105 elif args
and args
[0] in ["%pre", "%post", "%traceback", "%packages"]:
1106 # Otherwise we're now at the start of the next section.
1107 # Figure out what kind of a script we just finished
1108 # reading, add it to the list, and switch to the initial
1111 self
.state
= STATE_COMMANDS
1113 # Otherwise just add to the current script body.
1114 self
.script
["body"].append(line
)
1117 elif self
.state
== STATE_END
: