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 Oleg Pykhalov <go.wigust@gmail.com>
6 ;;; This file is part of GNU Guix.
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.
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.
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/>.
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 prometheus-node-exporter-configuration
41 prometheus-node-exporter-service-type
43 zabbix-server-configuration
44 zabbix-server-service-type
45 zabbix-agent-configuration
46 zabbix-agent-service-type
47 zabbix-front-end-configuration
48 zabbix-front-end-service-type
49 %zabbix-front-end-configuration-nginx))
56 (define-record-type* <darkstat-configuration>
57 darkstat-configuration make-darkstat-configuration darkstat-configuration?
58 (package darkstat-configuration-package
60 (interface darkstat-configuration-interface)
61 (port darkstat-configuration-port
63 (bind-address darkstat-configuration-bind-address
64 (default "127.0.0.1"))
65 (base darkstat-configuration-base
68 (define %darkstat-accounts
73 (comment "darkstat daemon user")
74 (home-directory "/var/lib/darkstat")
75 (shell (file-append shadow "/sbin/nologin")))
80 (define darkstat-shepherd-service
82 (($ <darkstat-configuration>
83 package interface port bind-address base)
85 (documentation "Network statistics gatherer.")
86 (provision '(darkstat))
87 (requirement '(networking))
88 (start #~(make-forkexec-constructor
89 (list #$(file-append package "/sbin/darkstat")
94 "--syslog" "--no-daemon"
95 "--chroot" "/var/lib/darkstat"
97 "--import" "darkstat.db"
98 "--export" "darkstat.db")))
99 (stop #~(make-kill-destructor))))))
101 (define darkstat-service-type
105 "Run @command{darkstat} to serve network traffic statistics reports over
108 (list (service-extension account-service-type
109 (const %darkstat-accounts))
110 (service-extension shepherd-root-service-type
111 (compose list darkstat-shepherd-service))))))
113 (define-record-type* <prometheus-node-exporter-configuration>
114 prometheus-node-exporter-configuration
115 make-prometheus-node-exporter-configuration
116 prometheus-node-exporter-configuration?
117 (package prometheus-node-exporter-configuration-package
118 (default go-github-com-prometheus-node-exporter))
119 (web-listen-address prometheus-node-exporter-web-listen-address
122 (define prometheus-node-exporter-shepherd-service
124 (( $ <prometheus-node-exporter-configuration>
125 package web-listen-address)
127 (documentation "Prometheus node exporter.")
128 (provision '(prometheus-node-exporter))
129 (requirement '(networking))
130 (start #~(make-forkexec-constructor
131 (list #$(file-append package "/bin/node_exporter")
132 "--web.listen-address" #$web-listen-address)))
133 (stop #~(make-kill-destructor))))))
135 (define prometheus-node-exporter-service-type
137 (name 'prometheus-node-exporter)
139 "Run @command{node_exporter} to serve hardware and OS metrics to
142 (list (service-extension
143 shepherd-root-service-type
144 (compose list prometheus-node-exporter-shepherd-service))))
145 (default-value (prometheus-node-exporter-configuration))))
152 (define (uglify-field-name field-name)
155 (if (member (string->symbol str) '(ca db ssl))
157 (string-capitalize str)))
158 (string-split (string-delete #\?
159 (symbol->string field-name))
162 (define (serialize-field field-name val)
163 (format #t "~a=~a~%" (uglify-field-name field-name) val))
165 (define (serialize-number field-name val)
166 (serialize-field field-name (number->string val)))
168 (define (serialize-list field-name val)
169 (if (null? val) "" (serialize-field field-name (string-join val ","))))
171 (define (serialize-string field-name val)
172 (if (and (string? val) (string=? val ""))
174 (serialize-field field-name val)))
176 (define group? string?)
178 (define serialize-group
181 (define include-files? list?)
183 (define (serialize-include-files field-name val)
184 (if (null? val) "" (for-each (cut serialize-field 'include <>) val)))
186 (define extra-options? string?)
188 (define (serialize-extra-options field-name val)
189 (if (null? val) "" (display val)))
191 (define (nginx-server-configuration-list? val)
192 (and (list? val) (and-map nginx-server-configuration? val)))
194 (define (serialize-nginx-server-configuration-list field-name val)
197 (define-configuration zabbix-server-configuration
199 (package zabbix-server)
200 "The zabbix-server package.")
203 "User who will run the Zabbix server.")
204 (group ;for zabbix-server-account procedure
206 "Group who will run the Zabbix server.")
209 "Database host name.")
218 "Database password. Please, use @code{include-files} with
219 @code{DBPassword=SECRET} inside a specified file instead.")
225 "Specifies where log messages are written to:
227 @item @code{system} - syslog.
228 @item @code{file} - file specified with @code{log-file} parameter.
229 @item @code{console} - standard output.
232 (string "/var/log/zabbix/server.log")
233 "Log file name for @code{log-type} @code{file} parameter.")
235 (string "/var/run/zabbix/zabbix_server.pid")
238 (string "/etc/ssl/certs/ca-certificates.crt")
239 "The location of certificate authority (CA) files for SSL server
240 certificate verification.")
242 (string "/etc/ssl/certs")
243 "Location of SSL client certificates.")
246 "Extra options will be appended to Zabbix server configuration file.")
249 "You may include individual files or all files in a directory in the
250 configuration file."))
252 (define (zabbix-server-account config)
253 "Return the user accounts and user groups for CONFIG."
254 (let ((zabbix-user (zabbix-server-configuration-user config))
255 (zabbix-group (zabbix-server-configuration-group config)))
256 (list (user-group (name zabbix-group) (system? #t))
261 (comment "zabbix privilege separation user")
262 (home-directory (string-append "/var/run/" zabbix-user))
263 (shell (file-append shadow "/sbin/nologin"))))))
265 (define (zabbix-server-config-file config)
266 "Return the zabbix-server configuration file corresponding to CONFIG."
270 (call-with-output-file #$output
272 (display "# Generated by 'zabbix-server-service'.\n" port)
273 (display #$(with-output-to-string
275 (serialize-configuration
276 config zabbix-server-configuration-fields)))
280 (define (zabbix-server-activation config)
281 "Return the activation gexp for CONFIG."
282 (with-imported-modules '((guix build utils)
285 (use-modules (guix build utils)
287 (let ((user (getpw #$(zabbix-server-configuration-user config))))
288 (for-each (lambda (file)
289 (let ((directory (dirname file)))
291 (chown directory (passwd:uid user) (passwd:gid user))
292 (chmod directory #o755)))
293 (list #$(zabbix-server-configuration-log-file config)
294 #$(zabbix-server-configuration-pid-file config)
295 "/etc/zabbix/maintenance.inc.php"))))))
297 (define (zabbix-server-shepherd-service config)
298 "Return a <shepherd-service> for Zabbix server with CONFIG."
299 (list (shepherd-service
300 (provision '(zabbix-server))
301 (documentation "Run Zabbix server daemon.")
302 (start #~(make-forkexec-constructor
303 (list #$(file-append (zabbix-server-configuration-zabbix-server config)
304 "/sbin/zabbix_server")
305 "--config" #$(zabbix-server-config-file config)
307 #:user #$(zabbix-server-configuration-user config)
308 #:group #$(zabbix-server-configuration-group config)
309 #:pid-file #$(zabbix-server-configuration-pid-file config)
310 #:environment-variables
311 (list "SSL_CERT_DIR=/run/current-system/profile\
313 "SSL_CERT_FILE=/run/current-system/profile\
314 /etc/ssl/certs/ca-certificates.crt")))
315 (stop #~(make-kill-destructor)))))
317 (define zabbix-server-service-type
319 (name 'zabbix-server)
321 (list (service-extension shepherd-root-service-type
322 zabbix-server-shepherd-service)
323 (service-extension account-service-type
324 zabbix-server-account)
325 (service-extension activation-service-type
326 zabbix-server-activation)))
327 (default-value (zabbix-server-configuration))))
329 (define (generate-zabbix-server-documentation)
330 (generate-documentation
331 `((zabbix-server-configuration
332 ,zabbix-server-configuration-fields))
333 'zabbix-server-configuration))
335 (define-configuration zabbix-agent-configuration
337 (package zabbix-agentd)
338 "The zabbix-agent package.")
341 "User who will run the Zabbix agent.")
344 "Group who will run the Zabbix agent.")
346 (string "Zabbix server")
347 "Unique, case sensitive hostname which is required for active checks and
348 must match hostname as configured on the server.")
351 "Specifies where log messages are written to:
353 @item @code{system} - syslog.
354 @item @code{file} - file specified with @code{log-file} parameter.
355 @item @code{console} - standard output.
358 (string "/var/log/zabbix/agent.log")
359 "Log file name for @code{log-type} @code{file} parameter.")
361 (string "/var/run/zabbix/zabbix_agent.pid")
364 (list '("127.0.0.1"))
365 "List of IP addresses, optionally in CIDR notation, or hostnames of Zabbix
366 servers and Zabbix proxies. Incoming connections will be accepted only from
367 the hosts listed here.")
369 (list '("127.0.0.1"))
370 "List of IP:port (or hostname:port) pairs of Zabbix servers and Zabbix
371 proxies for active checks. If port is not specified, default port is used.
372 If this parameter is not specified, active checks are disabled.")
375 "Extra options will be appended to Zabbix server configuration file.")
378 "You may include individual files or all files in a directory in the
379 configuration file."))
381 (define (zabbix-agent-account config)
382 "Return the user accounts and user groups for CONFIG."
383 (let ((zabbix-user "zabbix")
384 (zabbix-group "zabbix"))
385 (list (user-group (name zabbix-group) (system? #t))
390 (comment "zabbix privilege separation user")
391 (home-directory (string-append "/var/run/" zabbix-user))
392 (shell (file-append shadow "/sbin/nologin"))))))
394 (define (zabbix-agent-activation config)
395 "Return the activation gexp for CONFIG."
396 (with-imported-modules '((guix build utils)
399 (use-modules (guix build utils)
402 (getpw #$(zabbix-agent-configuration-user config))))
403 (for-each (lambda (file)
404 (let ((directory (dirname file)))
406 (chown directory (passwd:uid user) (passwd:gid user))
407 (chmod directory #o755)))
408 (list #$(zabbix-agent-configuration-log-file config)
409 #$(zabbix-agent-configuration-pid-file config)))))))
411 (define (zabbix-agent-config-file config)
412 "Return the zabbix-agent configuration file corresponding to CONFIG."
416 (call-with-output-file #$output
418 (display "# Generated by 'zabbix-agent-service'.\n" port)
419 (display #$(with-output-to-string
421 (serialize-configuration
422 config zabbix-agent-configuration-fields)))
426 (define (zabbix-agent-shepherd-service config)
427 "Return a <shepherd-service> for Zabbix agent with CONFIG."
428 (list (shepherd-service
429 (provision '(zabbix-agent))
430 (documentation "Run Zabbix agent daemon.")
431 (start #~(make-forkexec-constructor
432 (list #$(file-append (zabbix-agent-configuration-zabbix-agent config)
433 "/sbin/zabbix_agentd")
434 "--config" #$(zabbix-agent-config-file config)
436 #:user #$(zabbix-agent-configuration-user config)
437 #:group #$(zabbix-agent-configuration-group config)
438 #:pid-file #$(zabbix-agent-configuration-pid-file config)
439 #:environment-variables
440 (list "SSL_CERT_DIR=/run/current-system/profile\
442 "SSL_CERT_FILE=/run/current-system/profile\
443 /etc/ssl/certs/ca-certificates.crt")))
444 (stop #~(make-kill-destructor)))))
446 (define zabbix-agent-service-type
450 (list (service-extension shepherd-root-service-type
451 zabbix-agent-shepherd-service)
452 (service-extension account-service-type
453 zabbix-agent-account)
454 (service-extension activation-service-type
455 zabbix-agent-activation)))
456 (default-value (zabbix-agent-configuration))))
458 (define (generate-zabbix-agent-documentation)
459 (generate-documentation
460 `((zabbix-agent-configuration
461 ,zabbix-agent-configuration-fields))
462 'zabbix-agent-configuration))
464 (define %zabbix-front-end-configuration-nginx
465 (nginx-server-configuration
466 (root #~(string-append #$zabbix-server:front-end "/share/zabbix/php"))
467 (index '("index.php"))
469 (let ((php-location (nginx-php-location)))
470 (list (nginx-location-configuration
471 (inherit php-location)
472 (body (append (nginx-location-configuration-body php-location)
474 fastcgi_param PHP_VALUE \"post_max_size = 16M
475 max_execution_time = 300\";
479 (define-configuration zabbix-front-end-configuration
480 ;; TODO: Specify zabbix front-end package.
482 ;; (package zabbix-front-end)
483 ;; "The zabbix-front-end package.")
485 (nginx-server-configuration-list
486 (list %zabbix-front-end-configuration-nginx))
487 "NGINX configuration.")
490 "Database host name.")
502 "Database password. Please, use @code{db-secret-file} instead.")
505 "Secret file which will be appended to @file{zabbix.conf.php} file. This
506 file contains credentials for use by Zabbix front-end. You are expected to
507 create it manually.")
510 "Zabbix server hostname.")
513 "Zabbix server port."))
515 (define (zabbix-front-end-config config)
516 (match-record config <zabbix-front-end-configuration>
517 (%location db-host db-port db-name db-user db-password db-secret-file
518 zabbix-host zabbix-port)
519 (mixed-text-file "zabbix.conf.php"
522 // Zabbix GUI configuration file.
525 $DB['TYPE'] = 'POSTGRESQL';
526 $DB['SERVER'] = '" db-host "';
527 $DB['PORT'] = '" (number->string db-port) "';
528 $DB['DATABASE'] = '" db-name "';
529 $DB['USER'] = '" db-user "';
530 $DB['PASSWORD'] = '" (let ((file (location-file %location))
531 (line (location-line %location))
532 (column (location-column %location)))
533 (if (string-null? db-password)
534 (if (string-null? db-secret-file)
535 (raise (make-compound-condition
539 (format #f "no '~A' or '~A' field in your '~A' record"
540 'db-secret-file 'db-password
541 'zabbix-front-end-configuration))))
544 (location %location)))))
546 (with-input-from-file db-secret-file
549 (display-hint (format #f (G_ "~a:~a:~a: ~a:
550 Consider using @code{db-secret-file} instead of @code{db-password} for better
551 security.") file line column 'zabbix-front-end-configuration))
554 // Schema name. Used for IBM DB2 and PostgreSQL.
557 $ZBX_SERVER = '" zabbix-host "';
558 $ZBX_SERVER_PORT = '" (number->string zabbix-port) "';
559 $ZBX_SERVER_NAME = '';
561 $IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
564 (define %maintenance.inc.php
565 ;; Empty php file to allow us move zabbix-frontend configs to ‘/etc/zabbix’
566 ;; directory. See ‘install-front-end’ phase in
567 ;; (@ (gnu packages monitoring) zabbix-server) package.
572 (define (zabbix-front-end-activation config)
573 "Return the activation gexp for CONFIG."
575 (use-modules (guix build utils))
576 (mkdir-p "/etc/zabbix")
577 (call-with-output-file "/etc/zabbix/maintenance.inc.php"
579 (display #$%maintenance.inc.php port)))
580 (copy-file #$(zabbix-front-end-config config)
581 "/etc/zabbix/zabbix.conf.php")))
583 (define zabbix-front-end-service-type
585 (name 'zabbix-front-end)
587 (list (service-extension activation-service-type
588 zabbix-front-end-activation)
589 (service-extension nginx-service-type
590 zabbix-front-end-configuration-nginx)
591 ;; Make sure php-fpm is instantiated.
592 (service-extension php-fpm-service-type
594 (default-value (zabbix-front-end-configuration))
596 "Run the zabbix-front-end web interface, which allows users to interact
597 with Zabbix server.")))
599 (define (generate-zabbix-front-end-documentation)
600 (generate-documentation
601 `((zabbix-front-end-configuration
602 ,zabbix-front-end-configuration-fields))
603 'zabbix-front-end-configuration))