2
0
mirror of https://github.com/xcat2/confluent.git synced 2024-11-22 09:32:21 +00:00

Add affluent support to /networking

The /networking backend will now
check for affluent on the switches and
use it if possible for improved performance.
This commit is contained in:
Jarrod Johnson 2020-02-07 15:57:33 -05:00
parent 66e1d17d28
commit 48f0330568
3 changed files with 87 additions and 16 deletions

View File

@ -44,7 +44,7 @@ import eventlet
from eventlet.greenpool import GreenPool
import eventlet.semaphore
import re
webclient = eventlet.import_patched('pyghmi.util.webclient')
# The interesting OIDs are:
# lldpLocChassisId - to cross reference (1.0.8802.1.1.2.1.3.2.0)
# lldpLocPortId - for cross referencing.. (1.0.8802.1.1.2.1.3.7.1.3)
@ -85,6 +85,7 @@ _neighdata = {}
_neighbypeerid = {}
_updatelocks = {}
_chassisidbyswitch = {}
_noaffluent = set([])
def lenovoname(idx, desc):
if desc.isdigit():
@ -171,21 +172,59 @@ def _init_lldp(data, iname, idx, idxtoportid, switch):
data[iname] = {'port': iname, 'portid': str(idxtoportid[idx]),
'chassisid': _chassisidbyswitch[switch]}
def _extract_neighbor_data_affluent(switch, user, password, cfm, lldpdata):
kv = util.TLSCertVerifier(cfm, switch,
'pubkeys.tls_hardwaremanager').verify_cert
wc = webclient.SecureHTTPConnection(
switch, 443, verifycallback=kv, timeout=5)
wc.set_basic_credentials(user, password)
neighdata = wc.grab_json_response('/affluent/lldp/all')
chassisid = neighdata['chassis']['id']
_chassisidbyswitch[switch] = chassisid,
print(repr(neighdata))
for record in neighdata['neighbors']:
localport = record['localport']
peerid = '{0}.{1}'.format(
record.get('peerchassisid', '').replace(':', '-').replace('/', '-'),
record.get('peerportid', '').replace(':', '-').replace('/', '-'),
)
portdata = {
'verified': True, # It is over TLS after all
'peerdescription': record.get('peerdescription', None),
'peerchassisid': record['peerchassisid'],
'peername': record['peername'],
'switch': switch,
'chassisid': chassisid,
'portid': record['localport'],
'peerportid': record['peerportid'],
'port': record['localport'],
'peerid': peerid,
}
_neighbypeerid[peerid] = portdata
lldpdata[localport] = portdata
neighdata[switch] = lldpdata
def _extract_neighbor_data_b(args):
"""Build LLDP data about elements connected to switch
args are carried as a tuple, because of eventlet convenience
"""
switch, password, user, force = args[:4]
switch, password, user, cfm, force = args[:5]
vintage = _neighdata.get(switch, {}).get('!!vintage', 0)
now = util.monotonic_time()
if vintage > (now - 60) and not force:
return
lldpdata = {'!!vintage': now}
try:
return _extract_neighbor_data_affluent(switch, user, password, cfm, lldpdata)
except Exception:
pass
conn = snmp.Session(switch, password, user)
sid = None
lldpdata = {'!!vintage': now}
for sysid in conn.walk('1.3.6.1.2.1.1.2'):
sid = str(sysid[1][6:])
_noaffluent.add(switch)
idxtoifname = {}
idxtoportid = {}
_chassisidbyswitch[switch] = sanitize(list(
@ -268,8 +307,8 @@ def _extract_neighbor_data(args):
return _extract_neighbor_data_b(args)
except Exception as e:
yieldexc = False
if len(args) >= 5:
yieldexc = args[4]
if len(args) >= 6:
yieldexc = args[5]
if yieldexc:
return e
else:
@ -358,10 +397,3 @@ def _handle_neighbor_query(pathcomponents, configmanager):
raise x
return list_info(parms, listrequested)
def _list_interfaces(switchname, configmanager):
switchcreds = get_switchcreds(configmanager, (switchname,))
switchcreds = switchcreds[0]
conn = snmp.Session(*switchcreds)
ifnames = netutil.get_portnamemap(conn)
return util.natural_sort(ifnames.values())

View File

@ -45,13 +45,16 @@ from eventlet.greenpool import GreenPool
import eventlet
import eventlet.semaphore
import re
webclient = eventlet.import_patched('pyghmi.util.webclient')
noaffluent = set([])
_macmap = {}
_apimacmap = {}
_macsbyswitch = {}
_nodesbymac = {}
_switchportmap = {}
_neighdata = {}
vintage = None
@ -127,6 +130,36 @@ def _nodelookup(switch, ifname):
return None
def _affluent_map_switch(args):
switch, password, user, cfm = args
kv = util.TLSCertVerifier(cfm, switch,
'pubkeys.tls_hardwaremanager').verify_cert
wc = webclient.SecureHTTPConnection(
switch, 443, verifycallback=kv, timeout=5)
wc.set_basic_credentials(user, password)
macs = wc.grab_json_response('/affluent/macs/by-port')
_macsbyswitch[switch] = macs
for iface in macs:
nummacs = len(macs[iface])
for mac in macs[iface]:
if mac in _macmap:
_macmap[mac].append((switch, iface, nummacs))
else:
_macmap[mac] = [(switch, iface, nummacs)]
nodename = _nodelookup(switch, iface)
if nodename is not None:
if mac in _nodesbymac and _nodesbymac[mac][0] != nodename:
# For example, listed on both a real edge port
# and by accident a trunk port
log.log({'error': '{0} and {1} described by ambiguous'
' switch topology values'.format(
nodename, _nodesbymac[mac][0])})
_nodesbymac[mac] = (None, None)
else:
_nodesbymac[mac] = (nodename, nummacs)
def _map_switch_backend(args):
"""Manipulate portions of mac address map relevant to a given switch
"""
@ -144,13 +177,18 @@ def _map_switch_backend(args):
# fallback if ifName is empty
#
global _macmap
if len(args) == 3:
switch, password, user = args
if len(args) == 4:
switch, password, user, cfm = args
if not user:
user = None
else:
switch, password = args
user = None
if switch not in noaffluent:
try:
return _affluent_map_switch(args)
except Exception:
pass
haveqbridge = False
mactobridge = {}
conn = snmp.Session(switch, password, user)
@ -164,6 +202,7 @@ def _map_switch_backend(args):
*([int(x) for x in oid[-6:]])
)
mactobridge[macaddr] = int(bridgeport)
noaffluent.add(switch)
if not haveqbridge:
for vb in conn.walk('1.3.6.1.2.1.17.4.3.1.2'):
oid, bridgeport = vb

View File

@ -36,7 +36,7 @@ def get_switchcreds(configmanager, switches):
'secret.hardwaremanagementuser', {}).get('value', None)
if not user:
user = None
switchauth.append((switch, password, user))
switchauth.append((switch, password, user, configmanager))
return switchauth