add cli to list/clear failures and fix if-alerted alerting

This commit is contained in:
2026-08-02 07:09:30 +03:00
parent fb33fa7596
commit 85c97bcf12
2 changed files with 68 additions and 4 deletions
+15 -1
View File
@@ -2,7 +2,7 @@ import datetime
import os import os
import sqlite3 import sqlite3
def register_success(name, db): def clear_failure(name, db):
cur = db.cursor() cur = db.cursor()
cur.execute(''' cur.execute('''
DELETE FROM alert DELETE FROM alert
@@ -86,6 +86,20 @@ def get_failures(name, db):
failures.sort(key=lambda x: x['timestamp']) failures.sort(key=lambda x: x['timestamp'])
return failures return failures
def get_services(db):
cur = db.cursor()
cur.execute('''SELECT
service.name, COUNT(*)
FROM service
JOIN failure ON
failure.service=service.id
GROUP BY
service.name;
''')
db.commit()
ret = {name: failures for (name, failures) in cur.fetchall()}
return ret
def init(path): def init(path):
con = sqlite3.connect(path, detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES) con = sqlite3.connect(path, detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES)
+53 -3
View File
@@ -1,4 +1,4 @@
import argparse
import configparser import configparser
import datetime import datetime
import importlib import importlib
@@ -37,11 +37,12 @@ def register_exit(config, db):
if os.environ['MONITOR_SERVICE_RESULT'] == 'success': if os.environ['MONITOR_SERVICE_RESULT'] == 'success':
# exit with success status # exit with success status
failures = sysalert.db.get_failures(service_name, db) failures = sysalert.db.get_failures(service_name, db)
sysalert.db.register_success(service_name, db) sysalert.db.clear_failure(service_name, db)
try: try:
do_alert = config.getboolean(section_name, 'recovery_alert') do_alert = config.getboolean(section_name, 'recovery_alert')
except ValueError: except ValueError:
if config.get(section_name, 'recovery_alert') == 'if-alerted' and failures: if config.get(section_name, 'recovery_alert') == 'if-alerted' and \
any([f['alert_method'] for f in failures]):
do_alert = True do_alert = True
else: else:
do_alert = False do_alert = False
@@ -75,6 +76,27 @@ def register_exit(config, db):
alert.failure(service_name, failures, alert_config) alert.failure(service_name, failures, alert_config)
return 0 return 0
def cli_args():
parser = argparse.ArgumentParser(
description='Manage active sysalerts',
epilog='''Note that when called from systemd this argument parser
is not used. Use the provided sysalert-* services and see
documentation for details.''')
parser.add_argument('--service', '-s',
help='Only operate on specific service')
subparsers = parser.add_subparsers()
parser_list = subparsers.add_parser('list')
parser_list.set_defaults(cmd='list')
parser_clear = subparsers.add_parser('clear')
parser_clear.set_defaults(cmd='clear')
parser_clear.add_argument('--force', '-f',
action='store_true',
help='''Force clear for all services if service is
not specified''')
return parser.parse_args()
def cli(): def cli():
config = configparser.ConfigParser() config = configparser.ConfigParser()
@@ -85,9 +107,37 @@ def cli():
if _test_env(): if _test_env():
# invoked by systemd # invoked by systemd
ret = register_exit(config, db) ret = register_exit(config, db)
else:
args = cli_args()
if args.service and not args.service.endswith('.service'):
args.service = f'{args.service}.service'
if args.cmd == 'list':
cli_list(args, db)
elif args.cmd == 'clear':
cli_clear(args, db)
sysalert.db.close(db) sysalert.db.close(db)
return ret return ret
def cli_list(args, db):
for service, failures in sysalert.db.get_services(db).items():
if args.service and args.service == service:
print(f'{service}: {failures} failures')
return 0
def cli_clear(args, db):
if not args.service and not args.force:
print(f'No service specified, use "--force" to clear all services', sys.stderr)
return 1
if args.service:
sysalert.db.clear_failure(args.service, db)
print(f'Cleared failures for {args.service}')
else:
for service, failures in sysalert.db.get_services(db).items():
sysalert.db.clear_failure(service, db)
print(f'Cleared all failures')
return 0
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(cli()) sys.exit(cli())