Skip to content

Commit

Permalink
Merge pull request #342 from Juniper/junos-sax-parser
Browse files Browse the repository at this point in the history
handle rpc-reply start tag with no filter_xml
  • Loading branch information
einarnn committed Sep 6, 2019
2 parents a0cf92b + ed91c71 commit 10ebf71
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 1 deletion.
8 changes: 7 additions & 1 deletion ncclient/transport/third_party/junos/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ def parse(self, data):
self.sax_parser.feed(data)
except SAXParseException:
self._delimiter_check(data)
except SAXFilterXMLNotFoundError:
self.logger.debug('Missing SAX filter_xml. Switching from sax to dom parsing')
self._session.parser = DefaultXMLParser(self._session)
if not isinstance(data, bytes):
data = str.encode(data)
self._session._buffer.write(data)
finally:
self._parse10()

Expand Down Expand Up @@ -262,5 +268,5 @@ def _write_buffer(self, content, format_str, **kwargs):
for (name, value) in kwargs.items():
attr = ' {}={}'.format(name, quoteattr(value))
attrs = attrs + attr
data = format_str.format(content, attrs)
data = format_str.format(escape(content), attrs)
self._session._buffer.write(str.encode(data))
86 changes: 86 additions & 0 deletions test/unit/transport/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,92 @@ def test_filter_xml_delimiter_multiple_rpc_reply(self, mock_uuid4, mock_select,
self.assertEqual(len(resp.xpath('multi-routing-engine-item/re-name')), 2)
self.assertEqual(len(resp.xpath('multi-routing-engine-item/software-information')), 0)

@unittest.skipIf(sys.version_info.major == 2, "test not supported < Python3")
@patch('ncclient.transport.SSHSession.connected')
@patch('paramiko.channel.Channel.send_ready')
@patch('paramiko.channel.Channel.send')
@patch('ncclient.transport.ssh.SSHSession.close')
@patch('paramiko.channel.Channel.recv')
@patch('ncclient.transport.SSHSession')
@patch('selectors.DefaultSelector.select')
@patch('ncclient.operations.rpc.uuid4')
def test_filter_xml_delimiter_multiple_rpc_in_parallel(self, mock_uuid4, mock_select,
mock_session, mock_recv, mock_close,
mock_send, mock_send_ready,
mock_connected):
mock_send.return_value = True
mock_send_ready.return_value = -1
mock_uuid4.side_effect = [type('xyz', (), {'urn': "urn:uuid:ddef40cb-5745-481d-974d-7188f9f2bb33"}),
type('pqr', (), {'urn': "urn:uuid:549ef9d1-024a-4fd0-88bf-047d25f0870d"})]
device_handler = manager.make_device_handler({'name': 'junos', 'use_filter': True})
rpc = '<get-software-information/>'
mock_recv.side_effect = [b"""
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:junos="http://xml.juniper.net/junos/19.2I0/junos" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:ddef40cb-5745-481d-974d-7188f9f2bb33">
<ospf-neighbor-information xmlns="http://xml.juniper.net/junos/19.2I0/junos-routing">
<ospf-neighbor>
<neighbor-address>13.1.1.2</neighbor-address>
<interface-name>ge-0/0/0.1</interface-name>
<ospf-neighbor-state>Exchange</ospf-neighbor-state>
<neighbor-id>2.2.2.2</neighbor-id>
<neighbor-priority>128</neighbor-priority>
<activity-timer>36</activity-timer>
<ospf-area>0.0.0.0</ospf-area>
<options>0x52</options>
<dr-address>13.1.1.1</dr-address>
<bdr-address>13.1.1.2</bdr-address>
<neighbor-up-time junos:seconds="17812">
04:56:52
</neighbor-up-time>
<neighbor-adjacency-time junos:seconds="17812">
04:56:52
</neighbor-adjacency-time>
<master-slave>slave</master-slave>
<sequence-number>0x204b6fd</sequence-number>
<dbd-retransmit-time>3</dbd-retransmit-time>
<lsreq-retransmit-time>0</lsreq-retransmit-time>
<lsa-list>
Link state retransmission list:
Type LSA ID Adv rtr Seq
Router 1.1.1.1 1.1.1.1 0x80000019
OpaqArea 1.0.0.1 1.1.1.1 0x80000011
Router 3.3.3.3 3.3.3.3 0x80000004
Network 23.1.1.2 3.3.3.3 0x80000001
OpaqArea 1.0.0.1 2.2.2.2 0x80000002
OpaqArea 1.0.0.1 3.3.3.3 0x80000002
OpaqArea 1.0.0.3 1.1.1.1 0x80000002
OpaqArea 1.0.0.3 3.3.3.3 0x80000001
OpaqArea 1.0.0.4 2.2.2.2 0x80000001
</lsa-list>
<ospf-neighbor-topology>
<ospf-topology-name>default</ospf-topology-name>
<ospf-topology-id>0</ospf-topology-id>
<ospf-neighbor-topology-state>Forward Only</ospf-neighbor-topology-state>
</ospf-neighbor-topology>
</ospf-neighbor>
</ospf-neighbor-information>
</rpc-reply>]]>]]><rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:junos="http://xml.juniper.net/junos/19.2I0/junos" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:549ef9d1-024a-4fd0-88bf-047d25f0870d">
<pfe-statistics>
<pfe-traffic-statistics>
<pfe-input-packets>22450</pfe-input-packets>
<input-pps>0</input-pps>
<pfe-output-packets>31992</pfe-output-packets>
<output-pps>0</output-pps>
<pfe-fabric-input>0</pfe-fabric-input>
<pfe-fabric-input-pps>0</pfe-fabric-input-pps>
<pfe-fabric-output>0</pfe-fabric-output>
<pfe-fabric-output-pps>0</pfe-fabric-output-pps>
</pfe-traffic-statistics></pfe-statistics></rpc-reply>]]>]]>"""]
session = SSHSession(device_handler)
session._connected = True
session._channel = paramiko.Channel("c100")
session.parser = session._device_handler.get_xml_parser(session)
obj = ExecuteRpc(session, device_handler, raise_mode=RaiseMode.ALL)
obj = ExecuteRpc(session, device_handler, raise_mode=RaiseMode.ALL)
obj._filter_xml = '<multi-routing-engine-results><multi-routing-engine-item><re-name/></multi-routing-engine-item></multi-routing-engine-results>'
session.run()
resp = obj.request(rpc)._NCElement__doc[0]
self.assertEqual(len(resp.xpath('pfe-traffic-statistics')), 1)

@unittest.skipIf(sys.version_info.major == 2, "test not supported < Python3")
@patch('ncclient.transport.SSHSession.connected')
@patch('paramiko.channel.Channel.send_ready')
Expand Down

0 comments on commit 10ebf71

Please sign in to comment.