summaryrefslogtreecommitdiffstats
path: root/collectors/python.d.plugin/hpssa/hpssa.chart.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-07-24 09:54:23 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-07-24 09:54:44 +0000
commit836b47cb7e99a977c5a23b059ca1d0b5065d310e (patch)
tree1604da8f482d02effa033c94a84be42bc0c848c3 /collectors/python.d.plugin/hpssa/hpssa.chart.py
parentReleasing debian version 1.44.3-2. (diff)
downloadnetdata-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.py396
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