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

utils for loading phy/log interfaces

parent 2ad98c1a
No related branches found
No related tags found
No related merge requests found
......@@ -293,6 +293,134 @@ def _load_pic_connected_ports(
yield _p
def _load_aggregates(router: 'jnpr.junos.Device'):
"""
computes 802.3ad lag bundles
returns a dict formatted as:
{
lag interface name: set of physical interface names
}
"""
catalog_spec = {
'InterfacesTable': {
'rpc': 'get-configuration',
'item': '//interface//gigether-options//ieee-802.3ad',
'key': [
"ancestor::interface/name",
'bundle'
],
'view': '_interfaces_view'
},
'_interfaces_view': {
'fields': {
'bundle': 'bundle',
# "name" as a field is a reserved word
'interface': 'ancestor::interface/name',
}
}
}
loader = FactoryLoader()
catalog = loader.load(catalog_spec)
InterfacesTable = catalog['InterfacesTable']
bundles = {}
for ifc in InterfacesTable(router).get():
assert ifc.bundle # sanity check
# bundles.setdefault(ifc.bundle, set()).add(ifc.interface)
bundles.setdefault(ifc.bundle, []).append(ifc.interface)
return bundles
def _load_logical_interfaces(router: 'jnpr.junos.Device'):
"""
loads logical interfaces
returns a dict formatted as:
{
physical interface name: set of logical interface names
}
"""
catalog_spec = {
'LogicalInterfacesTable': {
'rpc': 'get-interface-information',
'item': '//physical-interface/logical-interface',
'key': 'name',
'view': '_logical_interfaces_view'
},
'_logical_interfaces_view': {
'fields': {
'logical': 'name',
'physical': 'ancestor::physical-interface/name',
}
}
}
loader = FactoryLoader()
catalog = loader.load(catalog_spec)
LogicalInterfacesTable = catalog['LogicalInterfacesTable']
interfaces = {}
for lu in LogicalInterfacesTable(router).get():
assert lu.logical.startswith(lu.physical) # sanity
interfaces.setdefault(lu.physical, set()).add(lu.logical)
return interfaces
def _load_installed_ethernet_ports(router: 'jnpr.junos.Device'):
"""
can't just use jnpr.junos.op.ethport.EthPortTable
some routers in our network don't return int for mtu from
that command, and the pyez view has some validation that fails
for each physical port on the router, yields a dict formatted like:
{
'name': str, # interface name
'admin': bool, # admin status ('up' == True)
'oper': bool, # operational status ('up' == True)
}
"""
catalog_spec = {
'PhysicalInterfacesTable': {
'rpc': 'get-interface-information',
'item': '//physical-interface',
'key': 'name',
'view': '_physical_interfaces_view'
},
'_physical_interfaces_view': {
'fields': {
'interface': 'name',
'admin': 'admin-status',
'oper': 'oper-status'
}
}
}
loader = FactoryLoader()
catalog = loader.load(catalog_spec)
PhysicalInterfacesTable = catalog['PhysicalInterfacesTable']
for ifc in PhysicalInterfacesTable(router).get():
yield {
'name': ifc.interface,
'admin': ifc.admin == 'up',
'oper': ifc.admin == 'up'
}
def load_router_ports(hostname, ssh_config, port=830):
"""
merges the results of calls to:
......
......@@ -16,7 +16,7 @@ from resource_management.db import model
RPC_DATA_DIR = os.path.join(os.path.dirname(__file__), 'rpc-data')
HOSTNAMES = [
# 'vmx',
# # 'vmx',
'mx1.lab.office.geant.net',
'mx2.lab.office.geant.net',
'mx3.lab.office.geant.net',
......@@ -34,7 +34,7 @@ HOSTNAMES = [
'mx1.lon.uk.geant.net',
'mx1.lon2.uk.geant.net',
'mx1.mad.es.geant.net',
'mx1.mil2.it.geant.net',
# 'mx1.mil2.it.geant.net',
'mx1.par.fr.geant.net',
'mx1.poz.pl.geant.net',
'mx1.sof.bg.geant.net',
......@@ -171,6 +171,8 @@ def mocked_router(netconf_rpc_replies):
# the test data format is documented
# in test/rpc-data/capture-test-data.py
if rpc_command.tag == 'get-configuration':
return 'configuration'
if rpc_command.tag == 'get-system-information':
return 'system'
if rpc_command.tag == 'get-chassis-inventory':
......
......@@ -3,8 +3,7 @@ import re
from jsonschema import validate
from lxml import etree
from resource_management.hardware.juniper \
import load_router_ports, LINE_CARDS_LIST_SCHEMA
from resource_management.hardware import juniper
def _remove_ns(xml):
......@@ -25,9 +24,9 @@ def test_router_ports(mocked_router, netconf_rpc_replies):
'username': 'bogus',
'private-key': 'no file'
}
fpcs = load_router_ports(hostname='bogus', ssh_config=ssh)
fpcs = juniper.load_router_ports(hostname='bogus', ssh_config=ssh)
fpcs = list(fpcs)
validate(fpcs, LINE_CARDS_LIST_SCHEMA)
validate(fpcs, juniper.LINE_CARDS_LIST_SCHEMA)
inventory = _remove_ns(netconf_rpc_replies['inventory'])
expected_fpcs = list(inventory.xpath(
......@@ -46,3 +45,32 @@ def test_router_ports(mocked_router, netconf_rpc_replies):
# would be hard to maintain against code changes)
assert set(map(_slot_number, expected_fpcs)) \
== {f['slot'] for f in fpcs}
def test_new_load_interfaces(mocked_router, netconf_rpc_replies):
"""
renewed design for this app: no chassis info for now
"""
ssh = {
'username': 'bogus',
'private-key': 'no file'
}
with juniper.router(
hostname='blah-bogus',
port=12345,
ssh_config=ssh) as dev:
# with contextlib.closing(dev.open()) as d:
# config = d.rpc.get_config()
# print(len(config))
# just sanity check there are non-empty responses
physical = list(juniper._load_installed_ethernet_ports(dev))
assert physical
logical = juniper._load_logical_interfaces(dev)
assert logical
aggregates = juniper._load_aggregates(dev)
assert aggregates
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment