Skip to content
Snippets Groups Projects
Commit 4b4ceb7f authored by Erik Reid's avatar Erik Reid
Browse files

initial phy ifc parsing

parent 860fc6a4
No related branches found
No related tags found
No related merge requests found
"""
# rpc: 'get-configuration'
# cli: 'show config'
'configuration': str (xml)
"""
import contextlib
import logging
import time
from lxml import etree
import ncclient.manager
from ncclient.devices.junos import JunosDeviceHandler
from ncclient.xml_ import NCElement
logger = logging.getLogger(__name__)
# SSH_CONFIG = {
# 'username': 'Monit0r',
# 'private-key': os.path.expanduser('~/.ssh/monitor_dsa')
# }
#
# ROUTER_NAME = 'mx1.ams.nl.geant.net'
def _remove_ns(rpc_response):
junos_dev_handler = JunosDeviceHandler(
device_params={'name': 'junos', 'local': False})
return NCElement(rpc_response, junos_dev_handler.transform_reply()) \
.remove_namespaces(rpc_response.xml)
def nc_connection(hostname):
conn = ncclient.manager.connect(
host=hostname,
port=830,
ssh_config='~/.ssh/config.d/routers-jump',
# hostkey_verify=False,
# device_params={'name': 'junos'}
)
conn.async_mode = True
return conn
def rpc(router, command):
obj = router.rpc(command)
logger.info(f'sent rpc command: {etree.tostring(command)}')
# just wait for the result
while not obj.event.is_set():
logging.info('waiting for rpc reply ...')
time.sleep(.3)
return obj.reply
def netconf_rpc(router_name, command):
with contextlib.closing(nc_connection(hostname=router_name)) as router:
reply = rpc(router, command)
return _remove_ns(reply)
def get_interface_info_ncrpc(router_name):
request = etree.Element('get-interface-information')
request.append(etree.Element('extensive'))
return netconf_rpc(router_name=router_name, command=request)
def interface_counters(ifc_doc):
# def _logical(phy_node):
# for
def _elem_int(node, name):
subelems = node.xpath(f'./{name}/text()')
if not subelems:
assert False, f"can't find {name} in {node} [{subelems}]"
return int(subelems[0])
def _ifc_name(ifc_node):
return ifc_node.xpath('./name/text()')[0].strip()
def _is_lag(ifc_node):
return _ifc_name(ifc_node).startswith('ae')
def _brian_counters(ifc_node):
tr_stats = ifc_node.xpath('./traffic-statistics')[0]
v6_stats = ifc_node.xpath('./traffic-statistics/ipv6-transit-statistics')[0]
in_errors = ifc_node.xpath('./input-error-list')[0]
out_errors = ifc_node.xpath('./output-error-list')[0]
baseline_stats = {
'ingress': {
'bytes': _elem_int(tr_stats, 'input-bytes'),
'packets': _elem_int(tr_stats, 'input-packets'),
'v6': {
'bytes': _elem_int(v6_stats, 'input-bytes'),
'packets': _elem_int(v6_stats, 'input-packets'),
},
'errors': {
'errors': _elem_int(in_errors, 'input-errors'),
'drops': _elem_int(in_errors, 'input-drops'),
'resource': _elem_int(in_errors, 'input-resource-errors'),
'discards': _elem_int(in_errors, 'input-discards'),
}
},
'egress': {
'bytes': _elem_int(tr_stats, 'output-bytes'),
'packets': _elem_int(tr_stats, 'output-packets'),
'v6': {
'bytes': _elem_int(v6_stats, 'output-bytes'),
'packets': _elem_int(v6_stats, 'output-packets'),
},
'errors': {
'errors': _elem_int(out_errors, 'output-errors'),
'drops': _elem_int(out_errors, 'output-drops'),
'resource': _elem_int(out_errors, 'output-resource-errors')
}
}
}
if not _is_lag(ifc_node):
baseline_stats['ingress']['errors']['fifo'] = _elem_int(in_errors, 'input-fifo-errors')
baseline_stats['egress']['errors']['fifo'] = _elem_int(out_errors, 'output-fifo-errors')
baseline_stats['egress']['errors']['collisions'] = _elem_int(out_errors, 'output-collisions')
return baseline_stats
def _l2_counters(ifc_node):
mac_stats = ifc_node.xpath('./ethernet-mac-statistics')[0]
baseline_stats = {
'ingress': {
'broadcast': _elem_int(mac_stats, 'input-broadcasts'),
'multicast': _elem_int(mac_stats, 'input-multicasts')
},
'egress': {
'broadcast': _elem_int(mac_stats, 'output-broadcasts'),
'multicast': _elem_int(mac_stats, 'output-multicasts')
}
}
if not _is_lag(ifc_node):
baseline_stats['ingress']['bytes'] = _elem_int(mac_stats, 'input-bytes')
baseline_stats['ingress']['packets'] = _elem_int(mac_stats, 'input-packets')
baseline_stats['ingress']['unicast'] = _elem_int(mac_stats, 'input-unicasts')
baseline_stats['ingress']['errors'] = {
'total': _elem_int(mac_stats, 'input-total-errors'),
'crc': _elem_int(mac_stats, 'input-crc-errors'),
'fifo': _elem_int(mac_stats, 'input-fifo-errors'),
}
baseline_stats['egress']['bytes'] = _elem_int(mac_stats, 'output-bytes')
baseline_stats['egress']['packets'] = _elem_int(mac_stats, 'output-packets')
baseline_stats['egress']['unicast'] = _elem_int(mac_stats, 'output-unicasts')
baseline_stats['egress']['errors'] = {
'total': _elem_int(mac_stats, 'output-total-errors'),
'crc': _elem_int(mac_stats, 'output-crc-errors'),
'fifo': _elem_int(mac_stats, 'output-fifo-errors'),
}
return baseline_stats
for phy in ifc_doc.xpath(
'//interface-information/physical-interface['
'count(ethernet-mac-statistics)>0'
' and normalize-space(admin-status)="up"'
' and normalize-space(oper-status)="up"'
']'):
yield {
'name': _ifc_name(phy),
'brian': _brian_counters(phy),
'l2': _l2_counters(phy)
}
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
logging.getLogger('ncclient').setLevel(level=logging.WARNING)
# r = netconf_interface_info('mx1.ams.nl.geant.net')
# with open('interface_info.xml', 'wb') as f:
# f.write(etree.tostring(r))
# # print(etree.tostring(r, pretty_print=True).decode('utf-8'))
with open('interface_info.xml') as f:
doc = etree.parse(f)
for x in interface_counters(doc):
print(x)
\ No newline at end of file
...@@ -3,6 +3,8 @@ jsonschema ...@@ -3,6 +3,8 @@ jsonschema
requests requests
statsd statsd
flask flask
lxml
ncclient
pytest pytest
responses responses
......
...@@ -13,7 +13,9 @@ setup( ...@@ -13,7 +13,9 @@ setup(
'requests', 'requests',
'jsonschema', 'jsonschema',
'statsd', 'statsd',
'flask' 'flask',
'lxml',
'ncclient'
], ],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment