From 39839a9f2a21f1e58d6f8f2bc764b96fb9bbe6c5 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 13 Nov 2018 15:37:41 -0500 Subject: [PATCH] Add auto-healing of incomplete SLP data If a device handler indicates an SLP data as incomplete, schedule a attempt to fixup that specific one. --- confluent_server/confluent/discovery/core.py | 10 +++++++--- .../confluent/discovery/handlers/generic.py | 5 +++++ .../confluent/discovery/handlers/imm.py | 5 +++++ .../confluent/discovery/handlers/xcc.py | 5 +++++ .../confluent/discovery/protocols/pxe.py | 2 +- .../confluent/discovery/protocols/slp.py | 17 ++++++++++++++--- 6 files changed, 37 insertions(+), 7 deletions(-) diff --git a/confluent_server/confluent/discovery/core.py b/confluent_server/confluent/discovery/core.py index 63ea0014..ba853299 100644 --- a/confluent_server/confluent/discovery/core.py +++ b/confluent_server/confluent/discovery/core.py @@ -579,6 +579,10 @@ def detected(info): break else: # no nodehandler, ignore for now return + if not handler.adequate(info) and info.get('protocol', None): + eventlet.spawn_after(10, info['protocol'].fix_info, info, + safe_detected) + return try: snum = info['attributes']['enclosure-serial-number'][0].strip() if snum: @@ -1159,7 +1163,7 @@ def rescan(): if scanner: return else: - scanner = eventlet.spawn(slp.active_scan, safe_detected) + scanner = eventlet.spawn(slp.active_scan, safe_detected, slp) def start_detection(): @@ -1188,8 +1192,8 @@ def stop_autosense(): autosensors.discard(watcher) def start_autosense(): - autosensors.add(eventlet.spawn(slp.snoop, safe_detected)) - autosensors.add(eventlet.spawn(pxe.snoop, safe_detected)) + autosensors.add(eventlet.spawn(slp.snoop, safe_detected, slp)) + autosensors.add(eventlet.spawn(pxe.snoop, safe_detected, pxe)) nodes_by_fprint = {} diff --git a/confluent_server/confluent/discovery/handlers/generic.py b/confluent_server/confluent/discovery/handlers/generic.py index b68bab3d..fe126276 100644 --- a/confluent_server/confluent/discovery/handlers/generic.py +++ b/confluent_server/confluent/discovery/handlers/generic.py @@ -40,6 +40,11 @@ class NodeHandler(object): targsa = info['addresses'][0] self.ipaddr = targsa[0] + def adequate(self, info): + # Check if the referenced info is really enough, if false, a rescan + # may occur against the target in a short while + return True + def scan(self): # Do completely passive things to enhance data. # Probe is permitted to for example attempt a login diff --git a/confluent_server/confluent/discovery/handlers/imm.py b/confluent_server/confluent/discovery/handlers/imm.py index dfd80813..ecb6b679 100644 --- a/confluent_server/confluent/discovery/handlers/imm.py +++ b/confluent_server/confluent/discovery/handlers/imm.py @@ -21,6 +21,11 @@ import struct class NodeHandler(bmchandler.NodeHandler): devname = 'IMM' + def adequate(self, info): + # We can sometimes receive a partially initialized SLP packet + # This is not adequate for being satisfied + return bool(info['attributes']) + def scan(self): slpattrs = self.info.get('attributes', {}) self.isdense = False diff --git a/confluent_server/confluent/discovery/handlers/xcc.py b/confluent_server/confluent/discovery/handlers/xcc.py index 7cbafd5e..34125fcb 100644 --- a/confluent_server/confluent/discovery/handlers/xcc.py +++ b/confluent_server/confluent/discovery/handlers/xcc.py @@ -23,6 +23,11 @@ import pyghmi.ipmi.oem.lenovo.imm as imm class NodeHandler(immhandler.NodeHandler): devname = 'XCC' + def adequate(self, info): + # We can sometimes receive a partially initialized SLP packet + # This is not adequate for being satisfied + return bool(info['attributes']) + def preconfig(self): ff = self.info.get('attributes', {}).get('enclosure-form-factor', '') if ff not in ('dense-computing', [u'dense-computing']): diff --git a/confluent_server/confluent/discovery/protocols/pxe.py b/confluent_server/confluent/discovery/protocols/pxe.py index f1003013..66369bf5 100644 --- a/confluent_server/confluent/discovery/protocols/pxe.py +++ b/confluent_server/confluent/discovery/protocols/pxe.py @@ -72,7 +72,7 @@ def find_info_in_options(rq, optidx): return uuid, arch return uuid, arch -def snoop(handler): +def snoop(handler, protocol=None): #TODO(jjohnson2): ipv6 socket and multicast for DHCPv6, should that be #prominent #TODO(jjohnson2): IP_PKTINFO, recvmsg to get the destination ip, per diff --git a/confluent_server/confluent/discovery/protocols/slp.py b/confluent_server/confluent/discovery/protocols/slp.py index 7ff97425..e419453b 100644 --- a/confluent_server/confluent/discovery/protocols/slp.py +++ b/confluent_server/confluent/discovery/protocols/slp.py @@ -307,6 +307,15 @@ def _parse_attrs(data, parsed): parsed['attributes'] = _parse_attrlist(attrstr) +def fix_info(info, handler): + if '_attempts' not in info: + info['_attempts'] = 10 + if info['_attempts'] == 0: + return + info['_attempts'] -= 1 + _add_attributes(info) + handler(info) + def _add_attributes(parsed): attrq = _generate_attr_request(parsed['services'][0], parsed['xid']) target = None @@ -383,7 +392,7 @@ def rescan(handler): handler(scanned) -def snoop(handler): +def snoop(handler, protocol=None): """Watch for SLP activity handler will be called with a dictionary of relevant attributes @@ -392,7 +401,7 @@ def snoop(handler): :return: """ tracelog = log.Logger('trace') - active_scan(handler) + active_scan(handler, protocol) net = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) net.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, 1) slpg = socket.inet_pton(socket.AF_INET6, 'ff01::123') @@ -469,13 +478,14 @@ def snoop(handler): peerbymacaddress[mac]['xid'] = 1 _add_attributes(peerbymacaddress[mac]) peerbymacaddress[mac]['hwaddr'] = mac + peerbymacaddress[mac]['protocol'] = protocol handler(peerbymacaddress[mac]) except Exception as e: tracelog.log(traceback.format_exc(), ltype=log.DataTypes.event, event=log.Events.stacktrace) -def active_scan(handler): +def active_scan(handler, protocol=None): known_peers = set([]) for scanned in scan(): for addr in scanned['addresses']: @@ -486,6 +496,7 @@ def active_scan(handler): break known_peers.add(addr) else: + scanned['protocol'] = protocol handler(scanned)