netbox-agent/netbox_agent/raid/omreport.py
Christophe Simon ad951b9288 Fixed HP raid parser when disks are in JBOD
The function parsing the RAID logical volumes in the HP module did not
manage the case where disks were set in JBOD mode, thus having no RAID
array set.

This patch fixes this by checking if arrays are defined on pdisks before
parsing the logical disks.

Also added returncode read when executing the RAID related commands to
raise a more precise error.
2022-03-11 15:55:07 +01:00

140 lines
4.4 KiB
Python

from netbox_agent.raid.base import Raid, RaidController
from netbox_agent.misc import get_vendor, get_mount_points
from netbox_agent.config import config
import subprocess
import logging
import re
class OmreportControllerError(Exception):
pass
def omreport(sub_command):
command = ["omreport"]
command.extend(sub_command.split())
p = subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT
)
p.wait()
stdout = p.stdout.read().decode("utf-8")
if p.returncode != 0:
mesg = "Failed to execute command '{}':\n{}".format(
" ".join(command), stdout
)
raise OmreportControllerError(mesg)
res = {}
section_re = re.compile('^[A-Z]')
current_section = None
current_obj = None
for line in stdout.split('\n'):
if ': ' in line:
attr, value = line.split(': ', 1)
attr = attr.strip()
value = value.strip()
if attr == 'ID':
obj = {}
res.setdefault(current_section, []).append(obj)
current_obj = obj
current_obj[attr] = value
elif section_re.search(line) is not None:
current_section = line.strip()
return res
class OmreportController(RaidController):
def __init__(self, controller_index, data):
self.data = data
self.controller_index = controller_index
def get_product_name(self):
return self.data['Name']
def get_manufacturer(self):
return None
def get_serial_number(self):
return self.data.get('DeviceSerialNumber')
def get_firmware_version(self):
return self.data.get('Firmware Version')
def _get_physical_disks(self):
pds = {}
res = omreport('storage pdisk controller={}'.format(
self.controller_index
))
for pdisk in [d for d in list(res.values())[0]]:
disk_id = pdisk['ID']
size = re.sub('B .*$', 'B', pdisk['Capacity'])
pds[disk_id] = {
'Vendor': get_vendor(pdisk['Vendor ID']),
'Model': pdisk['Product ID'],
'SN': pdisk['Serial No.'],
'Size': size,
'Type': pdisk['Media'],
'_src': self.__class__.__name__,
}
return pds
def _get_virtual_drives_map(self):
pds = {}
res = omreport('storage vdisk controller={}'.format(
self.controller_index
))
for vdisk in [d for d in list(res.values())[0]]:
vdisk_id = vdisk['ID']
device = vdisk['Device Name']
mount_points = get_mount_points()
mp = mount_points.get(device, 'n/a')
size = re.sub('B .*$', 'B', vdisk['Size'])
vd = {
'vd_array': vdisk_id,
'vd_size': size,
'vd_consistency': vdisk['State'],
'vd_raid_type': vdisk['Layout'],
'vd_device': vdisk['Device Name'],
'mount_point': ', '.join(sorted(mp)),
}
drives_res = omreport(
'storage pdisk controller={} vdisk={}'.format(
self.controller_index, vdisk_id
))
for pdisk in [d for d in list(drives_res.values())[0]]:
pds[pdisk['ID']] = vd
return pds
def get_physical_disks(self):
pds = self._get_physical_disks()
vds = self._get_virtual_drives_map()
for pd_identifier, vd in vds.items():
if pd_identifier not in pds:
logging.error(
'Physical drive {} listed in virtual drive {} not '
'found in drives list'.format(
pd_identifier, vd['vd_array']
)
)
continue
pds[pd_identifier].setdefault('custom_fields', {}).update(vd)
pds[pd_identifier]['custom_fields']['pd_identifier'] = pd_identifier
return list(pds.values())
class OmreportRaid(Raid):
def __init__(self):
self.controllers = []
res = omreport('storage controller')
for controller in res['Controller']:
ctrl_index = controller['ID']
self.controllers.append(
OmreportController(ctrl_index, controller)
)
def get_controllers(self):
return self.controllers