diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-07-24 09:54:23 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-07-24 09:54:44 +0000 |
commit | 836b47cb7e99a977c5a23b059ca1d0b5065d310e (patch) | |
tree | 1604da8f482d02effa033c94a84be42bc0c848c3 /collectors/python.d.plugin/hpssa/hpssa.chart.py | |
parent | Releasing debian version 1.44.3-2. (diff) | |
download | netdata-836b47cb7e99a977c5a23b059ca1d0b5065d310e.tar.xz netdata-836b47cb7e99a977c5a23b059ca1d0b5065d310e.zip |
Merging upstream version 1.46.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'collectors/python.d.plugin/hpssa/hpssa.chart.py')
-rw-r--r-- | collectors/python.d.plugin/hpssa/hpssa.chart.py | 396 |
1 files changed, 0 insertions, 396 deletions
diff --git a/collectors/python.d.plugin/hpssa/hpssa.chart.py b/collectors/python.d.plugin/hpssa/hpssa.chart.py deleted file mode 100644 index 66be0083..00000000 --- a/collectors/python.d.plugin/hpssa/hpssa.chart.py +++ /dev/null @@ -1,396 +0,0 @@ -# -*- coding: utf-8 -*- -# Description: hpssa netdata python.d module -# Author: Peter Gnodde (gnoddep) -# SPDX-License-Identifier: GPL-3.0-or-later - -import os -import re -from copy import deepcopy - -from bases.FrameworkServices.ExecutableService import ExecutableService -from bases.collection import find_binary - -disabled_by_default = True -update_every = 5 - -ORDER = [ - 'ctrl_status', - 'ctrl_temperature', - 'ld_status', - 'pd_status', - 'pd_temperature', -] - -CHARTS = { - 'ctrl_status': { - 'options': [ - None, - 'Status 1 is OK, Status 0 is not OK', - 'Status', - 'Controller', - 'hpssa.ctrl_status', - 'line' - ], - 'lines': [] - }, - 'ctrl_temperature': { - 'options': [ - None, - 'Temperature', - 'Celsius', - 'Controller', - 'hpssa.ctrl_temperature', - 'line' - ], - 'lines': [] - }, - 'ld_status': { - 'options': [ - None, - 'Status 1 is OK, Status 0 is not OK', - 'Status', - 'Logical drives', - 'hpssa.ld_status', - 'line' - ], - 'lines': [] - }, - 'pd_status': { - 'options': [ - None, - 'Status 1 is OK, Status 0 is not OK', - 'Status', - 'Physical drives', - 'hpssa.pd_status', - 'line' - ], - 'lines': [] - }, - 'pd_temperature': { - 'options': [ - None, - 'Temperature', - 'Celsius', - 'Physical drives', - 'hpssa.pd_temperature', - 'line' - ], - 'lines': [] - } -} - -adapter_regex = re.compile(r'^(?P<adapter_type>.+) in Slot (?P<slot>\d+)') -ignored_sections_regex = re.compile( - r''' - ^ - Physical[ ]Drives - | None[ ]attached - | (?:Expander|Enclosure|SEP|Port[ ]Name:)[ ].+ - | .+[ ]at[ ]Port[ ]\S+,[ ]Box[ ]\d+,[ ].+ - | Mirror[ ]Group[ ]\d+: - $ - ''', - re.X -) -mirror_group_regex = re.compile(r'^Mirror Group \d+:$') -disk_partition_regex = re.compile(r'^Disk Partition Information$') -array_regex = re.compile(r'^Array: (?P<id>[A-Z]+)$') -drive_regex = re.compile( - r''' - ^ - Logical[ ]Drive:[ ](?P<logical_drive_id>\d+) - | physicaldrive[ ](?P<fqn>[^:]+:\d+:\d+) - $ - ''', - re.X -) -key_value_regex = re.compile(r'^(?P<key>[^:]+): ?(?P<value>.*)$') -ld_status_regex = re.compile(r'^Status: (?P<status>[^,]+)(?:, (?P<percentage>[0-9.]+)% complete)?$') -error_match = re.compile(r'Error:') - - -class HPSSAException(Exception): - pass - - -class HPSSA(object): - def __init__(self, lines): - self.lines = [line.strip() for line in lines if line.strip()] - self.current_line = 0 - self.adapters = [] - self.parse() - - def __iter__(self): - return self - - def __next__(self): - if self.current_line == len(self.lines): - raise StopIteration - - line = self.lines[self.current_line] - self.current_line += 1 - - return line - - def next(self): - """ - This is for Python 2.7 compatibility - """ - return self.__next__() - - def rewind(self): - self.current_line = max(self.current_line - 1, 0) - - @staticmethod - def match_any(line, *regexes): - return any([regex.match(line) for regex in regexes]) - - def parse(self): - for line in self: - match = adapter_regex.match(line) - if match: - self.adapters.append(self.parse_adapter(**match.groupdict())) - - def parse_adapter(self, slot, adapter_type): - adapter = { - 'slot': int(slot), - 'type': adapter_type, - - 'controller': { - 'status': None, - 'temperature': None, - }, - 'cache': { - 'present': False, - 'status': None, - 'temperature': None, - }, - 'battery': { - 'status': None, - 'count': 0, - }, - - 'logical_drives': [], - 'physical_drives': [], - } - - for line in self: - if error_match.match(line): - raise HPSSAException('Error: {}'.format(line)) - elif adapter_regex.match(line): - self.rewind() - break - elif array_regex.match(line): - self.parse_array(adapter) - elif line in ('Unassigned', 'unassigned') or line == 'HBA Drives': - self.parse_physical_drives(adapter) - elif ignored_sections_regex.match(line): - self.parse_ignored_section() - else: - match = key_value_regex.match(line) - if match: - key, value = match.group('key', 'value') - if key == 'Controller Status': - adapter['controller']['status'] = value == 'OK' - elif key == 'Controller Temperature (C)': - adapter['controller']['temperature'] = int(value) - elif key == 'Cache Board Present': - adapter['cache']['present'] = value == 'True' - elif key == 'Cache Status': - adapter['cache']['status'] = value == 'OK' - elif key == 'Cache Module Temperature (C)': - adapter['cache']['temperature'] = int(value) - elif key == 'Battery/Capacitor Count': - adapter['battery']['count'] = int(value) - elif key == 'Battery/Capacitor Status': - adapter['battery']['status'] = value == 'OK' - else: - raise HPSSAException('Cannot parse line: {}'.format(line)) - - return adapter - - def parse_array(self, adapter): - for line in self: - if HPSSA.match_any(line, adapter_regex, array_regex, ignored_sections_regex): - self.rewind() - break - - match = drive_regex.match(line) - if match: - data = match.groupdict() - if data['logical_drive_id']: - self.parse_logical_drive(adapter, int(data['logical_drive_id'])) - else: - self.parse_physical_drive(adapter, data['fqn']) - elif not key_value_regex.match(line): - self.rewind() - break - - def parse_physical_drives(self, adapter): - for line in self: - match = drive_regex.match(line) - if match: - self.parse_physical_drive(adapter, match.group('fqn')) - else: - self.rewind() - break - - def parse_logical_drive(self, adapter, logical_drive_id): - ld = { - 'id': logical_drive_id, - 'status': None, - 'status_complete': None, - } - - for line in self: - if HPSSA.match_any(line, mirror_group_regex, disk_partition_regex): - self.parse_ignored_section() - continue - - match = ld_status_regex.match(line) - if match: - ld['status'] = match.group('status') == 'OK' - - if match.group('percentage'): - ld['status_complete'] = float(match.group('percentage')) / 100 - elif HPSSA.match_any(line, adapter_regex, array_regex, drive_regex, ignored_sections_regex) \ - or not key_value_regex.match(line): - self.rewind() - break - - adapter['logical_drives'].append(ld) - - def parse_physical_drive(self, adapter, fqn): - pd = { - 'fqn': fqn, - 'status': None, - 'temperature': None, - } - - for line in self: - if HPSSA.match_any(line, adapter_regex, array_regex, drive_regex, ignored_sections_regex): - self.rewind() - break - - match = key_value_regex.match(line) - if match: - key, value = match.group('key', 'value') - if key == 'Status': - pd['status'] = value == 'OK' - elif key == 'Current Temperature (C)': - pd['temperature'] = int(value) - else: - self.rewind() - break - - adapter['physical_drives'].append(pd) - - def parse_ignored_section(self): - for line in self: - if HPSSA.match_any(line, adapter_regex, array_regex, drive_regex, ignored_sections_regex) \ - or not key_value_regex.match(line): - self.rewind() - break - - -class Service(ExecutableService): - def __init__(self, configuration=None, name=None): - super(Service, self).__init__(configuration=configuration, name=name) - self.order = ORDER - self.definitions = deepcopy(CHARTS) - self.ssacli_path = self.configuration.get('ssacli_path', 'ssacli') - self.use_sudo = self.configuration.get('use_sudo', True) - self.cmd = [] - - def get_adapters(self): - try: - adapters = HPSSA(self._get_raw_data(command=self.cmd)).adapters - if not adapters: - # If no adapters are returned, run the command again but capture stderr - err = self._get_raw_data(command=self.cmd, stderr=True) - if err: - raise HPSSAException('Error executing cmd {}: {}'.format(' '.join(self.cmd), '\n'.join(err))) - return adapters - except HPSSAException as ex: - self.error(ex) - return [] - - def check(self): - if not os.path.isfile(self.ssacli_path): - ssacli_path = find_binary(self.ssacli_path) - if ssacli_path: - self.ssacli_path = ssacli_path - else: - self.error('Cannot locate "{}" binary'.format(self.ssacli_path)) - return False - - if self.use_sudo: - sudo = find_binary('sudo') - if not sudo: - self.error('Cannot locate "{}" binary'.format('sudo')) - return False - - allowed = self._get_raw_data(command=[sudo, '-n', '-l', self.ssacli_path]) - if not allowed or allowed[0].strip() != os.path.realpath(self.ssacli_path): - self.error('Not allowed to run sudo for command {}'.format(self.ssacli_path)) - return False - - self.cmd = [sudo, '-n'] - - self.cmd.extend([self.ssacli_path, 'ctrl', 'all', 'show', 'config', 'detail']) - self.info('Command: {}'.format(self.cmd)) - - adapters = self.get_adapters() - - self.info('Discovered adapters: {}'.format([adapter['type'] for adapter in adapters])) - if not adapters: - self.error('No adapters discovered') - return False - - return True - - def get_data(self): - netdata = {} - - for adapter in self.get_adapters(): - status_key = '{}_status'.format(adapter['slot']) - temperature_key = '{}_temperature'.format(adapter['slot']) - ld_key = 'ld_{}_'.format(adapter['slot']) - - data = { - 'ctrl_status': { - 'ctrl_' + status_key: adapter['controller']['status'], - 'cache_' + status_key: adapter['cache']['present'] and adapter['cache']['status'], - 'battery_' + status_key: - adapter['battery']['status'] if adapter['battery']['count'] > 0 else None - }, - - 'ctrl_temperature': { - 'ctrl_' + temperature_key: adapter['controller']['temperature'], - 'cache_' + temperature_key: adapter['cache']['temperature'], - }, - - 'ld_status': { - ld_key + '{}_status'.format(ld['id']): ld['status'] for ld in adapter['logical_drives'] - }, - - 'pd_status': {}, - 'pd_temperature': {}, - } - - for pd in adapter['physical_drives']: - pd_key = 'pd_{}_{}'.format(adapter['slot'], pd['fqn']) - data['pd_status'][pd_key + '_status'] = pd['status'] - data['pd_temperature'][pd_key + '_temperature'] = pd['temperature'] - - for chart, dimension_data in data.items(): - for dimension_id, value in dimension_data.items(): - if value is None: - continue - - if dimension_id not in self.charts[chart]: - self.charts[chart].add_dimension([dimension_id]) - - netdata[dimension_id] = value - - return netdata |