#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Univention Monitoring
#
# Copyright 2004-2022 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <https://www.gnu.org/licenses/>.

import re
from univention.config_registry import ucr
from univention.monitoring import Alert


class I2O_RAIDCheck(Alert):

	STATUS = {
		# OK:
		'Optimal': 0,
		# Warnings:
		'Rebuilding': 11,
		'Reconstruct': 12,
		'Reconstructing': 13,
		'Replaced Drive': 14,
		'Expanding': 15,
		'Warning': 16,
		'Verify': 17,
		# Errors:
		'Degraded': 20,
		'Dead': 21,
		'Failed': 22,
		'Error': 23,
		'Missing': 24,
	}

	re_other = re.compile(r'^\s*(d(\d{1,2})b\d{1,2}t\d{1,2}d\d{1,2})\s+(RAID|Disk).*\W(\d+MB)\s+\W(.*?)(?: \d{1,3}%)?$')
	re_controller = re.compile(r'^(d(\d{1,2})) -- --\s+(\w+)\s+\w+\s+\w+\s+\w+\s+[\w\.\_\-]+\s+([\.\-\_\w]+)\s*(%s)\s*$' % (
		'|'.join(re.escape(s) for s in STATUS)
	))

	def write_metrics(self):
		device = ucr.get_int('monitoring/raid/device')  # TODO: do we need to support more than one device?
		options = ('physical', 'logical', 'controller', 'raid')
		cmd = ['/usr/sbin/raidutil']
		for option in options:
			cmd.extend(['-L', option])
		try:
			rc, output = self.exec_command(cmd)
		except OSError as err:
			self.log.debug('error executing raidutil: %s' % (err,))
			for option in options:
				self.write_metric('univention_i2o_raid_%s' % (option,), -1, device=device)
			return

		for option, text in zip(options, output.split('\n\n')[0:4]):
			self.write_option_metric([device], option, text)  # test status of device

	def write_option_metric(self, devices, option, txt):
		for line in txt.splitlines():
			line = line.strip()

			result = self.re_other.match(line) if option in ['physical', 'logical', 'raid'] else self.re_controller.match(line)
			if not result:
				continue
			(addr, device, type_, size_or_serial, status) = result.groups()
			if int(device) not in devices:
				continue
			state = self.STATUS.get(status, -1)
			self.write_metric('univention_i2o_raid_%s' % (option,), state, device=device)


if __name__ == '__main__':
	I2O_RAIDCheck.main()
