[bug#33549,6/6] services: monitoring: Add 'zabbix-front-end'.

Message ID 20181129185042.6050-6-go.wigust@gmail.com
State Accepted
Headers show
Series Add Zabbix services. | expand

Checks

Context Check Description
cbaines/applying patch success Successfully applied
cbaines/applying patch success Successfully applied

Commit Message

Oleg Pykhalov Nov. 29, 2018, 6:50 p.m. UTC
* gnu/services/monitoring.scm (nginx-server-configuration-list?,
serialize-nginx-server-configuration-list, zabbix-front-end-configuration,
zabbix-front-end-config, zabbix-front-end-activation,
generate-zabbix-front-end-documentation): New procedures.
(%zabbix-front-end-configuration-nginx, %maintenance.inc.php,
zabbix-front-end-service-type): New variables.
* doc/guix.texi (Monitoring Services): Document this.
---
 doc/guix.texi               |  75 ++++++++++++++++++
 gnu/services/monitoring.scm | 146 +++++++++++++++++++++++++++++++++++-
 gnu/tests/monitoring.scm    |  49 ++++++++++++
 3 files changed, 269 insertions(+), 1 deletion(-)

Comments

Ludovic Courtès Dec. 19, 2018, 3:27 p.m. UTC | #1
Hi Oleg,

Oleg Pykhalov <go.wigust@gmail.com> skribis:

> +(define zabbix-front-end-config
> +  (match-lambda
> +    (($ <zabbix-front-end-configuration>
> +        _ db-host db-port db-name db-user db-password db-secret-file
> +        zabbix-host zabbix-port)
> +     (mixed-text-file "zabbix.conf.php"
> +                      "\
> +<?php
> +// Zabbix GUI configuration file.
> +global $DB;
> +
> +$DB['TYPE']     = 'POSTGRESQL';
> +$DB['SERVER']   = '" db-host "';
> +$DB['PORT']     = '" (number->string db-port) "';
> +$DB['DATABASE'] = '" db-name "';
> +$DB['USER']     = '" db-user "';
> +$DB['PASSWORD'] = '" (if (string-null? db-password)
> +                         (if (string-null? db-secret-file)
> +                             (display "Provide a `db-secret-file' \
> +or `db-password' field.
> +"
> +                                      (current-error-port))
> +                             (string-trim-both
> +                              (with-input-from-file db-secret-file
> +                                read-string)))
> +                         (begin
> +                           (display "
> +Hint: Consider use `db-secret-file' instead of `db-password' and unset
> +`db-password' in `zabbix-front-end-configuration' for security.
> +")
> +                           db-password)) "';
> +
> +// Schema name. Used for IBM DB2 and PostgreSQL.
> +$DB['SCHEMA'] = '';
> +
> +$ZBX_SERVER      = '" zabbix-host "';
> +$ZBX_SERVER_PORT = '" (number->string zabbix-port) "';
> +$ZBX_SERVER_NAME = '';
> +
> +$IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
> +"))))

I saw these “hints” in the build log of Cuirass and that got me curious.
:-)

A couple of comments…  For consistency, hints should be reported using
the ‘display-hint’ procedure, which takes a Texinfo string as input.

Second, while the second ‘display’ call does look like a hint, the first
one looks like it should be an error, shouldn’t it?  In that case, I’d
suggest something like:

  (raise (condition
           (&message
            (message "You must provide either 'db-secret-file' or 'db-password'."))))

Third, it would be nice to report source location info along with hints
and errors.  To do that, you could add an innate ‘location’ field to
<zabbix-front-end-configuration> as done for <package>.  Then, along
with the &message condition above, you could raise an &error-location as
is done in a few places.

Does that make sense?

Anyway thanks for this patch series, we’ll probably put it to good use
on the build farm!

Ludo’.
Oleg Pykhalov Dec. 19, 2018, 6:27 p.m. UTC | #2
Hi Ludovic,

Thank you for review.

Ludovic Courtès <ludo@gnu.org> writes:

[…]

>> +$DB['PASSWORD'] = '" (if (string-null? db-password)
>> +                         (if (string-null? db-secret-file)
>> +                             (display "Provide a `db-secret-file' \
>> +or `db-password' field.
>> +"
>> +                                      (current-error-port))
>> +                             (string-trim-both
>> +                              (with-input-from-file db-secret-file
>> +                                read-string)))
>> +                         (begin
>> +                           (display "
>> +Hint: Consider use `db-secret-file' instead of `db-password' and unset
>> +`db-password' in `zabbix-front-end-configuration' for security.
>> +")
>> +                           db-password)) "';
>> +
>> +// Schema name. Used for IBM DB2 and PostgreSQL.
>> +$DB['SCHEMA'] = '';
>> +
>> +$ZBX_SERVER      = '" zabbix-host "';
>> +$ZBX_SERVER_PORT = '" (number->string zabbix-port) "';
>> +$ZBX_SERVER_NAME = '';
>> +
>> +$IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
>> +"))))
>
> I saw these “hints” in the build log of Cuirass and that got me curious.
> :-)

Do you mean “hints” during ‘zabbix’ tests?

> A couple of comments…  For consistency, hints should be reported using
> the ‘display-hint’ procedure, which takes a Texinfo string as input.
>
> Second, while the second ‘display’ call does look like a hint, the first
> one looks like it should be an error, shouldn’t it?  In that case, I’d
> suggest something like:
>
>   (raise (condition
>            (&message
>             (message "You must provide either 'db-secret-file' or 'db-password'."))))

Thanks, pushed as 0485717ee94e7f161d072f017edce5d35df49c81 to master.

> Third, it would be nice to report source location info along with hints
> and errors.  To do that, you could add an innate ‘location’ field to
> <zabbix-front-end-configuration> as done for <package>.  Then, along
> with the &message condition above, you could raise an &error-location as
> is done in a few places.
>
> Does that make sense?

Sure.  I see innate location field in <package>, but unfortunately I'm
not sure how to implement it, because we use define-configuration for
<zabbix-front-end-configuration>.  So the implementation of that feature
may take a time.  ;-)

> Anyway thanks for this patch series, we’ll probably put it to good use
> on the build farm!

Feel free to ping me.


Oleg.
Ludovic Courtès Dec. 20, 2018, 11:06 a.m. UTC | #3
Hi Oleg,

Oleg Pykhalov <go.wigust@gmail.com> skribis:

> Ludovic Courtès <ludo@gnu.org> writes:
>
> […]
>
>>> +$DB['PASSWORD'] = '" (if (string-null? db-password)
>>> +                         (if (string-null? db-secret-file)
>>> +                             (display "Provide a `db-secret-file' \
>>> +or `db-password' field.
>>> +"
>>> +                                      (current-error-port))
>>> +                             (string-trim-both
>>> +                              (with-input-from-file db-secret-file
>>> +                                read-string)))
>>> +                         (begin
>>> +                           (display "
>>> +Hint: Consider use `db-secret-file' instead of `db-password' and unset
>>> +`db-password' in `zabbix-front-end-configuration' for security.
>>> +")
>>> +                           db-password)) "';
>>> +
>>> +// Schema name. Used for IBM DB2 and PostgreSQL.
>>> +$DB['SCHEMA'] = '';
>>> +
>>> +$ZBX_SERVER      = '" zabbix-host "';
>>> +$ZBX_SERVER_PORT = '" (number->string zabbix-port) "';
>>> +$ZBX_SERVER_NAME = '';
>>> +
>>> +$IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
>>> +"))))
>>
>> I saw these “hints” in the build log of Cuirass and that got me curious.
>> :-)
>
> Do you mean “hints” during ‘zabbix’ tests?

Yes, in the output of the “evaluation” of the ‘guix-master’ jobset.

>> Third, it would be nice to report source location info along with hints
>> and errors.  To do that, you could add an innate ‘location’ field to
>> <zabbix-front-end-configuration> as done for <package>.  Then, along
>> with the &message condition above, you could raise an &error-location as
>> is done in a few places.
>>
>> Does that make sense?
>
> Sure.  I see innate location field in <package>, but unfortunately I'm
> not sure how to implement it, because we use define-configuration for
> <zabbix-front-end-configuration>.  So the implementation of that feature
> may take a time.  ;-)

We could probably change ‘define-configuration’ to add a ‘location’
field unconditionally.  But yeah, we’ll see!

Thanks,
Ludo’.

Patch

diff --git a/doc/guix.texi b/doc/guix.texi
index d83071b432..a1de8b0f15 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -16854,6 +16854,81 @@  Defaults to @samp{()}.
 
 @end deftypevr
 
+@c %end of fragment
+
+@subsubheading Zabbix front-end
+@cindex zabbix zabbix-front-end
+
+This service provides a WEB interface to Zabbix server.
+
+@c %start of fragment
+
+Available @code{zabbix-front-end-configuration} fields are:
+
+@deftypevr {@code{zabbix-front-end-configuration} parameter} nginx-server-configuration-list nginx
+NGINX configuration.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-front-end-configuration} parameter} string db-host
+Database host name.
+
+Defaults to @samp{"localhost"}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-front-end-configuration} parameter} number db-port
+Database port.
+
+Defaults to @samp{5432}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-front-end-configuration} parameter} string db-name
+Database name.
+
+Defaults to @samp{"zabbix"}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-front-end-configuration} parameter} string db-user
+Database user.
+
+Defaults to @samp{"zabbix"}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-front-end-configuration} parameter} string db-password
+Database password.  Please, use @code{db-secret-file} instead.
+
+Defaults to @samp{""}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-front-end-configuration} parameter} string db-secret-file
+Secret file which will be appended to @file{zabbix.conf.php} file.  This
+file contains credentials for use by Zabbix front-end.  You are expected
+to create it manually.
+
+Defaults to @samp{""}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-front-end-configuration} parameter} string zabbix-host
+Zabbix server hostname.
+
+Defaults to @samp{"localhost"}.
+
+@end deftypevr
+
+@deftypevr {@code{zabbix-front-end-configuration} parameter} number zabbix-port
+Zabbix server port.
+
+Defaults to @samp{10051}.
+
+@end deftypevr
+
+
 @c %end of fragment
 
 @node Kerberos Services
diff --git a/gnu/services/monitoring.scm b/gnu/services/monitoring.scm
index 274228af89..452f26ef8a 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -22,6 +22,7 @@ 
   #:use-module (gnu services)
   #:use-module (gnu services configuration)
   #:use-module (gnu services shepherd)
+  #:use-module (gnu services web)
   #:use-module (gnu packages admin)
   #:use-module (gnu packages monitoring)
   #:use-module (gnu system shadow)
@@ -29,6 +30,7 @@ 
   #:use-module (guix packages)
   #:use-module (guix records)
   #:use-module (ice-9 match)
+  #:use-module (ice-9 rdelim)
   #:use-module (srfi srfi-26)
   #:export (darkstat-configuration
             prometheus-node-exporter-configuration
@@ -38,7 +40,10 @@ 
             zabbix-server-configuration
             zabbix-server-service-type
             zabbix-agent-configuration
-            zabbix-agent-service-type))
+            zabbix-agent-service-type
+            zabbix-front-end-configuration
+            zabbix-front-end-service-type
+            %zabbix-front-end-configuration-nginx))
 
 
 ;;;
@@ -174,6 +179,12 @@  prometheus.")
 (define (serialize-include-files field-name val)
   (if (null? val) "" (for-each (cut serialize-field 'include <>) val)))
 
+(define (nginx-server-configuration-list? val)
+  (and (list? val) (and-map nginx-server-configuration? val)))
+
+(define (serialize-nginx-server-configuration-list field-name val)
+  "")
+
 (define-configuration zabbix-server-configuration
   (zabbix-server
    (package zabbix-server)
@@ -439,3 +450,136 @@  configuration file."))
    `((zabbix-agent-configuration
       ,zabbix-agent-configuration-fields))
    'zabbix-agent-configuration))
+
+(define %zabbix-front-end-configuration-nginx
+  (nginx-server-configuration
+   (root #~(string-append #$zabbix-server:front-end "/share/zabbix/php"))
+   (index '("index.php"))
+   (locations
+    (let ((php-location (nginx-php-location)))
+      (list (nginx-location-configuration
+             (inherit php-location)
+             (body (append (nginx-location-configuration-body php-location)
+                           (list "
+fastcgi_param PHP_VALUE \"post_max_size = 16M
+                          max_execution_time = 300\";
+")))))))))
+
+(define-configuration zabbix-front-end-configuration
+  ;; TODO: Specify zabbix front-end package.
+  ;; (zabbix-
+  ;;  (package zabbix-front-end)
+  ;;  "The zabbix-front-end package.")
+  (nginx
+   (nginx-server-configuration-list
+    (list %zabbix-front-end-configuration-nginx))
+   "NGINX configuration.")
+  (db-host
+   (string "localhost")
+   "Database host name.")
+  (db-port
+   (number 5432)
+   "Database port.")
+  (db-name
+   (string "zabbix")
+   "Database name.")
+  (db-user
+   (string "zabbix")
+   "Database user.")
+  (db-password
+   (string "")
+   "Database password.  Please, use @code{db-secret-file} instead.")
+  (db-secret-file
+   (string "")
+   "Secret file which will be appended to @file{zabbix.conf.php} file.  This
+file contains credentials for use by Zabbix front-end.  You are expected to
+create it manually.")
+  (zabbix-host
+   (string "localhost")
+   "Zabbix server hostname.")
+  (zabbix-port
+   (number 10051)
+   "Zabbix server port."))
+
+(define zabbix-front-end-config
+  (match-lambda
+    (($ <zabbix-front-end-configuration>
+        _ db-host db-port db-name db-user db-password db-secret-file
+        zabbix-host zabbix-port)
+     (mixed-text-file "zabbix.conf.php"
+                      "\
+<?php
+// Zabbix GUI configuration file.
+global $DB;
+
+$DB['TYPE']     = 'POSTGRESQL';
+$DB['SERVER']   = '" db-host "';
+$DB['PORT']     = '" (number->string db-port) "';
+$DB['DATABASE'] = '" db-name "';
+$DB['USER']     = '" db-user "';
+$DB['PASSWORD'] = '" (if (string-null? db-password)
+                         (if (string-null? db-secret-file)
+                             (display "Provide a `db-secret-file' \
+or `db-password' field.
+"
+                                      (current-error-port))
+                             (string-trim-both
+                              (with-input-from-file db-secret-file
+                                read-string)))
+                         (begin
+                           (display "
+Hint: Consider use `db-secret-file' instead of `db-password' and unset
+`db-password' in `zabbix-front-end-configuration' for security.
+")
+                           db-password)) "';
+
+// Schema name. Used for IBM DB2 and PostgreSQL.
+$DB['SCHEMA'] = '';
+
+$ZBX_SERVER      = '" zabbix-host "';
+$ZBX_SERVER_PORT = '" (number->string zabbix-port) "';
+$ZBX_SERVER_NAME = '';
+
+$IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
+"))))
+
+(define %maintenance.inc.php
+  ;; Empty php file to allow us move zabbix-frontend configs to ‘/etc/zabbix’
+  ;; directory.  See ‘install-front-end’ phase in
+  ;; (@ (gnu packages monitoring) zabbix-server) package.
+    "\
+<?php
+")
+
+(define (zabbix-front-end-activation config)
+  "Return the activation gexp for CONFIG."
+  #~(begin
+      (use-modules (guix build utils))
+      (mkdir-p "/etc/zabbix")
+      (call-with-output-file "/etc/zabbix/maintenance.inc.php"
+            (lambda (port)
+              (display #$%maintenance.inc.php port)))
+      (copy-file #$(zabbix-front-end-config config)
+                 "/etc/zabbix/zabbix.conf.php")))
+
+(define zabbix-front-end-service-type
+  (service-type
+   (name 'zabbix-front-end)
+   (extensions
+    (list (service-extension activation-service-type
+                             zabbix-front-end-activation)
+          (service-extension nginx-service-type
+                             zabbix-front-end-configuration-nginx)
+          ;; Make sure php-fpm is instantiated.
+          (service-extension php-fpm-service-type
+                             (const #t))))
+   (default-value (zabbix-front-end-configuration))
+   (description
+    "Run the zabbix-front-end web interface, which allows users to interact
+with Zabbix server.")))
+
+(define (generate-zabbix-front-end-documentation)
+  (generate-documentation
+   `((zabbix-front-end-configuration
+      ,zabbix-front-end-configuration-fields))
+   'zabbix-front-end-configuration))
diff --git a/gnu/tests/monitoring.scm b/gnu/tests/monitoring.scm
index ec9e086ff4..3169e5b66f 100644
--- a/gnu/tests/monitoring.scm
+++ b/gnu/tests/monitoring.scm
@@ -20,11 +20,13 @@ 
 (define-module (gnu tests monitoring)
   #:use-module (gnu packages databases)
   #:use-module (gnu packages monitoring)
+  #:use-module (gnu packages php)
   #:use-module (gnu services)
   #:use-module (gnu services monitoring)
   #:use-module (gnu services networking)
   #:use-module (gnu services databases)
   #:use-module (gnu services shepherd)
+  #:use-module (gnu services web)
   #:use-module (gnu system vm)
   #:use-module (gnu system)
   #:use-module (gnu tests)
@@ -250,6 +252,44 @@  zabbix||{}
              '(file-exists? "/var/run/zabbix/zabbix_agent.pid")
              marionette))
 
+          ;; Wait for php-fpm to be up and running.
+          (test-assert "php-fpm running"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (start-service 'php-fpm))
+             marionette))
+
+          ;; Wait for nginx to be up and running.
+          (test-assert "nginx running"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (start-service 'nginx))
+             marionette))
+
+          ;; Make sure the PID file is created.
+          (test-assert "nginx PID file"
+            (marionette-eval
+             '(file-exists? "/var/run/nginx/pid")
+             marionette))
+
+          ;; Make sure we can access pages that correspond to our repository.
+          (letrec-syntax ((test-url
+                           (syntax-rules ()
+                             ((_ path code)
+                              (test-equal (string-append "GET " path)
+                                code
+                                (let-values (((response body)
+                                              (http-get (string-append
+                                                         "http://localhost:8080"
+                                                         path))))
+                                  (response-code response))))
+                             ((_ path)
+                              (test-url path 200)))))
+            (test-url "/")
+            (test-url "/does-not-exist" 404))
+
           (test-end)
 
           (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
@@ -262,6 +302,15 @@  zabbix||{}
          (simple-operating-system
           (service dhcp-client-service-type)
           (postgresql-service)
+          (service zabbix-front-end-service-type
+                   (zabbix-front-end-configuration
+                    (db-password "zabbix")))
+
+          (service php-fpm-service-type
+                   (php-fpm-configuration
+                    (timezone "Europe/Paris")
+                    (php php-with-bcmath)))
+
           (service zabbix-server-service-type
                    (zabbix-server-configuration
                     (db-password "zabbix")