diff --git a/README.md b/README.md index 4262fab75a5cf98fcbbe38898d8cece8a750b1f8..fd110ab447b607f6f14a5db24f6b53a05164f85c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ -# Alertmanager indicator +# Alertmanager status -Tray icon for [alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/), based on [libappindicator](https://launchpad.net/libappindicator). +`./alertmanager_status.py` will output the [alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/) +status details in a [waybar](https://github.com/Alexays/Waybar) compatible +JSON format. + +It also holds a historic `indicator.py` python class for a tray icon +based on [libappindicator](https://launchpad.net/libappindicator). I don't use +it anymore and it doesn't work in the current state, although it might be +easy to get it working again.  diff --git a/alertmanager_status.py b/alertmanager_status.py new file mode 100755 index 0000000000000000000000000000000000000000..4190e4b70e32e637a8d58d1c83c05d292005c442 --- /dev/null +++ b/alertmanager_status.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +""" +Alertmanager status applet using appindicator. +""" + +import json +import os +from pathlib import Path +import plac +import yaml +from query_alertmanager import get_alerts + + +def show_alerts(opts): + """Show alerts.""" + alerts = get_alerts(url=opts["url"], + port=opts["port"], + user=opts["user"], + password=opts["password"]) + + # Construct waybar output + # https://github.com/Alexays/Waybar/wiki/Module:-Custom#return-type + # {"text": "$text", "alt": "$alt", "tooltip": "$tooltip", + # "class": "$class", "percentage": $percentage }. + # This means the output should also be on a single line + output = {} + output["text"] = alerts['summary'] + if alerts['summary'] == "Cant connect": + output["alt"] = "error" + output["tooltip"] = "Some error occurred." + else: + if alerts["count"] > 0: + output["alt"] = "firing" + output["tooltip"] = '\n'.join(alerts['alerts']) + else: + output["alt"] = "snafu" + output["tooltip"] = "Situation normal, all fucked up 😃" + print(json.dumps(output)) + + +@plac.opt('configpath', "Path to alertmanager config", type=Path) +@plac.opt('mode', "Mode: wayland or indicator (not working)", type=str) +@plac.flg('debug', "Enable debug mode") +def main(configpath='~/.config/indicator_alertmanager/config.yml', + mode="wayland"): + """Main function.""" + + # Load config + with open(Path.expanduser(configpath), encoding="UTF8") as config_file: # type:ignore + opts_raw = yaml.load(config_file, Loader=yaml.FullLoader) + opts = {} + opts["url"] = opts_raw.get('url') + opts["port"] = opts_raw.get('port', 443) + opts["user"] = opts_raw.get('user', 'admin') + opts["password"] = opts_raw.get('password') + opts["icon_red"] = os.path.abspath("./prometheus.svg") + opts["icon_green"] = os.path.abspath("./prometheus-green.svg") + + if mode == "wayland": + show_alerts(opts) + # if mode == "indicator": + # Indicator() + + +if __name__ == "__main__": + plac.call(main) diff --git a/prometheus-green.svg b/img/prometheus-green.svg similarity index 100% rename from prometheus-green.svg rename to img/prometheus-green.svg diff --git a/prometheus.svg b/img/prometheus.svg similarity index 51% rename from prometheus.svg rename to img/prometheus.svg index b931fe76dd4b907b095e49f7d77c37fbfbfbcfd9..ccce45fcf39cdd9dfd8719286bcb36beef4ed19d 100644 Binary files a/prometheus.svg and b/img/prometheus.svg differ diff --git a/tray-example.png b/img/tray-example.png similarity index 100% rename from tray-example.png rename to img/tray-example.png diff --git a/indicator_alertmanager.py b/indicator.py similarity index 94% rename from indicator_alertmanager.py rename to indicator.py index 6d1ff58206c455e073fe6fc27d51ed879ef618ff..e4d406621aaec02e4d33ba21ecf9c6fafab1aa1e 100755 --- a/indicator_alertmanager.py +++ b/indicator.py @@ -1,20 +1,22 @@ #!/usr/bin/env python3 """ Alertmanager status applet using appindicator. + +Install dependencies (`libffi7` is needed by `pygobject`): + + sudo apt install gir1.2-appindicator3-0.1 libffi7 """ -# import json import os from pathlib import Path -import signal import time from threading import Thread import plac import gi import yaml -from gi.repository import Gtk, AppIndicator3, GLib # type: ignore from query_alertmanager import get_alerts +from gi.repository import Gtk, AppIndicator3, Glib # type: ignore gi.require_version('Gtk', '3.0') gi.require_version('AppIndicator3', '0.1') @@ -103,9 +105,3 @@ class Indicator(): def stop(self): """Exit indicator.""" Gtk.main_quit() - - -if __name__ == "__main__": - plac.call(Indicator) - signal.signal(signal.SIGINT, signal.SIG_DFL) - Gtk.main() diff --git a/query_alertmanager.py b/query_alertmanager.py deleted file mode 100755 index d14d6bbd2561e373ebdce7371fc943327c8ec9cf..0000000000000000000000000000000000000000 --- a/query_alertmanager.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python3 -"""Queries alertmanager for alerts, outputs json. - -Can be also used as cli application. -Usage: - - ./query_alertmananger.py -h -""" - -import json -import plac -import requests -from alertmanager import AlertManager - - -def get_alerts(url, password, port=443, user='admin'): - req = requests.Session() - req.auth = (user, password) - AM = AlertManager(host=url, port=port, req_obj=req) - - count = 0 - alerts = [] - state = "unknown" - - try: - alerts_raw = AM.get_alerts() - for alert in alerts_raw: - name = alert['labels']['alertname'] - severity = alert['labels']['severity'] - instance = alert['labels']['instance'] - alert_state = alert['status']['state'] - release_name = alert['labels']['release_name'] - - - if severity != "none" and alert_state != "suppressed": - count += 1 - alert_text = f'{name}: {instance}, {release_name} ({severity})' - alerts.append(alert_text) - - if count > 2: - state = "critical" - elif count > 0: - state = "warning" - elif count == 0: - state = "ok" - - summary = f'{count} alerts' - except: - summary = "Cant connect" - state = "warning" - - return_data = { - 'summary': summary, - 'alerts': alerts, - 'state': state, - 'count': count } - return return_data - - -@plac.opt('url', "URL of alertmanager instance", type=str, abbrev='U') -@plac.opt('port', "Port of alertmanager instance", type=int, abbrev='P') -@plac.opt('user', "User name", type=str) -@plac.opt('password', "Password", type=str) -def main(url, password, port=443, user='admin'): - """Main function.""" - alerts = get_alerts(url=url, password=password, port=port, user=user) - print(json.dumps(alerts)) - - -if __name__ == '__main__': - plac.call(main)