2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-09-12 12:36:24 +00:00
Files
confluent/confluent_server/confluent/plugins/hardwaremanagement/enlogic.py
T
Markus Hilger 2af402b13c ruff auto fixes
Apply ruff's safe autofixes.
The changes are mechanical and behaviour-preserving. Issues fixed:

- F401: remove unused imports.
- F841: drop unused local variables and assignments, including discarded
  await/return values, unused "except ... as e" bindings, and unused
  "with ... as name" targets.
- F541: remove the f prefix from f-strings that contain no placeholders.
- E711: compare against None with "is"/"is not" instead of "=="/"!=".
- E712: test truthiness directly instead of comparing to True.
- E713: use "x not in y" instead of "not x in y".
- E714: use "is not" instead of "not ... is".
- E731: convert lambdas bound to a name into def statements.
- W291/W293: trim trailing whitespace on touched lines.
2026-07-14 05:03:58 +02:00

273 lines
8.8 KiB
Python

# Copyright 2022 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import asyncio
import confluent.util as util
import confluent.messages as msg
import aiohmi.util.webclient as wc
import confluent.tasks as tasks
import time
def simplify_name(name):
return name.lower().replace(' ', '_').replace('/', '-').replace('_-_', '-')
pdupool = tasks.TaskPool(128)
_pduclients = {}
class EnlogicClient(object):
def __init__(self, pdu, configmanager):
self.node = pdu
self.configmanager = configmanager
self._token = None
self._wc = None
self.username = None
async def token(self):
if not self._token:
self._token = await self.login(self.configmanager)
return self._token
@property
def wc(self):
if self._wc:
return self._wc
targcfg = self.configmanager.get_node_attributes(
self.node, ['hardwaremanagement.manager'], decrypt=True
)
targcfg = targcfg.get(self.node, {})
target = targcfg.get('hardwaremanagement.manager', {}).get('value', None)
if not target:
target = self.node
target = target.split('/', 1)[0]
cv = util.TLSCertVerifier(
self.configmanager, self.node, 'pubkeys.tls_hardwaremanager'
).verify_cert
self._wc = wc.WebConnection(target, port=443, verifycallback=cv)
return self._wc
async def grab_json_response(self, url, body=None):
rsp, status = await self.wc.grab_json_response_with_status(url, body)
if status == 401:
self._token = None
if body and 'cookie' in body:
body['cookie'] = await self.token()
rsp, status = await self.wc.grab_json_response_with_status(url, body)
if status < 300:
return rsp
return {}
async def login(self, configmanager):
credcfg = configmanager.get_node_attributes(
self.node,
['secret.hardwaremanagementuser', 'secret.hardwaremanagementpassword'],
decrypt=True,
)
credcfg = credcfg.get(self.node, {})
username = credcfg.get('secret.hardwaremanagementuser', {}).get('value', None)
passwd = credcfg.get('secret.hardwaremanagementpassword', {}).get('value', None)
if not isinstance(username, str):
username = username.decode('utf8')
if not isinstance(passwd, str):
passwd = passwd.decode('utf8')
if not username or not passwd:
raise Exception('Missing username or password')
self.username = username
rsp = await self.wc.grab_json_response(
'/xhrlogin.jsp',
{'username': username, 'password': passwd, 'cookie': 0}
)
#print(repr(rsp))
self.authtoken = rsp['cookie']
self.wc.set_header('Authorization', self.authtoken)
return self.authtoken
async def logout(self):
if self._token:
await self.wc.grab_json_response(
'/xhrlogout.jsp',
{'timeout': 0, 'cookie': self._token},
)
self._token = None
async def get_outlet(self, outlet):
rsp = await self.grab_json_response(
'/xhroutgetgrid.jsp', {
'cookie': await self.token(),
'pduid': 1
})
outlets = rsp['outlet']
for olet in outlets:
if olet['id'] == int(outlet):
state = "on" if olet['powstat'] == 1 else "off"
return state
async def set_outlet(self, outlet, state):
bitflags = 2**(int(outlet) - 1)
outlet1 = bitflags & (2**24-1)
outlet2 = bitflags >> 24
if state == 'off':
state = 0
elif state == 'on':
state = 1
else:
raise Exception("Unrecognized state " + repr(state))
request = {
'cookie': await self.token(),
'outlet1': outlet1,
'outlet2': outlet2,
'pduid': 1,
'powstat': state
}
await self.grab_json_response('/xhroutpowstatset.jsp', request)
_sensors_by_node = {}
async def read_sensors(element, node, configmanager):
category, name = element[-2:]
justnames = False
msgs = []
if len(element) == 3:
# just get names
category = name
name = 'all'
justnames = True
if category in ('leds, fans', 'temperature'):
return
if justnames:
msgs.append(msg.ChildCollection('total_energy'))
msgs.append(msg.ChildCollection('total_apparent_power'))
msgs.append(msg.ChildCollection('total_real_power'))
return msgs
sn = _sensors_by_node.get(node, None)
if not sn or sn[1] < time.time():
gc = get_client(node, configmanager)
adev = await gc.grab_json_response('/energy_get', {'cookie': await gc.token(), 'end': 1, 'start': 1})
_sensors_by_node[node] = (adev, time.time() + 1)
sn = _sensors_by_node.get(node, None)
if sn:
sn = sn[0]
readings = [
{
'name': 'Total Energy',
'value': float(sn[0]['total_energy']) * 0.001,
'units': 'kWh',
'type': 'Energy',
},
{
'name': 'Total Real Power',
'value': float(sn[0]['active_power']),
'units': 'W',
'type': 'Power',
},
{
'name': 'Total Apparent Power',
'value': float(sn[0]['apparent_power']),
'units': 'W',
'type': 'Power',
},
]
return [msg.SensorReadings(readings, name=node)]
def get_client(node, configmanager):
if node not in _pduclients:
_pduclients[node] = EnlogicClient(node, configmanager)
return _pduclients[node]
async def get_outlet(element, node, configmanager):
gc = get_client(node, configmanager)
state = await gc.get_outlet(element[-1])
return msg.PowerState(node=node, state=state)
async def read_firmware(node, configmanager):
gc = get_client(node, configmanager)
adev = await gc.grab_json_response('/xhrgetuserlist.jsp')
myversion = adev[0]['fwver']
return msg.Firmware([{'PDU Firmware': {'version': myversion}}], node)
async def read_inventory(element, node, configmanager):
_inventory = {}
inventory = {}
gc = get_client(node, configmanager)
adev = await gc.grab_json_response('/sys_info_get', {
'cookie': await gc.token(), 'pduid': 1
})
inventory['present'] = True
inventory['name'] = 'PDU'
info = {}
info['Serial Number'] = adev['pdu'][0]['serial_number']
info['Product Name'] = adev['pdu'][0]['model']
info['Model'] = adev['pdu'][0]['part_number']
inventory['information'] = info
return msg.KeyValueData({'inventory': [inventory]}, node)
async def retrieve(nodes, element, configmanager, inputdata):
if 'outlets' in element:
gp = tasks.TaskPile(pdupool)
for node in nodes:
gp.spawn(get_outlet, element, node, configmanager)
async for res in gp:
yield res
return
elif element[0] == 'sensors':
gp = tasks.TaskPile(pdupool)
for node in nodes:
gp.spawn(read_sensors, element, node, configmanager)
async for rsp in gp:
for msg in rsp:
yield msg
return
elif '/'.join(element).startswith('inventory/firmware/all'):
gp = tasks.TaskPile(pdupool)
for node in nodes:
gp.spawn(read_firmware, node, configmanager)
async for rsp in gp:
yield rsp
elif '/'.join(element).startswith('inventory/hardware/all'):
gp = tasks.TaskPile(pdupool)
for node in nodes:
gp.spawn(read_inventory, element, node, configmanager)
async for rsp in gp:
yield rsp
else:
for node in nodes:
yield msg.ConfluentResourceUnavailable(node, 'Not implemented')
return
async def update(nodes, element, configmanager, inputdata):
if 'outlets' not in element:
for node in nodes:
yield msg.ConfluentResourceUnavailable(node, 'Not implemented')
return
for node in nodes:
gc = get_client(node, configmanager)
newstate = inputdata.powerstate(node)
await gc.set_outlet(element[-1], newstate)
await asyncio.sleep(1)
async for res in retrieve(nodes, element, configmanager, inputdata):
yield res