示例#1
0
    def parse(self, args):
        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        data = self.dataClass()  # pylint: disable=not-callable
        self.set_to_obj(ns, data)
        data.lineno = self.lineno

        if not data.format:
            data.preexist = True
        elif data.preexist:
            data.format = False

        if not extra:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("btrfs must be given a mountpoint")), lineno=self.lineno)
        elif any(arg for arg in extra if arg.startswith("-")):
            mapping = {"command": "btrfs", "options": extra}
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping), lineno=self.lineno)

        data.mountpoint = extra[0]
        data.devices = extra[1:]

        if not any([data.devices, data.subvol]):
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("btrfs must be given a list of partitions")), lineno=self.lineno)
        elif not data.devices:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("btrfs subvol requires specification of parent volume")), lineno=self.lineno)

        if data.subvol and not data.name:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("btrfs subvolume requires a name")), lineno=self.lineno)

        # Check for duplicates in the data list.
        if data in self.dataList():
            warnings.warn(_("A btrfs volume with the mountpoint %s has already been defined.") % data.label)

        return data
示例#2
0
    def handleHeader(self, lineno, args):
        """Process the arguments to the %packages header and set attributes
           on the Version's Packages instance appropriate.  This method may be
           overridden in a subclass if necessary.
        """
        Section.handleHeader(self, lineno, args)
        op = self._getParser()
        ns = op.parse_args(args=args[1:], lineno=lineno)

        if ns.defaultPackages and ns.nobase:
            raise KickstartParseError(formatErrorMsg(lineno, msg=_("--default and --nobase cannot be used together")), lineno=lineno)
        elif ns.defaultPackages and ns.nocore:
            raise KickstartParseError(formatErrorMsg(lineno, msg=_("--default and --nocore cannot be used together")), lineno=lineno)

        self.handler.packages.excludeDocs = ns.excludedocs
        self.handler.packages.addBase = not ns.nobase
        if ns.ignoremissing:
            self.handler.packages.handleMissing = KS_MISSING_IGNORE
        else:
            self.handler.packages.handleMissing = KS_MISSING_PROMPT

        if ns.defaultPackages:
            self.handler.packages.default = True

        if ns.instLangs is not None:
            self.handler.packages.instLangs = ns.instLangs

        self.handler.packages.nocore = ns.nocore
        self.handler.packages.multiLib = ns.multiLib
        self.handler.packages.excludeWeakdeps = ns.excludeWeakdeps
        self.handler.packages.timeout = ns.timeout
        self.handler.packages.retries = ns.retries
        self.handler.packages.seen = True
示例#3
0
    def _parseJoin(self, args):
        try:
            # We only support these args
            opts, remaining = getopt.getopt(args, "", ("client-software=",
                                                       "server-software=",
                                                       "membership-software=",
                                                       "one-time-password="******"no-password",
                                                       "computer-ou="))
        except getopt.GetoptError as ex:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_(
                "Invalid realm arguments: %s") % ex))

        if len(remaining) != 1:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_(
                "Specify only one realm to join")))

        # Parse successful, just use this as the join command
        self.join_realm = remaining[0]
        self.join_args = args

        # Build a discovery command
        self.discover_options = []
        supported_discover_options = ("--client-software",
                                      "--server-software",
                                      "--membership-software")
        for (o, a) in opts:
            if o in supported_discover_options:
                self.discover_options.append("%s=%s" % (o, a))
示例#4
0
    def parse(self, args):
        ns = self.op.parse_args(args=args, lineno=self.lineno)
        self.set_to_self(ns)

        # just "timezone" without any arguments and timezone specification doesn't really make sense,
        # so throw an error when we see it (it might even be an indication of an incorrect machine generated kickstart)
        if not args:
            error_message = _("At least one option and/or an argument are expected for the  %s command") % "timezone"
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=error_message))

        # To be able to support the timezone command being used without
        # a timezone specification:
        # - we don't call the parse() method of the ancestors
        # -> due to the FC3 parse() method that would be eventually called,
        #    which throws an exception if no timezone specification is provided
        # - we implement the relevant functionality of the ancestor methods here

        if len(ns.timezone) == 1:
            self.timezone = ns.timezone[0]
        elif len(ns.timezone) > 1:
            error_message = _("One or zero arguments are expected for the %s command") % "timezone"
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=error_message))

        if self.ntpservers and self.nontp:
            msg = formatErrorMsg(self.lineno, msg=_("Options --nontp and --ntpservers are mutually exclusive"))
            raise KickstartParseError(msg)

        return self
示例#5
0
    def parse(self, args):
        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if len(extra) > 1:
            raise KickstartParseError(
                formatErrorMsg(self.lineno, msg=_("Only one partition may be specified for driverdisk command."))
            )
        elif any(arg for arg in extra if arg.startswith("-")):
            mapping = {"command": "driverdisk", "options": extra}
            raise KickstartParseError(
                formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping)
            )

        if len(extra) == 1 and ns.source:
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno, msg=_("Only one of --source and partition may be specified for driverdisk command.")
                )
            )

        if not extra and not ns.source:
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno, msg=_("One of --source or partition must be specified for driverdisk command.")
                )
            )

        ddd = self.handler.DriverDiskData()
        self.set_to_obj(ns, ddd)
        ddd.lineno = self.lineno
        if len(extra) == 1:
            ddd.partition = extra[0]

        return ddd
示例#6
0
    def parse(self, args):
        (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
        data = self.handler.BTRFSData()
        self._setToObj(self.op, opts, data)
        data.lineno = self.lineno

        if len(extra) == 0:
            raise KickstartValueError(formatErrorMsg(self.lineno, msg=_("btrfs must be given a mountpoint")))

        if len(extra) == 1 and not data.subvol:
            raise KickstartValueError(formatErrorMsg(self.lineno, msg=_("btrfs must be given a list of partitions")))
        elif len(extra) == 1:
            raise KickstartValueError(formatErrorMsg(self.lineno, msg=_("btrfs subvol requires specification of parent volume")))

        if data.subvol and not data.name:
            raise KickstartValueError(formatErrorMsg(self.lineno, msg=_("btrfs subvolume requires a name")))

        data.mountpoint = extra[0]
        data.devices = extra[1:]

        # Check for duplicates in the data list.
        if data in self.dataList():
            warnings.warn(_("A btrfs volume with the mountpoint %s has already been defined.") % data.label)

        return data
    def handle_header(self, lineno, args):

        op = KSOptionParser()
        op.add_option("--enable", "-e", action="store_true", default=False,
                      dest="state", help="Enable Cloud Support")
        op.add_option("--disable", "-d", action="store_false",
                      dest="state", help="(Default) Disable Cloud Support")
        op.add_option("--allinone", "-a", action="store_true", default=False,
                      dest="mode", help="Specify the mode of Packstack Installation")
        op.add_option("--answer-file", "-f", action="store", type="string",
                      dest="file", help="Specify URL of answers file")
        (options, extra) = op.parse_args(args=args, lineno=lineno)

        # Error Handling
        if str(options.state) == "True":
            self.state = str(options.state)
            if options.file and options.mode:
                msg = "options --allinone and --answer-file are mutually exclusive"
                raise KickstartParseError(msg)
            elif options.file:
                try:
                    response = urllib2.urlopen(options.file)
                    for line in response:
                        self.lines += line
                except urllib2.HTTPError, e:
                    msg = "Kickstart Error:: HTTPError: " + str(e.code)
                    raise KickstartParseError, formatErrorMsg(lineno, msg=msg)
                except urllib2.URLError, e:
                    msg = "Kickstart Error: HTTPError: " + str(e.reason)
                    raise KickstartParseError, formatErrorMsg(lineno, msg=msg)
                except:
示例#8
0
    def parse(self, args):
        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if not ns.format:
            ns.preexist = True

        vg = self.handler.VolGroupData()
        self.set_to_obj(ns, vg)
        vg.lineno = self.lineno

        if len(extra) == 0:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("volgroup must be given a VG name")))
        elif any(arg for arg in extra if arg.startswith("-")):
            mapping = {"command": "volgroup", "options": extra}
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping))

        if len(extra) == 1 and not ns.preexist:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("volgroup must be given a list of partitions")))
        elif len(extra) > 1 and ns.preexist:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Members may not be specified for preexisting volgroup")))

        vg.vgname = extra[0]

        if len(extra) > 1:
            vg.physvols = extra[1:]

        # Check for duplicates in the data list.
        if vg in self.dataList():
            warnings.warn(_("A volgroup with the name %s has already been defined.") % vg.vgname)

        return vg
示例#9
0
    def parse(self, args):
        (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
        vg = self.handler.VolGroupData()
        self._setToObj(self.op, opts, vg)
        vg.lineno = self.lineno

        if len(extra) == 0:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("volgroup must be given a VG name")))

        if len(extra) == 1 and not opts.preexist:
            raise KickstartValueError(formatErrorMsg(self.lineno, msg=_("volgroup must be given a list of partitions")))
        elif len(extra) > 1 and opts.preexist:
            raise KickstartValueError(
                formatErrorMsg(self.lineno, msg=_("Members may not be specified for preexisting volgroup"))
            )

        vg.vgname = extra[0]

        if len(extra) > 1:
            vg.physvols = extra[1:]

        # Check for duplicates in the data list.
        if vg in self.dataList():
            warnings.warn(_("A volgroup with the name %s has already been defined.") % vg.vgname)

        return vg
示例#10
0
    def _stateMachine(self, lineIter):
        # For error reporting.
        lineno = 0

        while True:
            # Get the next line out of the file, quitting if this is the last line.
            try:
                self._line = next(lineIter)
                if self._line == "":
                    break
            except StopIteration:
                break

            lineno += 1

            # Eliminate blank lines, whitespace-only lines, and comments.
            if self._isBlankOrComment(self._line):
                self._handleSpecialComments(self._line)
                continue

            # Split the line, discarding comments.
            args = shlex.split(self._line, comments=True)

            if args[0] == "%include":
                if len(args) == 1 or not args[1]:
                    raise KickstartParseError(formatErrorMsg(lineno))

                self._handleInclude(args[1])
                continue

            # Now on to the main event.
            if self._state == STATE_COMMANDS:
                if args[0] == "%ksappend":
                    # This is handled by the preprocess* functions, so continue.
                    continue
                elif args[0][0] == '%':
                    # This is the beginning of a new section.  Handle its header
                    # here.
                    newSection = args[0]
                    if not self._validState(newSection):
                        raise KickstartParseError(formatErrorMsg(lineno, msg=_("Unknown kickstart section: %s") % newSection))

                    self._state = newSection
                    obj = self._sections[self._state]
                    self._tryFunc(lambda: obj.handleHeader(lineno, args))

                    # This will handle all section processing, kicking us back
                    # out to STATE_COMMANDS at the end with the current line
                    # being the next section header, etc.
                    lineno = self._readSection(lineIter, lineno)
                else:
                    # This is a command in the command section.  Dispatch to it.
                    self._tryFunc(lambda: self.handleCommand(lineno, args))
            elif self._state == STATE_END:
                break
            elif self._includeDepth > 0:
                lineIter.put(self._line)
                lineno -= 1
                lineno = self._readSection(lineIter, lineno)
示例#11
0
def _preprocessStateMachine (lineIter):
    l = None
    lineno = 0

    # Now open an output kickstart file that we are going to write to one
    # line at a time.
    (outF, outName) = tempfile.mkstemp("-ks.cfg", "", "/tmp")

    while True:
        try:
            l = next(lineIter)
        except StopIteration:
            break

        # At the end of the file?
        if l == "":
            break

        lineno += 1
        url = None

        ll = l.strip()
        if not ll.startswith("%ksappend"):
            os.write(outF, l)
            continue

        # Try to pull down the remote file.
        try:
            ksurl = ll.split(' ')[1]
        except:
            raise KickstartParseError(formatErrorMsg(lineno, msg=_("Illegal url for %%ksappend: %s") % ll))

        try:
            if '://' in ksurl:
                url = urlopen(ksurl)
            else:
                url = open(ksurl, 'r')
        except (URLError, IOError) as e:
            raise KickstartError(formatErrorMsg(lineno, msg=_("Unable to open %%ksappend file: %s") % str(e)))
        else:
            # Sanity check result.  Sometimes FTP doesn't catch a file
            # is missing.
            try:
                if url.size < 1:
                    raise KickstartError(formatErrorMsg(lineno, msg=_("Unable to open %%ksappend file")))
            except:
                raise KickstartError(formatErrorMsg(lineno, msg=_("Unable to open %%ksappend file")))

        # If that worked, write the remote file to the output kickstart
        # file in one burst.  Then close everything up to get ready to
        # read ahead in the input file.  This allows multiple %ksappend
        # lines to exist.
        if url is not None:
            os.write(outF, url.read())
            url.close()

    # All done - close the temp file and return its location.
    os.close(outF)
    return outName
示例#12
0
    def parse(self, args):
        # the 'mount' command can't be used together with any other
        # partitioning-related command
        conflicting_command = None

        # seen indicates that the corresponding
        # command has been seen in kickstart
        if self.handler.autopart.seen:
            conflicting_command = "autopart"
        if self.handler.partition.seen:
            conflicting_command = "part/partition"
        elif self.handler.raid.seen:
            conflicting_command = "raid"
        elif self.handler.volgroup.seen:
            conflicting_command = "volgroup"
        elif self.handler.logvol.seen:
            conflicting_command = "logvol"
        elif hasattr(self.handler, "reqpart") and self.handler.reqpart.seen:
            conflicting_command = "reqpart"

        if conflicting_command:
            # allow for translation of the error message
            errorMsg = _("The '%s' and 'mount' commands can't be used at the same time") % \
                         conflicting_command
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=errorMsg), lineno=self.lineno)

        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if extra:
            mapping = {"command": "mount", "options": extra}
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping), lineno=self.lineno)

        md = self.dataClass()  # pylint: disable=not-callable
        self.set_to_obj(ns, md)
        md.lineno = self.lineno
        md.device = ns.device[0]
        md.mount_point = ns.mntpoint[0]

        if md.mount_point.lower() != "none" and not md.mount_point.startswith("/"):
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Invalid mount point '%s' given") % md.mount_point), lineno=self.lineno)

        if md.reformat is False and md.mkfs_opts:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("'--mkfsoptions' requires --reformat")), lineno=self.lineno)

        # The semantics is as follows:
        #   --reformat          -> just reformat with the same format as existing
        #   --reformat=SOME_FMT -> reformat to given format
        #   no '--reformat'     -> don't reformat
        #
        # md.reformat can either be 'False' (not specified), 'True' (just
        # '--reformat') or a non-empty string ('--reformat=FORMAT'). Only the
        # last case requires special treatment.
        if md.reformat and md.reformat is not True:
            # a new format given
            md.format = md.reformat
            md.reformat = True

        return md
示例#13
0
    def parse(self, args):
        retval = F15_LogVol.parse(self, args)

        if retval.resize and not retval.preexist:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("--resize can only be used in conjunction with --useexisting")))

        if retval.resize and not retval.size:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("--resize requires --size to indicate new size")))

        return retval
示例#14
0
    def parse(self, args):
        retval = F21_LogVol.parse(self, args)

        if not retval.format and retval.mkfsopts:
            raise KickstartValueError(formatErrorMsg(self.lineno, msg=_("--mkfsoptions with --noformat has no effect.")))

        if retval.fsprofile and retval.mkfsopts:
            raise KickstartValueError(formatErrorMsg(self.lineno, msg=_("--mkfsoptions and --fsprofile cannot be used together.")))

        return retval
示例#15
0
    def parse(self, args):
        retval = F14_Partition.parse(self, args)

        if retval.resize and not retval.onPart:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("--resize can only be used in conjunction with --onpart")))

        if retval.resize and not retval.size:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("--resize requires --size to specify new size")))

        return retval
示例#16
0
    def parse(self, args):
        retval = F14_Url.parse(self, args)

        if self.url and self.mirrorlist:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Only one of --url and --mirrorlist may be specified for url command.")))

        if not self.url and not self.mirrorlist:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("One of --url or --mirrorlist must be specified for url command.")))

        return retval
示例#17
0
    def parse(self, args):
        (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
        self._setToSelf(self.op, opts)

        if len(extra) != 0:
            raise KickstartValueError(formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not take any arguments") % "eula"))

        if not self.agreed:
            raise KickstartValueError(formatErrorMsg(self.lineno, msg=_("Kickstart command eula expects the --agreed option")))

        return self
示例#18
0
    def parse(self, args):
        (_ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if len(extra) != 1:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Kickstart command %s requires one argument") % "iscsiname"))
        elif any(arg for arg in extra if arg.startswith("-")):
            mapping = {"command": "iscsiname", "options": extra}
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping))

        self.iscsiname = extra[0]
        return self
示例#19
0
    def parse(self, args):
        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if not ns.password:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("A single argument is expected for the %s command") % "rootpw"))
        elif extra:
            mapping = {"command": "rootpw", "options": extra}
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping))

        self.set_to_self(ns)
        return self
示例#20
0
    def parse(self, args):
        (_ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if len(_ns.kbd) != 1:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Kickstart command %s requires one argument") % "keyboard"))
        elif extra:
            mapping = {"command": "keyboard", "options": extra}
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping))

        self.keyboard = _ns.kbd[0]
        return self
示例#21
0
    def parse(self, args):
        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)
        self.set_to_self(ns)

        if len(extra) != 1:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("A single argument is expected for the %s command") % "timezone"))
        elif any(arg for arg in extra if arg.startswith("-")):
            mapping = {"command": "timezone", "options": extra}
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping))

        self.timezone = extra[0]
        return self
示例#22
0
    def parse(self, args):
        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        self.set_to_self(ns)

        if extra:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not take any arguments") % "eula"), lineno=self.lineno)

        if not self.agreed:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Kickstart command eula expects the --agreed option")), lineno=self.lineno)

        return self
示例#23
0
    def parse(self, args):
        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if len(extra) != 2:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("device command requires two arguments: module type and name")), lineno=self.lineno)
        elif any(arg for arg in extra if arg.startswith("-")):
            mapping = {"command": "device", "options": extra}
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping), lineno=self.lineno)

        self.moduleOpts = ns.moduleOpts
        self.type = extra[0]
        self.moduleName = extra[1]
        return self
示例#24
0
 def parse(self, args):
     # first call the overriden method
     retval = F19_Raid.parse(self, args)
     # the raid command can't be used together with the autopart command
     # due to the hard to debug behavior their combination introduces
     if self.handler.autopart.seen:
         errorMsg = _("The raid and autopart commands can't be used at the same time")
         raise KickstartParseError(formatErrorMsg(self.lineno, msg=errorMsg), lineno=self.lineno)
     # the same applies to the 'mount' command
     if hasattr(self.handler, "mount") and self.handler.mount.seen:
         errorMsg = _("The raid and mount commands can't be used at the same time")
         raise KickstartParseError(formatErrorMsg(self.lineno, msg=errorMsg), lineno=self.lineno)
     return retval
示例#25
0
    def parse(self, args):
        (_ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if len(_ns.updates) > 1:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Kickstart command %s only takes one argument") % "updates"), lineno=self.lineno)
        elif extra:
            mapping = {"command": "updates", "options": extra}
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping), lineno=self.lineno)
        elif not _ns.updates:
            self.url = "floppy"
        else:
            self.url = _ns.updates[0]

        return self
示例#26
0
    def parse(self, args):
        (_ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if len(extra) > 1:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Kickstart command %s only takes one argument") % "updates"))
        elif any(arg for arg in extra if arg.startswith("-")):
            mapping = {"command": "updates", "options": extra}
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping))
        elif len(extra) == 0:
            self.url = "floppy"
        else:
            self.url = extra[0]

        return self
示例#27
0
    def parse(self, args):
        # call the overriden command to do its job first
        retval = F20_AutoPart.parse(self, args)

        # btrfs is not a valid filesystem type
        if self.fstype == "btrfs":
            raise KickstartParseError(formatErrorMsg(self.lineno,
                    msg=_("autopart --fstype=btrfs is not valid fstype, use --type=btrfs instead")))

        if self._typeAsStr() == "btrfs" and self.fstype:
            raise KickstartParseError(formatErrorMsg(self.lineno,
                    msg=_("autopart --fstype cannot be used with --type=btrfs")))

        return retval
示例#28
0
    def runTest(self):
        # For now, just verify that calling formatErrorMsg with no message
        # returns something.  Digging in and checking what the message is
        # when we could be running "make check" in another language is hard.

        # NOTE: formatErrorMsg is replaced with _format_error_message.
        self.assertNotEqual(_format_error_message(47), "")

        # Function formatErrorMsg is deprecated and returns its arguments now.
        with self.assertWarns(DeprecationWarning):
            self.assertEqual(formatErrorMsg(47), (47, ""))

        with self.assertWarns(DeprecationWarning):
            self.assertEqual(formatErrorMsg(47, "OH NO!"), (47, "OH NO!"))
示例#29
0
def _preprocessStateMachine (lineIter):
    l = None
    lineno = 0

    # Now open an output kickstart file that we are going to write to one
    # line at a time.
    (outF, outName) = tempfile.mkstemp("-ks.cfg", "", "/tmp")

    while True:
        try:
            l = next(lineIter)
        except StopIteration:
            break

        # At the end of the file?
        if l == "":
            break

        lineno += 1
        ksurl = None

        ll = l.strip()
        if not ll.startswith("%ksappend"):
            if six.PY3:
                import sys
                l = l.encode(sys.getdefaultencoding())
            os.write(outF, l)
            continue

        # Try to pull down the remote file.
        try:
            ksurl = ll.split(' ')[1]
        except:
            raise KickstartParseError(formatErrorMsg(lineno, msg=_("Illegal url for %%ksappend: %s") % ll))

        try:
            contents = load_to_str(ksurl)
        except KickstartError as e:
            raise KickstartError(formatErrorMsg(lineno, msg=_("Unable to open %%ksappend file: %s") % str(e)))

        # If that worked, write the remote file to the output kickstart
        # file in one burst.  Then close everything up to get ready to
        # read ahead in the input file.  This allows multiple %ksappend
        # lines to exist.
        if contents is not None:
            os.write(outF, contents)

    # All done - close the temp file and return its location.
    os.close(outF)
    return outName
示例#30
0
 def _parseArguments(self, string):
     if self.join_realm:
         raise KickstartParseError(formatErrorMsg(self.lineno, msg=_(
             "The realm command 'join' should only be specified once")))
     args = shlex.split(string)
     if not args:
         raise KickstartParseError(formatErrorMsg(self.lineno, msg=_(
             "Missing realm command arguments")))
     command = args.pop(0)
     if command == "join":
         self._parseJoin(args)
     else:
         raise KickstartParseError(formatErrorMsg(self.lineno, msg=_(
             "Unsupported realm '%s' command") % command))
示例#31
0
    def parse(self, args):
        # Using reqpart and autopart at the same time is not allowed.
        if self.handler.autopart.seen:
            errorMsg = _("The %s and reqpart commands can't be used at the same time") % \
                         "autopart"
            raise KickstartParseError(formatErrorMsg(self.lineno,
                                                     msg=errorMsg))

        (opts, _extra) = self.op.parse_args(args=args, lineno=self.lineno)
        self._setToSelf(self.op, opts)
        self.reqpart = True
        return self
示例#32
0
 def parse(self, args):
     # first call the overriden command
     retval = F12_Partition.parse(self, args)
     # the part command can't be used together with the autopart command
     # due to the hard to debug behavior their combination introduces
     if self.handler.autopart.seen:
         errorMsg = _(
             "The part/partition and autopart commands can't be used at the same time"
         )
         raise KickstartParseError(formatErrorMsg(self.lineno,
                                                  msg=errorMsg))
     return retval
示例#33
0
    def parse(self, args):
        if len(args) > 0:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not take any arguments") % self.currentCmd))

        if self.currentCmd == "cmdline":
            self.displayMode = DISPLAY_MODE_CMDLINE
        elif self.currentCmd == "graphical":
            self.displayMode = DISPLAY_MODE_GRAPHICAL
        elif self.currentCmd == "text":
            self.displayMode = DISPLAY_MODE_TEXT

        return self
示例#34
0
 def _parseArguments(self, string):
     if self.join_realm:
         raise KickstartParseError(
             formatErrorMsg(
                 self.lineno,
                 msg=_(
                     "The realm command 'join' should only be specified once"
                 )))
     args = shlex.split(string)
     if not args:
         raise KickstartParseError(
             formatErrorMsg(self.lineno,
                            msg=_("Missing realm command arguments")))
     command = args.pop(0)
     if command == "join":
         self._parseJoin(args)
     else:
         raise KickstartParseError(
             formatErrorMsg(self.lineno,
                            msg=_("Unsupported realm '%s' command") %
                            command))
示例#35
0
    def parse(self, args):
        # call the overriden command to do it's job first
        retval = F20_AutoPart.parse(self, args)

        # btrfs is not a valid filesystem type
        if self.fstype == "btrfs":
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno,
                    msg=
                    _("autopart --fstype=btrfs is not valid fstype, use --type=btrfs instead"
                      )))

        if self._typeAsStr() == "btrfs" and self.fstype:
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno,
                    msg=_(
                        "autopart --fstype cannot be used with --type=btrfs")))

        return retval
示例#36
0
    def parse(self, args):
        (_opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)

        if len(extra) > 0:
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno,
                    msg=_("Kickstart command %s does not take any arguments") %
                    "zerombr"))

        self.zerombr = True
        return self
示例#37
0
    def parse(self, args):
        (_opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)

        if len(extra) > 0:
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno,
                    msg=_("Kickstart command %s does not take any arguments") %
                    self.currentCmd))

        self.unsupported_hardware = True
        return self
示例#38
0
    def parse(self, args):
        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if len(extra) == 0:
            msg = _("Snapshot origin must be specified!")
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=msg))
        elif len(extra) > 1:
            msg = _("Snapshot origin can be specified only once!")
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=msg))

        snap_data = self.dataClass()   # pylint: disable=not-callable
        self.set_to_obj(ns, snap_data)
        snap_data.lineno = self.lineno
        snap_data.origin = extra[0]

        # Check for duplicates
        if snap_data.name in [snap.name for snap in self.dataList()]:
            msg = (_("Snapshot with the name %s has been already defined!") % snap_data.name)
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=msg))

        if snap_data.when is None:
            msg = _("Snapshot \"when\" parameter must be specified!")
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=msg))

        groups = snap_data.origin.split('/')
        if len(groups) != 2 or len(groups[0]) == 0 or len(groups[1]) == 0:
            msg = (_("Snapshot origin %s must be specified by VG/LV!") % snap_data.origin)
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=msg))

        # Check if value in a '--when' param is valid
        if snap_data.when != "" and snap_data.when not in self.whenMap.values():
            msg = (_("Snapshot when param must have one of these values %s!") % self.whenMap.keys())
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=msg))
        return snap_data
示例#39
0
    def parse(self, args):
        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if len(ns.partition) > 1:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Only one partition may be specified for driverdisk command.")), lineno=self.lineno)
        elif extra:
            mapping = {"command": "driverdisk", "options": extra}
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping), lineno=self.lineno)

        if len(ns.partition) == 1 and ns.source:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Only one of --source and partition may be specified for driverdisk command.")), lineno=self.lineno)
        elif len(ns.partition) == 1 and ns.biospart:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Only one of --biospart and partition may be specified for driverdisk command.")), lineno=self.lineno)
        elif ns.source and ns.biospart:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("Only one of --biospart and --source may be specified for driverdisk command.")), lineno=self.lineno)

        if not ns.partition and not ns.source and not ns.biospart:
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=_("One of --source, --biospart, or partition must be specified for driverdisk command.")), lineno=self.lineno)

        ddd = self.dataClass()  # pylint: disable=not-callable
        self.set_to_obj(ns, ddd)
        ddd.lineno = self.lineno
        if len(ns.partition) == 1:
            ddd.partition = ns.partition[0]

        return ddd
示例#40
0
    def parse(self, args):
        # call the overridden command to do it's job first
        retval = F21_Network.parse(self, args)

        # validate the network interface name
        error_message = validate_network_interface_name(retval.interfacename)
        # something is wrong with the interface name
        if error_message:
            raise KickstartParseError(
                formatErrorMsg(self.lineno, msg=error_message))

        if retval.bridgeopts:
            if not retval.bridgeslaves:
                msg = formatErrorMsg(
                    self.lineno,
                    msg=
                    _("Option --bridgeopts requires --bridgeslaves to be specified"
                      ))
                raise KickstartParseError(msg)
            opts = retval.bridgeopts.split(",")
            for opt in opts:
                _key, _sep, value = opt.partition("=")
                if not value or "=" in value:
                    msg = formatErrorMsg(
                        self.lineno,
                        msg=
                        _("Bad format of --bridgeopts, expecting key=value options separated by ','"
                          ))
                    raise KickstartParseError(msg)

        if retval.bindto == BIND_TO_MAC:
            if retval.vlanid and not retval.bondopts:
                msg = formatErrorMsg(
                    self.lineno,
                    msg=_(
                        "--bindto=%s is not supported for this type of device")
                    % BIND_TO_MAC)
                raise KickstartParseError(msg)

        return retval
示例#41
0
    def parse(self, args):
        (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
        if extra:
            mapping = {"command": "xconfig", "options": extra}
            raise KickstartValueError(
                formatErrorMsg(
                    self.lineno,
                    msg=
                    _("Unexpected arguments to %(command)s command: %(options)s"
                      ) % mapping))

        self._setToSelf(self.op, opts)
        return self
示例#42
0
    def parse(self, args):
        # first call the overriden method
        retval = FC3_VolGroup.parse(self, args)

        # Check that any reserved space options are in their valid ranges.
        if getattr(retval, "reserved_space",
                   None) and retval.reserved_space < 0:
            raise KickstartParseError(formatErrorMsg(
                self.lineno,
                msg="Volume group reserved space must be a positive integer."),
                                      lineno=self.lineno)

        if getattr(retval, "reserved_percent",
                   None) is not None and not 0 < retval.reserved_percent < 100:
            raise KickstartParseError(formatErrorMsg(
                self.lineno,
                msg=
                "Volume group reserved space percentage must be between 1 and 99."
            ),
                                      lineno=self.lineno)

        # the volgroup command can't be used together with the autopart command
        # due to the hard to debug behavior their combination introduces
        if self.handler.autopart.seen:
            errorMsg = _(
                "The volgroup and autopart commands can't be used at the same time"
            )
            raise KickstartParseError(formatErrorMsg(self.lineno,
                                                     msg=errorMsg),
                                      lineno=self.lineno)
        # the same applies to the 'mount' command
        if hasattr(self.handler, "mount") and self.handler.mount.seen:
            errorMsg = _(
                "The volgroup and mount commands can't be used at the same time"
            )
            raise KickstartParseError(formatErrorMsg(self.lineno,
                                                     msg=errorMsg),
                                      lineno=self.lineno)
        return retval
示例#43
0
    def parse(self, args):
        # first call the overriden command
        retval = F18_Partition.parse(self, args)
        # the part command can't be used together with the autopart command
        # due to the hard to debug behavior their combination introduces
        if self.handler.autopart.seen:
            errorMsg = _(
                "The part/partition and autopart commands can't be used at the same time"
            )
            raise KickstartParseError(formatErrorMsg(self.lineno,
                                                     msg=errorMsg))

        # when using tmpfs, grow is not suported
        if retval.fstype == "tmpfs":
            if retval.grow or retval.maxSizeMB != 0:
                errorMsg = _(
                    "The --fstype=tmpfs option can't be used together with --grow or --maxsize"
                )
                raise KickstartParseError(
                    formatErrorMsg(self.lineno, msg=errorMsg))

        return retval
示例#44
0
    def handleHeader(self, lineno, args):
        """Process the arguments to the %packages header and set attributes
           on the Version's Packages instance appropriate.  This method may be
           overridden in a subclass if necessary.
        """
        Section.handleHeader(self, lineno, args)
        op = self._getParser()
        ns = op.parse_args(args=args[1:], lineno=lineno)

        if ns.defaultPackages and ns.nobase:
            raise KickstartParseError(
                formatErrorMsg(
                    lineno,
                    msg=_("--default and --nobase cannot be used together")))
        elif ns.defaultPackages and ns.nocore:
            raise KickstartParseError(
                formatErrorMsg(
                    lineno,
                    msg=_("--default and --nocore cannot be used together")))

        self.handler.packages.excludeDocs = ns.excludedocs
        self.handler.packages.addBase = not ns.nobase
        if ns.ignoremissing:
            self.handler.packages.handleMissing = KS_MISSING_IGNORE
        else:
            self.handler.packages.handleMissing = KS_MISSING_PROMPT

        if ns.defaultPackages:
            self.handler.packages.default = True

        if ns.instLangs is not None:
            self.handler.packages.instLangs = ns.instLangs

        self.handler.packages.nocore = ns.nocore
        self.handler.packages.multiLib = ns.multiLib
        self.handler.packages.excludeWeakdeps = ns.excludeWeakdeps
        self.handler.packages.timeout = ns.timeout
        self.handler.packages.retries = ns.retries
        self.handler.packages.seen = True
示例#45
0
    def parse(self, args):
        (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
        self._setToSelf(self.op, opts)

        if len(extra) != 1:
            raise KickstartValueError(
                formatErrorMsg(
                    self.lineno,
                    msg=_("Kickstart command %s requires one argument") %
                    "mouse"))

        self.mouse = extra[0]
        return self
示例#46
0
    def parse(self, args):
        ns = self.op.parse_args(args=args, lineno=self.lineno)
        self.set_to_self(ns)
        if not self.remote:
            self.remote = self.osname

        if not self.url.startswith(("file:", "http:", "https:")):
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno,
                    msg="ostree repos must use file, HTTP or HTTPS protocol."))

        return self
示例#47
0
    def parse(self, args):
        (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
        self._setToSelf(self.op, opts)

        if len(extra) != 1:
            raise KickstartValueError(
                formatErrorMsg(
                    self.lineno,
                    msg=_("A single argument is expected for the %s command") %
                    "rootpw"))

        self.password = extra[0]
        return self
示例#48
0
    def parse(self, args):
        (opts, _extra) = self.op.parse_args(args=args, lineno=self.lineno)
        self._setToSelf(self.op, opts)
        if self.remote is None:
            self.remote = self.osname

        if not self.url.startswith(("http:", "https:")):
            raise KickstartValueError(
                formatErrorMsg(
                    self.lineno,
                    msg="ostree repos must use HTTP or HTTPS protocol."))

        return self
示例#49
0
    def parse(self, args):
        (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
        data = self.handler.BTRFSData()
        self._setToObj(self.op, opts, data)
        data.lineno = self.lineno

        if len(extra) == 0:
            raise KickstartValueError(
                formatErrorMsg(self.lineno,
                               msg=_("btrfs must be given a mountpoint")))

        if len(extra) == 1 and not data.subvol:
            raise KickstartValueError(
                formatErrorMsg(
                    self.lineno,
                    msg=_("btrfs must be given a list of partitions")))
        elif len(extra) == 1:
            raise KickstartValueError(
                formatErrorMsg(
                    self.lineno,
                    msg=_(
                        "btrfs subvol requires specification of parent volume")
                ))

        if data.subvol and not data.name:
            raise KickstartValueError(
                formatErrorMsg(self.lineno,
                               msg=_("btrfs subvolume requires a name")))

        data.mountpoint = extra[0]
        data.devices = extra[1:]

        # Check for duplicates in the data list.
        if data in self.dataList():
            warnings.warn(
                _("A btrfs volume with the mountpoint %s has already been defined."
                  ) % data.label)

        return data
示例#50
0
def preprocessKickstart(f):
    """Preprocess the kickstart file, given by the filename file.  This
        method is currently only useful for handling %ksappend lines,
        which need to be fetched before the real kickstart parser can be
        run.  Returns the location of the complete kickstart file.
    """
    try:
        fh = grabber.urlopen(f)
    except grabber.URLGrabError, e:
        raise KickstartError(
            formatErrorMsg(0,
                           msg=_("Unable to open input kickstart file: %s") %
                           e.strerror))
示例#51
0
    def parse(self, args):
        ns = self.op.parse_args(args=args, lineno=self.lineno)
        self.set_to_self(ns)

        if self.biospart is None and self.partition is None or \
           self.biospart is not None and self.partition is not None:
            raise KickstartParseError(formatErrorMsg(
                self.lineno,
                msg=_("One of biospart or partition options must be specified."
                      )),
                                      lineno=self.lineno)

        return self
示例#52
0
    def parse(self, args):
        (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
        self._setToSelf(self.op, opts)

        # just "timezone" without any arguments and timezone specification doesn't really make sense,
        # so throw an error when we see it (it might even be an indication of an incorrect machine generated kickstart)
        if not args:
            error_message = _(
                "At least one option and/or an argument are expected for the  %s command"
            ) % "timezone"
            raise KickstartParseError(
                formatErrorMsg(self.lineno, msg=error_message))

        # To be able to support the timezone command being used without
        # a timezone specification:
        # - we don't call the parse() method of the ancestors
        # -> due to the FC3 parse() method that would be eventually called,
        #    which throws an exception if no timezone specification is provided
        # - we implement the relevant functionality of the ancestor methods here

        if len(extra) > 1:
            error_message = _(
                "One or zero arguments are expected for the %s command"
            ) % "timezone"
            raise KickstartValueError(
                formatErrorMsg(self.lineno, msg=error_message))

        if len(extra) > 0:
            self.timezone = extra[0]

        if self.ntpservers and self.nontp:
            msg = formatErrorMsg(
                self.lineno,
                msg=_(
                    "Options --nontp and --ntpservers are mutually exclusive"))
            raise KickstartParseError(msg)

        return self
示例#53
0
    def parse(self, args):
        # call the overriden command to do its job first
        retval = F21_AutoPart.parse(self, args)

        conflicting_command = ""
        if hasattr(self.handler, "reqpart") and self.handler.reqpart.seen:
            conflicting_command = "reqpart"

        if conflicting_command:
            # allow for translation of the error message
            errorMsg = _("The %s and autopart commands can't be used at the same time") % conflicting_command
            raise KickstartParseError(formatErrorMsg(self.lineno, msg=errorMsg))

        return retval
示例#54
0
    def parse(self, args):
        (_ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if len(_ns.updates) > 1:
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno,
                    msg=_("Kickstart command %s only takes one argument") %
                    "updates"))
        elif extra:
            mapping = {"command": "updates", "options": extra}
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno,
                    msg=
                    _("Unexpected arguments to %(command)s command: %(options)s"
                      ) % mapping))
        elif not _ns.updates:
            self.url = "floppy"
        else:
            self.url = _ns.updates[0]

        return self
示例#55
0
    def check_values(self, values, args):
        def seen(option):
            return option in self.option_seen

        def usedTooNew(option):
            return option.introduced and option.introduced > self.version

        def usedDeprecated(option):
            return option.deprecated

        def usedRemoved(option):
            return option.removed and option.removed <= self.version

        for option in [o for o in self.option_list if isinstance(o, Option)]:
            if option.required and not seen(option):
                raise KickstartValueError(
                    formatErrorMsg(self.lineno,
                                   _("Option %s is required") % option))
            elif seen(option) and usedTooNew(option):
                mapping = {
                    "option": option,
                    "intro": versionToString(option.introduced),
                    "version": versionToString(self.version)
                }
                self.error(
                    _("The %(option)s option was introduced in version %(intro)s, but you are using kickstart syntax version %(version)s."
                      ) % mapping)
            elif seen(option) and usedRemoved(option):
                mapping = {
                    "option": option,
                    "removed": versionToString(option.removed),
                    "version": versionToString(self.version)
                }

                if option.removed == self.version:
                    self.error(
                        _("The %(option)s option is no longer supported.") %
                        mapping)
                else:
                    self.error(
                        _("The %(option)s option was removed in version %(removed)s, but you are using kickstart syntax version %(version)s."
                          ) % mapping)
            elif seen(option) and usedDeprecated(
                    option) and self.version >= option.deprecated:
                mapping = {"lineno": self.lineno, "option": option}
                warnings.warn(
                    _("Ignoring deprecated option on line %(lineno)s:  The %(option)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."
                      ) % mapping, DeprecationWarning)

        return (values, args)
示例#56
0
    def parse(self, args):
        ns = self.op.parse_args(args=args, lineno=self.lineno)
        self.set_to_self(ns)

        if self.port and not self.host:
            raise KickstartParseError(
                formatErrorMsg(self.lineno,
                               msg=_("Can't specify --port without --host.")))

        self._levelProvided = self.level != ""
        if not self._levelProvided:
            self.level = "info"

        return self
示例#57
0
    def parse(self, args):
        (opts, _extra) = self.op.parse_args(args=args, lineno=self.lineno)
        self._setToSelf(self.op, opts)

        if self.biospart is None and self.partition is None or \
           self.biospart is not None and self.partition is not None:
            raise KickstartValueError(
                formatErrorMsg(
                    self.lineno,
                    msg=
                    _("One of biospart or partition options must be specified."
                      )))

        return self
示例#58
0
    def parse(self, args):
        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)
        self.set_to_self(ns)

        if len(extra) != 1 and not self.lock:
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno,
                    msg=_("A single argument is expected for the %s command") %
                    "rootpw"))
        elif any(arg for arg in extra if arg.startswith("-")):
            mapping = {"command": "rootpw", "options": extra}
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno,
                    msg=
                    _("Unexpected arguments to %(command)s command: %(options)s"
                      ) % mapping))

        if len(extra) == 1:
            self.password = extra[0]

        return self
示例#59
0
    def parse(self, args):
        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)
        if any(arg for arg in extra if arg.startswith("-")):
            mapping = {"command": "langsupport", "options": extra}
            raise KickstartParseError(formatErrorMsg(
                self.lineno,
                msg=_(
                    "Unexpected arguments to %(command)s command: %(options)s")
                % mapping),
                                      lineno=self.lineno)

        self.set_to_self(ns)
        self.supported = extra
        return self
示例#60
0
    def parse(self, args):
        (ns, extra) = self.op.parse_known_args(args=args, lineno=self.lineno)

        if len(extra) != 2:
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno,
                    msg=
                    _("device command requires two arguments: module type and name"
                      )))
        elif any(arg for arg in extra if arg.startswith("-")):
            mapping = {"command": "device", "options": extra}
            raise KickstartParseError(
                formatErrorMsg(
                    self.lineno,
                    msg=
                    _("Unexpected arguments to %(command)s command: %(options)s"
                      ) % mapping))

        self.moduleOpts = ns.moduleOpts
        self.type = extra[0]
        self.moduleName = extra[1]
        return self