gnu: services: Fix the NFS service.
[jackhill/guix/guix.git] / gnu / services / monitoring.scm
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2018 Sou Bunnbu <iyzsong@member.fsf.org>
3 ;;; Copyright © 2018, 2019 Gábor Boskovits <boskovits@gmail.com>
4 ;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov <go.wigust@gmail.com>
5 ;;;
6 ;;; This file is part of GNU Guix.
7 ;;;
8 ;;; GNU Guix is free software; you can redistribute it and/or modify it
9 ;;; under the terms of the GNU General Public License as published by
10 ;;; the Free Software Foundation; either version 3 of the License, or (at
11 ;;; your option) any later version.
12 ;;;
13 ;;; GNU Guix is distributed in the hope that it will be useful, but
14 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;;; GNU General Public License for more details.
17 ;;;
18 ;;; You should have received a copy of the GNU General Public License
19 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
20
21 (define-module (gnu services monitoring)
22 #:use-module (gnu services)
23 #:use-module (gnu services configuration)
24 #:use-module (gnu services shepherd)
25 #:use-module (gnu services web)
26 #:use-module (gnu packages admin)
27 #:use-module (gnu packages monitoring)
28 #:use-module (gnu system shadow)
29 #:use-module (guix gexp)
30 #:use-module (guix packages)
31 #:use-module (guix records)
32 #:use-module (guix utils)
33 #:use-module ((guix ui) #:select (display-hint G_))
34 #:use-module (ice-9 match)
35 #:use-module (ice-9 rdelim)
36 #:use-module (srfi srfi-26)
37 #:use-module (srfi srfi-35)
38 #:export (darkstat-configuration
39 darkstat-service-type
40
41 prometheus-node-exporter-configuration
42 prometheus-node-exporter-configuration?
43 prometheus-node-exporter-configuration-package
44 prometheus-node-exporter-web-listen-address
45 prometheus-node-exporter-service-type
46
47 zabbix-server-configuration
48 zabbix-server-service-type
49 zabbix-agent-configuration
50 zabbix-agent-service-type
51 zabbix-front-end-configuration
52 zabbix-front-end-service-type
53 %zabbix-front-end-configuration-nginx))
54
55 \f
56 ;;;
57 ;;; darkstat
58 ;;;
59
60 (define-record-type* <darkstat-configuration>
61 darkstat-configuration make-darkstat-configuration darkstat-configuration?
62 (package darkstat-configuration-package
63 (default darkstat))
64 (interface darkstat-configuration-interface)
65 (port darkstat-configuration-port
66 (default "667"))
67 (bind-address darkstat-configuration-bind-address
68 (default "127.0.0.1"))
69 (base darkstat-configuration-base
70 (default "/")))
71
72 (define %darkstat-accounts
73 (list (user-account
74 (name "darkstat")
75 (group "darkstat")
76 (system? #t)
77 (comment "darkstat daemon user")
78 (home-directory "/var/lib/darkstat")
79 (shell (file-append shadow "/sbin/nologin")))
80 (user-group
81 (name "darkstat")
82 (system? #t))))
83
84 (define darkstat-shepherd-service
85 (match-lambda
86 (($ <darkstat-configuration>
87 package interface port bind-address base)
88 (shepherd-service
89 (documentation "Network statistics gatherer.")
90 (provision '(darkstat))
91 (requirement '(networking))
92 (start #~(make-forkexec-constructor
93 (list #$(file-append package "/sbin/darkstat")
94 "-i" #$interface
95 "-p" #$port
96 "-b" #$bind-address
97 "--base" #$base
98 "--syslog" "--no-daemon"
99 "--chroot" "/var/lib/darkstat"
100 "--user" "darkstat"
101 "--import" "darkstat.db"
102 "--export" "darkstat.db")))
103 (stop #~(make-kill-destructor))))))
104
105 (define darkstat-service-type
106 (service-type
107 (name 'darkstat)
108 (description
109 "Run @command{darkstat} to serve network traffic statistics reports over
110 HTTP.")
111 (extensions
112 (list (service-extension account-service-type
113 (const %darkstat-accounts))
114 (service-extension shepherd-root-service-type
115 (compose list darkstat-shepherd-service))))))
116
117 \f
118 ;;;
119 ;;; Prometheus node exporter
120 ;;;
121
122 (define-record-type* <prometheus-node-exporter-configuration>
123 prometheus-node-exporter-configuration
124 make-prometheus-node-exporter-configuration
125 prometheus-node-exporter-configuration?
126 (package prometheus-node-exporter-configuration-package
127 (default go-github-com-prometheus-node-exporter))
128 (web-listen-address prometheus-node-exporter-web-listen-address
129 (default ":9100"))
130 (textfile-directory prometheus-node-exporter-textfile-directory
131 (default "/var/lib/prometheus/node-exporter"))
132 (extra-options prometheus-node-exporter-extra-options
133 (default '())))
134
135 (define %prometheus-node-exporter-accounts
136 (list (user-account
137 (name "prometheus-node-exporter")
138 (group "prometheus-node-exporter")
139 (system? #t)
140 (comment "Prometheus node exporter daemon user")
141 (home-directory "/var/empty")
142 (shell (file-append shadow "/sbin/nologin")))
143 (user-group
144 (name "prometheus-node-exporter")
145 (system? #t))))
146
147 (define prometheus-node-exporter-shepherd-service
148 (match-lambda
149 (( $ <prometheus-node-exporter-configuration>
150 package web-listen-address textfile-directory extra-options)
151 (list
152 (shepherd-service
153 (documentation "Prometheus node exporter.")
154 (provision '(prometheus-node-exporter))
155 (requirement '(networking))
156 (start #~(make-forkexec-constructor
157 (list #$(file-append package "/bin/node_exporter")
158 "--web.listen-address" #$web-listen-address
159 #$@(if textfile-directory
160 (list "--collector.textfile.directory"
161 textfile-directory)
162 '())
163 #$@extra-options)
164 #:user "prometheus-node-exporter"
165 #:group "prometheus-node-exporter"
166 #:log-file "/var/log/prometheus-node-exporter.log"))
167 (stop #~(make-kill-destructor)))))))
168
169 (define (prometheus-node-exporter-activation config)
170 (with-imported-modules '((guix build utils))
171 #~(let ((textfile-directory
172 #$(prometheus-node-exporter-textfile-directory config)))
173 (use-modules (guix build utils))
174
175 (when textfile-directory
176 (let ((user (getpw "prometheus-node-exporter")))
177 #t
178 (mkdir-p textfile-directory)
179 (chown textfile-directory (passwd:uid user) (passwd:gid user))
180 (chmod textfile-directory #o775))))))
181
182 (define prometheus-node-exporter-service-type
183 (service-type
184 (name 'prometheus-node-exporter)
185 (description
186 "Run @command{node_exporter} to serve hardware and OS metrics to
187 Prometheus.")
188 (extensions
189 (list
190 (service-extension account-service-type
191 (const %prometheus-node-exporter-accounts))
192 (service-extension activation-service-type
193 prometheus-node-exporter-activation)
194 (service-extension shepherd-root-service-type
195 prometheus-node-exporter-shepherd-service)))
196 (default-value (prometheus-node-exporter-configuration))))
197
198 \f
199 ;;;
200 ;;; Zabbix server
201 ;;;
202
203 (define (uglify-field-name field-name)
204 (apply string-append
205 (map (lambda (str)
206 (if (member (string->symbol str) '(ca db ssl))
207 (string-upcase str)
208 (string-capitalize str)))
209 (string-split (string-delete #\?
210 (symbol->string field-name))
211 #\-))))
212
213 (define (serialize-field field-name val)
214 (format #t "~a=~a~%" (uglify-field-name field-name) val))
215
216 (define (serialize-number field-name val)
217 (serialize-field field-name (number->string val)))
218
219 (define (serialize-list field-name val)
220 (if (null? val) "" (serialize-field field-name (string-join val ","))))
221
222 (define (serialize-string field-name val)
223 (if (and (string? val) (string=? val ""))
224 ""
225 (serialize-field field-name val)))
226
227 (define group? string?)
228
229 (define serialize-group
230 (const ""))
231
232 (define include-files? list?)
233
234 (define (serialize-include-files field-name val)
235 (if (null? val) "" (for-each (cut serialize-field 'include <>) val)))
236
237 (define extra-options? string?)
238
239 (define (serialize-extra-options field-name val)
240 (if (null? val) "" (display val)))
241
242 (define (nginx-server-configuration-list? val)
243 (and (list? val) (and-map nginx-server-configuration? val)))
244
245 (define (serialize-nginx-server-configuration-list field-name val)
246 "")
247
248 (define-configuration zabbix-server-configuration
249 (zabbix-server
250 (package zabbix-server)
251 "The zabbix-server package.")
252 (user
253 (string "zabbix")
254 "User who will run the Zabbix server.")
255 (group ;for zabbix-server-account procedure
256 (group "zabbix")
257 "Group who will run the Zabbix server.")
258 (db-host
259 (string "127.0.0.1")
260 "Database host name.")
261 (db-name
262 (string "zabbix")
263 "Database name.")
264 (db-user
265 (string "zabbix")
266 "Database user.")
267 (db-password
268 (string "")
269 "Database password. Please, use @code{include-files} with
270 @code{DBPassword=SECRET} inside a specified file instead.")
271 (db-port
272 (number 5432)
273 "Database port.")
274 (log-type
275 (string "")
276 "Specifies where log messages are written to:
277 @itemize
278 @item @code{system} - syslog.
279 @item @code{file} - file specified with @code{log-file} parameter.
280 @item @code{console} - standard output.
281 @end itemize\n")
282 (log-file
283 (string "/var/log/zabbix/server.log")
284 "Log file name for @code{log-type} @code{file} parameter.")
285 (pid-file
286 (string "/var/run/zabbix/zabbix_server.pid")
287 "Name of PID file.")
288 (ssl-ca-location
289 (string "/etc/ssl/certs/ca-certificates.crt")
290 "The location of certificate authority (CA) files for SSL server
291 certificate verification.")
292 (ssl-cert-location
293 (string "/etc/ssl/certs")
294 "Location of SSL client certificates.")
295 (extra-options
296 (extra-options "")
297 "Extra options will be appended to Zabbix server configuration file.")
298 (include-files
299 (include-files '())
300 "You may include individual files or all files in a directory in the
301 configuration file."))
302
303 (define (zabbix-server-account config)
304 "Return the user accounts and user groups for CONFIG."
305 (let ((zabbix-user (zabbix-server-configuration-user config))
306 (zabbix-group (zabbix-server-configuration-group config)))
307 (list (user-group (name zabbix-group) (system? #t))
308 (user-account
309 (name zabbix-user)
310 (system? #t)
311 (group zabbix-group)
312 (comment "zabbix privilege separation user")
313 (home-directory (string-append "/var/run/" zabbix-user))
314 (shell (file-append shadow "/sbin/nologin"))))))
315
316 (define (zabbix-server-config-file config)
317 "Return the zabbix-server configuration file corresponding to CONFIG."
318 (computed-file
319 "zabbix_server.conf"
320 #~(begin
321 (call-with-output-file #$output
322 (lambda (port)
323 (display "# Generated by 'zabbix-server-service'.\n" port)
324 (display #$(with-output-to-string
325 (lambda ()
326 (serialize-configuration
327 config zabbix-server-configuration-fields)))
328 port)
329 #t)))))
330
331 (define (zabbix-server-activation config)
332 "Return the activation gexp for CONFIG."
333 (with-imported-modules '((guix build utils))
334 #~(begin
335 (use-modules (guix build utils)
336 (ice-9 rdelim))
337
338 (let ((user (getpw #$(zabbix-server-configuration-user config))))
339 (for-each (lambda (file)
340 (let ((directory (dirname file)))
341 (mkdir-p directory)
342 (chown directory (passwd:uid user) (passwd:gid user))
343 (chmod directory #o755)))
344 (list #$(zabbix-server-configuration-log-file config)
345 #$(zabbix-server-configuration-pid-file config)
346 "/etc/zabbix/maintenance.inc.php"))))))
347
348 (define (zabbix-server-shepherd-service config)
349 "Return a <shepherd-service> for Zabbix server with CONFIG."
350 (list (shepherd-service
351 (provision '(zabbix-server))
352 (documentation "Run Zabbix server daemon.")
353 (start #~(make-forkexec-constructor
354 (list #$(file-append (zabbix-server-configuration-zabbix-server config)
355 "/sbin/zabbix_server")
356 "--config" #$(zabbix-server-config-file config)
357 "--foreground")
358 #:user #$(zabbix-server-configuration-user config)
359 #:group #$(zabbix-server-configuration-group config)
360 #:pid-file #$(zabbix-server-configuration-pid-file config)
361 #:environment-variables
362 (list "SSL_CERT_DIR=/run/current-system/profile\
363 /etc/ssl/certs"
364 "SSL_CERT_FILE=/run/current-system/profile\
365 /etc/ssl/certs/ca-certificates.crt")))
366 (stop #~(make-kill-destructor)))))
367
368 (define zabbix-server-service-type
369 (service-type
370 (name 'zabbix-server)
371 (extensions
372 (list (service-extension shepherd-root-service-type
373 zabbix-server-shepherd-service)
374 (service-extension account-service-type
375 zabbix-server-account)
376 (service-extension activation-service-type
377 zabbix-server-activation)))
378 (default-value (zabbix-server-configuration))))
379
380 (define (generate-zabbix-server-documentation)
381 (generate-documentation
382 `((zabbix-server-configuration
383 ,zabbix-server-configuration-fields))
384 'zabbix-server-configuration))
385
386 (define-configuration zabbix-agent-configuration
387 (zabbix-agent
388 (package zabbix-agentd)
389 "The zabbix-agent package.")
390 (user
391 (string "zabbix")
392 "User who will run the Zabbix agent.")
393 (group
394 (group "zabbix")
395 "Group who will run the Zabbix agent.")
396 (hostname
397 (string "")
398 "Unique, case sensitive hostname which is required for active checks and
399 must match hostname as configured on the server.")
400 (log-type
401 (string "")
402 "Specifies where log messages are written to:
403 @itemize
404 @item @code{system} - syslog.
405 @item @code{file} - file specified with @code{log-file} parameter.
406 @item @code{console} - standard output.
407 @end itemize\n")
408 (log-file
409 (string "/var/log/zabbix/agent.log")
410 "Log file name for @code{log-type} @code{file} parameter.")
411 (pid-file
412 (string "/var/run/zabbix/zabbix_agent.pid")
413 "Name of PID file.")
414 (server
415 (list '("127.0.0.1"))
416 "List of IP addresses, optionally in CIDR notation, or hostnames of Zabbix
417 servers and Zabbix proxies. Incoming connections will be accepted only from
418 the hosts listed here.")
419 (server-active
420 (list '("127.0.0.1"))
421 "List of IP:port (or hostname:port) pairs of Zabbix servers and Zabbix
422 proxies for active checks. If port is not specified, default port is used.
423 If this parameter is not specified, active checks are disabled.")
424 (extra-options
425 (extra-options "")
426 "Extra options will be appended to Zabbix server configuration file.")
427 (include-files
428 (include-files '())
429 "You may include individual files or all files in a directory in the
430 configuration file."))
431
432 (define (zabbix-agent-account config)
433 "Return the user accounts and user groups for CONFIG."
434 (let ((zabbix-user "zabbix")
435 (zabbix-group "zabbix"))
436 (list (user-group (name zabbix-group) (system? #t))
437 (user-account
438 (name zabbix-user)
439 (system? #t)
440 (group zabbix-group)
441 (comment "zabbix privilege separation user")
442 (home-directory (string-append "/var/run/" zabbix-user))
443 (shell (file-append shadow "/sbin/nologin"))))))
444
445 (define (zabbix-agent-activation config)
446 "Return the activation gexp for CONFIG."
447 (with-imported-modules '((guix build utils))
448 #~(begin
449 (use-modules (guix build utils)
450 (ice-9 rdelim))
451 (let ((user
452 (getpw #$(zabbix-agent-configuration-user config))))
453 (for-each (lambda (file)
454 (let ((directory (dirname file)))
455 (mkdir-p directory)
456 (chown directory (passwd:uid user) (passwd:gid user))
457 (chmod directory #o755)))
458 (list #$(zabbix-agent-configuration-log-file config)
459 #$(zabbix-agent-configuration-pid-file config)))))))
460
461 (define (zabbix-agent-config-file config)
462 "Return the zabbix-agent configuration file corresponding to CONFIG."
463 (computed-file
464 "zabbix_agent.conf"
465 #~(begin
466 (call-with-output-file #$output
467 (lambda (port)
468 (display "# Generated by 'zabbix-agent-service'.\n" port)
469 (display #$(with-output-to-string
470 (lambda ()
471 (serialize-configuration
472 config zabbix-agent-configuration-fields)))
473 port)
474 #t)))))
475
476 (define (zabbix-agent-shepherd-service config)
477 "Return a <shepherd-service> for Zabbix agent with CONFIG."
478 (list (shepherd-service
479 (provision '(zabbix-agent))
480 (documentation "Run Zabbix agent daemon.")
481 (start #~(make-forkexec-constructor
482 (list #$(file-append (zabbix-agent-configuration-zabbix-agent config)
483 "/sbin/zabbix_agentd")
484 "--config" #$(zabbix-agent-config-file config)
485 "--foreground")
486 #:user #$(zabbix-agent-configuration-user config)
487 #:group #$(zabbix-agent-configuration-group config)
488 #:pid-file #$(zabbix-agent-configuration-pid-file config)
489 #:environment-variables
490 (list "SSL_CERT_DIR=/run/current-system/profile\
491 /etc/ssl/certs"
492 "SSL_CERT_FILE=/run/current-system/profile\
493 /etc/ssl/certs/ca-certificates.crt")))
494 (stop #~(make-kill-destructor)))))
495
496 (define zabbix-agent-service-type
497 (service-type
498 (name 'zabbix-agent)
499 (extensions
500 (list (service-extension shepherd-root-service-type
501 zabbix-agent-shepherd-service)
502 (service-extension account-service-type
503 zabbix-agent-account)
504 (service-extension activation-service-type
505 zabbix-agent-activation)))
506 (default-value (zabbix-agent-configuration))))
507
508 (define (generate-zabbix-agent-documentation)
509 (generate-documentation
510 `((zabbix-agent-configuration
511 ,zabbix-agent-configuration-fields))
512 'zabbix-agent-configuration))
513
514 (define %zabbix-front-end-configuration-nginx
515 (nginx-server-configuration
516 (root #~(string-append #$zabbix-server:front-end "/share/zabbix/php"))
517 (index '("index.php"))
518 (locations
519 (let ((php-location (nginx-php-location)))
520 (list (nginx-location-configuration
521 (inherit php-location)
522 (body (append (nginx-location-configuration-body php-location)
523 (list "
524 fastcgi_param PHP_VALUE \"post_max_size = 16M
525 max_execution_time = 300\";
526 ")))))))
527 (listen '("80"))))
528
529 (define-configuration zabbix-front-end-configuration
530 ;; TODO: Specify zabbix front-end package.
531 ;; (zabbix-
532 ;; (package zabbix-front-end)
533 ;; "The zabbix-front-end package.")
534 (nginx
535 (nginx-server-configuration-list
536 (list %zabbix-front-end-configuration-nginx))
537 "NGINX configuration.")
538 (db-host
539 (string "localhost")
540 "Database host name.")
541 (db-port
542 (number 5432)
543 "Database port.")
544 (db-name
545 (string "zabbix")
546 "Database name.")
547 (db-user
548 (string "zabbix")
549 "Database user.")
550 (db-password
551 (string "")
552 "Database password. Please, use @code{db-secret-file} instead.")
553 (db-secret-file
554 (string "")
555 "Secret file which will be appended to @file{zabbix.conf.php} file. This
556 file contains credentials for use by Zabbix front-end. You are expected to
557 create it manually.")
558 (zabbix-host
559 (string "localhost")
560 "Zabbix server hostname.")
561 (zabbix-port
562 (number 10051)
563 "Zabbix server port."))
564
565 (define (zabbix-front-end-config config)
566 (match-record config <zabbix-front-end-configuration>
567 (%location db-host db-port db-name db-user db-password db-secret-file
568 zabbix-host zabbix-port)
569 (mixed-text-file "zabbix.conf.php"
570 "\
571 <?php
572 // Zabbix GUI configuration file.
573 global $DB;
574
575 $DB['TYPE'] = 'POSTGRESQL';
576 $DB['SERVER'] = '" db-host "';
577 $DB['PORT'] = '" (number->string db-port) "';
578 $DB['DATABASE'] = '" db-name "';
579 $DB['USER'] = '" db-user "';
580 $DB['PASSWORD'] = '" (let ((file (location-file %location))
581 (line (location-line %location))
582 (column (location-column %location)))
583 (if (string-null? db-password)
584 (if (string-null? db-secret-file)
585 (raise (make-compound-condition
586 (condition
587 (&message
588 (message
589 (format #f "no '~A' or '~A' field in your '~A' record"
590 'db-secret-file 'db-password
591 'zabbix-front-end-configuration))))
592 (condition
593 (&error-location
594 (location %location)))))
595 (string-trim-both
596 (with-input-from-file db-secret-file
597 read-string)))
598 (begin
599 (display-hint (format #f (G_ "~a:~a:~a: ~a:
600 Consider using @code{db-secret-file} instead of @code{db-password} for better
601 security.") file line column 'zabbix-front-end-configuration))
602 db-password))) "';
603
604 // Schema name. Used for IBM DB2 and PostgreSQL.
605 $DB['SCHEMA'] = '';
606
607 $ZBX_SERVER = '" zabbix-host "';
608 $ZBX_SERVER_PORT = '" (number->string zabbix-port) "';
609 $ZBX_SERVER_NAME = '';
610
611 $IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
612 ")))
613
614 (define %maintenance.inc.php
615 ;; Empty php file to allow us move zabbix-frontend configs to ‘/etc/zabbix’
616 ;; directory. See ‘install-front-end’ phase in
617 ;; (@ (gnu packages monitoring) zabbix-server) package.
618 "\
619 <?php
620 ")
621
622 (define (zabbix-front-end-activation config)
623 "Return the activation gexp for CONFIG."
624 #~(begin
625 (use-modules (guix build utils))
626 (mkdir-p "/etc/zabbix")
627 (call-with-output-file "/etc/zabbix/maintenance.inc.php"
628 (lambda (port)
629 (display #$%maintenance.inc.php port)))
630 (copy-file #$(zabbix-front-end-config config)
631 "/etc/zabbix/zabbix.conf.php")))
632
633 (define zabbix-front-end-service-type
634 (service-type
635 (name 'zabbix-front-end)
636 (extensions
637 (list (service-extension activation-service-type
638 zabbix-front-end-activation)
639 (service-extension nginx-service-type
640 zabbix-front-end-configuration-nginx)
641 ;; Make sure php-fpm is instantiated.
642 (service-extension php-fpm-service-type
643 (const #t))))
644 (default-value (zabbix-front-end-configuration))
645 (description
646 "Run the zabbix-front-end web interface, which allows users to interact
647 with Zabbix server.")))
648
649 (define (generate-zabbix-front-end-documentation)
650 (generate-documentation
651 `((zabbix-front-end-configuration
652 ,zabbix-front-end-configuration-fields))
653 'zabbix-front-end-configuration))