aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2020-12-29 22:06:59 +0100
committerIsmaël Bouya <ismael.bouya@normalesup.org>2020-12-29 22:06:59 +0100
commit2edbb2d889bd9d1787bc1745a75c1b6969d148ab (patch)
treea2784aad8833d4a1303e7bd90a2ec1587579ad7a /modules
parentb4b5eadc29d2547e181ce60d735a4b943beb2a9a (diff)
downloadNix-2edbb2d889bd9d1787bc1745a75c1b6969d148ab.tar.gz
Nix-2edbb2d889bd9d1787bc1745a75c1b6969d148ab.tar.zst
Nix-2edbb2d889bd9d1787bc1745a75c1b6969d148ab.zip
Add Eban monitoring
Diffstat (limited to 'modules')
-rw-r--r--modules/private/environment.nix8
-rw-r--r--modules/private/monitoring/default.nix6
-rw-r--r--modules/private/monitoring/objects_common.nix3
-rw-r--r--modules/private/monitoring/objects_eban.nix60
-rw-r--r--modules/private/monitoring/objects_phare.nix1
-rw-r--r--modules/private/monitoring/objects_tiboqorl-fr.nix1
-rw-r--r--modules/private/monitoring/objects_ulminfo-fr.nix1
-rwxr-xr-xmodules/private/monitoring/plugins/notify_eban_url13
-rw-r--r--modules/private/monitoring/status.nix7
-rwxr-xr-xmodules/private/monitoring/status/app.py35
-rw-r--r--modules/private/system.nix3
11 files changed, 121 insertions, 17 deletions
diff --git a/modules/private/environment.nix b/modules/private/environment.nix
index e79feec..490a405 100644
--- a/modules/private/environment.nix
+++ b/modules/private/environment.nix
@@ -558,6 +558,14 @@ in
558 }; 558 };
559 }; 559 };
560 }; 560 };
561 eban = mkOption {
562 description = "Eban credentials for webhook";
563 type = submodule {
564 options = {
565 password = mkOption { type = str; description = "Password"; };
566 };
567 };
568 };
561 nrdp_tokens = mkOption { type = listOf str; description = "Tokens allowed to push status update"; }; 569 nrdp_tokens = mkOption { type = listOf str; description = "Tokens allowed to push status update"; };
562 slack_url = mkOption { type = str; description = "Slack webhook url to push status update"; }; 570 slack_url = mkOption { type = str; description = "Slack webhook url to push status update"; };
563 slack_channel = mkOption { type = str; description = "Slack channel to push status update"; }; 571 slack_channel = mkOption { type = str; description = "Slack channel to push status update"; };
diff --git a/modules/private/monitoring/default.nix b/modules/private/monitoring/default.nix
index a298f92..73e4275 100644
--- a/modules/private/monitoring/default.nix
+++ b/modules/private/monitoring/default.nix
@@ -78,6 +78,9 @@ let
78 wrapProgram $out/notify_by_slack --prefix PATH : ${lib.makeBinPath [ 78 wrapProgram $out/notify_by_slack --prefix PATH : ${lib.makeBinPath [
79 pkgs.curl pkgs.jq 79 pkgs.curl pkgs.jq
80 ]} 80 ]}
81 wrapProgram $out/notify_eban_url --prefix PATH : ${lib.makeBinPath [
82 pkgs.curl
83 ]}
81 wrapProgram $out/check_ovh_sms --prefix PATH : ${lib.makeBinPath [ 84 wrapProgram $out/check_ovh_sms --prefix PATH : ${lib.makeBinPath [
82 (pkgs.python3.withPackages (ps: [ps.ovh])) 85 (pkgs.python3.withPackages (ps: [ps.ovh]))
83 ]} 86 ]}
@@ -157,7 +160,7 @@ let
157 }; 160 };
158 otherObjects = map 161 otherObjects = map
159 (n: (pkgs.callPackage (./. + "/objects_" + n + ".nix") { inherit emailCheck; })) 162 (n: (pkgs.callPackage (./. + "/objects_" + n + ".nix") { inherit emailCheck; }))
160 [ "ulminfo-fr" "phare" ]; 163 [ "ulminfo-fr" "phare" "eban" ];
161 masterObjects = pkgs.callPackage ./objects_master.nix { inherit config; }; 164 masterObjects = pkgs.callPackage ./objects_master.nix { inherit config; };
162 commonObjects = pkgs.callPackage ./objects_common.nix ({ 165 commonObjects = pkgs.callPackage ./objects_common.nix ({
163 master = cfg.master; 166 master = cfg.master;
@@ -326,6 +329,7 @@ in
326 config.myEnv.monitoring.ovh_sms.consumer_key 329 config.myEnv.monitoring.ovh_sms.consumer_key
327 config.myEnv.monitoring.ovh_sms.account 330 config.myEnv.monitoring.ovh_sms.account
328 ]} 331 ]}
332 $USER210$=${config.myEnv.monitoring.eban.password}
329 ''; 333 '';
330 objectDefs = toObjects commonObjects 334 objectDefs = toObjects commonObjects
331 + toObjects hostObjects 335 + toObjects hostObjects
diff --git a/modules/private/monitoring/objects_common.nix b/modules/private/monitoring/objects_common.nix
index 7f553a0..df378b5 100644
--- a/modules/private/monitoring/objects_common.nix
+++ b/modules/private/monitoring/objects_common.nix
@@ -34,6 +34,7 @@ in
34 use = "linux-server"; 34 use = "linux-server";
35 hostgroups = "webstatus-hosts"; 35 hostgroups = "webstatus-hosts";
36 _webstatus_name = hostName; 36 _webstatus_name = hostName;
37 _webstatus_vhost = "status.immae.eu";
37 }; 38 };
38 }; 39 };
39 service = [ 40 service = [
@@ -155,6 +156,8 @@ in
155 # $OVE is to force naemon to run via shell instead of execve which fails here 156 # $OVE is to force naemon to run via shell instead of execve which fails here
156 notify-service-by-email = "ADMINEMAIL=\"$ADMINEMAIL$\" SERVICENOTIFICATIONID=\"$SERVICENOTIFICATIONID$\" SERVICEDESC=\"$SERVICEDESC$\" SERVICESTATE=\"$SERVICESTATE$\" SERVICEOUTPUT=\"$SERVICEOUTPUT$\" $USER2$/notify_by_email service \"$NOTIFICATIONTYPE$\" \"$HOSTALIAS$\" \"$LONGDATETIME$\" \"$CONTACTEMAIL$\" $OVE"; 157 notify-service-by-email = "ADMINEMAIL=\"$ADMINEMAIL$\" SERVICENOTIFICATIONID=\"$SERVICENOTIFICATIONID$\" SERVICEDESC=\"$SERVICEDESC$\" SERVICESTATE=\"$SERVICESTATE$\" SERVICEOUTPUT=\"$SERVICEOUTPUT$\" $USER2$/notify_by_email service \"$NOTIFICATIONTYPE$\" \"$HOSTALIAS$\" \"$LONGDATETIME$\" \"$CONTACTEMAIL$\" $OVE";
157 notify-by-slack = "HOST=\"$HOSTALIAS$\" SERVICESTATE=\"$SERVICESTATE$\" SERVICEDESC=\"$SERVICEDESC$\" SERVICEOUTPUT=\"$SERVICEOUTPUT$\" $USER2$/notify_by_slack \"$ARG1$\" \"$ARG2$\""; 158 notify-by-slack = "HOST=\"$HOSTALIAS$\" SERVICESTATE=\"$SERVICESTATE$\" SERVICEDESC=\"$SERVICEDESC$\" SERVICEOUTPUT=\"$SERVICEOUTPUT$\" $USER2$/notify_by_slack \"$ARG1$\" \"$ARG2$\"";
159 notify-host-eban-url = "STATUS_NAME=\"Server\" PASSWORD=\"$USER210$\" HOSTSTATE=\"$HOSTSTATE$\" $USER2$/notify_eban_url";
160 notify-service-eban-url = "STATUS_NAME=\"$_SERVICEWEBSTATUS_NAME$\" PASSWORD=\"$USER210$\" SERVICESTATE=\"$SERVICESTATE$\" $USER2$/notify_eban_url";
158 161
159 notify-master = "$USER2$/send_nrdp.sh -u \"$USER200$\" -t \"$USER201$\" -H \"$HOSTADDRESS$\" -s \"$SERVICEDESC$\" -S \"$SERVICESTATEID$\" -o \"$SERVICEOUTPUT$ | $SERVICEPERFDATA$\""; 162 notify-master = "$USER2$/send_nrdp.sh -u \"$USER200$\" -t \"$USER201$\" -H \"$HOSTADDRESS$\" -s \"$SERVICEDESC$\" -S \"$SERVICESTATEID$\" -o \"$SERVICEOUTPUT$ | $SERVICEPERFDATA$\"";
160 }; 163 };
diff --git a/modules/private/monitoring/objects_eban.nix b/modules/private/monitoring/objects_eban.nix
new file mode 100644
index 0000000..659b0ec
--- /dev/null
+++ b/modules/private/monitoring/objects_eban.nix
@@ -0,0 +1,60 @@
1{ ... }:
2let
3 serviceTemplate = rest: {
4 host_name = "eban.bzh";
5 use = "external-web-service";
6 contacts = "eban";
7 contact_groups = "null";
8 check_interval = "15";
9
10 servicegroups = "webstatus-resources";
11 } // rest;
12in
13{
14 contact = {
15 eban = {
16 use = "generic-contact";
17 host_notification_commands = "notify-host-eban-url";
18 service_notification_commands = "notify-service-eban-url";
19 };
20 };
21 host = {
22 "eban.bzh" = {
23 alias = "eban.bzh";
24 address = "eban.bzh";
25 use = "linux-server";
26 hostgroups = "webstatus-hosts";
27 contacts = "eban";
28 contact_groups = "null";
29 _webstatus_name = "Eban";
30 _webstatus_vhost = "status.eban.bzh";
31 };
32 };
33 service = [
34 (serviceTemplate {
35 service_description = "Eban website is up and running";
36 check_command = ["check_https" "eban.bzh" "/" "<title>"];
37 _webstatus_name = "Main Website";
38 _webstatus_url = "https://eban.bzh/";
39 })
40 (serviceTemplate {
41 service_description = "Eban blog is up and running";
42 check_command = ["check_https" "blog.eban.bzh" "/" "<title>"];
43 _webstatus_name = "Blog";
44 _webstatus_url = "https://blog.eban.bzh/";
45 })
46 (serviceTemplate {
47 service_description = "Eban gitea is up and running";
48 check_command = ["check_https" "git.eban.bzh" "/" "<title>"];
49 _webstatus_name = "Git";
50 _webstatus_url = "https://git.eban.bzh/";
51 })
52 (serviceTemplate {
53 service_description = "Eban Cloud is up and running";
54 check_command = ["check_https" "cloud.eban.bzh" "/" "<title>"];
55
56 _webstatus_name = "Cloud";
57 _webstatus_url = "https://cloud.eban.bzh/";
58 })
59 ];
60}
diff --git a/modules/private/monitoring/objects_phare.nix b/modules/private/monitoring/objects_phare.nix
index a00e5e8..a61b46e 100644
--- a/modules/private/monitoring/objects_phare.nix
+++ b/modules/private/monitoring/objects_phare.nix
@@ -7,6 +7,7 @@
7 use = "linux-server"; 7 use = "linux-server";
8 hostgroups = "webstatus-hosts"; 8 hostgroups = "webstatus-hosts";
9 _webstatus_name = "phare"; 9 _webstatus_name = "phare";
10 _webstatus_vhost = "status.immae.eu";
10 }; 11 };
11 }; 12 };
12 service = [ 13 service = [
diff --git a/modules/private/monitoring/objects_tiboqorl-fr.nix b/modules/private/monitoring/objects_tiboqorl-fr.nix
index c3851b5..77403ba 100644
--- a/modules/private/monitoring/objects_tiboqorl-fr.nix
+++ b/modules/private/monitoring/objects_tiboqorl-fr.nix
@@ -22,6 +22,7 @@ in
22 contact_groups = "tiboqorl"; 22 contact_groups = "tiboqorl";
23 hostgroups = "webstatus-hosts"; 23 hostgroups = "webstatus-hosts";
24 _webstatus_name = "tiboqorl"; 24 _webstatus_name = "tiboqorl";
25 _webstatus_vhost = "status.immae.eu";
25 }; 26 };
26 }; 27 };
27 service = [ 28 service = [
diff --git a/modules/private/monitoring/objects_ulminfo-fr.nix b/modules/private/monitoring/objects_ulminfo-fr.nix
index b970ecd..574e0e3 100644
--- a/modules/private/monitoring/objects_ulminfo-fr.nix
+++ b/modules/private/monitoring/objects_ulminfo-fr.nix
@@ -7,6 +7,7 @@
7 use = "linux-server"; 7 use = "linux-server";
8 hostgroups = "webstatus-hosts"; 8 hostgroups = "webstatus-hosts";
9 _webstatus_name = "ulminfo"; 9 _webstatus_name = "ulminfo";
10 _webstatus_vhost = "status.immae.eu";
10 }; 11 };
11 }; 12 };
12 service = [ 13 service = [
diff --git a/modules/private/monitoring/plugins/notify_eban_url b/modules/private/monitoring/plugins/notify_eban_url
new file mode 100755
index 0000000..431e320
--- /dev/null
+++ b/modules/private/monitoring/plugins/notify_eban_url
@@ -0,0 +1,13 @@
1#!/usr/bin/env bash
2
3PASS=$(echo "$PASSWORD" | base64 -d)
4
5if [ "$SERVICESTATE" = "CRITICAL" -o "$SERVICESTATE" = "UNKNOWN" -o "$HOSTSTATE" = "DOWN" -o "$HOSTSTATE" = "UNREACHABLE" ]; then
6 action=downAlert
7elif [ "$SERVICESTATE" = "OK" -o "$HOSTSTATE" = "UP" ]; then
8 action=upAlert
9fi
10
11if [ -n "$action" ]; then
12 curl -X GET -G --data-urlencode "service=$STATUS_NAME" --data-urlencode "mdp=$PASS" https://infra.eban.bzh/$action
13fi
diff --git a/modules/private/monitoring/status.nix b/modules/private/monitoring/status.nix
index 4ca0327..73f4749 100644
--- a/modules/private/monitoring/status.nix
+++ b/modules/private/monitoring/status.nix
@@ -32,6 +32,12 @@
32 upstreams."netdata".extraConfig = '' 32 upstreams."netdata".extraConfig = ''
33 keepalive 64; 33 keepalive 64;
34 ''; 34 '';
35 virtualHosts."status.eban.bzh" = {
36 acmeRoot = config.myServices.certificates.webroot;
37 useACMEHost = name;
38 forceSSL = true;
39 locations."/".proxyPass = "http://unix:/run/naemon-status/socket.sock:/";
40 };
35 virtualHosts."status.immae.eu" = { 41 virtualHosts."status.immae.eu" = {
36 acmeRoot = config.myServices.certificates.webroot; 42 acmeRoot = config.myServices.certificates.webroot;
37 useACMEHost = name; 43 useACMEHost = name;
@@ -60,6 +66,7 @@
60 }; 66 };
61 security.acme.certs."${name}" = { 67 security.acme.certs."${name}" = {
62 extraDomains."status.immae.eu" = null; 68 extraDomains."status.immae.eu" = null;
69 extraDomains."status.eban.bzh" = null;
63 user = config.services.nginx.user; 70 user = config.services.nginx.user;
64 group = config.services.nginx.group; 71 group = config.services.nginx.group;
65 }; 72 };
diff --git a/modules/private/monitoring/status/app.py b/modules/private/monitoring/status/app.py
index b1d419c..ff92891 100755
--- a/modules/private/monitoring/status/app.py
+++ b/modules/private/monitoring/status/app.py
@@ -55,33 +55,34 @@ def get_lq(request):
55 return b"".join(chunks).decode() 55 return b"".join(chunks).decode()
56 56
57class Host: 57class Host:
58 def __init__(self, name, alias, status, webname): 58 def __init__(self, name, alias, status, webname, vhost):
59 self.name = name 59 self.name = name
60 self.alias = alias 60 self.alias = alias
61 self.webname = webname or alias 61 self.webname = webname or alias
62 self.vhost = vhost
62 self.status = status 63 self.status = status
63 self.services = [] 64 self.services = []
64 65
65 @classmethod 66 @classmethod
66 def parse_hosts(cls, payload): 67 def parse_hosts(cls, payload, vhost):
67 parsed = [cls.parse(p) for p in json.loads(payload)] 68 parsed = filter(lambda x: x.vhost == vhost, [cls.parse(p) for p in json.loads(payload)])
68 return {p.name: p for p in parsed} 69 return {p.name: p for p in parsed}
69 70
70 @classmethod 71 @classmethod
71 def parse(cls, payload): 72 def parse(cls, payload):
72 return cls(payload[0], payload[1], HOST_STATUS[payload[2]], payload[3].get("WEBSTATUS_NAME")) 73 return cls(payload[0], payload[1], HOST_STATUS[payload[2]], payload[3].get("WEBSTATUS_NAME"), payload[3].get("WEBSTATUS_VHOST"))
73 74
74 def __repr__(self): 75 def __repr__(self):
75 return "Host {}: {} ({})".format(self.name, self.alias, self.webname) 76 return "Host {}: {} ({})".format(self.name, self.alias, self.webname)
76 77
77 @classmethod 78 @classmethod
78 def query(cls): 79 def query(cls, vhost):
79 answer = get_lq("""GET hosts 80 answer = get_lq("""GET hosts
80Filter: groups >= webstatus-hosts 81Filter: groups >= webstatus-hosts
81Columns: name alias state custom_variables 82Columns: name alias state custom_variables
82OutputFormat: json 83OutputFormat: json
83""") 84""")
84 return cls.parse_hosts(answer) 85 return cls.parse_hosts(answer, vhost)
85 86
86 def fill_services(self, services): 87 def fill_services(self, services):
87 self.services = [service for service in services if service.host == self.name] 88 self.services = [service for service in services if service.host == self.name]
@@ -110,8 +111,8 @@ OutputFormat: json
110""") 111""")
111 return cls.parse_groups(answer) 112 return cls.parse_groups(answer)
112 113
113 def fill_services(self, services): 114 def fill_services(self, services, hosts):
114 self.services = [service for service in services if any([group == self.name for group in service.groups])] 115 self.services = [service for service in services if any([group == self.name for group in service.groups]) and service.host in hosts]
115 116
116 def __repr__(self): 117 def __repr__(self):
117 return "ServiceGroup {}: {}".format(self.name, self.alias) 118 return "ServiceGroup {}: {}".format(self.name, self.alias)
@@ -158,15 +159,15 @@ OutputFormat: json
158 def __repr__(self): 159 def __repr__(self):
159 return "Service {}: {}".format(self.name, self.webname) 160 return "Service {}: {}".format(self.name, self.webname)
160 161
161def get_infos(): 162def get_infos(vhost):
162 hosts = Host.query() 163 hosts = Host.query(vhost)
163 servicegroups = ServiceGroup.query() 164 servicegroups = ServiceGroup.query()
164 services = Service.query() 165 services = Service.query()
165 166
166 for host in hosts: 167 for host in hosts:
167 hosts[host].fill_services(services) 168 hosts[host].fill_services(services)
168 for group in servicegroups: 169 for group in servicegroups:
169 servicegroups[group].fill_services(services) 170 servicegroups[group].fill_services(services, hosts)
170 return (hosts, servicegroups, services) 171 return (hosts, servicegroups, services)
171 172
172TEMPLATE='''<?xml version="1.0" encoding="UTF-8"?> 173TEMPLATE='''<?xml version="1.0" encoding="UTF-8"?>
@@ -254,12 +255,14 @@ TEMPLATE='''<?xml version="1.0" encoding="UTF-8"?>
254 {% endfor %} 255 {% endfor %}
255 {%- endfor %} 256 {%- endfor %}
256 257
258 {%- for group in servicegroups.values() if group.services and group.name != "webstatus-resources" %}
259 {%- if loop.first %}
257 <h2>Services</h2> 260 <h2>Services</h2>
258 <div id="services"> 261 <div id="services">
259 {%- for group in servicegroups.values() if group.services and group.name != "webstatus-resources" %} 262 {%- endif %}
260 <div class="servicegroup"> 263 <div class="servicegroup">
261 <h3 class="servicegroup_title">{{ group.alias }}</h3> 264 <h3 class="servicegroup_title">{{ group.alias }}</h3>
262 {%- for service in group.services -%} 265 {%- for service in group.services if service.host in hosts -%}
263 {%- if loop.first %} 266 {%- if loop.first %}
264 <ul class="services"> 267 <ul class="services">
265 {% endif %} 268 {% endif %}
@@ -281,8 +284,10 @@ TEMPLATE='''<?xml version="1.0" encoding="UTF-8"?>
281 {% endif %} 284 {% endif %}
282 {%- endfor -%} 285 {%- endfor -%}
283 </div> 286 </div>
284 {%- endfor %} 287 {%- if loop.last %}
285 </div> 288 </div>
289 {% endif %}
290 {%- endfor %}
286 </body> 291 </body>
287</html> 292</html>
288''' 293'''
@@ -307,7 +312,7 @@ def live():
307 312
308@app.route("/", methods=["GET"]) 313@app.route("/", methods=["GET"])
309def get(): 314def get():
310 (hosts, servicegroups, services) = get_infos() 315 (hosts, servicegroups, services) = get_infos(request.host)
311 resp = make_response(render_template_string(TEMPLATE, hosts=hosts, servicegroups=servicegroups)) 316 resp = make_response(render_template_string(TEMPLATE, hosts=hosts, servicegroups=servicegroups))
312 resp.content_type = "text/html" 317 resp.content_type = "text/html"
313 return resp 318 return resp
diff --git a/modules/private/system.nix b/modules/private/system.nix
index 71a49e3..0e72d99 100644
--- a/modules/private/system.nix
+++ b/modules/private/system.nix
@@ -26,7 +26,8 @@
26 ]; 26 ];
27 27
28 services.journald.extraConfig = '' 28 services.journald.extraConfig = ''
29 MaxLevelStore=warning 29 #Should be "warning" but disabled for now, it prevents anything from being stored
30 MaxLevelStore=info
30 MaxRetentionSec=1year 31 MaxRetentionSec=1year
31 ''; 32 '';
32 33