From 12599959d0f9bf0e8caf4b43d3d83b8fc0884577 Mon Sep 17 00:00:00 2001 From: nik gaffney Date: Tue, 16 Jan 2024 16:49:46 +0100 Subject: [PATCH] Put in earplugs --- packages/zzkt/plugdata.scm | 2 +- packages/zzkt/services/grafana.scm | 230 ++++++++++++++++++++++++++ packages/zzkt/services/prometheus.scm | 143 ++++++++++++++++ 3 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 packages/zzkt/services/grafana.scm create mode 100644 packages/zzkt/services/prometheus.scm diff --git a/packages/zzkt/plugdata.scm b/packages/zzkt/plugdata.scm index 714c6fc..ab254c4 100644 --- a/packages/zzkt/plugdata.scm +++ b/packages/zzkt/plugdata.scm @@ -36,7 +36,7 @@ (sha256 (base32 "18c340hnx1sny87dby8wahijl1ssj1av67ff232gfwymfra6rdxm")))) ;; see https://github.com/juce-framework/JUCE/blob/master/docs/Linux%20Dependencies.md (inputs - (list gawk)) + (list gawk perl)) (build-system cmake-build-system) (arguments `(#:tests? #f)) diff --git a/packages/zzkt/services/grafana.scm b/packages/zzkt/services/grafana.scm new file mode 100644 index 0000000..d5723da --- /dev/null +++ b/packages/zzkt/services/grafana.scm @@ -0,0 +1,230 @@ +;;; SPDX-License-Identifier: GPL-3.0-or-later +;;; Copyright © 2023 Giacomo Leidi + +;; via https://git.sr.ht/~fishinthecalculator/gocix/tree/main/item/modules/oci/services/grafana.scm +;; and see also https://fishinthecalculator.me/blog/monitor-your-guix-system-with-grafana.html + +(define-module (zzkt services grafana) + #:use-module (gnu packages admin) + #:use-module (gnu services) + #:use-module (gnu services configuration) + #:use-module (gnu services docker) + #:use-module (gnu system shadow) + #:use-module (guix gexp) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:use-module (ice-9 string-fun) + #:export (oci-grafana-service-type + oci-grafana-configuration + oci-grafana-configuration? + oci-grafana-configuration-fields + oci-grafana-configuration-datadir + oci-grafana-configuration-image + oci-grafana-configuration-port + oci-grafana-configuration-grafana.ini + oci-grafana-configuration-network + oci-grafana-configuration->oci-container-configuration + + %grafana-accounts + %grafana-activation + + grafana-configuration + grafana-configuration? + grafana-configuration-fields + grafana-configuration-server + grafana-configuration-smtp + grafana-configuration-extra-content + + grafana-server-configuration + grafana-server-configuration? + grafana-server-configuration-fields + grafana-server-configuration-root-url + grafana-server-configuration-serve-from-subpath? + + grafana-smtp-configuration + grafana-smtp-configuration? + grafana-smtp-configuration-fields + grafana-smtp-configuration-enabled? + grafana-smtp-configuration-host + grafana-smtp-configuration-user + grafana-smtp-configuration-password + grafana-smtp-configuration-from-address)) + +;; Some of this code comes from the Guix manual. +;; Check it out! It's pretty cool. + +(define grafana-tag + "10.1.5") + +(define grafana-image + (string-append "bitnami/grafana:" grafana-tag)) + +;; Turn field names, which are Scheme symbols into strings +(define (uglify-field-name field-name) + (string-replace-substring + (string-replace-substring + (symbol->string field-name) "?" "") "-" "_")) + +(define (serialize-string field-name value) + #~(string-append #$(uglify-field-name field-name) " = " #$value "\n")) + +(define (serialize-integer field-name value) + (serialize-string field-name (number->string value))) + +(define (serialize-boolean field-name value) + (serialize-string field-name (if value "true" "false"))) + +(define (gf-serialize-grafana-server-configuration field-name value) + #~(string-append + "[server]\n" + #$(serialize-configuration + value grafana-server-configuration-fields))) + +(define-configuration grafana-server-configuration + (domain + (string "example.org") + "The public host where grafana will be exposed.") + (root-url + (string "%(protocol)s://%(domain)s:%(http_port)s/") + "The url where grafana will be exposed.") + (serve-from-sub-path? + (boolean #f) + "The image to use for the OCI backed Shepherd service.")) + +(define (gf-serialize-grafana-smtp-configuration field-name value) + #~(string-append + "[smtp]\n" + #$(serialize-configuration + value grafana-smtp-configuration-fields))) + +(define-configuration grafana-smtp-configuration + (enabled? + (boolean #f) + "Whether to enable Grafana's email alerting.") + (host + (string "smtp.example.org:587") + "The connection string representing your SMTP server.") + (user + (string "you@example.org") + "The email used to authenticate with the SMTP server.") + (password + (string "") + "The password used to authenticate with the SMTP server.") + (from-address + (string "alert@example.org") + "The sender of the email alerts Grafana will send.")) + +(define (gf-serialize-grafana-configuration configuration) + (mixed-text-file + "grafana.ini" + (serialize-configuration + configuration grafana-configuration-fields))) + +(define (gf-serialize-string field-name value) + value) + +(define-maybe string) + +(define-configuration grafana-configuration + (server + (grafana-server-configuration (grafana-server-configuration)) + "grafana.ini's [server] section.") + (smtp + (grafana-smtp-configuration (grafana-smtp-configuration)) + "grafana.ini's [smtp] section.") + (extra-content + (string "") + "Everything you want to manually add to grafana.ini.") + (prefix gf-)) + +(define-configuration oci-grafana-configuration + (datadir + (string "/var/lib/grafana") + "The directory where grafana writes state.") + (image + (string grafana-image) + "The image to use for the OCI backed Shepherd service.") + (port + (string "3000") + "This host port will be mapped onto the Grafana configured port inside the container.") + (grafana.ini + (grafana-configuration (grafana-configuration)) + "This field will be serialized as graphana.ini.") + (network + (maybe-string) + "The docker network where the grafana container will be attached. When equal +to \"host\" the @code{port} field will be ignored.") + (no-serialization)) + +(define %grafana-accounts + (list (user-account + (name "grafana") + (comment "Grafana's Service Account") + (uid 1001) + (group "root") + (supplementary-groups '("tty")) + (system? #t) + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin"))))) + +(define (%grafana-activation config) + "Return an activation gexp for Grafana." + (let* ((datadir (oci-grafana-configuration-datadir config)) + (grafana.ini + (mixed-text-file + "grafana.ini" + (serialize-configuration (oci-grafana-configuration-grafana.ini config) + grafana-configuration-fields)))) + #~(begin + (use-modules (guix build utils)) + (let* ((user (getpwnam "grafana")) + (uid (passwd:uid user)) + (gid (passwd:gid user)) + (datadir #$datadir)) + ;; Setup datadir + (mkdir-p datadir) + (chown datadir uid gid) + ;; Activate configuration + (activate-special-files + '(("/etc/grafana/grafana.ini" + #$grafana.ini))))))) + +(define oci-grafana-configuration->oci-container-configuration + (lambda (config) + (let* ((datadir + (oci-grafana-configuration-datadir config)) + (grafana.ini (oci-grafana-configuration-grafana.ini config)) + (network + (oci-grafana-configuration-network config)) + (image + (oci-grafana-configuration-image config)) + (port + (oci-grafana-configuration-port config)) + (container-config + (oci-container-configuration + (image image) + (ports + `((,port . "3000"))) + (volumes + `((,datadir . "/var/lib/grafana") + ;; Needed because grafana.ini is a symlink to an item in the store. + ("/gnu/store" . "/gnu/store") + ("/etc/grafana/grafana.ini" . "/opt/bitnami/grafana/conf/grafana.ini")))))) + (list + (if (maybe-value-set? network) + (oci-container-configuration + (inherit container-config) + (network network)) + container-config))))) + +(define oci-grafana-service-type + (service-type (name 'grafana) + (extensions (list (service-extension oci-container-service-type + oci-grafana-configuration->oci-container-configuration) + (service-extension account-service-type + (const %grafana-accounts)) + (service-extension activation-service-type + %grafana-activation))) + (default-value (oci-grafana-configuration)) + (description + "This service install a OCI backed Grafana Shepherd Service."))) diff --git a/packages/zzkt/services/prometheus.scm b/packages/zzkt/services/prometheus.scm new file mode 100644 index 0000000..8b3fe7e --- /dev/null +++ b/packages/zzkt/services/prometheus.scm @@ -0,0 +1,143 @@ +;;; SPDX-License-Identifier: GPL-3.0-or-later +;;; Copyright © 2023 Giacomo Leidi + +;; via https://git.sr.ht/~fishinthecalculator/gocix/tree/main/item/modules/oci/services/prometheus.scm + +(define-module (zzkt services prometheus) + #:use-module (gnu packages admin) + #:use-module (gnu services) + #:use-module (gnu services configuration) + #:use-module (gnu services docker) + #:use-module (gnu system shadow) + #:use-module (guix gexp) + #:export (oci-prometheus-service-type + oci-prometheus-configuration + oci-prometheus-configuration? + oci-prometheus-configuration-fields + oci-prometheus-configuration-datadir + oci-prometheus-configuration-network + oci-prometheus-configuration-file + oci-prometheus-configuration-image + oci-prometheus-configuration-port + oci-prometheus-configuration->oci-container-configuration + %prometheus-accounts + %prometheus-activation)) + +(define prometheus-tag + "v2.45.0") + +(define prometheus-image + (string-append "prom/prometheus:" prometheus-tag)) + +(define prometheus-file + (plain-file "prometheus.yml" + "global: + scrape_interval: 30s + scrape_timeout: 12s + +scrape_configs: + - job_name: prometheus + metrics_path: /metrics + static_configs: + - targets: ['localhost:9090','localhost:9100']\n")) + +(define-maybe string) + +(define-configuration oci-prometheus-configuration + (datadir + (string "/var/lib/prometheus") + "The directory where prometheus writes state.") + (file + (file-like prometheus-file) + "The configuration file to use for the OCI backed Shepherd service.") + (image + (string prometheus-image) + "The image to use for the OCI backed Shepherd service.") + (network + (maybe-string) + "The docker network where the grafana container will be attached. When equal +to \"host\" the @code{port} field will be ignored.") + (port + (string "9000") + "This host port will be mapped onto the Prometheus dashboard configured port +inside the container.") + (metrics-port + (string "9090") + "This host port will be mapped onto the Prometheus health endpoint configured +port inside the container.") + (no-serialization)) + +(define %prometheus-accounts + (list (user-group + (name "prometheus") + (id 65534) + (system? #t)) + (user-account + (name "prometheus") + (comment "Prometheus's Service Account") + (uid 65534) + (group "prometheus") + (supplementary-groups '("tty")) + (system? #t) + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin"))))) + +(define (%prometheus-activation config) + "Return an activation gexp for Prometheus." + (let ((datadir (oci-prometheus-configuration-datadir config))) + #~(begin + (use-modules (guix build utils)) + (let* ((user (getpwnam "prometheus")) + (uid (passwd:uid user)) + (gid (passwd:gid user)) + (datadir #$datadir)) + (mkdir-p datadir) + (chown datadir uid gid))))) + +(define oci-prometheus-configuration->oci-container-configuration + (lambda (config) + (let* ((datadir + (oci-prometheus-configuration-datadir config)) + (network + (oci-prometheus-configuration-network config)) + (image + (oci-prometheus-configuration-image config)) + (port + (oci-prometheus-configuration-port config)) + (metrics-port + (oci-prometheus-configuration-metrics-port config)) + (prometheus.yml + (oci-prometheus-configuration-file config)) + (container-config + (oci-container-configuration + (command + '("--web.enable-lifecycle" + "--config.file=/etc/prometheus/prometheus.yml" + "--web.enable-admin-api")) + (image image) + (ports + `((,port . "9000") + (,metrics-port . "9090"))) + (volumes + `((,datadir . "/prometheus") + (,prometheus.yml . "/etc/prometheus/prometheus.yml:ro")))))) + + (list + (if (maybe-value-set? network) + (oci-container-configuration + (inherit container-config) + (network network)) + container-config))))) + + +(define oci-prometheus-service-type + (service-type (name 'prometheus) + (extensions (list (service-extension oci-container-service-type + oci-prometheus-configuration->oci-container-configuration) + (service-extension account-service-type + (const %prometheus-accounts)) + (service-extension activation-service-type + %prometheus-activation))) + (default-value (oci-prometheus-configuration)) + (description + "Prometheus as a Shepherd Service.")))