diff --git a/confluent_server/confluent/discovery/core.py b/confluent_server/confluent/discovery/core.py index 380df65c..c23ab5ec 100644 --- a/confluent_server/confluent/discovery/core.py +++ b/confluent_server/confluent/discovery/core.py @@ -92,6 +92,7 @@ import shlex import struct import socket import socket as nsocket +import aiohmi.util.webclient as webclient autosensors = set() @@ -962,7 +963,7 @@ def get_enclosure_chain_head(nodename, cfg): return nodename -def get_chained_smm_name(nodename, cfg, handler, nl=None, checkswitch=True): +async def get_chained_smm_name(nodename, cfg, handler, nl=None, checkswitch=True): # nodename is the head of the chain, cfg is a configmanager, handler # is the handler of the current candidate, nl is optional indication # of the next link in the chain, checkswitch can disable the switch @@ -998,7 +999,7 @@ def get_chained_smm_name(nodename, cfg, handler, nl=None, checkswitch=True): if pkey: cv = util.TLSCertVerifier( cfg, nodename, 'pubkeys.tls_hardwaremanager').verify_cert - for fprint in get_smm_neighbor_fingerprints(smmaddr, cv): + async for fprint in get_smm_neighbor_fingerprints(smmaddr, cv): if util.cert_matches(fprint, mycert): # a trusted chain member vouched for the cert # so it's validated @@ -1010,12 +1011,12 @@ def get_chained_smm_name(nodename, cfg, handler, nl=None, checkswitch=True): return None, False -def get_smm_neighbor_fingerprints(smmaddr, cv): +async def get_smm_neighbor_fingerprints(smmaddr, cv): if ':' in smmaddr: smmaddr = '[{0}]'.format(smmaddr) - wc = webclient.SecureHTTPConnection(smmaddr, verifycallback=cv) + wc = webclient.WebConnection(smmaddr, verifycallback=cv) try: - neighs = wc.grab_json_response('/scripts/neighdata.json') + neighs = await wc.grab_json_response('/scripts/neighdata.json') except Exception: log.log({'error': 'Failure getting LLDP information from {}'.format(smmaddr)}) return @@ -1196,7 +1197,7 @@ def get_nodename_from_enclosures(cfg, info): return nodename -def search_smms_by_cert(currsmm, cert, cfg): +async def search_smms_by_cert(currsmm, cert, cfg): neighs = [] cv = util.TLSCertVerifier( cfg, currsmm, 'pubkeys.tls_hardwaremanager').verify_cert @@ -1206,8 +1207,8 @@ def search_smms_by_cert(currsmm, cert, cfg): smmaddr = cd.get(currsmm, {}).get('hardwaremanagement.manager', {}).get('value', None) if not smmaddr: smmaddr = currsmm - wc = webclient.SecureHTTPConnection(smmaddr, verifycallback=cv) - neighs = wc.grab_json_response('/scripts/neighdata.json') + wc = webclient.WebConnection(smmaddr, verifycallback=cv) + neighs = await wc.grab_json_response('/scripts/neighdata.json') except Exception: return None for neigh in neighs: @@ -1227,7 +1228,7 @@ def search_smms_by_cert(currsmm, cert, cfg): return currsmm, bay, None exnl = list(cfg.filter_node_attributes('enclosure.extends=' + currsmm)) if len(exnl) == 1: - return search_smms_by_cert(exnl[0], cert, cfg) + return await search_smms_by_cert(exnl[0], cert, cfg) async def eval_node(cfg, handler, info, nodename, manual=False): @@ -1264,7 +1265,7 @@ async def eval_node(cfg, handler, info, nodename, manual=False): # The specified node is an enclosure (has nodes mapped to it), but # what we are talking to is *not* an enclosure # might be ambiguous, need to match chassis-uuid as well.. - match = search_smms_by_cert(nodename, handler.https_cert, cfg) + match = await search_smms_by_cert(nodename, handler.https_cert, cfg) if match: info['verfied'] = True info['enclosure.bay'] = match[1] diff --git a/confluent_server/confluent/discovery/handlers/cpstorage.py b/confluent_server/confluent/discovery/handlers/cpstorage.py index ab099ab8..5403b0b7 100644 --- a/confluent_server/confluent/discovery/handlers/cpstorage.py +++ b/confluent_server/confluent/discovery/handlers/cpstorage.py @@ -35,7 +35,7 @@ class NodeHandler(bmchandler.NodeHandler): return util.cert_matches(fprint, certificate) def get_webclient(self, user, passwd, newuser, newpass): - wc = webclient.SecureHTTPConnection(self.ipaddr, 443, + wc = webclient.WebConnection(self.ipaddr, 443, verifycallback=self.validate_cert) wc.connect() authdata = urlencode({'username': user, 'password': passwd, diff --git a/confluent_server/confluent/discovery/handlers/generic.py b/confluent_server/confluent/discovery/handlers/generic.py index 7d95ff97..873df813 100644 --- a/confluent_server/confluent/discovery/handlers/generic.py +++ b/confluent_server/confluent/discovery/handlers/generic.py @@ -69,7 +69,7 @@ class NodeHandler(object): if not self._ipaddr: return try: - wc = webclient.SecureHTTPConnection(self._ipaddr, verifycallback=self._savecert, port=443) + wc = webclient.WebConnection(self._ipaddr, verifycallback=self._savecert, port=443) wc.connect() wc.close() if not self._fp: diff --git a/confluent_server/confluent/discovery/handlers/smm.py b/confluent_server/confluent/discovery/handlers/smm.py index 185cc251..d5bd696a 100644 --- a/confluent_server/confluent/discovery/handlers/smm.py +++ b/confluent_server/confluent/discovery/handlers/smm.py @@ -140,7 +140,7 @@ class NodeHandler(bmchandler.NodeHandler): def _webconfigcreds(self, username, password): ip, port = self.get_web_port_and_ip() - wc = webclient.SecureHTTPConnection(ip, port, verifycallback=self._validate_cert) + wc = webclient.WebConnection(ip, port, verifycallback=self._validate_cert) wc.connect() authdata = { # start by trying factory defaults 'user': 'USERID', diff --git a/confluent_server/confluent/discovery/handlers/tsm.py b/confluent_server/confluent/discovery/handlers/tsm.py index 478360a1..c46a8d05 100644 --- a/confluent_server/confluent/discovery/handlers/tsm.py +++ b/confluent_server/confluent/discovery/handlers/tsm.py @@ -87,14 +87,14 @@ class NodeHandler(generic.NodeHandler): rpasschange = { 'Password': self.targpass, } - rwc = webclient.SecureHTTPConnection( + rwc = webclient.WebConnection( self.ipaddr, 443, verifycallback=self.validate_cert) rwc.set_basic_credentials(authdata['username'], authdata['password']) rwc.set_header('If-Match', '*') rwc.set_header('Content-Type', 'application/json') - rsp, status = rwc.grab_json_response_with_status( + rsp, status = await rwc.grab_json_response_with_status( '/redfish/v1/AccountService/Accounts/1', rpasschange, method='PATCH') if status >= 200 and status < 300: diff --git a/confluent_server/confluent/discovery/handlers/xcc.py b/confluent_server/confluent/discovery/handlers/xcc.py index c23fbd2f..4dc3cb5d 100644 --- a/confluent_server/confluent/discovery/handlers/xcc.py +++ b/confluent_server/confluent/discovery/handlers/xcc.py @@ -701,7 +701,7 @@ def remote_nodecfg(nodename, cfm): 'address') info = {'addresses': [ipaddr]} ipaddr = ipaddr[0] - wc = webclient.SecureHTTPConnection( + wc = webclient.WebConnection( ipaddr, 443, verifycallback=lambda x: True) rsp = wc.grab_json_response('/DeviceDescription.json') if isinstance(rsp, list): diff --git a/confluent_server/confluent/discovery/protocols/mdns.py b/confluent_server/confluent/discovery/protocols/mdns.py index 2e09075f..7f63e59f 100644 --- a/confluent_server/confluent/discovery/protocols/mdns.py +++ b/confluent_server/confluent/discovery/protocols/mdns.py @@ -28,6 +28,7 @@ # NTS: ssdp:alive +import asyncio import confluent.config.configmanager as cfm import confluent.collective.manager as collective import confluent.neighutil as neighutil @@ -43,6 +44,7 @@ import os import time import struct import traceback +import confluent.tasks as tasks import aiohmi.util.webclient as webclient @@ -95,14 +97,14 @@ def _process_snoop(peer, rsp, mac, known_peers, newmacs, peerbymacaddress, byeha } if sdata.get('ttl', 0) == 0: if byehandler: - eventlet.spawn_n(check_fish_handler, byehandler, peerdata, known_peers, newmacs, peerbymacaddress, machandlers, mac, peer) + tasks.spawn(check_fish_handler(byehandler, peerdata, known_peers, newmacs, peerbymacaddress, machandlers, mac, peer)) return 1 if handler: - eventlet.spawn_n(check_fish_handler, handler, peerdata, known_peers, newmacs, peerbymacaddress, machandlers, mac, peer) + tasks.spawn(check_fish_handler(handler, peerdata, known_peers, newmacs, peerbymacaddress, machandlers, mac, peer)) return 2 -def check_fish_handler(handler, peerdata, known_peers, newmacs, peerbymacaddress, machandlers, mac, peer): - retdata = check_fish(('/redfish/v1/', peerdata)) +async def check_fish_handler(handler, peerdata, known_peers, newmacs, peerbymacaddress, machandlers, mac, peer): + retdata = await check_fish(('/redfish/v1/', peerdata)) if retdata: known_peers.add(peer) newmacs.add(mac) @@ -110,7 +112,7 @@ def check_fish_handler(handler, peerdata, known_peers, newmacs, peerbymacaddress machandlers[mac] = handler -def snoop(handler, byehandler=None, protocol=None, uuidlookup=None): +async def snoop(handler, byehandler=None, protocol=None, uuidlookup=None): """Watch for unsolicited mDNS answers The handler shall be called on any service coming online. @@ -132,7 +134,7 @@ def snoop(handler, byehandler=None, protocol=None, uuidlookup=None): net6.bind(('', 5353)) net4.bind(('', 5353)) try: - active_scan(handler, protocol) + await active_scan(handler, protocol) except Exception as e: tracelog.log(traceback.format_exc(), ltype=log.DataTypes.event, event=log.Events.stacktrace) @@ -181,7 +183,7 @@ def snoop(handler, byehandler=None, protocol=None, uuidlookup=None): if r: r = r[0] if deferrednotifies: - eventlet.sleep(2.2) + await asyncio.sleep(2.2) for peerrsp in deferrednotifies: peer, rsp = peerrsp mac = neighutil.get_hwaddr(peer[0]) @@ -213,7 +215,7 @@ def get_sockets(): net4.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) return net4, net6 -def active_scan(handler, protocol=None): +async def active_scan(handler, protocol=None): net4, net6 = get_sockets() for idx in util.list_interface_indexes(): net6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, @@ -255,7 +257,7 @@ def active_scan(handler, protocol=None): timeout = 0 r, _, _ = select.select((net4, net6), (), (), timeout) if deferparse: - eventlet.sleep(2.2) + await asyncio.sleep(2.2) for dp in deferparse: rsp, peer = dp _parse_mdns(peer, rsp, peerdata, '_obmc_console._tcp.local') @@ -276,13 +278,13 @@ def active_scan(handler, protocol=None): if pi is not None: handler(pi) -def check_fish(urldata, port=443, verifycallback=None): +async def check_fish(urldata, port=443, verifycallback=None): if not verifycallback: verifycallback = lambda x: True url, data = urldata try: - wc = webclient.SecureHTTPConnection(_get_svrip(data), port, verifycallback=verifycallback, timeout=1.5) - peerinfo = wc.grab_json_response(url) + wc = webclient.WebConnection(_get_svrip(data), port, verifycallback=verifycallback, timeout=1.5) + peerinfo = await wc.grab_json_response(url) except socket.error: return None if url == '/DeviceDescription.json': diff --git a/confluent_server/confluent/networking/nxapi.py b/confluent_server/confluent/networking/nxapi.py index ebe227c0..dab97395 100644 --- a/confluent_server/confluent/networking/nxapi.py +++ b/confluent_server/confluent/networking/nxapi.py @@ -89,40 +89,41 @@ class NxApiClient: self.password = self.password.decode() except Exception: pass - self.wc = webclient.SecureHTTPConnection(switch, port=443, verifycallback=cv) - self.login() + self.wc = webclient.WebConnection(switch, port=443, verifycallback=cv) + self.logged = False - def login(self): + async def login(self): payload = {'aaaUser': {'attributes': {'name': self.user, 'pwd': self.password}}} - rsp = self.wc.grab_json_response_with_status('/api/mo/aaaLogin.json', payload) + rsp = await self.wc.grab_json_response_with_status('/api/mo/aaaLogin.json', payload) if rsp[1] != 200: raise Exception("Failed authenticating") rsp = rsp[0] self.authtoken = rsp['imdata'][0]['aaaLogin']['attributes']['token'] self.wc.cookies['Apic-Cookie'] = self.authtoken + self.logged = True - def get_firmware(self): + async def get_firmware(self): firmdata = {} - for imdata in self.grab_imdata('/api/mo/sys/showversion.json'): + async for imdata in self.grab_imdata('/api/mo/sys/showversion.json'): attrs = imdata['sysmgrShowVersion']['attributes'] firmdata['NX-OS'] = {'version': attrs['nxosVersion'], 'date': attrs['nxosCompileTime']} firmdata['BIOS'] = {'version': attrs['biosVersion'], 'date': attrs['biosCompileTime']} return firmdata - def get_sensors(self): + async def get_sensors(self): sensedata = [] - for imdata in self.grab_imdata('/api/mo/sys/ch.json?rsp-subtree=full'): + async for imdata in self.grab_imdata('/api/mo/sys/ch.json?rsp-subtree=full'): hwinfo = imdata['eqptCh']['children'] for component in hwinfo: add_sensedata(component, sensedata) return sensedata - def get_health(self): + async def get_health(self): healthdata = {'health': 'ok', 'sensors': []} - for sensor in self.get_sensors(): + async for sensor in self.get_sensors(): currhealth = sensor.get('health', 'ok') if currhealth != 'ok': healthdata['sensors'].append(sensor) @@ -132,9 +133,9 @@ class NxApiClient: healthdata['health'] = 'warning' return healthdata - def get_inventory(self): + async def get_inventory(self): invdata = [] - for imdata in self.grab_imdata('/api/mo/sys/ch.json?rsp-subtree=full'): + async for imdata in self.grab_imdata('/api/mo/sys/ch.json?rsp-subtree=full'): hwinfo = imdata['eqptCh'] chattr = hwinfo['attributes'] invinfo = {'name': 'System', 'present': True} @@ -162,7 +163,9 @@ class NxApiClient: invdata.append(invinfo) return invdata - def grab(self, url, cache=True, retry=True): + async def grab(self, url, cache=True, retry=True): + if not self.logged: + await self.login() if cache is True: cache = 1 if cache: @@ -178,14 +181,14 @@ class NxApiClient: self.cachedurls[url] = rsp[0], time.monotonic() return rsp[0] - def grab_imdata(self, url): - response = self.grab(url) + async def grab_imdata(self, url): + response = await self.grab(url) for imdata in response['imdata']: yield imdata - def get_mac_table(self): + async def get_mac_table(self): macdict = {} - for macinfo in self.grab_imdata('/api/mo/sys/mac/table.json?rsp-subtree=full'): + async for macinfo in self.grab_imdata('/api/mo/sys/mac/table.json?rsp-subtree=full'): mactable = macinfo['l2MacAddressTable']['children'] for macent in mactable: mace = macent['l2MacAddressEntry']['attributes'] @@ -197,9 +200,9 @@ class NxApiClient: return macdict - def get_lldp(self): + async def get_lldp(self): lldpbyport = {} - for lldpimdata in self.grab_imdata('/api/mo/sys/lldp/inst.json?rsp-subtree=full'): + async for lldpimdata in self.grab_imdata('/api/mo/sys/lldp/inst.json?rsp-subtree=full'): lldpdata = lldpimdata['lldpInst']['children'] for lldpinfo in lldpdata: if 'lldpIf' not in lldpinfo: diff --git a/confluent_server/confluent/plugins/hardwaremanagement/eatonpdu.py b/confluent_server/confluent/plugins/hardwaremanagement/eatonpdu.py index 9e0ea547..f00c3b14 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/eatonpdu.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/eatonpdu.py @@ -69,14 +69,14 @@ class WebResponse(httplib.HTTPResponse): def _check_close(self): return True -class WebConnection(wc.SecureHTTPConnection): +class WebConnection(wc.WebConnection): response_class = WebResponse def __init__(self, host, secure, verifycallback): if secure: port = 443 else: port = 80 - wc.SecureHTTPConnection.__init__(self, host, port, verifycallback=verifycallback) + wc.WebConnection.__init__(self, host, port, verifycallback=verifycallback) self.secure = secure self.cookies = {}