From c4616745c4c786812d6228d9134aeea2a77d17ba Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 23 Jan 2026 13:31:09 -0500 Subject: [PATCH] Remove pyghmi usage across multiple areas --- .../plugins/hardwaremanagement/eatonpdu.py | 3 +- .../plugins/hardwaremanagement/enlogic.py | 46 ++++----- .../plugins/hardwaremanagement/geist.py | 53 ++++++----- .../plugins/hardwaremanagement/pdu.py | 2 +- .../plugins/hardwaremanagement/vcenter.py | 93 ++++++++++--------- confluent_server/confluentsrv.spec | 2 +- 6 files changed, 103 insertions(+), 96 deletions(-) diff --git a/confluent_server/confluent/plugins/hardwaremanagement/eatonpdu.py b/confluent_server/confluent/plugins/hardwaremanagement/eatonpdu.py index 5ef16311..9e0ea547 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/eatonpdu.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/eatonpdu.py @@ -18,7 +18,8 @@ import confluent.messages as msg import confluent.exceptions as exc import eventlet import eventlet.green.socket as socket -wc = eventlet.import_patched('pyghmi.util.webclient') + +import aiohmi.util.webclient as wc import confluent.util as util import re import hashlib diff --git a/confluent_server/confluent/plugins/hardwaremanagement/enlogic.py b/confluent_server/confluent/plugins/hardwaremanagement/enlogic.py index de9b13d5..c053447a 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/enlogic.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/enlogic.py @@ -18,7 +18,7 @@ import confluent.exceptions as exc import eventlet.green.time as time import eventlet import eventlet.greenpool as greenpool -wc = eventlet.import_patched('pyghmi.util.webclient') +import aiohmi.util.webclient as wc @@ -62,7 +62,7 @@ class EnlogicClient(object): cv = util.TLSCertVerifier( self.configmanager, self.node, 'pubkeys.tls_hardwaremanager' ).verify_cert - self._wc = wc.SecureHTTPConnection(target, port=443, verifycallback=cv) + self._wc = wc.WebConnection(target, port=443, verifycallback=cv) return self._wc def grab_json_response(self, url, body=None): @@ -76,7 +76,7 @@ class EnlogicClient(object): return rsp return {} - def login(self, configmanager): + async def login(self, configmanager): credcfg = configmanager.get_node_attributes( self.node, ['secret.hardwaremanagementuser', 'secret.hardwaremanagementpassword'], @@ -93,25 +93,25 @@ class EnlogicClient(object): if not username or not passwd: raise Exception('Missing username or password') self.username = username - rsp = self.wc.grab_json_response( + rsp = await self.wc.grab_json_response( '/xhrlogin.jsp', {'username': username, 'password': passwd, 'cookie': 0} ) - print(repr(rsp)) + #print(repr(rsp)) self.authtoken = rsp['cookie'] self.wc.set_header('Authorization', self.authtoken) return self.authtoken - def logout(self): + async def logout(self): if self._token: - self.wc.grab_json_response( + await self.wc.grab_json_response( '/xhrlogout.jsp', {'timeout': 0, 'cookie': self._token}, ) self._token = None - def get_outlet(self, outlet): - rsp = self.grab_json_response( + async def get_outlet(self, outlet): + rsp = await self.grab_json_response( '/xhroutgetgrid.jsp', { 'cookie': self.token, 'pduid': 1 @@ -122,7 +122,7 @@ class EnlogicClient(object): state = "on" if olet['powstat'] == 1 else "off" return state - def set_outlet(self, outlet, state): + async def set_outlet(self, outlet, state): bitflags = 2**(int(outlet) - 1) outlet1 = bitflags & (2**24-1) outlet2 = bitflags >> 24 @@ -139,13 +139,13 @@ class EnlogicClient(object): 'pduid': 1, 'powstat': state } - rsp = self.grab_json_response('/xhroutpowstatset.jsp', request) + rsp = await self.grab_json_response('/xhroutpowstatset.jsp', request) _sensors_by_node = {} -def read_sensors(element, node, configmanager): +async def read_sensors(element, node, configmanager): category, name = element[-2:] justnames = False if len(element) == 3: @@ -163,7 +163,7 @@ def read_sensors(element, node, configmanager): sn = _sensors_by_node.get(node, None) if not sn or sn[1] < time.time(): gc = get_client(node, configmanager) - adev = gc.grab_json_response('/energy_get', {'cookie': gc.token, 'end': 1, 'start': 1}) + adev = await gc.grab_json_response('/energy_get', {'cookie': gc.token, 'end': 1, 'start': 1}) _sensors_by_node[node] = (adev, time.time() + 1) sn = _sensors_by_node.get(node, None) if sn: @@ -196,24 +196,24 @@ def get_client(node, configmanager): _pduclients[node] = EnlogicClient(node, configmanager) return _pduclients[node] -def get_outlet(element, node, configmanager): +async def get_outlet(element, node, configmanager): gc = get_client(node, configmanager) - state = gc.get_outlet(element[-1]) + state = await gc.get_outlet(element[-1]) return msg.PowerState(node=node, state=state) -def read_firmware(node, configmanager): +async def read_firmware(node, configmanager): gc = get_client(node, configmanager) - adev = gc.grab_json_response('/xhrgetuserlist.jsp') + adev = await gc.grab_json_response('/xhrgetuserlist.jsp') myversion = adev[0]['fwver'] yield msg.Firmware([{'PDU Firmware': {'version': myversion}}], node) -def read_inventory(element, node, configmanager): +async def read_inventory(element, node, configmanager): _inventory = {} inventory = {} gc = get_client(node, configmanager) - adev = gc.grab_json_response('/sys_info_get', { + adev = await gc.grab_json_response('/sys_info_get', { 'cookie': gc.token, 'pduid': 1 }) inventory['present'] = True @@ -225,7 +225,7 @@ def read_inventory(element, node, configmanager): inventory['information'] = info yield msg.KeyValueData({'inventory': [inventory]}, node) -def retrieve(nodes, element, configmanager, inputdata): +async def retrieve(nodes, element, configmanager, inputdata): if 'outlets' in element: gp = greenpool.GreenPile(pdupool) @@ -265,7 +265,7 @@ def retrieve(nodes, element, configmanager, inputdata): return -def update(nodes, element, configmanager, inputdata): +async def update(nodes, element, configmanager, inputdata): if 'outlets' not in element: for node in nodes: yield msg.ConfluentResourceUnavailable(node, 'Not implemented') @@ -273,7 +273,7 @@ def update(nodes, element, configmanager, inputdata): for node in nodes: gc = get_client(node, configmanager) newstate = inputdata.powerstate(node) - gc.set_outlet(element[-1], newstate) + await gc.set_outlet(element[-1], newstate) eventlet.sleep(1) - for res in retrieve(nodes, element, configmanager, inputdata): + async for res in retrieve(nodes, element, configmanager, inputdata): yield res diff --git a/confluent_server/confluent/plugins/hardwaremanagement/geist.py b/confluent_server/confluent/plugins/hardwaremanagement/geist.py index f2e0418c..80522dbc 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/geist.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/geist.py @@ -19,7 +19,7 @@ import confluent.exceptions as exc import eventlet.green.time as time import eventlet import eventlet.greenpool as greenpool -wc = eventlet.import_patched('pyghmi.util.webclient') +import aiohmi.util.webclient as wc @@ -54,10 +54,9 @@ class GeistClient(object): self._wc = None self.username = None - @property - def token(self): + async def token(self): if not self._token: - self._token = self.login(self.configmanager) + self._token = await self.login(self.configmanager) return self._token @property @@ -75,10 +74,10 @@ class GeistClient(object): cv = util.TLSCertVerifier( self.configmanager, self.node, 'pubkeys.tls_hardwaremanager' ).verify_cert - self._wc = wc.SecureHTTPConnection(target, port=443, verifycallback=cv) + self._wc = wc.WebConnection(target, port=443, verifycallback=cv) return self._wc - def login(self, configmanager): + async def login(self, configmanager): credcfg = configmanager.get_node_attributes( self.node, ['secret.hardwaremanagementuser', 'secret.hardwaremanagementpassword'], @@ -95,7 +94,7 @@ class GeistClient(object): if not username or not passwd: raise Exception('Missing username or password') self.username = username - rsp = self.wc.grab_json_response( + rsp = await self.wc.grab_json_response( '/api/auth/{0}'.format(username), {'cmd': 'login', 'data': {'password': passwd}}, ) @@ -103,16 +102,16 @@ class GeistClient(object): token = rsp['data']['token'] return token - def logout(self): + async def logout(self): if self._token: - self.wc.grab_json_response( + await self.wc.grab_json_response( '/api/auth/{0}'.format(self.username), - {'cmd': 'logout', 'token': self.token}, + {'cmd': 'logout', 'token': await self.token()}, ) self._token = None - def get_outlet(self, outlet): - rsp = self.wc.grab_json_response('/api/dev') + async def get_outlet(self, outlet): + rsp = await self.wc.grab_json_response('/api/dev') rsp = rsp['data'] dbt = data_by_type(rsp) @@ -126,22 +125,22 @@ class GeistClient(object): state = outlet['state'].split('2')[-1] return state - def set_outlet(self, outlet, state): - rsp = self.wc.grab_json_response('/api/dev') + async def set_outlet(self, outlet, state): + rsp = await self.wc.grab_json_response('/api/dev') dbt = data_by_type(rsp['data']) if 't3hd' in dbt: del dbt['t3hd'] if len(dbt) != 1: - self.logout() + await self.logout() raise Exception('Multiple PDUs per endpoint not supported') pdu = dbt[list(dbt)[0]]['keyname'] outlet = int(outlet) - 1 - rsp = self.wc.grab_json_response( + rsp = await self.wc.grab_json_response( '/api/dev/{0}/outlet/{1}'.format(pdu, outlet), { 'cmd': 'control', - 'token': self.token, + 'token': await self.token(), 'data': {'action': state, 'delay': False}, }, ) @@ -210,7 +209,7 @@ def process_measurements(name, category, measurements, enttype, readings): _sensors_by_node = {} -def read_sensors(element, node, configmanager): +async def read_sensors(element, node, configmanager): category, name = element[-2:] justnames = False if len(element) == 3: @@ -223,7 +222,7 @@ def read_sensors(element, node, configmanager): sn = _sensors_by_node.get(node, None) if not sn or sn[1] < time.time(): gc = GeistClient(node, configmanager) - adev = gc.wc.grab_json_response('/api/dev') + adev = await gc.wc.grab_json_response('/api/dev') _sensors_by_node[node] = (adev, time.time() + 1) sn = _sensors_by_node.get(node, None) dbt = data_by_type(sn[0]['data']) @@ -242,25 +241,25 @@ def read_sensors(element, node, configmanager): yield msg.SensorReadings(readings, name=node) -def get_outlet(element, node, configmanager): +async def get_outlet(element, node, configmanager): gc = GeistClient(node, configmanager) - state = gc.get_outlet(element[-1]) + state = await gc.get_outlet(element[-1]) return msg.PowerState(node=node, state=state) -def read_firmware(node, configmanager): +async def read_firmware(node, configmanager): gc = GeistClient(node, configmanager) - adev = gc.wc.grab_json_response('/api/sys') + adev = await gc.wc.grab_json_response('/api/sys') myversion = adev['data']['version'] yield msg.Firmware([{'PDU Firmware': {'version': myversion}}], node) -def read_inventory(element, node, configmanager): +async def read_inventory(element, node, configmanager): _inventory = {} inventory = {} gc = GeistClient(node, configmanager) - adev = gc.wc.grab_json_response('/api/sys') + adev = await gc.wc.grab_json_response('/api/sys') basedata = adev['data'] inventory['present'] = True inventory['name'] = 'PDU' @@ -303,7 +302,7 @@ def read_inventory(element, node, configmanager): yield msg.KeyValueData({'inventory': [inventory]}, node) -def retrieve(nodes, element, configmanager, inputdata): +async def retrieve(nodes, element, configmanager, inputdata): if 'outlets' in element: gp = greenpool.GreenPile(pdupool) @@ -343,7 +342,7 @@ def retrieve(nodes, element, configmanager, inputdata): return -def update(nodes, element, configmanager, inputdata): +async def update(nodes, element, configmanager, inputdata): if 'outlets' not in element: yield msg.ConfluentResourceUnavailable(node, 'Not implemented') return diff --git a/confluent_server/confluent/plugins/hardwaremanagement/pdu.py b/confluent_server/confluent/plugins/hardwaremanagement/pdu.py index 4ca3f50a..ed1e71e4 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/pdu.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/pdu.py @@ -13,7 +13,7 @@ # limitations under the License. import confluent.core as core import confluent.messages as msg -import pyghmi.exceptions as pygexc +import aiohmi.exceptions as pygexc import confluent.exceptions as exc import eventlet.greenpool as greenpool import eventlet.queue as queue diff --git a/confluent_server/confluent/plugins/hardwaremanagement/vcenter.py b/confluent_server/confluent/plugins/hardwaremanagement/vcenter.py index bdd1366d..c3d8d83f 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/vcenter.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/vcenter.py @@ -3,9 +3,9 @@ import codecs import confluent.util as util import confluent.messages as msg import eventlet -import json import struct -webclient = eventlet.import_patched('pyghmi.util.webclient') + +import aiohmi.util.webclient as webclient import eventlet.green.socket as socket import eventlet.green.ssl as ssl import eventlet @@ -124,8 +124,8 @@ class VmwApiClient: self.password = self.password.decode() except Exception: pass - self.wc = webclient.SecureHTTPConnection(vcsa, port=443, verifycallback=cv) - self.login() + self.wc = webclient.Web(vcsa, port=443, verifycallback=cv) + self.logged = False self.vmlist = {} self.vmbyid = {} @@ -136,8 +136,11 @@ class VmwApiClient: body = rsp.read().decode().replace('"', '') del self.wc.stdheaders['Authorization'] self.wc.set_header('vmware-api-session-id', body) + self.logged = True - def get_screenshot(self, vm, outfile): + async def get_screenshot(self, vm, outfile): + if not self.logged: + await self.login() vm = self.index_vm(vm) url = f'/screen?id={vm}' wc = self.wc.dupe() @@ -146,8 +149,10 @@ class VmwApiClient: fd.start() fd.join() - def list_vms(self): - rsp = self.wc.grab_json_response('/api/vcenter/vm') + async def list_vms(self): + if not self.logged: + await self.login() + rsp = await self.wc.grab_json_response('/api/vcenter/vm') self.vmlist = {} for vm in rsp: name = vm['name'] @@ -156,25 +161,27 @@ class VmwApiClient: self.vmbyid[vmid] = name return self.vmlist - def index_vm(self, vm): + async def index_vm(self, vm): + if not self.logged: + await self.login() if vm in self.vmlist: return self.vmlist[vm] if vm in self.vmbyid: return vm - self.list_vms() + await self.list_vms() if vm not in self.vmlist: if vm in self.vmbyid: return vm raise Exception("VM not found") return self.vmlist[vm] - def get_vm(self, vm): - vm = self.index_vm(vm) - rsp = self.wc.grab_json_response(f'/api/vcenter/vm/{vm}') + async def get_vm(self, vm): + vm = await self.index_vm(vm) + rsp = await self.wc.grab_json_response(f'/api/vcenter/vm/{vm}') return rsp - def get_vm_inventory(self, vm): - rawinv = self.get_vm(vm) + async def get_vm_inventory(self, vm): + rawinv = await self.get_vm(vm) hwver = rawinv['hardware']['version'] uuid = fixuuid(rawinv['identity']['bios_uuid']) serial = rawinv['identity']['instance_uuid'] @@ -206,23 +213,23 @@ class VmwApiClient: - def get_vm_host(self, vm): + async def get_vm_host(self, vm): # unfortunately, the REST api doesn't manifest this as a simple attribute, - vm = self.index_vm(vm) - rsp = self.wc.grab_json_response(f'/api/vcenter/host') + vm = await self.index_vm(vm) + rsp = await self.wc.grab_json_response(f'/api/vcenter/host') for hostinfo in rsp: host = hostinfo['host'] - rsp = self.wc.grab_json_response(f'/api/vcenter/vm?hosts={host}') + rsp = await self.wc.grab_json_response(f'/api/vcenter/vm?hosts={host}') for guest in rsp: if guest['vm'] == vm: return hostinfo - def get_vm_serial(self, vm): - vm = self.index_vm(vm) - rsp = self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/serial') + async def get_vm_serial(self, vm): + vm = await self.index_vm(vm) + rsp = await self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/serial') if rsp[1] == 200 and len(rsp[0]) > 0: portid = rsp[0][0]['port'] - rsp = self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/serial/{portid}') + rsp = await self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/serial/{portid}') if rsp[1] == 200: if rsp[0]['backing']['type'] != 'NETWORK_SERVER': return @@ -231,7 +238,7 @@ class VmwApiClient: tlsenabled = False if netloc.startswith('telnets'): tlsenabled = True - hostinfo = self.get_vm_host(vm) + hostinfo = await self.get_vm_host(vm) hostname = hostinfo['name'] rsp[0] return { @@ -240,9 +247,9 @@ class VmwApiClient: 'tls': tlsenabled, } - def get_vm_bootdev(self, vm): - vm = self.index_vm(vm) - rsp = self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/boot') + async def get_vm_bootdev(self, vm): + vm = await self.index_vm(vm) + rsp = await self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/boot') if rsp[0]['enter_setup_mode']: return 'setup' rsp = self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/boot/device') @@ -253,9 +260,9 @@ class VmwApiClient: pass return 'default' - def get_vm_power(self, vm): - vm = self.index_vm(vm) - rsp = self.wc.grab_json_response(f'/api/vcenter/vm/{vm}/power') + async def get_vm_power(self, vm): + vm = await self.index_vm(vm) + rsp = await self.wc.grab_json_response(f'/api/vcenter/vm/{vm}/power') if rsp['state'] == 'POWERED_ON': return 'on' if rsp['state'] == 'POWERED_OFF': @@ -264,12 +271,12 @@ class VmwApiClient: return 'suspended' raise Exception("Unknown response {}".format(repr(rsp))) - def set_vm_power(self, vm, state): + async def set_vm_power(self, vm, state): current = None targstate = state - vm = self.index_vm(vm) + vm = await self.index_vm(vm) if state == 'boot': - current = self.get_vm_power(vm) + current = await self.get_vm_power(vm) if current == 'on': state = 'reset' targstate = state @@ -280,12 +287,12 @@ class VmwApiClient: state = 'start' elif state == 'off': state = 'stop' - rsp = self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/power?action={state}', method='POST') + rsp = await self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/power?action={state}', method='POST') return targstate, current - def set_vm_bootdev(self, vm, bootdev): - vm = self.index_vm(vm) + async def set_vm_bootdev(self, vm, bootdev): + vm = await self.index_vm(vm) self.wc.set_header('Content-Type', 'application/json') try: bootdevs = [] @@ -297,18 +304,18 @@ class VmwApiClient: # However, vmware api counter to documentation seems to just ignore # such a request. So instead we just go "disk first" # and rely upon fast fail/retry to take us to a normal place - currdisks, rcode = self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/disk') + currdisks, rcode = await self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/disk') currdisks = [x['disk'] for x in currdisks] bootdevs.append({'type': 'DISK', 'disks': currdisks}) elif bootdev in ('net', 'network'): - currnics, rcode = self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/ethernet') + currnics, rcode = await self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/ethernet') for nic in currnics: bootdevs.append({'type': 'ETHERNET', 'nic': nic['nic']}) payload = {'devices': bootdevs} - rsp = self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/boot/device', + rsp = await self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/boot/device', payload, method='PUT') - rsp = self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/boot', + rsp = await self.wc.grab_json_response_with_status(f'/api/vcenter/vm/{vm}/hardware/boot', {'enter_setup_mode': entersetup}, method='PATCH') finally: @@ -329,16 +336,16 @@ def prep_vcsa_clients(nodes, configmanager): clientsbynode[node] = clientsbyvcsa[currvcsa] return clientsbynode -def retrieve(nodes, element, configmanager, inputdata): +async def retrieve(nodes, element, configmanager, inputdata): clientsbynode = prep_vcsa_clients(nodes, configmanager) for node in nodes: currclient = clientsbynode[node] if element == ['power', 'state']: - yield msg.PowerState(node, currclient.get_vm_power(node)) + yield msg.PowerState(node, await currclient.get_vm_power(node)) elif element == ['boot', 'nextdevice']: - yield msg.BootDevice(node, currclient.get_vm_bootdev(node)) + yield msg.BootDevice(node, await currclient.get_vm_bootdev(node)) elif element[:2] == ['inventory', 'hardware'] and len(element) == 4: - for rsp in currclient.get_vm_inventory(node): + async for rsp in currclient.get_vm_inventory(node): yield rsp elif element == ['console', 'ikvm_methods']: dsc = {'ikvm_methods': ['screenshot']} diff --git a/confluent_server/confluentsrv.spec b/confluent_server/confluentsrv.spec index 0d558ad2..a0797042 100644 --- a/confluent_server/confluentsrv.spec +++ b/confluent_server/confluentsrv.spec @@ -5,7 +5,7 @@ block_cipher = None a = Analysis(['c:/Python27/Scripts/confluentsrv.py'], pathex=[], - hiddenimports=['pyghmi.constants', 'pyghmi.exceptions', 'pyghmi.ipmi.console', 'pyghmi.ipmi.private.constants', 'pyghmi.ipmi.private', 'pyghmi.ipmi.private.session', 'pyghmi.ipmi.command', 'pyghmi.ipmi.events', 'pyghmi.ipmi.fru', 'pyghmi.ipmi.private.spd', 'pyghmi.ipmi.oem.lookup', 'pyghmi.ipmi.oem.generic', 'pyghmi.ipmi.oem.lenovo', 'pyghmi.ipmi.private.util', 'pyghmi.ipmi.sdr'], + hiddenimports=[], # ['pyghmi.constants', 'pyghmi.exceptions', 'pyghmi.ipmi.console', 'pyghmi.ipmi.private.constants', 'pyghmi.ipmi.private', 'pyghmi.ipmi.private.session', 'pyghmi.ipmi.command', 'pyghmi.ipmi.events', 'pyghmi.ipmi.fru', 'pyghmi.ipmi.private.spd', 'pyghmi.ipmi.oem.lookup', 'pyghmi.ipmi.oem.generic', 'pyghmi.ipmi.oem.lenovo', 'pyghmi.ipmi.private.util', 'pyghmi.ipmi.sdr'], hookspath=None, runtime_hooks=None, excludes=None,