Esempio n. 1
0
    def load_candidate_config(self, filename=None, config=None):
        """
        Load candidate confguration.

        Populate the attribute candidate_config with the desired
        configuration and loads it into the router. You can populate it from
        a file or from a string. If you send both a filename and a string
        containing the configuration, the file takes precedence.

        :param filename:  Path to the file containing the desired
                          configuration. By default is None.
        :param config:    String containing the desired configuration.
        """
        configuration = ""

        if filename is None:
            configuration = config
        else:
            with open(filename) as f:
                configuration = f.read()

        rpc_command = (
            "<CLI><Configuration>{configuration}</Configuration></CLI>".format(
                configuration=escape_xml(
                    configuration
                )  # need to escape, otherwise will try to load invalid XML
            ))

        try:
            self._execute_rpc(rpc_command)
        except InvalidInputError as e:
            self.discard_config()
            raise InvalidInputError(e.args[0], self)
Esempio n. 2
0
    def commit_replace_config(self, label=None, comment=None, confirmed=None):
        """
        Commit the candidate config to the device, by replacing the existing one.

        :param comment:   User comment saved on this commit on the device
        :param label:     User label saved on this commit on the device
        :param confirmed: Commit with auto-rollback if new commit is not made in 30 to 300 sec
        """
        rpc_command = '<Commit Replace="true"'
        if label:
            rpc_command += ' Label="%s"' % label
        if comment:
            rpc_command += ' Comment="%s"' % comment
        if confirmed:
            if 30 <= int(confirmed) <= 300:
                rpc_command += ' Confirmed="%d"' % int(confirmed)
            else:
                raise InvalidInputError(
                    "confirmed needs to be between 30 and 300 seconds", self)
        rpc_command += "/>"
        self._execute_rpc(rpc_command)
Esempio n. 3
0
    def commit_config(self, label=None, comment=None, confirmed=None):
        """
        Commit the candidate config.

        :param label:     Commit comment, displayed in the commit entry on the device.
        :param comment:   Commit label, displayed instead of the commit ID on the device.
                          (Max 60 characters)
        :param confirmed: Commit with auto-rollback if new commit is not made in 30 to 300 sec
        """
        rpc_command = "<Commit"
        if label:
            rpc_command += ' Label="%s"' % label
        if comment:
            rpc_command += ' Comment="%s"' % comment[:60]
        if confirmed:
            if 30 <= int(confirmed) <= 300:
                rpc_command += ' Confirmed="%d"' % int(confirmed)
            else:
                raise InvalidInputError(
                    "confirmed needs to be between 30 and 300 seconds", self)
        rpc_command += "/>"

        self._execute_rpc(rpc_command)
Esempio n. 4
0
    def _execute_rpc(self, command_xml, delay_factor=0.1):

        xml_rpc_command = (
            '<?xml version="1.0" encoding="UTF-8"?><Request MajorVersion="1" MinorVersion="0">'
            + command_xml + "</Request>")

        response = self._send_command(xml_rpc_command,
                                      delay_factor=delay_factor)

        try:
            root = ET.fromstring(str.encode(response))
        except ET.XMLSyntaxError:
            if 'IteratorID="' in response:
                logger.error(self._ITERATOR_ID_ERROR_MSG)
                raise IteratorIDError(self._ITERATOR_ID_ERROR_MSG, self)
            raise InvalidXMLResponse(
                "Unable to process the XML Response from the device!", self)

        if "IteratorID" in root.attrib:
            logger.error(self._ITERATOR_ID_ERROR_MSG)
            raise IteratorIDError(self._ITERATOR_ID_ERROR_MSG, self)

        childs = [x.tag for x in list(root)]

        result_summary = root.find("ResultSummary")

        if result_summary is not None and int(
                result_summary.get("ErrorCount", 0)) > 0:

            if "CLI" in childs:
                error_msg = root.find("CLI").get("ErrorMsg") or ""
            elif "Commit" in childs:
                error_msg = root.find("Commit").get("ErrorMsg") or ""
                error_code = root.find("Commit").get("ErrorCode") or ""
                if error_code == "0x41866c00":
                    # yet another pointless IOS-XR error:
                    # if the config DB was changed by another process,
                    # while the current SSH connection is established and alive,
                    # we won't be able to commit and the device will throw the following error:
                    # 'CfgMgr' detected the 'warning' condition
                    # 'One or more commits have occurred from other configuration sessions since
                    # this session started or since the last commit was made from this session.'
                    # in this case we need to re-open the connection with the XML agent
                    _candidate_config = self.get_candidate_config(merge=True)
                    self.discard_config()  # discard candidate config
                    try:
                        # exiting from the XML mode
                        self._send_command("exit",
                                           expect_string=self._cli_prompt)
                    except XMLCLIError:
                        pass  # because does not end with `XML>`
                    self._enter_xml_mode()  # re-entering XML mode
                    self.load_candidate_config(config=_candidate_config)
                    return self.commit_config()
                elif error_code == "0x41864e00" or error_code == "0x43682c00":
                    # raises this error when the commit buffer is empty
                    raise CommitError(
                        "The target configuration buffer is empty.", self)

            else:
                error_msg = root.get("ErrorMsg") or ""

            error_msg += "\nOriginal call was: %s" % xml_rpc_command
            logger.error(error_msg)
            raise XMLCLIError(error_msg, self)

        if "CLI" in childs:
            cli_childs = [x.tag for x in list(root.find("CLI"))]
            if "Configuration" in cli_childs:
                output = root.find("CLI").find("Configuration").text
            elif "Exec" in cli_childs:
                output = root.find("CLI").find("Exec").text
            if output is None:
                output = ""
            elif "Invalid input detected" in output:
                logger.error("Invalid input entered:\n%s" % (output))
                raise InvalidInputError("Invalid input entered:\n%s" % output,
                                        self)

        return root