From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp10.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id GCYKEqBD5mO61wAAbAwnHQ (envelope-from ) for ; Fri, 10 Feb 2023 14:16:16 +0100 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp10.migadu.com with LMTPS id YGAuEaBD5mNj1QAAG6o9tA (envelope-from ) for ; Fri, 10 Feb 2023 14:16:16 +0100 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id A3D83E56C for ; Fri, 10 Feb 2023 14:16:15 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pQTG2-000384-6A; Fri, 10 Feb 2023 08:16:06 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pQTFz-00037W-To for guix-patches@gnu.org; Fri, 10 Feb 2023 08:16:03 -0500 Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pQTFy-0003aH-9l for guix-patches@gnu.org; Fri, 10 Feb 2023 08:16:02 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1pQTFx-0003Rn-Un for guix-patches@gnu.org; Fri, 10 Feb 2023 08:16:01 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#60788] [PATCH v5] services: Add vnstat-service-type. References: <95b646eb6b23dec213cba43b6e4e7ddc4a601d0f.1673640404.git.mirai@makinata.eu> In-Reply-To: <95b646eb6b23dec213cba43b6e4e7ddc4a601d0f.1673640404.git.mirai@makinata.eu> Resent-From: Bruno Victal Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Fri, 10 Feb 2023 13:16:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 60788 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 60788@debbugs.gnu.org Cc: Bruno Victal , maxim.cournoyer@gmail.com Received: via spool by 60788-submit@debbugs.gnu.org id=B60788.167603493613214 (code B ref 60788); Fri, 10 Feb 2023 13:16:01 +0000 Received: (at 60788) by debbugs.gnu.org; 10 Feb 2023 13:15:36 +0000 Received: from localhost ([127.0.0.1]:34474 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pQTFW-0003R2-Cl for submit@debbugs.gnu.org; Fri, 10 Feb 2023 08:15:36 -0500 Received: from smtpmciv7.myservices.hosting ([185.26.106.202]:49488) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pQTFR-0003Qr-EL for 60788@debbugs.gnu.org; Fri, 10 Feb 2023 08:15:32 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpmciv7.myservices.hosting (Postfix) with ESMTP id BCAED20D57; Fri, 10 Feb 2023 14:15:27 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 6FB7380097; Fri, 10 Feb 2023 14:15:27 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id 5MBHPy63nGY5; Fri, 10 Feb 2023 14:15:23 +0100 (CET) Received: from guix-nuc.home.arpa (bl9-118-236.dsl.telepac.pt [85.242.118.236]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id 6863680093; Fri, 10 Feb 2023 14:15:23 +0100 (CET) From: Bruno Victal Date: Fri, 10 Feb 2023 13:15:13 +0000 Message-Id: <965e112603934b79ec784738a3ad075bfdb0dd51.1676034889.git.mirai@makinata.eu> X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: guix-patches-bounces+larch=yhetil.org@gnu.org X-Migadu-Country: US X-Migadu-Flow: FLOW_IN ARC-Seal: i=1; s=key1; d=yhetil.org; t=1676034976; a=rsa-sha256; cv=none; b=R4pOWkcta9RqvYNkaiWMpJQKhj07dJIeLbp7StavQLwpzup+vlE9j1zA3noz/ioFGphsRy LGSu1lFUlMA5VX7dvniRJ2NuSLvhSVOgUGRhM6mYwD9yDV0WrKWR/RfX0wR0tKhmOnKSKU N9TvLAhUFoWSCx2dGBIDfd5NNZ9mFbYALCxw0PhbUA3WODtbUb/0+w1G4zfyvlZzMrur0p r2m1232z9QOwuJOhbYeeTzj8DJIqMBpSn64P5Aqwq0A3aCpJpE5EgYGL2cIi7VsCFWEDke kqZ+KDpyCv0dyeil300cuIXb5lrOL6kcdBHK77qPC/oyY6DSDK3iUIDo624P2Q== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=none; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1676034976; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:resent-cc: resent-from:resent-sender:resent-message-id:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post; bh=yO9J4WqmTa2fU6hb3wTH9Pk1FwXGe5VMH/wzmYnONQo=; b=NxUWdVjd/iPuE4/vCUtW3oiG1HNnmSbgEVaw5RWYs3yM+/3O7VtbKCxdZOrhNLhOmxBLIP GSQQoDsz2NgNr4mhiU9WB4P6hktnwiHHDa6au9jSjcQK0HU9YGanHyImc0ajv0inMfhqBL hT+tON1YhUbqBTsxeMIUEfOlkQ5EOvdHzj4NTqR+Xh+o2xDhWr3dy7xo0BXuTyTMYlJUQ9 ABZR6egs147KrzTIR49zPh3Kkbkzh8krbNpQz57RaDC8gkUooGPPME3PoyliF8WkBChreN yQp9VZgyG4sn2H+O0c468Wa54LFJxInkBePzPH0E1jp4nf+kPUu73uC6ln6erw== X-Migadu-Scanner: scn0.migadu.com X-Spam-Score: -4.66 X-Migadu-Queue-Id: A3D83E56C X-Migadu-Spam-Score: -4.66 Authentication-Results: aspmx1.migadu.com; dkim=none; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=none X-TUID: gCIz/EuRm0aQ * gnu/services/monitoring.scm (vnstat-service-type): New variable. * doc/guix.texi (Monitoring Services): Document it. --- doc/guix.texi | 246 ++++++++++++++++++- gnu/services/monitoring.scm | 457 ++++++++++++++++++++++++++++++++++++ 2 files changed, 701 insertions(+), 2 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 5fb5850a6c..c54e9e5beb 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -109,11 +109,10 @@ Copyright @copyright{} 2022 Simon Streit@* Copyright @copyright{} 2022 (@* Copyright @copyright{} 2022 John Kehayias@* -Copyright @copyright{} 2022 Bruno Victal@* +Copyright @copyright{} 2022⁠–⁠2023 Bruno Victal@* Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@* Copyright @copyright{} 2023 Giacomo Leidi@* Copyright @copyright{} 2022 Antero Mejr@* -Copyright @copyright{} 2023 Bruno Victal@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -28241,6 +28240,249 @@ Monitoring Services @end table @end deftp +@anchor{vnstat} +@subsubheading vnStat Network Traffic Monitor +@cindex vnstat + +vnStat is a network traffic monitor that uses interface statistics provided +by the kernel rather than traffic sniffing. This makes it a light resource +monitor, regardless of network traffic rate. + +@defvar vnstat-service-type +This is the service type for the @uref{https://humdi.net/vnstat/,vnStat} daemon +and accepts a @code{vnstat-configuration} value. + +The following example will configure the service with default values: + +@lisp +(service vnstat-service-type) +@end lisp +@end defvar + +@c %start of fragment +@deftp {Data Type} vnstat-configuration +Available @code{vnstat-configuration} fields are: + +@table @asis +@item @code{package} (default: @code{vnstat}) (type: file-like) +The vnstat package. + +@item @code{database-dir} (default: @code{"/var/lib/vnstat"}) (type: string) +Specifies the directory where the database is to be stored. A full path +must be given and a leading '/' isn't required. + +@item @code{5-minute-hours} (default: @code{48}) (type: maybe-integer) +Data retention duration for the 5 minute resolution entries. The +configuration defines for how many past hours entries will be stored. +Set to @code{-1} for unlimited entries or to @code{0} to disable the +data collection of this resolution. + +@item @code{64bit-interface-counters} (default: @code{-2}) (type: maybe-integer) +Select interface counter handling. Set to @code{1} for defining that +all interfaces use 64-bit counters on the kernel side and @code{0} for +defining 32-bit counter. Set to @code{-1} for using the old style logic +used in earlier versions where counter values within 32-bits are assumed +to be 32-bit and anything larger is assumed to be a 64-bit counter. This +may produce false results if a 64-bit counter is reset within the +32-bits. Set to @code{-2} for using automatic detection based on +available kernel datastructures. + +@item @code{always-add-new-interfaces?} (default: @code{#t}) (type: maybe-boolean) +Enable or disable automatic creation of new database entries for +interfaces not currently in the database even if the database file +already exists when the daemon is started. New database entries will +also get created for new interfaces seen while the daemon is running. +Pseudo interfaces @samp{lo}, @samp{lo0} and @samp{sit0} are always excluded from getting +added. + +@item @code{bandwidth-detection?} (default: @code{#t}) (type: maybe-boolean) +Try to automatically detect @var{max-bandwidth} value for each monitored +interface. Mostly only ethernet interfaces support this feature. +@var{max-bandwidth} will be used as fallback value if detection fails. +Any interface specific @var{max-BW} configuration will disable the +detection for the specified interface. In Linux, the detection is +disabled for tun interfaces due to the Linux kernel always reporting 10 +Mbit regardless of the used real interface. + +@item @code{bandwidth-detection-interval} (default: @code{5}) (type: maybe-integer) +How often in minutes interface specific detection of @var{max-bandwidth} +is done for detecting possible changes when @var{bandwidth-detection} is +enabled. Can be disabled by setting to @code{0}. Value range: +@samp{0}..@samp{30} + +@item @code{boot-variation} (default: @code{15}) (type: maybe-integer) +Time in seconds how much the boot time reported by system kernel can +variate between updates. Value range: @samp{0}..@samp{300} + +@item @code{check-disk-space?} (default: @code{#t}) (type: maybe-boolean) +Enable or disable the availability check of at least some free disk +space before a database write. + +@item @code{create-dirs?} (default: @code{#t}) (type: maybe-boolean) +Enable or disable the creation of directories when a configured path +doesn't exist. This includes @var{database-dir}. + +@item @code{daemon-group} (type: maybe-string) +Specify the group to which the daemon process should switch during +startup. The group can either be the name of the group or a numerical +group id. Leave empty to disable group switching. This option can only +be used when the process is started as root. + +@item @code{daemon-user} (type: maybe-string) +Specify the user to which the daemon process should switch during +startup. The user can either be the login of the user or a numerical +user id. Leave empty to disable user switching. This option can only +be used when the process is started as root. + +@item @code{daily-days} (default: @code{62}) (type: maybe-integer) +Data retention duration for the one day resolution entries. The +configuration defines for how many past days entries will be stored. Set +to @code{-1} for unlimited entries or to @code{0} to disable the data +collection of this resolution. + +@item @code{database-synchronous} (default: @code{-1}) (type: maybe-integer) +Change the setting of the SQLite "synchronous" flag which controls how +much care is taken to ensure disk writes have fully completed when +writing data to the database before continuing other actions. Higher +values take extra steps to ensure data safety at the cost of slower +performance. A value of @code{0} will result in all handling being left +to the filesystem itself. Set to @code{-1} to select the default value +according to database mode controlled by +@var{database-write-ahead-logging} setting. See SQLite documentation +for more details regarding values from @code{1} to @code{3}. Value +range: @samp{-1}..@samp{3} + +@item @code{database-write-ahead-logging?} (default: @code{#f}) (type: maybe-boolean) +Enable or disable SQLite Write-Ahead Logging mode for the database. See +SQLite documentation for more details and note that support for +read-only operations isn't available in older SQLite versions. + +@item @code{hourly-days} (default: @code{4}) (type: maybe-integer) +Data retention duration for the one hour resolution entries. The +configuration defines for how many past days entries will be stored. Set +to @code{-1} for unlimited entries or to @code{0} to disable the data +collection of this resolution. + +@item @code{log-file} (type: maybe-string) +Specify log file path and name to be used if @var{use-logging} is set to +@code{1}. + +@item @code{max-bandwidth} (type: maybe-integer) +Maximum bandwidth for all interfaces. If the interface specific traffic +exceeds the given value then the data is assumed to be invalid and +rejected. Set to 0 in order to disable the feature. Value range: +@samp{0}..@samp{50000} + +@item @code{max-bw} (type: maybe-alist) +Same as @var{max-bandwidth} but can be used for setting individual +limits for selected interfaces. This is an association list of +interfaces as symbols/strings to integer values. For example, +@lisp +(max-bw `((eth0 . 15000) + (ppp0 . 10000))) +@end lisp +@var{bandwidth-detection} is disabled on an interface specific level for +each @var{max-bw} configuration. Value range: @samp{0}..@samp{50000} + +@item @code{monthly-months} (default: @code{25}) (type: maybe-integer) +Data retention duration for the one month resolution entries. The +configuration defines for how many past months entries will be stored. +Set to @code{-1} for unlimited entries or to @code{0} to disable the +data collection of this resolution. + +@item @code{month-rotate} (default: @code{1}) (type: maybe-integer) +Day of month that months are expected to change. Usually set to 1 but +can be set to alternative values for example for tracking monthly billed +traffic where the billing period doesn't start on the first day. For +example, if set to 7, days of February up to and including the 6th will +count for January. Changing this option will not cause existing data to +be recalculated. Value range: @samp{1}..@samp{28} + +@item @code{month-rotate-affects-years?} (default: @code{#f}) (type: maybe-boolean) +Enable or disable @var{month-rotate} also affecting yearly data. +Applicable only when @var{month-rotate} has a value greater than one. + +@item @code{offline-save-interval} (default: @code{30}) (type: maybe-integer) +How often in minutes cached interface data is saved to file when all +monitored interfaces are offline. Value range: +@var{save-interval}..@samp{60} + +@item @code{pid-file} (default: @code{"/var/run/vnstatd.pid"}) (type: maybe-string) +Specify pid file path and name to be used. + +@item @code{poll-interval} (default: @code{5}) (type: maybe-integer) +How often in seconds interfaces are checked for status changes. Value +range: @samp{2}..@samp{60} + +@item @code{rescan-database-on-save?} (type: maybe-boolean) +Automatically discover added interfaces from the database and start +monitoring. The rescan is done every @var{save-interval} or +@var{offline-save-interval} minutes depending on the current activity +state. + +@item @code{save-interval} (default: @code{5}) (type: maybe-integer) +How often in minutes cached interface data is saved to file. Value +range: ( @var{update-interval} / 60 )..@samp{60} + +@item @code{save-on-status-change?} (default: @code{#t}) (type: maybe-boolean) +Enable or disable the additional saving to file of cached interface data +when the availability of an interface changes, i.e., when an interface +goes offline or comes online. + +@item @code{time-sync-wait} (default: @code{5}) (type: maybe-integer) +How many minutes to wait during daemon startup for system clock to sync +if most recent database update appears to be in the future. This may be +needed in systems without a real-time clock (RTC) which require some +time after boot to query and set the correct time. @code{0} = wait +disabled. Value range: @samp{0}..@samp{60} + +@item @code{top-day-entries} (default: @code{20}) (type: maybe-integer) +Data retention duration for the top day entries. The configuration +defines how many of the past top day entries will be stored. Set to +@code{-1} for unlimited entries or to @code{0} to disable the data +collection of this resolution. + +@item @code{trafficless-entries?} (default: @code{#t}) (type: maybe-boolean) +Create database entries even when there is no traffic during the entry's +time period. + +@item @code{update-file-owner?} (default: @code{#t}) (type: maybe-boolean) +Enable or disable the update of file ownership during daemon process +startup. During daemon startup, only database, log and pid files will +be modified if the user or group change feature ( @var{daemon-user} or +@var{daemon-group} ) is enabled and the files don't match the requested +user or group. During manual database creation, this option will cause +file ownership to be inherited from the database directory if the +directory already exists. This option only has effect when the process +is started as root or via sudo. + +@item @code{update-interval} (default: @code{20}) (type: maybe-integer) +How often in seconds the interface data is updated. Value range: +@var{poll-interval}..@samp{300} + +@item @code{use-logging} (default: @code{2}) (type: maybe-integer) +Enable or disable logging. This option is ignored when the daemon is +started with .B "-n, --nodaemon" which results in all log output being +shown in terminal the daemon process is using. @code{0} = disabled, +@code{1} = logfile and @code{2} = syslog. + +@item @code{use-utc?} (type: maybe-boolean) +Enable or disable using UTC as timezone in the database for all entries. +When enabled, all entries added to the database will use UTC regardless +of the configured system timezone. When disabled, the configured system +timezone will be used. Changing this setting will not result in already +existing data to be modified. + +@item @code{yearly-years} (default: @code{-1}) (type: maybe-integer) +Data retention duration for the one year resolution entries. The +configuration defines for how many past years entries will be stored. +Set to @code{-1} for unlimited entries or to @code{0} to disable the +data collection of this resolution. + +@end table +@end deftp +@c %end of fragment + @subsubheading Zabbix server @cindex zabbix zabbix-server Zabbix is a high performance monitoring system that can collect data from a diff --git a/gnu/services/monitoring.scm b/gnu/services/monitoring.scm index 44e2e8886c..e7b515d6b0 100644 --- a/gnu/services/monitoring.scm +++ b/gnu/services/monitoring.scm @@ -3,6 +3,7 @@ ;;; Copyright © 2018, 2019 Gábor Boskovits ;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov ;;; Copyright © 2022 Marius Bakke +;;; Copyright © 2023 Bruno Victal ;;; ;;; This file is part of GNU Guix. ;;; @@ -26,6 +27,7 @@ (define-module (gnu services monitoring) #:use-module (gnu services web) #:use-module (gnu packages admin) #:use-module (gnu packages monitoring) + #:use-module (gnu packages networking) #:use-module (gnu system shadow) #:use-module (guix gexp) #:use-module (guix packages) @@ -34,6 +36,7 @@ (define-module (gnu services monitoring) #:use-module ((guix ui) #:select (display-hint G_)) #:use-module (ice-9 match) #:use-module (ice-9 rdelim) + #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) #:use-module (srfi srfi-35) #:export (darkstat-configuration @@ -45,6 +48,46 @@ (define-module (gnu services monitoring) prometheus-node-exporter-web-listen-address prometheus-node-exporter-service-type + vnstat-configuration + vnstat-configuration? + vnstat-service-type + vnstat-configuration-package + vnstat-configuration-database-dir + vnstat-configuration-5-minute-hours + vnstat-configuration-64bit-interface-counters + vnstat-configuration-always-add-new-interfaces? + vnstat-configuration-bandwidth-detection? + vnstat-configuration-bandwidth-detection-interval + vnstat-configuration-boot-variation + vnstat-configuration-check-disk-space? + vnstat-configuration-create-dirs? + vnstat-configuration-daemon-group + vnstat-configuration-daemon-user + vnstat-configuration-daily-days + vnstat-configuration-database-synchronous + vnstat-configuration-database-write-ahead-logging? + vnstat-configuration-hourly-days + vnstat-configuration-log-file + vnstat-configuration-max-bandwidth + vnstat-configuration-max-BW + vnstat-configuration-monthly-months + vnstat-configuration-month-rotate + vnstat-configuration-month-rotate-affects-years? + vnstat-configuration-offline-save-interval + vnstat-configuration-pid-file + vnstat-configuration-poll-interval + vnstat-configuration-rescan-database-on-save? + vnstat-configuration-save-interval + vnstat-configuration-save-on-status-change? + vnstat-configuration-time-sync-wait + vnstat-configuration-top-day-entries + vnstat-configuration-trafficless-entries? + vnstat-configuration-update-file-owner? + vnstat-configuration-update-interval + vnstat-configuration-use-logging + vnstat-configuration-use-UTC? + vnstat-configuration-yearly-years + zabbix-server-configuration zabbix-server-service-type zabbix-agent-configuration @@ -196,6 +239,420 @@ (define prometheus-node-exporter-service-type prometheus-node-exporter-shepherd-service))) (default-value (prometheus-node-exporter-configuration)))) + +;;; +;;; vnstat daemon +;;; + +(define* (camelfy-field-name field-name #:key (dromedary? #f)) + (match (string-split (symbol->string field-name) #\-) + ((head tail ...) + (string-join (cons (if dromedary? head (string-upcase head 0 1)) + (map (cut string-upcase <> 0 1) tail)) "")))) + +(define (strip-trailing-?-character field-name) + "Drop rightmost '?' character" + (let ((str (symbol->string field-name))) + (if (string-suffix? "?" str) + (string->symbol (string-drop-right str 1)) + field-name))) + +(define (vnstat-serialize-string field-name value) + #~(format #f "~a ~s~%" + #$(camelfy-field-name field-name) + #$value)) + +(define vnstat-serialize-integer vnstat-serialize-string) + +(define (vnstat-serialize-boolean field-name value) + #~(format #f "~a ~a~%" + #$(camelfy-field-name (strip-trailing-?-character field-name)) + #$(if value 1 0))) + +(define (vnstat-serialize-alist field-name value) + (generic-serialize-alist string-append + (lambda (iface val) + (vnstat-serialize-integer + (format #f "MaxBW~a" iface) val)) + value)) + +(define-maybe string (prefix vnstat-)) +(define-maybe integer (prefix vnstat-)) +(define-maybe boolean (prefix vnstat-)) +(define-maybe alist (prefix vnstat-)) + +;; Documentation strings from vnstat.conf manpage adapted to texinfo. +;; vnstat checkout: v2.10, commit b3408af1c609aa6265d296cab7bfe59a61d7cf70 +;; Do not reflow these strings or drop the initial \ escape as it makes it +;; harder to diff against the manpage. +(define-configuration vnstat-configuration + (package + (file-like vnstat) + "The vnstat package." + empty-serializer) + + (database-dir + (string "/var/lib/vnstat") + "\ +Specifies the directory where the database is to be stored. +A full path must be given and a leading '/' isn't required.") + + (5-minute-hours + (maybe-integer 48) + "\ +Data retention duration for the 5 minute resolution entries. The configuration +defines for how many past hours entries will be stored. Set to @code{-1} for +unlimited entries or to @code{0} to disable the data collection of this +resolution.") + + (64bit-interface-counters + (maybe-integer -2) + "\ +Select interface counter handling. Set to @code{1} for defining that all interfaces +use 64-bit counters on the kernel side and @code{0} for defining 32-bit counter. Set +to @code{-1} for using the old style logic used in earlier versions where counter +values within 32-bits are assumed to be 32-bit and anything larger is assumed to +be a 64-bit counter. This may produce false results if a 64-bit counter is +reset within the 32-bits. Set to @code{-2} for using automatic detection based on +available kernel datastructures.") + + (always-add-new-interfaces? + (maybe-boolean #t) + "\ +Enable or disable automatic creation of new database entries for interfaces not +currently in the database even if the database file already exists when the +daemon is started. New database entries will also get created for new interfaces +seen while the daemon is running. Pseudo interfaces @samp{lo}, @samp{lo0} and @samp{sit0} are always +excluded from getting added.") + + (bandwidth-detection? + (maybe-boolean #t) + "\ +Try to automatically detect +@var{max-bandwidth} +value for each monitored interface. Mostly only ethernet interfaces support +this feature. +@var{max-bandwidth} +will be used as fallback value if detection fails. Any interface specific +@var{max-BW} +configuration will disable the detection for the specified interface. +In Linux, the detection is disabled for tun interfaces due to the +Linux kernel always reporting 10 Mbit regardless of the used real interface.") + + (bandwidth-detection-interval + (maybe-integer 5) + "\ +How often in minutes interface specific detection of +@var{max-bandwidth} +is done for detecting possible changes when +@var{bandwidth-detection} +is enabled. Can be disabled by setting to @code{0}. Value range: @samp{0}..@samp{30}") + + (boot-variation + (maybe-integer 15) + "\ +Time in seconds how much the boot time reported by system kernel can variate +between updates. Value range: @samp{0}..@samp{300}") + + (check-disk-space? + (maybe-boolean #t) + "\ +Enable or disable the availability check of at least some free disk space before +a database write.") + + (create-dirs? + (maybe-boolean #t) + "\ +Enable or disable the creation of directories when a configured path doesn't +exist. This includes @var{database-dir}.") + + (daemon-group + maybe-string + "\ +Specify the group to which the daemon process should switch during startup. +The group can either be the name of the group or a numerical group id. +Leave empty to disable group switching. This option can only be used when +the process is started as root.") + + (daemon-user + maybe-string + "\ +Specify the user to which the daemon process should switch during startup. +The user can either be the login of the user or a numerical user id. +Leave empty to disable user switching. This option can only be used when +the process is started as root.") + + (daily-days + (maybe-integer 62) + "\ +Data retention duration for the one day resolution entries. The configuration +defines for how many past days entries will be stored. Set to @code{-1} for +unlimited entries or to @code{0} to disable the data collection of this +resolution.") + + (database-synchronous + (maybe-integer -1) + "\ +Change the setting of the SQLite \"synchronous\" flag which controls how much +care is taken to ensure disk writes have fully completed when writing data to +the database before continuing other actions. Higher values take extra steps +to ensure data safety at the cost of slower performance. A value of @code{0} will +result in all handling being left to the filesystem itself. Set to @code{-1} to +select the default value according to database mode controlled by +@var{database-write-ahead-logging} +setting. See SQLite documentation for more details regarding values from @code{1} +to @code{3}. Value range: @samp{-1}..@samp{3}") + + (database-write-ahead-logging? + (maybe-boolean #f) + "\ +Enable or disable SQLite Write-Ahead Logging mode for the database. See SQLite +documentation for more details and note that support for read-only operations +isn't available in older SQLite versions.") + + (hourly-days + (maybe-integer 4) + "\ +Data retention duration for the one hour resolution entries. The configuration +defines for how many past days entries will be stored. Set to @code{-1} for +unlimited entries or to @code{0} to disable the data collection of this +resolution.") + + (log-file + maybe-string + "\ +Specify log file path and name to be used if @var{use-logging} is set to @code{1}.") + + (max-bandwidth + maybe-integer + "\ +Maximum bandwidth for all interfaces. If the interface specific traffic +exceeds the given value then the data is assumed to be invalid and rejected. +Set to 0 in order to disable the feature. Value range: @samp{0}..@samp{50000}") + + ;; documentation adapted for alist type + (max-bw + maybe-alist + "\ +Same as +@var{max-bandwidth} +but can be used for setting individual limits +for selected interfaces. This is an association list of interfaces +as symbols/strings to integer values. For example, +@lisp +(max-bw + `((eth0 . 15000) + (ppp0 . 10000))) +@end lisp +@var{bandwidth-detection} +is disabled on an interface specific level for each +@var{max-bw} +configuration. Value range: @samp{0}..@samp{50000}" + (lambda (field-name value) + (if (maybe-value-set? value) + (vnstat-serialize-alist field-name value) ""))) + + (monthly-months + (maybe-integer 25) + "\ +Data retention duration for the one month resolution entries. The configuration +defines for how many past months entries will be stored. Set to @code{-1} for +unlimited entries or to @code{0} to disable the data collection of this +resolution.") + + (month-rotate + (maybe-integer 1) + "\ +Day of month that months are expected to change. Usually set to +1 but can be set to alternative values for example for tracking +monthly billed traffic where the billing period doesn't start on +the first day. For example, if set to 7, days of February up to and +including the 6th will count for January. Changing this option will +not cause existing data to be recalculated. Value range: @samp{1}..@samp{28}") + + (month-rotate-affects-years? + (maybe-boolean #f) + "\ +Enable or disable +@var{month-rotate} +also affecting yearly data. Applicable only when +@var{month-rotate} +has a value greater than one.") + + (offline-save-interval + (maybe-integer 30) + "\ +How often in minutes cached interface data is saved to file when all monitored +interfaces are offline. Value range: +@var{save-interval}..@samp{60}") + + (pid-file + (maybe-string "/var/run/vnstatd.pid") + "\ +Specify pid file path and name to be used.") + + (poll-interval + (maybe-integer 5) + "\ +How often in seconds interfaces are checked for status changes. +Value range: @samp{2}..@samp{60}") + + (rescan-database-on-save? + maybe-boolean + "\ +Automatically discover added interfaces from the database and start monitoring. +The rescan is done every +@var{save-interval} +or +@var{offline-save-interval} +minutes depending on the current activity state.") + + (save-interval + (maybe-integer 5) + "\ +How often in minutes cached interface data is saved to file. +Value range: ( +@var{update-interval} / 60 )..@samp{60}") + + (save-on-status-change? + (maybe-boolean #t) + "\ +Enable or disable the additional saving to file of cached interface data +when the availability of an interface changes, i.e., when an interface goes +offline or comes online.") + + (time-sync-wait + (maybe-integer 5) + "\ +How many minutes to wait during daemon startup for system clock to sync if +most recent database update appears to be in the future. This may be needed +in systems without a real-time clock (RTC) which require some time after boot +to query and set the correct time. @code{0} = wait disabled. +Value range: @samp{0}..@samp{60}") + + (top-day-entries + (maybe-integer 20) + "\ +Data retention duration for the top day entries. The configuration +defines how many of the past top day entries will be stored. Set to @code{-1} for +unlimited entries or to @code{0} to disable the data collection of this +resolution.") + + (trafficless-entries? + (maybe-boolean #t) + "\ +Create database entries even when there is no traffic during the entry's time +period.") + + (update-file-owner? + (maybe-boolean #t) + "\ +Enable or disable the update of file ownership during daemon process startup. +During daemon startup, only database, log and pid files will be modified if the +user or group change feature ( +@var{daemon-user} +or +@var{daemon-group} +) is enabled and the files don't match the requested user or group. During manual +database creation, this option will cause file ownership to be inherited from the +database directory if the directory already exists. This option only has effect +when the process is started as root or via sudo.") + + (update-interval + (maybe-integer 20) + "\ +How often in seconds the interface data is updated. Value range: +@var{poll-interval}..@samp{300}") + + (use-logging + (maybe-integer 2) + "\ +Enable or disable logging. This option is ignored when the daemon is started with +.B \"-n, --nodaemon\" +which results in all log output being shown in terminal the daemon process is using. +@code{0} = disabled, @code{1} = logfile and @code{2} = syslog.") + + (use-utc? + maybe-boolean + "\ +Enable or disable using UTC as timezone in the database for all entries. When +enabled, all entries added to the database will use UTC regardless of the +configured system timezone. When disabled, the configured system timezone +will be used. Changing this setting will not result in already existing +data to be modified." + (lambda (_ value) + (if (maybe-value-set? value) + (vnstat-serialize-boolean 'use-UTC value) ""))) + + (yearly-years + (maybe-integer -1) + "\ +Data retention duration for the one year resolution entries. The configuration +defines for how many past years entries will be stored. Set to @code{-1} for +unlimited entries or to @code{0} to disable the data collection of this +resolution.") + + (prefix vnstat-)) + +(define (vnstat-serialize-configuration config) + (mixed-text-file + "vnstat.conf" + (serialize-configuration config vnstat-configuration-fields))) + +(define (vnstat-shepherd-service config) + (let ((config-file (vnstat-serialize-configuration config))) + (match-record config (package pid-file) + (shepherd-service + (documentation "Run vnstatd.") + (requirement `(networking)) + (provision '(vnstatd)) + (start #~(make-forkexec-constructor + (list #$(file-append package "/sbin/vnstatd") + "--daemon" + "--config" #$config-file) + #:pid-file #$pid-file)) + (stop #~(make-kill-destructor)) + (actions + (list (shepherd-configuration-action config-file) + (shepherd-action + (name 'reload) + (documentation "Reload vnstatd.") + (procedure + #~(lambda (pid) + (if pid + (begin + (kill pid SIGHUP) + (format #t + "Issued SIGHUP to vnstatd (PID ~a)." + pid)) + (format #t "vnstatd is not running."))))))))))) + +(define (vnstat-account-service config) + (match-record config (daemon-group daemon-user) + (if (every maybe-value-set? (list daemon-group daemon-user)) + (list + (user-group + (name daemon-group) + (system? #t)) + (user-account + (name daemon-user) + (group daemon-group) + (system? #t) + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin")))) + '()))) + +(define vnstat-service-type + (service-type + (name 'vnstat) + (description "vnStat network-traffic monitor service.") + (extensions + (list (service-extension shepherd-root-service-type + (compose list vnstat-shepherd-service)) + (service-extension account-service-type + vnstat-account-service))) + (default-value (vnstat-configuration)))) + ;;; ;;; Zabbix server -- 2.38.1