Subject: [bug#40738] [PATCH 2/4] services: Add a Prometheus service.

From: Christopher Baines <[email-masked]>
Date: Mon, 20 Apr 2020 22:17:41 +0100

---
 gnu/services/monitoring.scm | 82 +++++++++++++++++++++++++++++++++++++
 gnu/tests/monitoring.scm    | 73 ++++++++++++++++++++++++++++++++-
 2 files changed, 154 insertions(+), 1 deletion(-)

diff --git a/gnu/services/monitoring.scm b/gnu/services/monitoring.scm
index 511f4fb2fe..a37dfd80d8 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -40,6 +40,17 @@
             darkstat-service-type
             prometheus-node-exporter-service-type
 
+            prometheus-service-type
+            <prometheus-configuration>
+            prometheus-configuration
+            prometheus-configuration-package
+            prometheus-configuration-user
+            prometheus-configuration-group
+            prometheus-configuration-config-file
+            prometheus-configuration-web-listen-address
+            prometheus-configuration-storage-tsdb-path
+            prometheus-configuration-extra-options
+
             zabbix-server-configuration
             zabbix-server-service-type
             zabbix-agent-configuration
@@ -110,6 +121,77 @@ HTTP.")
           (service-extension shepherd-root-service-type
                              (compose list darkstat-shepherd-service))))))
 
+
+;;;
+;;; Prometheus
+;;;
+
+(define-record-type* <prometheus-configuration>
+  prometheus-configuration
+  make-prometheus-configuration
+  prometheus-configuration?
+  (package            prometheus-configuration-package
+                      (default prometheus))
+  (user               prometheus-configuration-user
+                      (default "prometheus"))
+  (group              prometheusconfiguration-group
+                      (default "prometheus"))
+  (config-file        prometheus-config-file
+                      (default (plain-file "prometheus.yml" "")))
+  (web-listen-address prometheus-web-listen-address
+                      (default "0.0.0.0:9090"))
+  (storage-tsdb-path  prometheus-storage-tsdb-path
+                      (default "/var/lib/prometheus/data/"))
+  (extra-options      prometheus-configuration-extra-options
+                      (default '())))
+
+(define prometheus-shepherd-service
+  (match-lambda
+    (($ <prometheus-configuration> package user group
+                                   config-file web-listen-address
+                                   storage-tsdb-path extra-options)
+     (shepherd-service
+      (documentation "Prometheus monitoring system and time series database.")
+      (provision '(prometheus))
+      (requirement '(networking))
+      (start #~(make-forkexec-constructor
+                (list #$(file-append package "/bin/prometheus")
+                      "--config.file" #$config-file
+                      "--web.listen-address" #$web-listen-address
+                      "--storage.tsdb.path" #$storage-tsdb-path
+                      #$@extra-options)
+                #:user #$user
+                #:group #$group
+                #:log-file "/var/log/prometheus.log"))
+      (stop #~(make-kill-destructor))))))
+
+(define (prometheus-account config)
+  (match-record config <prometheus-configuration>
+    (user group)
+    (list (user-group
+           (name group)
+           (system? #t))
+          (user-account
+           (name user)
+           (group group)
+           (system? #t)
+           (comment "Prometheus user")
+           (home-directory "/var/lib/prometheus")
+           (shell (file-append shadow "/sbin/nologin"))))))
+
+(define prometheus-service-type
+  (service-type
+   (name 'prometheus)
+   (description
+    "Run @command{prometheus} to scrape targets for mertrics and provide the
+web interface.")
+   (extensions
+    (list (service-extension shepherd-root-service-type
+                             (compose list prometheus-shepherd-service))
+          (service-extension account-service-type
+                             prometheus-account)))
+   (default-value (prometheus-configuration))))
+
 (define-record-type* <prometheus-node-exporter-configuration>
   prometheus-node-exporter-configuration
   make-prometheus-node-exporter-configuration
diff --git a/gnu/tests/monitoring.scm b/gnu/tests/monitoring.scm
index 732fbc54d7..e8c0847229 100644
--- a/gnu/tests/monitoring.scm
+++ b/gnu/tests/monitoring.scm
@@ -31,9 +31,80 @@
   #:use-module (gnu system)
   #:use-module (gnu tests)
   #:use-module (guix gexp)
-  #:export (%test-prometheus-node-exporter
+  #:export (%test-prometheus
+            %test-prometheus-node-exporter
             %test-zabbix))
 
+
+;;;
+;;; Prometheus
+;;;
+
+(define* (run-prometheus-test name test-os)
+  "Run tests in %TEST-OS, which has Prometheus running."
+  (define os
+    (marionette-operating-system
+     test-os
+     #:imported-modules '((gnu services herd))))
+
+  (define vm
+    (virtual-machine
+     (operating-system os)
+     (port-forwardings '((8080 . 9090)))))
+
+  (define test
+    (with-imported-modules '((gnu build marionette))
+      #~(begin
+          (use-modules (srfi srfi-11)
+                       (srfi srfi-64)
+                       (gnu build marionette)
+                       (web client)
+                       (web response))
+
+          (define marionette
+            (make-marionette (list #$vm)))
+
+          (mkdir #$output)
+          (chdir #$output)
+
+          (test-begin #$name)
+
+          (test-assert "prometheus running"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (match (start-service 'prometheus)
+                  (#f #f)
+                  (('service response-parts ...)
+                   (match (assq-ref response-parts 'running)
+                     ((pid) (number? pid))))))
+             marionette))
+
+          (test-equal "prometheus healthy"
+            200
+            (begin
+              (wait-for-tcp-port 9090 marionette)
+              (let-values (((response text)
+                            (http-get "http://localhost:8080/-/healthy")))
+                (response-code response))))
+
+          (test-end)
+          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
+
+  (gexp->derivation (string-append name "-test") test))
+
+(define %prometheus-test-os
+  (simple-operating-system
+   (service dhcp-client-service-type)
+   (service prometheus-service-type)))
+
+(define %test-prometheus
+  (system-test
+   (name "prometheus")
+   (description "Connect to a running Prometheus service.")
+   (value (run-prometheus-test name
+                               %prometheus-test-os))))
+
 
 ;;;
 ;;; Prometheus Node Exporter
-- 
2.26.0