def _read_file(self, fname): from ncclient.xml_ import NCElement fpath = os.path.join(os.path.dirname(__file__), 'rpc-reply', fname) foo = open(fpath).read() reply = RPCReply(foo) reply.parse() rpc_reply = NCElement(reply, self.dev._conn. _device_handler.transform_reply())\ ._NCElement__doc[0] return rpc_reply
def rpc(self, cmd): """ Write the XML cmd and return the response as XML object. :cmd: <str> of the XML command. if the :cmd: is not XML, then this routine will perform the brackets; i.e. if given 'get-software-information', this routine will turn it into '<get-software-information/>' NOTES: The return XML object is the first child element after the <rpc-reply>. There is also no error-checking performing by this routine. """ if not cmd.startswith('<'): cmd = '<{}/>'.format(cmd) rpc = six.b('<rpc>{}</rpc>'.format(cmd)) logger.info('Calling rpc: %s' % rpc) self._tty.rawwrite(rpc) rsp = self._receive() rsp = rsp.decode('utf-8') if isinstance(rsp, bytes) else rsp reply = RPCReply(rsp) errors = reply.errors if len(errors) > 1: raise RPCError(to_ele(reply._raw), errs=errors) elif len(errors) == 1: raise reply.error return rsp
def edit_config(self, config, target='running', default_operation='merge', test_option=None, error_option=None): """ Loads all or part of the specified config to the target configuration datastore with the ability to lock the datastore during the edit. :param config is the configuration, which must be rooted in the config element. It can be specified either as a string or an Element.format="xml" :param target is the name of the configuration datastore being edited :param default_operation if specified must be one of { 'merge', 'replace', or 'none' } :param test_option if specified must be one of { 'test_then_set', 'set' } :param error_option if specified must be one of { 'stop-on-error', 'continue-on-error', 'rollback-on-error' } The 'rollback-on-error' error_option depends on the :rollback-on-error capability. :return: (defeered) for RpcReply """ try: yield asleep(random.uniform(0.1, 2.0)) # Simulate NETCONF request delay except Exception as e: log.exception('edit_config', e=e) raise # TODO: Customize if needed... xml = _dummy_xml returnValue(RPCReply(xml))
def lock(self, source, lock_timeout): """ Lock the configuration system :param source: is the name of the configuration datastore accessed :param lock_timeout: timeout in seconds for holding the lock :return: (defeered) for RpcReply """ expire_time = time.time() + lock_timeout if source not in self._locked: self._locked[source] = None while self._locked[source] is not None: # Watch for lock timeout if time.time() >= self._locked[source]: self._locked[source] = None break yield asleep(0.1) if time.time() < expire_time: yield asleep(random.uniform(0.1, 0.5)) # Simulate NETCONF request delay self._locked[source] = expire_time returnValue( RPCReply(_dummy_xml ) if expire_time > time.time() else RPCError('TODO'))
def rpc(self, rpc_string): """ Custom RPC request :param rpc_string: (string) RPC request :return: (defeered) for GetReply """ yield asleep(random.uniform(0.1, 2.0)) # Simulate NETCONF request delay # TODO: Customize if needed... xml = _dummy_xml returnValue(RPCReply(xml))
def get_config(self, source='running'): """ Get the configuration from the specified source :param source: (string) Configuration source, 'running', 'candidate', ... :return: (deferred) Deferred request that wraps the GetReply class """ yield asleep(random.uniform(0.1, 4.0)) # Simulate NETCONF request delay # TODO: Customize if needed... xml = _dummy_xml returnValue(RPCReply(xml))
def get(self, payload): """ Get the requested data from the server :param payload: Payload/filter :return: (defeered) for GetReply """ yield asleep(random.uniform(0.1, 3.0)) # Simulate NETCONF request delay # TODO: Customize if needed... xml = _dummy_xml returnValue(RPCReply(xml))
def test_cli_config(self, mock_execute): mock_execute.return_value = RPCReply( """<?xml version="1.0" encoding="UTF-8"?><rpc-reply xmlns:config="http://www.hp.com/netconf/config:1.0" xmlns:data="http://www.hp.com/netconf/data:1.0" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:5dcf4d19-e98b-11e5-8af9-60f81db7542c"><CLI><Configuration><![CDATA[<HP1>system System View: return to User View with Ctrl+Z. [HP1]interface FortyGigE1/0/1 ]]></Configuration></CLI></rpc-reply>""") command = 'FortyGigE1/0/1' result = self.device.cli_config(command) expected = '<HP1>system\nSystem View: return to User View with Ctrl+Z.\n[HP1]interface FortyGigE1/0/1\n' mock_execute.assert_called_with(self.device.connection.cli_config, [command]) self.assertEqual(result, expected)
def test_cli_display(self, mock_execute): mock_execute.return_value = RPCReply( """<?xml version="1.0" encoding="UTF-8"?><rpc-reply xmlns:config="http://www.hp.com/netconf/config:1.0" xmlns:data="http://www.hp.com/netconf/data:1.0" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:44406142-e989-11e5-a4a3-60f81db7542c"><CLI><Execution><![CDATA[<HP1>display arp Type: S-Static D-Dynamic O-Openflow R-Rule M-Multiport I-Invalid IP address MAC address VLAN Interface Aging Type 10.1.100.1 0014-1c57-a4c2 N/A M-GE0/0/0 18 D ]]></Execution></CLI></rpc-reply>""") command = 'display arp' result = self.device.cli_display(command) expected = '<HP1>display arp\n Type: S-Static D-Dynamic O-Openflow R-Rule M-Multiport I-Invalid\nIP address MAC address VLAN Interface Aging Type\n10.1.100.1 0014-1c57-a4c2 N/A M-GE0/0/0 18 D\n' mock_execute.assert_called_with(self.device.connection.cli_display, [command]) self.assertEqual(result, expected)
def unlock(self, source): """ Get the requested data from the server :param rpc_string: RPC request :param source: is the name of the configuration datastore accessed :return: (defeered) for RpcReply """ if source not in self._locked: self._locked[source] = None if self._locked[source] is not None: yield asleep(random.uniform(0.1, 0.5)) # Simulate NETCONF request delay self._locked[source] = None returnValue(RPCReply(_dummy_xml))
def edit_config(self, config, target='running', default_operation='merge', test_option=None, error_option=None, lock_timeout=-1): """ Loads all or part of the specified config to the target configuration datastore with the ability to lock the datastore during the edit. To change multiple items, use your own calls to lock/unlock instead of using the lock_timeout value :param config is the configuration, which must be rooted in the config element. It can be specified either as a string or an Element.format="xml" :param target is the name of the configuration datastore being edited :param default_operation if specified must be one of { 'merge', 'replace', or 'none' } :param test_option if specified must be one of { 'test_then_set', 'set' } :param error_option if specified must be one of { 'stop-on-error', 'continue-on-error', 'rollback-on-error' } The 'rollback-on-error' error_option depends on the :rollback-on-error capability. :param lock_timeout if >0, the maximum number of seconds to hold a lock on the datastore while the edit operation is underway :return: (defeered) for RpcReply """ if lock_timeout > 0: try: request = self.lock(target, lock_timeout) yield request except Exception as e: log.exception('edit_config-lock', e=e) raise try: yield asleep(random.uniform(0.1, 2.0)) # Simulate NETCONF request delay except Exception as e: log.exception('edit_config', e=e) raise finally: if lock_timeout > 0: yield self.unlock(target) # TODO: Customize if needed... xml = _dummy_xml returnValue(RPCReply(xml))
def edit_config(self, config, target='running', default_operation='merge', test_option=None, error_option=None, ignore_delete_error=False): """ Loads all or part of the specified config to the target configuration datastore with the ability to lock the datastore during the edit. :param config is the configuration, which must be rooted in the config element. It can be specified either as a string or an Element.format="xml" :param target is the name of the configuration datastore being edited :param default_operation if specified must be one of { 'merge', 'replace', or 'none' } :param test_option if specified must be one of { 'test_then_set', 'set' } :param error_option if specified must be one of { 'stop-on-error', 'continue-on-error', 'rollback-on-error' } The 'rollback-on-error' error_option depends on the :rollback-on-error capability. :param ignore_delete_error: (bool) For some startup deletes/clean-ups, we do a delete high up in the config to get whole lists. If these lists are empty, this helps suppress any error message from NETConf on failure to delete an empty list :return: (deferred) for RpcReply """ try: yield asleep(random.uniform( 0.01, 0.02)) # Simulate NETCONF request delay except Exception as e: if ignore_delete_error and 'operation="delete"' in config.lower(): returnValue('ignoring-delete-error') log.exception('edit_config', e=e) raise # TODO: Customize if needed... xml = _dummy_xml returnValue(RPCReply(xml))