Subject: [bug#33549] [PATCH 3/6] services: monitoring: Add 'zabbix-agent'.

From: Oleg Pykhalov <[email-masked]>
Date: Thu, 29 Nov 2018 21:50:39 +0300

* doc/guix.texi (Monitoring Services): Document 'zabbix-agent'.
* gnu/services/monitoring.scm (zabbix-server-service-type,
zabbix-agent-account, zabbix-agent-activation, zabbix-agent-config-file,
zabbix-agent-shepherd-service, generate-zabbix-agent-documentation): New
procedures.
(zabbix-agent-service-type): New variable.
* gnu/tests/monitoring.scm (run-zabbix-server-test): Test 'zabbix-agent'.
(%zabbix-os): Add 'zabbix-agent' service.
---
 doc/guix.texi               | 103 ++++++++++++++++++++++++++++
 gnu/services/monitoring.scm | 133 +++++++++++++++++++++++++++++++++++-
 gnu/tests/monitoring.scm    |  18 ++++-
 3 files changed, 252 insertions(+), 2 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 48f7798742..7b8f7acd29 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -16750,6 +16750,109 @@ Defaults to @samp{()}.
 
 @end deftypevr
 
+@c %end of fragment
+
+@subsubheading Zabbix agent
+@cindex zabbix zabbix-agent
+
+Zabbix agent gathers information for Zabbix server.
+
+@c %start of fragment
+
+Available @code{zabbix-agent-configuration} fields are:
+
+@deftypevr {@code{zabbix-agent-configuration} parameter} package zabbix-agent
+The zabbix-agent package.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-agent-configuration} parameter} string user
+User who will run the Zabbix agent.
+
+Defaults to @samp{"zabbix"}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-agent-configuration} parameter} group group
+Group who will run the Zabbix agent.
+
+Defaults to @samp{"zabbix"}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-agent-configuration} parameter} string hostname
+Unique, case sensitive hostname which is required for active checks and
+must match hostname as configured on the server.
+
+Defaults to @samp{"Zabbix server"}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-agent-configuration} parameter} string log-type
+Specifies where log messages are written to:
+
+@itemize @bullet
+@item
+@code{system} - syslog.
+
+@item
+@code{file} - file specified with @code{log-file} parameter.
+
+@item
+@code{console} - standard output.
+
+@end itemize
+
+Defaults to @samp{""}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-agent-configuration} parameter} string log-file
+Log file name for @code{log-type} @code{file} parameter.
+
+Defaults to @samp{"/var/log/zabbix/agent.log"}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-agent-configuration} parameter} string pid-file
+Name of PID file.
+
+Defaults to @samp{"/var/run/zabbix/zabbix_agent.pid"}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-agent-configuration} parameter} list server
+List of IP addresses, optionally in CIDR notation, or hostnames of
+Zabbix servers and Zabbix proxies.  Incoming connections will be
+accepted only from the hosts listed here.
+
+Defaults to @samp{("127.0.0.1")}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-agent-configuration} parameter} list server-active
+List of IP:port (or hostname:port) pairs of Zabbix servers and Zabbix
+proxies for active checks.  If port is not specified, default port is
+used.  If this parameter is not specified, active checks are disabled.
+
+Defaults to @samp{("127.0.0.1")}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-agent-configuration} parameter} string extra-options
+Extra options will be appended to Zabbix server configuration file.
+
+Defaults to @samp{""}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-agent-configuration} parameter} include-files include-files
+You may include individual files or all files in a directory in the
+configuration file.
+
+Defaults to @samp{()}.
+
+@end deftypevr
 
 @c %end of fragment
 
diff --git a/gnu/services/monitoring.scm b/gnu/services/monitoring.scm
index 9655fb95e9..274228af89 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -36,7 +36,9 @@
             prometheus-node-exporter-service-type
 
             zabbix-server-configuration
-            zabbix-server-service-type))
+            zabbix-server-service-type
+            zabbix-agent-configuration
+            zabbix-agent-service-type))
 
 
 ;;;
@@ -308,3 +310,132 @@ configuration file."))
    `((zabbix-server-configuration
       ,zabbix-server-configuration-fields))
    'zabbix-server-configuration))
+
+(define-configuration zabbix-agent-configuration
+  (zabbix-agent
+   (package zabbix-agentd)
+   "The zabbix-agent package.")
+  (user
+   (string "zabbix")
+   "User who will run the Zabbix agent.")
+  (group
+   (group "zabbix")
+   "Group who will run the Zabbix agent.")
+  (hostname
+   (string "Zabbix server")
+   "Unique, case sensitive hostname which is required for active checks and
+must match hostname as configured on the server.")
+  (log-type
+   (string "")
+   "Specifies where log messages are written to:
+@itemize
+@item @code{system} - syslog.
+@item @code{file} - file specified with @code{log-file} parameter.
+@item @code{console} - standard output.
+@end itemize\n")
+  (log-file
+   (string "/var/log/zabbix/agent.log")
+   "Log file name for @code{log-type} @code{file} parameter.")
+  (pid-file
+   (string "/var/run/zabbix/zabbix_agent.pid")
+   "Name of PID file.")
+  (server
+   (list '("127.0.0.1"))
+   "List of IP addresses, optionally in CIDR notation, or hostnames of Zabbix
+servers and Zabbix proxies.  Incoming connections will be accepted only from
+the hosts listed here.")
+  (server-active
+   (list '("127.0.0.1"))
+   "List of IP:port (or hostname:port) pairs of Zabbix servers and Zabbix
+proxies for active checks.  If port is not specified, default port is used.
+If this parameter is not specified, active checks are disabled.")
+  (extra-options
+   (string "")
+   "Extra options will be appended to Zabbix server configuration file.")
+  (include-files
+   (include-files '())
+   "You may include individual files or all files in a directory in the
+configuration file."))
+
+(define (zabbix-agent-account config)
+  "Return the user accounts and user groups for CONFIG."
+  (let ((zabbix-user "zabbix")
+        (zabbix-group "zabbix"))
+    (list (user-group (name zabbix-group) (system? #t))
+          (user-account
+           (name zabbix-user)
+           (system? #t)
+           (group zabbix-group)
+           (comment "zabbix privilege separation user")
+           (home-directory (string-append "/var/run/" zabbix-user))
+           (shell #~(string-append #$shadow "/sbin/nologin"))))))
+
+(define (zabbix-agent-activation config)
+  "Return the activation gexp for CONFIG."
+  (with-imported-modules '((guix build utils)
+                           (ice-9 rdelim))
+    #~(begin
+        (use-modules (guix build utils)
+                     (ice-9 rdelim))
+        (let ((user
+               (getpw #$(zabbix-agent-configuration-user config))))
+          (for-each (lambda (file)
+                      (let ((directory (dirname file)))
+                        (mkdir-p directory)
+                        (chown directory (passwd:uid user) (passwd:gid user))
+                        (chmod directory #o755)))
+                    (list #$(zabbix-agent-configuration-log-file config)
+                          #$(zabbix-agent-configuration-pid-file config)))))))
+
+(define (zabbix-agent-config-file config)
+  "Return the zabbix-agent configuration file corresponding to CONFIG."
+  (computed-file
+   "zabbix_agent.conf"
+   #~(begin
+       (call-with-output-file #$output
+         (lambda (port)
+           (display "# Generated by 'zabbix-agent-service'.\n" port)
+           (display #$(with-output-to-string
+                        (lambda ()
+                          (serialize-configuration
+                           config zabbix-agent-configuration-fields)))
+                    port)
+           #t)))))
+
+(define (zabbix-agent-shepherd-service config)
+  "Return a <shepherd-service> for Zabbix agent with CONFIG."
+  (list (shepherd-service
+         (provision '(zabbix-agent))
+         (documentation "Run Zabbix agent daemon.")
+         (start #~(make-forkexec-constructor
+                   (list #$(file-append (zabbix-agent-configuration-zabbix-agent config)
+                                        "/sbin/zabbix_agentd")
+                         "--config" #$(zabbix-agent-config-file config)
+                         "--foreground")
+                   #:user #$(zabbix-agent-configuration-user config)
+                   #:group #$(zabbix-agent-configuration-group config)
+                   #:pid-file #$(zabbix-agent-configuration-pid-file config)
+                   #:environment-variables
+                   (list "SSL_CERT_DIR=/run/current-system/profile\
+/etc/ssl/certs"
+                         "SSL_CERT_FILE=/run/current-system/profile\
+/etc/ssl/certs/ca-certificates.crt")))
+         (stop #~(make-kill-destructor)))))
+
+(define zabbix-agent-service-type
+  (service-type
+   (name 'zabbix-agent)
+   (extensions
+    (list (service-extension shepherd-root-service-type
+                             zabbix-agent-shepherd-service)
+          (service-extension account-service-type
+                             zabbix-agent-account)
+          (service-extension activation-service-type
+                             zabbix-agent-activation)))
+   (default-value (zabbix-agent-configuration))))
+
+(define (generate-zabbix-agent-documentation)
+  (generate-documentation
+   `((zabbix-agent-configuration
+      ,zabbix-agent-configuration-fields))
+   'zabbix-agent-configuration))
diff --git a/gnu/tests/monitoring.scm b/gnu/tests/monitoring.scm
index 7a704eb01d..ec9e086ff4 100644
--- a/gnu/tests/monitoring.scm
+++ b/gnu/tests/monitoring.scm
@@ -236,6 +236,20 @@ zabbix||{}
              '(file-exists? "/var/run/zabbix/zabbix_server.pid")
              marionette))
 
+          ;; Wait for zabbix-agent to be up and running.
+          (test-assert "zabbix-agent running"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (start-service 'zabbix-agent))
+             marionette))
+
+          ;; Make sure the PID file is created.
+          (test-assert "zabbix-agent PID file"
+            (marionette-eval
+             '(file-exists? "/var/run/zabbix/zabbix_agent.pid")
+             marionette))
+
           (test-end)
 
           (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
@@ -251,7 +265,9 @@ zabbix||{}
           (service zabbix-server-service-type
                    (zabbix-server-configuration
                     (db-password "zabbix")
-                    (log-type "console"))))))
+                    (log-type "console")))
+
+          (service zabbix-agent-service-type))))
     (operating-system
       (inherit base-os)
       (packages (cons* postgresql (operating-system-packages base-os))))))
-- 
2.19.1