コード例 #1
0
def test_response_init(response_setup):
    netconf_version = response_setup[0]
    channel_input = response_setup[1]
    xml_input = etree.fromstring(text=channel_input)
    response = NetconfResponse(
        host="localhost",
        channel_input=channel_input,
        xml_input=xml_input,
        netconf_version=netconf_version,
        failed_when_contains=[b"<rpc-error>"],
    )
    response_start_time = str(datetime.now())[:-7]
    assert response.host == "localhost"
    assert response.channel_input == "<something/>"
    assert response.xml_input == xml_input
    assert str(response.start_time)[:-7] == response_start_time
    assert response.failed is True
    assert bool(response) is True
    assert (
        repr(response) ==
        "NetconfResponse(host='localhost',channel_input='<something/>',textfsm_platform='',genie_platform='',failed_when_contains=[b'<rpc-error>'])"
    )
    assert str(response) == "NetconfResponse <Success: False>"
    assert response.failed_when_contains == [b"<rpc-error>"]
    with pytest.raises(ScrapliCommandFailure):
        response.raise_for_status()
コード例 #2
0
def test_failed_when_contains_default_values(response_data):
    response_output = response_data[0]
    response_success = response_data[1]

    channel_input = "<something/>"
    xml_input = etree.fromstring(text=channel_input)
    response = NetconfResponse(
        host="localhost",
        channel_input=channel_input,
        xml_input=xml_input,
        netconf_version=NetconfVersion.VERSION_1_0,
    )
    response.record_response(result=response_output)
    assert response.failed is not response_success
コード例 #3
0
def test_parse_error_messages(response_data):
    response_output = response_data[0]
    expected_errors = response_data[1]

    channel_input = "<something/>"
    xml_input = etree.fromstring(text=channel_input)
    response = NetconfResponse(
        host="localhost",
        channel_input=channel_input,
        xml_input=xml_input,
        netconf_version=NetconfVersion.VERSION_1_1,
    )
    response.record_response(result=response_output.encode())
    assert response.error_messages == expected_errors
コード例 #4
0
    def _pre_discard(self) -> NetconfResponse:
        """
        Handle pre "discard" tasks for consistency between sync/async versions

        Args:
            N/A

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug("Building payload for 'discard' operation.")
        xml_request = self._build_base_elem()
        xml_commit_element = etree.fromstring(
            NetconfBaseOperations.DISCARD.value, parser=self.xml_parser)
        xml_request.insert(0, xml_commit_element)

        channel_input = self._finalize_channel_input(xml_request=xml_request)

        response = NetconfResponse(
            host=self.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for 'discard' operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #5
0
def test__validate_chunk_size_netconf_1_1(response_data):
    chunk_input = response_data[0]
    response_success = response_data[1]

    channel_input = "<something/>"
    xml_input = etree.fromstring(text=channel_input)
    response = NetconfResponse(
        host="localhost",
        channel_input=channel_input,
        xml_input=xml_input,
        netconf_version=NetconfVersion.VERSION_1_1,
        failed_when_contains=[b"<rpc-error>"],
    )
    # set response.failed because we are skipping "record_response"
    response.failed = False
    response._validate_chunk_size_netconf_1_1(result=chunk_input)
    assert response.failed is not response_success
コード例 #6
0
    def _pre_edit_config(self,
                         config: Union[str, List[str]],
                         target: str = "running") -> NetconfResponse:
        """
        Handle pre "edit_config" tasks for consistency between sync/async versions

        Args:
            config: configuration to send to device
            target: configuration source to target; running|startup|candidate

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug(
            f"Building payload for `get-config` operation. target: {target}, config: {config}"
        )
        self._validate_edit_config_target(target=target)

        # build config first to ensure valid xml
        xml_config = etree.fromstring(config)

        # build base request and insert the edit-config element
        xml_request = self._build_base_elem()
        xml_edit_config_element = etree.fromstring(
            NetconfBaseOperations.EDIT_CONFIG.value.format(target=target))
        xml_request.insert(0, xml_edit_config_element)

        # insert parent filter element to first position so that target stays first just for nice
        # output/readability
        edit_config_element = xml_request.find("edit-config")
        edit_config_element.insert(1, xml_config)

        channel_input = etree.tostring(element_or_tree=xml_request,
                                       xml_declaration=True,
                                       encoding="utf-8")

        if self.netconf_version == NetconfVersion.VERSION_1_0:
            channel_input = channel_input + b"\n]]>]]>"

        response = NetconfResponse(
            host=self.transport.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for `edit-config` operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #7
0
    def _pre_get(self,
                 filter_: str,
                 filter_type: str = "subtree") -> NetconfResponse:
        """
        Handle pre "get" tasks for consistency between sync/async versions

        Args:
            filter_: string filter to apply to the get
            filter_type: type of filter; subtree|xpath

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug(
            f"Building payload for `get` operation. filter_type: {filter_type}, filter_: {filter_}"
        )

        # build base request and insert the get element
        xml_request = self._build_base_elem()
        xml_get_element = etree.fromstring(NetconfBaseOperations.GET.value)
        xml_request.insert(0, xml_get_element)

        xml_filter_elem = self._build_filters(filters=[filter_],
                                              filter_type=filter_type)

        # insert filter element into parent get element
        get_element = xml_request.find("get")
        get_element.insert(0, xml_filter_elem)

        channel_input = etree.tostring(element_or_tree=xml_request,
                                       xml_declaration=True,
                                       encoding="utf-8")

        if self.netconf_version == NetconfVersion.VERSION_1_0:
            channel_input = channel_input + b"\n]]>]]>"

        response = NetconfResponse(
            host=self.transport.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for `get` operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #8
0
def test_record_response(response_setup):
    netconf_version = response_setup[0]
    strip_namespaces = response_setup[1]
    channel_input = response_setup[2]
    result = response_setup[3]
    final_result = response_setup[4]
    xml_elements = response_setup[5]
    xml_input = etree.fromstring(text=channel_input)
    response_end_time = str(datetime.now())[:-7]
    response = NetconfResponse(
        host="localhost",
        channel_input=channel_input,
        xml_input=xml_input,
        netconf_version=netconf_version,
        failed_when_contains=[b"<rpc-error>"],
        strip_namespaces=strip_namespaces,
    )
    response.record_response(result=result.encode())
    assert str(response.finish_time)[:-7] == response_end_time
    assert response.result == final_result
    assert response.failed is False
    assert list(response.get_xml_elements().keys()) == xml_elements
コード例 #9
0
def test_response_init_exception():
    netconf_version = "blah"
    channel_input = "<something/>"
    xml_input = etree.fromstring(text=channel_input)
    with pytest.raises(ValueError) as exc:
        NetconfResponse(
            host="localhost",
            channel_input=channel_input,
            xml_input=xml_input,
            netconf_version=netconf_version,
            failed_when_contains=[b"<rpc-error>"],
        )
    assert str(exc.value) == "`netconf_version` should be one of 1.0|1.1, got `blah`"
コード例 #10
0
def test_response_not_implemented_exceptions(method_to_test):
    channel_input = "<something/>"
    xml_input = etree.fromstring(text=channel_input)
    response = NetconfResponse(
        host="localhost",
        channel_input=channel_input,
        xml_input=xml_input,
        netconf_version=NetconfVersion.VERSION_1_0,
        failed_when_contains=[b"<rpc-error>"],
    )
    method = getattr(response, f"{method_to_test}_parse_output")
    with pytest.raises(NotImplementedError) as exc:
        method()
    assert str(exc.value) == f"No {method_to_test} parsing for netconf output!"
コード例 #11
0
    def _pre_validate(self, source: str) -> NetconfResponse:
        """
        Handle pre "validate" tasks for consistency between sync/async versions

        Args:
            source: configuration source to validate; typically one of running|startup|candidate

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            CapabilityNotSupported: if 'validate' capability does not exist

        """
        self.logger.debug("Building payload for 'validate' operation.")

        if not any(cap in self.server_capabilities for cap in (
                "urn:ietf:params:netconf:capability:validate:1.0",
                "urn:ietf:params:netconf:capability:validate:1.1",
        )):
            msg = "validate requested, but is not supported by the server"
            self.logger.exception(msg)
            raise CapabilityNotSupported(msg)

        self._validate_edit_config_target(target=source)

        xml_request = self._build_base_elem()
        xml_validate_element = etree.fromstring(
            NetconfBaseOperations.VALIDATE.value.format(source=source),
            parser=PARSER)
        xml_request.insert(0, xml_validate_element)
        channel_input = etree.tostring(element_or_tree=xml_request,
                                       xml_declaration=True,
                                       encoding="utf-8")

        if self.netconf_version == NetconfVersion.VERSION_1_0:
            channel_input = channel_input + b"\n]]>]]>"

        response = NetconfResponse(
            host=self.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for 'validate' operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #12
0
    def _pre_edit_config(self,
                         config: str,
                         target: str = "running") -> NetconfResponse:
        """
        Handle pre "edit_config" tasks for consistency between sync/async versions

        Args:
            config: configuration to send to device
            target: configuration source to target; running|startup|candidate

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug(
            f"Building payload for 'edit-config' operation. target: {target}, config: {config}"
        )
        self._validate_edit_config_target(target=target)

        xml_config = etree.fromstring(config, parser=self.xml_parser)

        # build base request and insert the edit-config element
        xml_request = self._build_base_elem()
        xml_edit_config_element = etree.fromstring(
            NetconfBaseOperations.EDIT_CONFIG.value.format(target=target))
        xml_request.insert(0, xml_edit_config_element)

        # insert parent filter element to first position so that target stays first just for nice
        # output/readability
        edit_config_element = xml_request.find("edit-config")
        edit_config_element.insert(1, xml_config)

        channel_input = self._finalize_channel_input(xml_request=xml_request)

        response = NetconfResponse(
            host=self.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for 'edit-config' operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #13
0
    def _pre_copy_config(self, source: str, target: str) -> NetconfResponse:
        """
        Handle pre "copy_config" tasks for consistency between sync/async versions

        Note that source is not validated/checked since it could be a url or a full configuration
        element itself.

        Args:
            source: configuration, url, or datastore to copy into the target datastore
            target: copy config destination/target; typically one of running|startup|candidate

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug("Building payload for 'copy_config' operation.")

        self._validate_edit_config_target(target=target)

        xml_request = self._build_base_elem()
        xml_validate_element = etree.fromstring(
            NetconfBaseOperations.COPY_CONFIG.value.format(source=source,
                                                           target=target),
            parser=self.xml_parser,
        )
        xml_request.insert(0, xml_validate_element)

        channel_input = self._finalize_channel_input(xml_request=xml_request)

        response = NetconfResponse(
            host=self.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for 'copy-config' operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #14
0
    def _pre_delete_config(self, target: str = "running") -> NetconfResponse:
        """
        Handle pre "edit_config" tasks for consistency between sync/async versions

        Args:
            target: configuration source to target; startup|candidate

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug(
            f"Building payload for 'delete-config' operation. target: {target}"
        )
        self._validate_delete_config_target(target=target)

        xml_request = self._build_base_elem()
        xml_validate_element = etree.fromstring(
            NetconfBaseOperations.DELETE_CONFIG.value.format(target=target),
            parser=PARSER)
        xml_request.insert(0, xml_validate_element)
        channel_input = etree.tostring(element_or_tree=xml_request,
                                       xml_declaration=True,
                                       encoding="utf-8")

        if self.netconf_version == NetconfVersion.VERSION_1_0:
            channel_input = channel_input + b"\n]]>]]>"

        response = NetconfResponse(
            host=self.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for 'delete-config' operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #15
0
    def _pre_rpc(self, filter_: str) -> NetconfResponse:
        """
        Handle pre "rpc" tasks for consistency between sync/async versions

        Args:
            filter_: filter/rpc to execute

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug("Building payload for `rpc` operation.")
        xml_request = self._build_base_elem()

        # build filter element
        xml_filter_elem = etree.fromstring(filter_)

        # insert filter element
        xml_request.insert(0, xml_filter_elem)

        channel_input = etree.tostring(element_or_tree=xml_request,
                                       xml_declaration=True,
                                       encoding="utf-8")

        if self.netconf_version == NetconfVersion.VERSION_1_0:
            channel_input = channel_input + b"\n]]>]]>"

        response = NetconfResponse(
            host=self.transport.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for `rpc` operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #16
0
    def _pre_rpc(self, filter_: Union[str, _Element]) -> NetconfResponse:
        """
        Handle pre "rpc" tasks for consistency between sync/async versions

        Args:
            filter_: filter/rpc to execute

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug("Building payload for 'rpc' operation.")
        xml_request = self._build_base_elem()

        # build filter element
        if isinstance(filter_, str):
            xml_filter_elem = etree.fromstring(filter_, parser=self.xml_parser)
        else:
            xml_filter_elem = filter_

        # insert filter element
        xml_request.insert(0, xml_filter_elem)

        channel_input = self._finalize_channel_input(xml_request=xml_request)

        response = NetconfResponse(
            host=self.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for 'rpc' operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #17
0
    def _pre_discard(self) -> NetconfResponse:
        """
        Handle pre "discard" tasks for consistency between sync/async versions

        Args:
            N/A

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug("Building payload for `discard` operation.")
        xml_request = self._build_base_elem()
        xml_commit_element = etree.fromstring(
            NetconfBaseOperations.DISCARD.value)
        xml_request.insert(0, xml_commit_element)
        channel_input = etree.tostring(element_or_tree=xml_request,
                                       xml_declaration=True,
                                       encoding="utf-8")

        if self.netconf_version == NetconfVersion.VERSION_1_0:
            channel_input = channel_input + b"\n]]>]]>"

        response = NetconfResponse(
            host=self.transport.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for `discard` operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #18
0
    def _pre_unlock(self, target: str) -> NetconfResponse:
        """
        Handle pre "unlock" tasks for consistency between sync/async versions

        Args:
            target: configuration source to target; running|startup|candidate

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug("Building payload for 'unlock' operation.")
        self._validate_edit_config_target(target=target)

        xml_request = self._build_base_elem()
        xml_lock_element = etree.fromstring(
            NetconfBaseOperations.UNLOCK.value.format(target=target,
                                                      parser=self.xml_parser))
        xml_request.insert(0, xml_lock_element)

        channel_input = self._finalize_channel_input(xml_request=xml_request)

        response = NetconfResponse(
            host=self.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for 'unlock' operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #19
0
    def _pre_commit(self) -> NetconfResponse:
        """
        Handle pre "commit" tasks for consistency between sync/async versions

        Args:
            N/A

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug("Building payload for 'commit' operation")
        xml_request = self._build_base_elem()
        xml_commit_element = etree.fromstring(
            NetconfBaseOperations.COMMIT.value, parser=PARSER)
        xml_request.insert(0, xml_commit_element)
        channel_input = etree.tostring(xml_request)

        if self.netconf_version == NetconfVersion.VERSION_1_0:
            channel_input = channel_input + b"\n]]>]]>"

        response = NetconfResponse(
            host=self.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for 'commit' operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #20
0
def test_raise_for_status(response_data):
    response_output = response_data[0]
    expected_errors = response_data[1]

    channel_input = "<something/>"
    xml_input = etree.fromstring(text=channel_input)
    response = NetconfResponse(
        host="localhost",
        channel_input=channel_input,
        xml_input=xml_input,
        netconf_version=NetconfVersion.VERSION_1_1,
    )
    response.record_response(result=response_output.encode())

    if not expected_errors:
        assert not response.error_messages
        return

    with pytest.raises(ScrapliCommandFailure) as exc:
        response.raise_for_status()

    assert str(exc.value
               ) == f"operation failed, reported rpc errors: {expected_errors}"
コード例 #21
0
    def _pre_get_config(
        self,
        source: str = "running",
        filters: Optional[Union[str, List[str]]] = None,
        filter_type: str = "subtree",
    ) -> NetconfResponse:
        """
        Handle pre "get_config" tasks for consistency between sync/async versions

        Args:
            source: configuration source to get; typically one of running|startup|candidate
            filters: string or list of strings of filters to apply to configuration
            filter_type: type of filter; subtree|xpath

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug(
            f"Building payload for `get-config` operation. source: {source}, filter_type: "
            f"{filter_type}, filters: {filters}")
        self._validate_get_config_target(source=source)

        # build base request and insert the get-config element
        xml_request = self._build_base_elem()
        xml_get_config_element = etree.fromstring(
            NetconfBaseOperations.GET_CONFIG.value.format(source=source))
        xml_request.insert(0, xml_get_config_element)

        if filters is not None:
            if isinstance(filters, str):
                filters = [filters]
            xml_filter_elem = self._build_filters(filters=filters,
                                                  filter_type=filter_type)
            # insert filter element into parent get element
            get_element = xml_request.find("get-config")
            # insert *after* source, otherwise juniper seems to gripe, maybe/probably others as well
            get_element.insert(1, xml_filter_elem)

        channel_input = etree.tostring(element_or_tree=xml_request,
                                       xml_declaration=True,
                                       encoding="utf-8")

        if self.netconf_version == NetconfVersion.VERSION_1_0:
            channel_input = channel_input + b"\n]]>]]>"

        response = NetconfResponse(
            host=self.transport.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for `get-config` operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #22
0
    def _pre_commit(
        self,
        confirmed: bool = False,
        timeout: Optional[int] = None,
        persist: Optional[Union[int, str]] = None,
        persist_id: Optional[Union[int, str]] = None,
    ) -> NetconfResponse:
        """
        Handle pre "commit" tasks for consistency between sync/async versions

        Args:
            confirmed: whether this is a confirmed commit
            timeout: specifies the confirm timeout in seconds
            persist: make the confirmed commit survive a session termination, and set a token on
                the ongoing confirmed commit
            persist_id: value must be equal to the value given in the <persist> parameter to the
                original <commit> operation.

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            ScrapliValueError: if persist and persist_id are provided (cannot combine)
            ScrapliValueError: if confirmed and persist_id are provided (cannot combine)
            CapabilityNotSupported: if device does not have confirmed-commit capability

        """
        self.logger.debug("Building payload for 'commit' operation")
        xml_request = self._build_base_elem()
        xml_commit_element = etree.fromstring(
            NetconfBaseOperations.COMMIT.value, parser=self.xml_parser)

        if persist and persist_id:
            raise ScrapliValueError(
                "Invalid combination - 'persist' cannot be present with 'persist-id'"
            )
        if confirmed and persist_id:
            raise ScrapliValueError(
                "Invalid combination - 'confirmed' cannot be present with 'persist-id'"
            )

        if confirmed or persist_id:
            if not any(cap in self.server_capabilities for cap in (
                    "urn:ietf:params:netconf:capability:confirmed-commit:1.0",
                    "urn:ietf:params:netconf:capability:confirmed-commit:1.1",
            )):
                msg = "confirmed-commit requested, but is not supported by the server"
                self.logger.exception(msg)
                raise CapabilityNotSupported(msg)

        if confirmed:
            xml_confirmed_element = etree.fromstring(
                NetconfBaseOperations.COMMIT_CONFIRMED.value,
                parser=self.xml_parser)
            xml_commit_element.append(xml_confirmed_element)

            if timeout is not None:
                xml_timeout_element = etree.fromstring(
                    NetconfBaseOperations.COMMIT_CONFIRMED_TIMEOUT.value.
                    format(timeout=timeout),
                    parser=self.xml_parser,
                )
                xml_commit_element.append(xml_timeout_element)

            if persist is not None:
                xml_persist_element = etree.fromstring(
                    NetconfBaseOperations.COMMIT_CONFIRMED_PERSIST.value.
                    format(persist=persist),
                    parser=self.xml_parser,
                )
                xml_commit_element.append(xml_persist_element)

        if persist_id is not None:
            xml_persist_id_element = etree.fromstring(
                NetconfBaseOperations.COMMIT_PERSIST_ID.value.format(
                    persist_id=persist_id),
                parser=self.xml_parser,
            )
            xml_commit_element.append(xml_persist_id_element)

        xml_request.insert(0, xml_commit_element)

        channel_input = self._finalize_channel_input(xml_request=xml_request)

        response = NetconfResponse(
            host=self.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for 'commit' operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #23
0
    def _pre_get_config(
        self,
        source: str = "running",
        filter_: Optional[str] = None,
        filter_type: str = "subtree",
        default_type: Optional[str] = None,
    ) -> NetconfResponse:
        """
        Handle pre "get_config" tasks for consistency between sync/async versions

        Args:
            source: configuration source to get; typically one of running|startup|candidate
            filter_: string of filter(s) to apply to configuration
            filter_type: type of filter; subtree|xpath
            default_type: string of with-default mode to apply when retrieving configuration

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug(
            f"Building payload for 'get-config' operation. source: {source}, filter_type: "
            f"{filter_type}, filter: {filter_}, default_type: {default_type}")
        self._validate_get_config_target(source=source)

        # build base request and insert the get-config element
        xml_request = self._build_base_elem()
        xml_get_config_element = etree.fromstring(
            NetconfBaseOperations.GET_CONFIG.value.format(source=source),
            parser=self.xml_parser)
        xml_request.insert(0, xml_get_config_element)

        if filter_ is not None:
            xml_filter_elem = self._build_filter(filter_=filter_,
                                                 filter_type=filter_type)
            # insert filter element into parent get element
            get_element = xml_request.find("get-config")
            # insert *after* source, otherwise juniper seems to gripe, maybe/probably others as well
            get_element.insert(1, xml_filter_elem)

        if default_type is not None:
            xml_with_defaults_elem = self._build_with_defaults(
                default_type=default_type)
            get_element = xml_request.find("get-config")
            get_element.insert(2, xml_with_defaults_elem)

        channel_input = self._finalize_channel_input(xml_request=xml_request)

        response = NetconfResponse(
            host=self.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for 'get-config' operation. Payload: {channel_input.decode()}"
        )
        return response
コード例 #24
0
    def _pre_get(self,
                 filter_: str,
                 filter_type: str = "subtree") -> NetconfResponse:
        """
        Handle pre "get" tasks for consistency between sync/async versions

        *NOTE*
        The channel input (filter_) is loaded up as an lxml etree element here, this is done with a
        parser that removes whitespace. This has a somewhat undesirable effect of making any
        "pretty" input not pretty, however... after we load the xml object (which we do to validate
        that it is valid xml) we dump that xml object back to a string to be used as the actual
        raw payload we send down the channel, which means we are sending "flattened" (not pretty/
        indented xml) to the device. This is important it seems! Some devices seme to not mind
        having the "nicely" formatted input (pretty xml). But! On devices that "echo" the inputs
        back -- sometimes the device will respond to our rpc without "finishing" echoing our inputs
        to the device, this breaks the core "read until input" processing that scrapli always does.
        For whatever reason if there are no line breaks this does not seem to happen? /shrug. Note
        that this comment applies to all of the "pre" methods that we parse a filter/payload!

        Args:
            filter_: string filter to apply to the get
            filter_type: type of filter; subtree|xpath

        Returns:
            NetconfResponse: scrapli_netconf NetconfResponse object containing all the necessary
                channel inputs (string and xml)

        Raises:
            N/A

        """
        self.logger.debug(
            f"Building payload for 'get' operation. filter_type: {filter_type}, filter_: {filter_}"
        )

        # build base request and insert the get element
        xml_request = self._build_base_elem()
        xml_get_element = etree.fromstring(NetconfBaseOperations.GET.value)
        xml_request.insert(0, xml_get_element)

        # build filter element
        xml_filter_elem = self._build_filter(filter_=filter_,
                                             filter_type=filter_type)

        # insert filter element into parent get element
        get_element = xml_request.find("get")
        get_element.insert(0, xml_filter_elem)

        channel_input = self._finalize_channel_input(xml_request=xml_request)

        response = NetconfResponse(
            host=self.host,
            channel_input=channel_input.decode(),
            xml_input=xml_request,
            netconf_version=self.netconf_version,
            strip_namespaces=self.strip_namespaces,
        )
        self.logger.debug(
            f"Built payload for 'get' operation. Payload: {channel_input.decode()}"
        )
        return response