From bd2c740c8c028743f1f62fea5258640788851ba7 Mon Sep 17 00:00:00 2001 From: Varac <varac@varac.net> Date: Sun, 5 Feb 2023 20:48:26 +0100 Subject: [PATCH] Migrate to waybar --- README.md | 11 ++- alertmanager_status.py | 66 ++++++++++++++++ .../prometheus-green.svg | 0 prometheus.svg => img/prometheus.svg | Bin 33843 -> 33835 bytes tray-example.png => img/tray-example.png | Bin indicator_alertmanager.py => indicator.py | 14 ++-- query_alertmanager.py | 71 ------------------ 7 files changed, 80 insertions(+), 82 deletions(-) create mode 100755 alertmanager_status.py rename prometheus-green.svg => img/prometheus-green.svg (100%) rename prometheus.svg => img/prometheus.svg (51%) rename tray-example.png => img/tray-example.png (100%) rename indicator_alertmanager.py => indicator.py (94%) delete mode 100755 query_alertmanager.py diff --git a/README.md b/README.md index 4262fab..fd110ab 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 0000000..4190e4b --- /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 GIT binary patch delta 969 zcmdno!L+)AiMunv&z(z(i-CcGYa@?36C>AV6DCPUMy}0%%+pyIxi&vzHv;h_IfX%# zF4qB&l6O42nKifq_yU4z-!AukJNwTAu6JdInGDJa-xhoLXdRkR#4x2@YI5C;>$iSz zO};4bosnzuNkLOauFd}i6IdC!HYbYnfs8AVc*4lYH91tOl#y%mX{qHPvx{XN7=^gZ z_nR!sx1H_r<2={)a}`JXxi%k_I|oubMZtLU2?ZgL?%RsSOpIKU`Bk(Sxh7kw6fkma zUafK%B$Thdmyv6-u0|&#*W~RQxr|(!RW)Nkx|_6&#JFtkEU~G(EuZ#i-tk6h#v4m} zcoc%THlNlKXJO=;{8;ZgBiH2J`sR#WlRxXLF>+0oGVo&L+MH@o%*?^{@9h?)&ri8F zKQI;t+4I9RiIHn^w3!kk*XBC2aAroX&DSh7Ko<SCn#9Ppd6IQI<76pYS!u3`ECEGd zXGi<l8VWsi2>VgJnrVW{+tv3CE4elY*}8)KJ;OepNr&sp3uivLf+q|bja=#HSE{ix ze9U5(6JQd!dNsIGi~X1>yMw0BDz5-Oh9g{)m7Q)eadB<_@AR38lS}6d>k@_|Wn7d0 zxOOvgZSHVu0J(<KO9A8>EpJ^$uE`PJ3XEKvE4}5|8M!vk2#N<O_z|iC3QE~<CXjy= zB6}IRHm{3R1ZlbuCCSJ&`Bl^gMy}1XqfHr^xu$S!z8oV6QvWpeIEY#s{|uyZN@6G@ z*XCD=4$O>PleJSpk-0E6oRNu(Yx1wO6O3Gw52vRwa&6YiP+=70ntS*D^xOU(ObiSQ z4DP&L%QZPZ(~yyC^2E#(My|=<GWRobZQhop1ai&IoC-#+$w9d}j9ioV=l)^jn!Gn} z8za}|lKiV6TfGWx8M!8R6dq;dn(SAk#K<+duxO$ZC{>2k=Jw_nUN=8to}jVj^lR(t zdkO6C&T<{O)c5VDJJ)2@;%H$ml}3wKx9xs#&5Uyq(s*F@NsDXq<YG{woV=*Sjgf2e z%aVPJT$@*vIx<RfH6LL-#c1Hft{?Vq+mg;DjW&5t<tDvh=Gx3ut`BmFQH3ib*W`+d zTt=?R&nmVsa!sCHIbV!x=Ff29M!Tb>E(}i@L{q%IA9J7m!nHY|sv4x{Om#LR*JO*D z?QC2{|5xzYO#W7Ln2~Gpu3At?Db_6jC5b}~;6y9mRKm&Cc=P_@hmBlZljk(4Fmg>k P*woC(HQBZK9U~V2M!rqu delta 986 zcmZ48!L+%9iKjEb&z+Y`ii?4Pfp;UfIuj%BW@9EvMn>MvzRc5E7<o58Wj6xxBshgZ zln&Pckdn7NyO}k31NZ`hYTqvReLMTl1KxLKhM5e?3Evib_-GxPP{c5$U21aOjqA65 z@J_xU@STx&@(DpxM&8Z;1QS@96nHnsi}QiZ%aeG*$jCc6SgMqfck@Z9<sicgWgQrW zc+K~lEX%i@?eXJ0*Y<N2NBem<AC@}@Qaee(n2~4mQ3WB8{u_$MOpLsfc~rC*c_*8z z6fp8`UZHXrB$T7Rmyvg}mPRKd@8m5Sxs1G<l{8~O`s=lf7!@XO)DmUn-F#e2oQ08h z@_oJQjJ%V#>zgz3PJXYi#>hKa%)pD0cXOgaF*676zqebIK0oE%e8*TEWbhZ$Bu3uJ z;buyVyql}c!kHO)H(#>U0Ga&TY7!&w=059oMoR^*&&=@xGm8>#-q{?f<gjs{6vsaw z4u(aG@=op8t;#!*C7|f*>}Wq*L!qY*VLz%@Gfhx=yZXLiCGTcmTUSsZOtz0_;^F=B z!kJI5;0c39Bk$yYj`EDWljWRlG4b+l{^j(UiA#Y?=L_o+h9hOXlfSukGxBb3a%%uN zhuKR3<Qx@mT_xVRGbexgB`vP~;`|c7uoah`w=bXh@@3InEltmR?VH<vSMqKy_LgI3 z<lQ_eC?2HuQ>Y3kT*bqgKz@~q>;;8rq#~m<??xX1bG^BjuV4C6Hi>~j=8k@ZZ_*DV zPk%Mu$xos-F!FAm8g0tR%sYj5^Vt|dkQw)5kAtY?@y|f6=}Qb{<lX!v(Sezfcd}|K zD86T>hBGqp@=pGec7l<2^4|0`M&8XT87ho|ymRl~pMKllgNcD*fx(@(Yk4O}W*Rc` zPVUZ3VdS0sA#*<?@8%6zN+1_r&Z%JJo$QmF!^k^%XYL;+1>VWq^0qPZZqCiW3bNL@ z(3X*Ra%169M&8NpMM{jkle3B@GAc~|T_nZ9d*o8zx1a93lVyveg?UvPEneNW`@uUi z&P7P$f!QZ5-p$>`phP-(R*4%U@8pLi`xtpQFDP|nl;mwb!gz|&z=>Ty?BBK}ol6>R z@}9~~dc(}S`B#}f$X2ZiS4Q5+1r@oByp!)$Y+>Y`Jh^hd81KxV;lhn}M@wB8o-&B0 zczZwQKKq4tvqx1mNY9b#Y)0P61~uE+d5iw9;ImPf{I=#WBk$ymwV-g3s9OL^7CRfj kX;`eOgp;@N=KaGD8+myrPi|6S<ej{ushN>?vQ6_l0K!&V5C8xG 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 6d1ff58..e4d4066 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 d14d6bb..0000000 --- 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) -- GitLab