[PATCH] services: Add vnstat-service-type.

  • Done
  • quality assurance status badge
Details
3 participants
  • Ludovic Courtès
  • Maxim Cournoyer
  • Bruno Victal
Owner
unassigned
Submitted by
Bruno Victal
Severity
normal
B
B
Bruno Victal wrote on 13 Jan 2023 21:07
(address . guix-patches@gnu.org)(name . Bruno Victal)(address . mirai@makinata.eu)
95b646eb6b23dec213cba43b6e4e7ddc4a601d0f.1673640404.git.mirai@makinata.eu
* gnu/services/monitoring.scm (vnstat-service-type): New variable.
* doc/guix.texi (Monitoring Services): Document it.
---
doc/guix.texi | 238 +++++++++++++++++++++
gnu/services/monitoring.scm | 413 ++++++++++++++++++++++++++++++++++++
2 files changed, 651 insertions(+)

Toggle diff (452 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 751d0957d8..b51a488a85 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -111,6 +111,7 @@
Copyright @copyright{} 2022 John Kehayias@*
Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@*
Copyright @copyright{} 2023 Giacomo Leidi@*
+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
@@ -28219,6 +28220,243 @@ 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.
+@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 lo, lo0 and 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..a83dcf315b 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018, 2019 Gábor Boskovits <boskovits@gmail.com>
;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2022 Marius Bakke <marius@gnu.org>
+;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;;
;;; 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,10 @@ (define-module (gnu services monitoring)
prometheus-node-exporter-web-listen-address
prometheus-node-exporter-service-type
+ vnstat-configuration
+ vnstat-configuration?
+ vnstat-service-type
+
zabbix-server-configuration
zabbix-server-service-type
zabbix-agent-configuration
@@ -196,6 +203,412 @@ (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 string-capitalize tail)) ""))))
+
+(define (dock-field-name 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 (dock-field-name 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
+(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 lo, lo0 and 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 SQ
This message was truncated. Download the full message here.
B
B
Bruno Victal wrote on 14 Jan 2023 22:06
[PATCH v2] services: Add vnstat-service-type.
(address . 60788@debbugs.gnu.org)(name . Bruno Victal)(address . mirai@makinata.eu)
f3b90db7de20b4deab630a53c5c970fa776b0e7a.1673730322.git.mirai@makinata.eu
* gnu/services/monitoring.scm (vnstat-service-type): New variable.
* doc/guix.texi (Monitoring Services): Document it.
---

Fix for camelfy-field-name.

doc/guix.texi | 238 +++++++++++++++++++++
gnu/services/monitoring.scm | 413 ++++++++++++++++++++++++++++++++++++
2 files changed, 651 insertions(+)

Toggle diff (450 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index c07ec89b2f..1f6e5d9ed6 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -111,6 +111,7 @@
Copyright @copyright{} 2022 John Kehayias@*
Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@*
Copyright @copyright{} 2023 Giacomo Leidi@*
+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
@@ -28219,6 +28220,243 @@ 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.
+@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 lo, lo0 and 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..7017c677ea 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018, 2019 Gábor Boskovits <boskovits@gmail.com>
;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2022 Marius Bakke <marius@gnu.org>
+;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;;
;;; 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,10 @@ (define-module (gnu services monitoring)
prometheus-node-exporter-web-listen-address
prometheus-node-exporter-service-type
+ vnstat-configuration
+ vnstat-configuration?
+ vnstat-service-type
+
zabbix-server-configuration
zabbix-server-service-type
zabbix-agent-configuration
@@ -196,6 +203,412 @@ (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 (dock-field-name 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 (dock-field-name 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
+(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 lo, lo0 and 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 -
This message was truncated. Download the full message here.
M
M
Maxim Cournoyer wrote on 16 Jan 2023 19:42
Re: bug#60788: [PATCH] services: Add vnstat-service-type.
(name . Bruno Victal)(address . mirai@makinata.eu)(address . 60788@debbugs.gnu.org)
87o7qy48zm.fsf@gmail.com
Hello!

Bruno Victal <mirai@makinata.eu> writes:

[...]

Toggle quote (3 lines)
> @@ -45,6 +48,10 @@ (define-module (gnu services monitoring)
> prometheus-node-exporter-web-listen-address
> prometheus-node-exporter-service-type
Toggle quote (5 lines)
> + vnstat-configuration
> + vnstat-configuration?
> + vnstat-service-type
> +

Normally, all the accessors are exported, otherwise there's no means to
introspect a vnstat-configuration, which may be useful at the REPL.

[...]

Toggle quote (11 lines)
> +
> +;;;
> +;;; 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 string-capitalize tail)) ""))))

I'd name this pascal-case-field-name, and drop the apparently unused
dromerady? argument (fun, though :-)). If we need it, we could
introduce a 2nd camel-case-field-name.

Toggle quote (7 lines)
> +(define (dock-field-name field-name)
> + "Drop rightmost '?' character"
> + (let ((str (symbol->string field-name)))
> + (if (string-suffix? "?" str)
> + (string->symbol (string-drop-right str 1))
> + field-name)))

I'm not sure about the meaning of 'dock' in this procedure name.
Perhaps 'strip-trailing-?-character' would be better?

Toggle quote (57 lines)
> +(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 (dock-field-name 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
> +(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.")

Please reflow these paragraphs so they fit under the 80 characters width
limit. Perhaps drop the \ escape, as it doesn't provide much and looks
a bit worst, in my opinion. Each sentence should be separated by two
spaces (that's a Texinfo convention). This comment applies to all
similar documentation texts.

Toggle quote (9 lines)
> + (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 lo, lo0 and sit0 are always
> +excluded from getting added.")

The lo, lo0 and sit0 could use a @samp{} or decorator.

[...]

Toggle quote (21 lines)
> +(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 <vnstat-configuration> (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)

I don't understand what (shepherd-configuration-action config-file)
corresponds to?

Toggle quote (39 lines)
> + (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 <vnstat-configuration> (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))))

The rest LGTM (a system test would be nice, but since the Shepherd
service definition is straightforward, it could come later, when the
need arise).

That appears carefully crafted, thank you! Could you send a v2 with my
above comments addressed, keeping me in CC?

--
Thanks,
Maxim
B
B
Bruno Victal wrote on 16 Jan 2023 20:31
(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)
7d22fea8-112d-1c01-6b6a-6cfe4e0fa9e3@makinata.eu
On 2023-01-16 18:42, Maxim Cournoyer wrote:

Toggle quote (15 lines)
>> Bruno Victal <mirai@makinata.eu> writes:
>> +;;;
>> +;;; 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 string-capitalize tail)) ""))))
>
> I'd name this pascal-case-field-name, and drop the apparently unused
> dromerady? argument (fun, though :-)). If we need it, we could
> introduce a 2nd camel-case-field-name.

I was anticipating that this snippet would get reused (i.e. copy-pasted) by
other services so I wanted to generalize it before it starts spawning
its dromedary cousin.

If this isn't preferred, I can drop it and just leave it as
pascal-case-field-name. (maybe these kinds of procedures could go into
a new "configuration utils" module with useful auxiliary functions?)

Toggle quote (11 lines)
>
>> +(define (dock-field-name field-name)
>> + "Drop rightmost '?' character"
>> + (let ((str (symbol->string field-name)))
>> + (if (string-suffix? "?" str)
>> + (string->symbol (string-drop-right str 1))
>> + field-name)))
>
> I'm not sure about the meaning of 'dock' in this procedure name.
> Perhaps 'strip-trailing-?-character' would be better?

I couldn't think of any other word that would essentially describe
whats amounts to "dropping" the tail of a list/string.
(here, 'dock': "the practice of cutting off or trimming the tail of an animal")

Toggle quote (39 lines)
>> +;; Documentation strings from vnstat.conf manpage adapted to texinfo.
>> +;; vnstat checkout: v2.10, commit b3408af1c609aa6265d296cab7bfe59a61d7cf70
>> +(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.")
>
> Please reflow these paragraphs so they fit under the 80 characters width
> limit. Perhaps drop the \ escape, as it doesn't provide much and looks
> a bit worst, in my opinion. Each sentence should be separated by two
> spaces (that's a Texinfo convention). This comment applies to all
> similar documentation texts.

They're formatted this way as I find it easier to compare against upstream troff sources.
If they're reflowed or if the \ escape is dropped then the diffs get larger to compare against
(most of the changes here are easier to compare using word-diffs)

Toggle quote (11 lines)
>> + (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 lo, lo0 and sit0 are always
>> +excluded from getting added.")
>
> The lo, lo0 and sit0 could use a @samp{} or decorator.

Noted.

Toggle quote (27 lines)
>
> [...]
>
>> +(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 <vnstat-configuration> (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)
>
> I don't understand what (shepherd-configuration-action config-file)
> corresponds to?

It shows the path to the config file with `herd configuration vnstatd'.
It was introduced with 'ebc7de6a1efb702fd0364128cbde19697966c4f4'.

Toggle quote (43 lines)
>> + (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 <vnstat-configuration> (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))))
>
> The rest LGTM (a system test would be nice, but since the Shepherd
> service definition is straightforward, it could come later, when the
> need arise).

I've thought a bit about the system test though the way vnstat works is that
it needs to collect some data and it also takes a while for the daemon to flag it
as ready (~5 minutes). This would be a somewhat slow and non-trivial test to write.


WDYT?



Cheers,
Bruno
M
M
Maxim Cournoyer wrote on 16 Jan 2023 20:56
(name . Bruno Victal)(address . mirai@makinata.eu)(address . 60788@debbugs.gnu.org)
87fsca45j1.fsf@gmail.com
Hi Bruno,

Bruno Victal <mirai@makinata.eu> writes:

Toggle quote (40 lines)
> On 2023-01-16 18:42, Maxim Cournoyer wrote:
>
>>> Bruno Victal <mirai@makinata.eu> writes:
>>> +;;;
>>> +;;; 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 string-capitalize tail)) ""))))
>>
>> I'd name this pascal-case-field-name, and drop the apparently unused
>> dromerady? argument (fun, though :-)). If we need it, we could
>> introduce a 2nd camel-case-field-name.
>
> I was anticipating that this snippet would get reused (i.e. copy-pasted) by
> other services so I wanted to generalize it before it starts spawning
> its dromedary cousin.
>
> If this isn't preferred, I can drop it and just leave it as
> pascal-case-field-name. (maybe these kinds of procedures could go into
> a new "configuration utils" module with useful auxiliary functions?)
>
>>
>>> +(define (dock-field-name field-name)
>>> + "Drop rightmost '?' character"
>>> + (let ((str (symbol->string field-name)))
>>> + (if (string-suffix? "?" str)
>>> + (string->symbol (string-drop-right str 1))
>>> + field-name)))
>>
>> I'm not sure about the meaning of 'dock' in this procedure name.
>> Perhaps 'strip-trailing-?-character' would be better?
>
> I couldn't think of any other word that would essentially describe
> whats amounts to "dropping" the tail of a list/string.
> (here, 'dock': "the practice of cutting off or trimming the tail of an animal")

Ouch. I'm even more in favor of an alternative name now that I know the
meaning of 'dock' :-).

Toggle quote (43 lines)
>>> +;; Documentation strings from vnstat.conf manpage adapted to texinfo.
>>> +;; vnstat checkout: v2.10, commit b3408af1c609aa6265d296cab7bfe59a61d7cf70
>>> +(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.")
>>
>> Please reflow these paragraphs so they fit under the 80 characters width
>> limit. Perhaps drop the \ escape, as it doesn't provide much and looks
>> a bit worst, in my opinion. Each sentence should be separated by two
>> spaces (that's a Texinfo convention). This comment applies to all
>> similar documentation texts.
>
> They're formatted this way as I find it easier to compare against upstream troff sources.
> If they're reflowed or if the \ escape is dropped then the diffs get larger to compare against
> (most of the changes here are easier to compare using word-diffs)

I think we should take ownership of that text, and update it when it
makes sense without necessarily having to keep every details the same
with upstream (especially for the double space rule and other
conventions); in this view I'd opt to adjust it so the Guix source reads
beautifully rather than for diffing against the orginal source :-).

If this truly provides value to you (to be able to more easily diff
against the troff source), then perhaps how to do so should be detailed
in a comment for the next person to understand how this works and why it
is this way.

Toggle quote (43 lines)
>>> + (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 lo, lo0 and sit0 are always
>>> +excluded from getting added.")
>>
>> The lo, lo0 and sit0 could use a @samp{} or decorator.
>
> Noted.
>
>>
>> [...]
>>
>>> +(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 <vnstat-configuration> (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)
>>
>> I don't understand what (shepherd-configuration-action config-file)
>> corresponds to?
>
> It shows the path to the config file with `herd configuration vnstatd'.
> It was introduced with 'ebc7de6a1efb702fd0364128cbde19697966c4f4'.

Thanks! That's news to me :-).

Toggle quote (47 lines)
>>> + (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 <vnstat-configuration> (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))))
>>
>> The rest LGTM (a system test would be nice, but since the Shepherd
>> service definition is straightforward, it could come later, when the
>> need arise).
>
> I've thought a bit about the system test though the way vnstat works is that
> it needs to collect some data and it also takes a while for the daemon to flag it
> as ready (~5 minutes). This would be a somewhat slow and non-trivial test to write.

Hm, not nice indeed. Then I guess it's fine without a test.

One last thing: in general I think we should try to have our services
run in a Linux namespace (unprivileged); have you tried running vnstat
in a wrapper produced with least-authority-wrapper (from (guix
least-authority)) ?

--
Thanks,
Maxim
B
B
Bruno Victal wrote on 18 Jan 2023 01:34
[PATCH v2] services: Add vnstat-service-type.
(address . 60788@debbugs.gnu.org)
beb55c678fea6c72c593dad446592ada135ee8c4.1674002048.git.mirai@makinata.eu
* gnu/services/monitoring.scm (vnstat-service-type): New variable.
* doc/guix.texi (Monitoring Services): Document it.
---
doc/guix.texi | 238 +++++++++++++++++++++
gnu/services/monitoring.scm | 415 ++++++++++++++++++++++++++++++++++++
2 files changed, 653 insertions(+)

Toggle diff (447 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 9b478733eb..6bda366750 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -112,6 +112,7 @@
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
@@ -28266,6 +28267,243 @@ 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.
+@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..78fc49da5c 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018, 2019 Gábor Boskovits <boskovits@gmail.com>
;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2022 Marius Bakke <marius@gnu.org>
+;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;;
;;; 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,10 @@ (define-module (gnu services monitoring)
prometheus-node-exporter-web-listen-address
prometheus-node-exporter-service-type
+ vnstat-configuration
+ vnstat-configuration?
+ vnstat-service-type
+
zabbix-server-configuration
zabbix-server-service-type
zabbix-agent-configuration
@@ -196,6 +203,414 @@ (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
This message was truncated. Download the full message here.
B
B
Bruno Victal wrote on 18 Jan 2023 01:37
[PATCH v2] services: vnstat: Use least-authority-wrapper.
(address . 60788@debbugs.gnu.org)
f24c76b56d278f662437c96f45e5b9b7c88dfcf5.1674002230.git.mirai@makinata.eu
* gnu/services/monitoring.scm (vnstat-shepherd-service): Use
least-authority-wrapper.
---

This patch SHOULD NOT be applied, this is a wip patch with least-authority-wrapper
and it doesn't seem to work (at least when launched within a VM).
I leave it here in case anyone interested wants to dig in further.


gnu/services/monitoring.scm | 42 ++++++++++++++++++++++++++++++-------
1 file changed, 34 insertions(+), 8 deletions(-)

Toggle diff (73 lines)
diff --git a/gnu/services/monitoring.scm b/gnu/services/monitoring.scm
index 78fc49da5c..c9e4f85701 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -29,6 +29,9 @@ (define-module (gnu services monitoring)
#:use-module (gnu packages monitoring)
#:use-module (gnu packages networking)
#:use-module (gnu system shadow)
+ #:use-module ((gnu system file-systems) #:select (file-system-mapping))
+ #:use-module (gnu build linux-container)
+ #:autoload (guix least-authority) (least-authority-wrapper)
#:use-module (guix gexp)
#:use-module (guix packages)
#:use-module (guix records)
@@ -448,7 +451,7 @@ (define-configuration vnstat-configuration
@var{save-interval}..@samp{60}")
(pid-file
- (maybe-string "/var/run/vnstatd.pid")
+ (maybe-string "/var/run/vnstatd/vnstatd.pid")
"\
Specify pid file path and name to be used.")
@@ -558,17 +561,40 @@ (define (vnstat-serialize-configuration config)
(serialize-configuration config vnstat-configuration-fields)))
(define (vnstat-shepherd-service config)
- (let ((config-file (vnstat-serialize-configuration config)))
- (match-record config <vnstat-configuration> (package pid-file)
+ (match-record config <vnstat-configuration> (package database-dir pid-file use-logging)
+ (let* ((config-file (vnstat-serialize-configuration config))
+ (vnstatd (least-authority-wrapper
+ (file-append package "/sbin/vnstatd")
+ #:name "vnstatd"
+ #:mappings (append (if (eqv? use-logging 2)
+ (list (file-system-mapping
+ (source "/dev/log") ; for syslog
+ (target source)))
+ '())
+ (list (file-system-mapping
+ (source database-dir)
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source (dirname pid-file))
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source config-file)
+ (target source))))
+ #:namespaces (delq 'net %namespaces))))
(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))
+ (start #~(begin
+ (mkdir-p #$database-dir)
+ (mkdir-p (dirname #$pid-file))
+ (make-forkexec-constructor
+ (list #$vnstatd
+ "--daemon"
+ "--config" #$config-file)
+ #:pid-file #$pid-file)))
(stop #~(make-kill-destructor))
(actions
(list (shepherd-configuration-action config-file)
--
2.38.1
B
B
Bruno Victal wrote on 2 Feb 2023 15:21
[PATCH v3] services: Add vnstat-service-type.
(address . 60788@debbugs.gnu.org)
b5735989f39c757c4a9d9425f4131675a7d260fd.1675347634.git.mirai@makinata.eu
* gnu/services/monitoring.scm (vnstat-service-type): New variable.
* doc/guix.texi (Monitoring Services): Document it.
---

Changes since v2:
* Export accessors.

doc/guix.texi | 238 +++++++++++++++++++
gnu/services/monitoring.scm | 451 ++++++++++++++++++++++++++++++++++++
2 files changed, 689 insertions(+)

Toggle diff (430 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 64873db00b..cb2c1c3c13 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -112,6 +112,7 @@
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
@@ -28267,6 +28268,243 @@ 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.
+@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..870943e80b 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018, 2019 Gábor Boskovits <boskovits@gmail.com>
;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2022 Marius Bakke <marius@gnu.org>
+;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;;
;;; 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,414 @@ (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 i
This message was truncated. Download the full message here.
B
B
Bruno Victal wrote on 7 Feb 2023 15:25
[PATCH v4] services: Add vnstat-service-type.
(address . 60788@debbugs.gnu.org)
8b62c1b5643a09163b53af4bf03bb12862770b50.1675779899.git.mirai@makinata.eu
* gnu/services/monitoring.scm (vnstat-service-type): New variable.
* doc/guix.texi (Monitoring Services): Document it.
---
doc/guix.texi | 240 ++++++++++++++++++-
gnu/services/monitoring.scm | 451 ++++++++++++++++++++++++++++++++++++
2 files changed, 689 insertions(+), 2 deletions(-)

Toggle diff (430 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 359c9b7a47..7779aadd83 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 Ivan Vilata-i-Balaguer@*
Copyright @copyright{} 2023 Giacomo Leidi@*
Copyright @copyright{} 2022 Antero Mejr@*
-Copyright @copyright{} 2022 Bruno Victal@*
+Copyright @copyright{} 2022?–?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
@@ -28269,6 +28268,243 @@ 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.
+@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..870943e80b 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018, 2019 Gábor Boskovits <boskovits@gmail.com>
;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2022 Marius Bakke <marius@gnu.org>
+;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;;
;;; 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,414 @@ (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 detec
This message was truncated. Download the full message here.
M
M
Maxim Cournoyer wrote on 9 Feb 2023 04:34
Re: bug#60788: [PATCH] services: Add vnstat-service-type.
(name . Bruno Victal)(address . mirai@makinata.eu)(address . 60788@debbugs.gnu.org)
87357fjyuc.fsf_-_@gmail.com
Hi Bruno,

Bruno Victal <mirai@makinata.eu> writes:

Toggle quote (7 lines)
> * gnu/services/monitoring.scm (vnstat-service-type): New variable.
> * doc/guix.texi (Monitoring Services): Document it.
> ---
> doc/guix.texi | 240 ++++++++++++++++++-
> gnu/services/monitoring.scm | 451 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 689 insertions(+), 2 deletions(-)

Two remaining comments from me:

1. I'd normalize all the configuration field names to lowercase, so
max-BW and use-UTC? would become max-bw and use-utc?, for example.

2. I'd add a simple example vnstat usage example to the manual.

With this done, I think it should be good to go!

--
Thanks,
Maxim
B
B
Bruno Victal wrote on 9 Feb 2023 05:19
(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)(address . 60788@debbugs.gnu.org)
cdb1263f-bb9b-e83a-6567-eec31e52e632@makinata.eu
Hi Maxim,

On 2023-02-09 03:34, Maxim Cournoyer wrote:
Toggle quote (5 lines)
> Two remaining comments from me:
>
> 1. I'd normalize all the configuration field names to lowercase, so
> max-BW and use-UTC? would become max-bw and use-utc?, for example.

No, this is intentional so that uglify+case-conversion yields correct configuration directives.

Toggle quote (2 lines)
> 2. I'd add a simple example vnstat usage example to the manual.

The service is "ready to be used" with the default values, so I didn't think
it'd add much value adding an example here. Do you think we should add one?


Cheers,
Bruno
M
M
Maxim Cournoyer wrote on 9 Feb 2023 14:31
(name . Bruno Victal)(address . mirai@makinata.eu)(address . 60788@debbugs.gnu.org)
87h6vvge2j.fsf@gmail.com
Hi Bruno,

Bruno Victal <mirai@makinata.eu> writes:

Toggle quote (10 lines)
> Hi Maxim,
>
> On 2023-02-09 03:34, Maxim Cournoyer wrote:
>> Two remaining comments from me:
>>
>> 1. I'd normalize all the configuration field names to lowercase, so
>> max-BW and use-UTC? would become max-bw and use-utc?, for example.
>
> No, this is intentional so that uglify+case-conversion yields correct configuration directives.

OK; the case conversion could be special-cased (max-bw -> max-BW,
use-utc? -> utc-UTC?) in the uglify+case-conversion logic. But it seems
that vnstat doesn't care about case when parsing its options; it uses
strcasecmp, which ignores the case of the characters per 'man 3
strcasecmp' [0].


Toggle quote (5 lines)
>> 2. I'd add a simple example vnstat usage example to the manual.
>
> The service is "ready to be used" with the default values, so I didn't think
> it'd add much value adding an example here. Do you think we should add one?

I think so; with so many switches it can appear intimidating; but a
minimal working example would show to users that they can start simple.

--
Thanks,
Maxim
B
B
Bruno Victal wrote on 10 Feb 2023 14:15
[PATCH v5] services: Add vnstat-service-type.
(address . 60788@debbugs.gnu.org)
965e112603934b79ec784738a3ad075bfdb0dd51.1676034889.git.mirai@makinata.eu
* 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(-)

Toggle diff (430 lines)
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 <boskovits@gmail.com>
;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2022 Marius Bakke <marius@gnu.org>
+;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;;
;;; 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
This message was truncated. Download the full message here.
M
M
Maxim Cournoyer wrote on 10 Feb 2023 15:07
(name . Bruno Victal)(address . mirai@makinata.eu)(address . 60788@debbugs.gnu.org)
87lel5fwb7.fsf@gmail.com
Hi!

Bruno Victal <mirai@makinata.eu> writes:

[...]

Toggle quote (23 lines)
> + 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

^ Looks like you forgot to adjust to use the now all lowercase symbol
here.

Toggle quote (17 lines)
> + 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?

Ditto.

The rest LGTM.

--
Thanks,
Maxim
B
B
Bruno Victal wrote on 10 Feb 2023 15:14
[PATCH v6] services: Add vnstat-service-type.
(address . 60788@debbugs.gnu.org)
7754c52c58be91a73a2947bb43baba962749def2.1676038434.git.mirai@makinata.eu
* 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(-)

Toggle diff (430 lines)
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..ef88c82357 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018, 2019 Gábor Boskovits <boskovits@gmail.com>
;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2022 Marius Bakke <marius@gnu.org>
+;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;;
;;; 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
This message was truncated. Download the full message here.
B
B
Bruno Victal wrote on 21 Mar 2023 16:54
control-msg
(name . control)(address . control@debbugs.gnu.org)
1be1f685-6ccc-9d11-7305-1d7c3706a341@makinata.eu
# fields 'user' and 'group' to be replaced from string to user-account + user-group
# in the next patch revision
tags 60788 + pending

quit
B
B
Bruno Victal wrote on 22 Mar 2023 17:15
[PATCH v7] services: Add vnstat-service-type.
(address . 60788@debbugs.gnu.org)
7a6d4c5c48307b39198c63312d3d9ea06c2fba4d.1679501719.git.mirai@makinata.eu
* gnu/services/monitoring.scm (vnstat-service-type): New variable.
* doc/guix.texi (Monitoring Services): Document it.
---
doc/guix.texi | 239 ++++++++++++++++++
gnu/services/monitoring.scm | 465 ++++++++++++++++++++++++++++++++++++
2 files changed, 704 insertions(+)

Toggle diff (442 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index dfdb26103a..9353f06f07 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -28566,6 +28566,245 @@ 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-user-group)
+Specify the group to which the daemon process should switch during
+startup. Set to @code{%unset-value} to disable group switching.
+
+@item @code{daemon-user} (type: maybe-user-account)
+Specify the user to which the daemon process should switch during
+startup. Set to @code{%unset-value} to disable user switching.
+
+@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 bbf8b10f8b..0cfbff0946 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018, 2019 Gábor Boskovits <boskovits@gmail.com>
;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2022 Marius Bakke <marius@gnu.org>
+;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;;
;;; 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,428 @@ (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 (vnstat-serialize-user-account field-name value)
+ (vnstat-serialize-string field-name (user-account-name value)))
+
+(define (vnstat-serialize-user-group field-name value)
+ (vnstat-serialize-string field-name (user-group-name value)))
+
+(define-maybe string (prefix vnstat-))
+(define-maybe integer (prefix vnstat-))
+(define-maybe boolean (prefix vnstat-))
+(define-maybe alist (prefix vnstat-))
+(define-maybe user-account (prefix vnstat-))
+(define-maybe user-group (prefix vnstat-))
+
+(define %vnstat-user
+ (user-account
+ (name "vnstat")
+ (group "vnstat")
+ (system? #t)
+ (home-directory "/var/empty")
+ (shell (file-append shadow "/sbin/nologin"))))
+
+(define %vnstat-group
+ (user-group
+ (name "vnstat")
+ (system? #t)))
+
+;; 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 message was truncated. Download the full message here.
B
B
Bruno Victal wrote on 3 Apr 2023 16:14
[PATCH v8] services: Add vnstat-service-type.
(address . 60788@debbugs.gnu.org)
2e611090530b4a45b15134fbece343fd4953e646.1680531257.git.mirai@makinata.eu
* gnu/services/monitoring.scm (vnstat-service-type): New variable.
* doc/guix.texi (Monitoring Services): Document it.
---

Notable changes since v7:
* Adapted to the recent changes in define-configuration.

doc/guix.texi | 239 ++++++++++++++++++
gnu/services/monitoring.scm | 465 ++++++++++++++++++++++++++++++++++++
2 files changed, 704 insertions(+)

Toggle diff (441 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 4f72e2f34a..7e69098267 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -28569,6 +28569,245 @@ 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-user-group)
+Specify the group to which the daemon process should switch during
+startup. Set to @code{%unset-value} to disable group switching.
+
+@item @code{daemon-user} (type: maybe-user-account)
+Specify the user to which the daemon process should switch during
+startup. Set to @code{%unset-value} to disable user switching.
+
+@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 bbf8b10f8b..0cfbff0946 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018, 2019 Gábor Boskovits <boskovits@gmail.com>
;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2022 Marius Bakke <marius@gnu.org>
+;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;;
;;; 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,428 @@ (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 (vnstat-serialize-user-account field-name value)
+ (vnstat-serialize-string field-name (user-account-name value)))
+
+(define (vnstat-serialize-user-group field-name value)
+ (vnstat-serialize-string field-name (user-group-name value)))
+
+(define-maybe string (prefix vnstat-))
+(define-maybe integer (prefix vnstat-))
+(define-maybe boolean (prefix vnstat-))
+(define-maybe alist (prefix vnstat-))
+(define-maybe user-account (prefix vnstat-))
+(define-maybe user-group (prefix vnstat-))
+
+(define %vnstat-user
+ (user-account
+ (name "vnstat")
+ (group "vnstat")
+ (system? #t)
+ (home-directory "/var/empty")
+ (shell (file-append shadow "/sbin/nologin"))))
+
+(define %vnstat-group
+ (user-group
+ (name "vnstat")
+ (system? #t)))
+
+;; 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-ba
This message was truncated. Download the full message here.
B
B
Bruno Victal wrote on 4 Apr 2023 15:08
[PATCH v9] services: Add vnstat-service-type.
(address . 60788@debbugs.gnu.org)
a77e9de7969534568b2481225844eeae7d7ef3f7.1680613664.git.mirai@makinata.eu
* gnu/services/monitoring.scm (vnstat-service-type): New variable.
* doc/guix.texi (Monitoring Services): Document it.
---

Changes since v8:
* Forgot to amend commit in v8, v9 corrects this.

doc/guix.texi | 239 ++++++++++++++++++
gnu/services/monitoring.scm | 467 ++++++++++++++++++++++++++++++++++++
2 files changed, 706 insertions(+)

Toggle diff (442 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 4f72e2f34a..7e69098267 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -28569,6 +28569,245 @@ 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-user-group)
+Specify the group to which the daemon process should switch during
+startup. Set to @code{%unset-value} to disable group switching.
+
+@item @code{daemon-user} (type: maybe-user-account)
+Specify the user to which the daemon process should switch during
+startup. Set to @code{%unset-value} to disable user switching.
+
+@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 bbf8b10f8b..09de7807c0 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018, 2019 Gábor Boskovits <boskovits@gmail.com>
;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2022 Marius Bakke <marius@gnu.org>
+;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;;
;;; 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,430 @@ (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 (vnstat-serialize-user-account field-name value)
+ (vnstat-serialize-string field-name (user-account-name value)))
+
+(define (vnstat-serialize-user-group field-name value)
+ (vnstat-serialize-string field-name (user-group-name value)))
+
+(define-maybe string (prefix vnstat-))
+(define-maybe integer (prefix vnstat-))
+(define-maybe boolean (prefix vnstat-))
+(define-maybe alist (prefix vnstat-))
+(define-maybe user-account (prefix vnstat-))
+(define-maybe user-group (prefix vnstat-))
+
+(define %vnstat-user
+ (user-account
+ (name "vnstat")
+ (group "vnstat")
+ (system? #t)
+ (home-directory "/var/empty")
+ (shell (file-append shadow "/sbin/nologin"))))
+
+(define %vnstat-group
+ (user-group
+ (name "vnstat")
+ (system? #t)))
+
+;; 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
This message was truncated. Download the full message here.
B
B
Bruno Victal wrote on 4 Apr 2023 15:31
control-msg
(name . control)(address . control@debbugs.gnu.org)
b1c28681-d877-2cdd-db09-0895fa9a8a72@makinata.eu
tags 62324 patch
tags 61462 patch
tags 60788 - pending
tags 59971 wishlist
tags 51737 patch

tags 62624 + security
tags 49817 + security

# resend control-msg
close 37740


quit
L
L
Ludovic Courtès wrote on 7 Apr 2023 17:22
Re: bug#60788: [PATCH] services: Add vnstat-service-type.
(name . Bruno Victal)(address . mirai@makinata.eu)
87edovd8em.fsf_-_@gnu.org
Hi!

Bruno Victal <mirai@makinata.eu> skribis:

Toggle quote (7 lines)
> * gnu/services/monitoring.scm (vnstat-service-type): New variable.
> * doc/guix.texi (Monitoring Services): Document it.
> ---
>
> Changes since v8:
> * Forgot to amend commit in v8, v9 corrects this.

Sorry to chime in after 9 versions (!).

I think a system test would be nice, we generally require it upfront,
but since Maxim wrote it can come later, let’s not let it block this
patch any longer.

One comment:

Toggle quote (2 lines)
> +@item @code{database-dir} (default: @code{"/var/lib/vnstat"}) (type: string)

[...]

Toggle quote (2 lines)
> +@item @code{create-dirs?} (default: @code{#t}) (type: maybe-boolean)

For consistency, both within this record and with the rest of Guix, I
suggest avoiding abbreviations. Since this will be part of the API,
better fix it now than later.

Toggle quote (15 lines)
> +@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

Both the naming and semantics are a bit confusing to me.

How about s/max-bw/per-interface-max-bandwidth/ ?

Side note: I’d represent interfaces as strings because there’s no
guarantee they “fit” in a symbol.

That’s all, thanks!

Ludo’.
M
M
Maxim Cournoyer wrote on 7 Apr 2023 22:04
(name . Ludovic Courtès)(address . ludo@gnu.org)
87cz4ftq5z.fsf@gmail.com
Hi Ludo,

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

Toggle quote (17 lines)
> Hi!
>
> Bruno Victal <mirai@makinata.eu> skribis:
>
>> * gnu/services/monitoring.scm (vnstat-service-type): New variable.
>> * doc/guix.texi (Monitoring Services): Document it.
>> ---
>>
>> Changes since v8:
>> * Forgot to amend commit in v8, v9 corrects this.
>
> Sorry to chime in after 9 versions (!).
>
> I think a system test would be nice, we generally require it upfront,
> but since Maxim wrote it can come later, let’s not let it block this
> patch any longer.

I didn't mean to lower our standards; I wasn't sure if that policy of
ours was strict, since a few system services do not have corresponding
tests, IIRC. I wary a bit that demanding a system test for each added
service may cause scalability problems in the long run, as each demand a
disk-heavy image to be generated and the test to run in a VM, which
makes it expensive/slow. On the other hand, it's nice to know about any
regressions when they happen rather than on a reboot...

If we have such a policy, perhaps we should explicit it in
our documented contribution guidelines?

--
Thanks,
Maxim
B
B
Bruno Victal wrote on 8 Apr 2023 14:40
(name . Ludovic Courtès)(address . ludo@gnu.org)
07feadac-18b2-7e82-9798-3e3872efcd4a@makinata.eu
Hi Ludo’,

On 2023-04-07 16:22, Ludovic Courtès wrote:
Toggle quote (4 lines)
> I think a system test would be nice, we generally require it upfront,
> but since Maxim wrote it can come later, let’s not let it block this
> patch any longer.

Originally I thought it was unfeasible to write a test for this service
since it required network activity within the VM and it seemed to take more
than 10 minutes for it to pick it up.

I did some manual experiments on it much later and I managed to get it down to
approx. between 2 and 3 minutes for a partially automated test.

What's blocking the test from being implemented in Guix is that my (incomplete) test-suite
for this depends on guile 'spawn', which isn't available yet,
For reference, I've attached the test-suite here [1], the plan is to finish it up and
add it to Guix after the 'spawn' issue is resolved. (or perhaps refactor this to use another approach?)

Toggle quote (13 lines)
>
> One comment:
>
>> +@item @code{database-dir} (default: @code{"/var/lib/vnstat"}) (type: string)
>
> [...]
>
>> +@item @code{create-dirs?} (default: @code{#t}) (type: maybe-boolean)
>
> For consistency, both within this record and with the rest of Guix, I
> suggest avoiding abbreviations. Since this will be part of the API,
> better fix it now than later.

I should mention that almost all of the field names here are near verbatim
vnstat config-file directives, i.e. a near 1-1 Scheme translation of vnstat config.
This has the benefit that it makes serialization pretty much straightforward.

It's possible to override their names by the use of the custom serializer parameter
but would it be acceptable to leave them as-is?

Toggle quote (19 lines)
>> +@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
>
> Both the naming and semantics are a bit confusing to me.
>
> How about s/max-bw/per-interface-max-bandwidth/ ?

I found it a bit confusing as well but I'm not too familiar with this part of
the config to comment about it.
I lifted most of the field-names and documentations straight from the manpage.

Toggle quote (3 lines)
> Side note: I’d represent interfaces as strings because there’s no
> guarantee they “fit” in a symbol.

Thanks! I'll have this amended in the next revision.


[1]: Listing of vnstat-test.scm

Toggle snippet (131 lines)
(define-module (gnu tests vnstat)
#:use-module (gnu tests)
#:use-module ((gnu packages networking) #:select (socat vnstat))
#:use-module (gnu services)
#:use-module (gnu services networking)
#:use-module (gnu services monitoring)
#:use-module (gnu system)
#:use-module (gnu system vm)
#:use-module (guix gexp)
#:use-module (ice-9 format)
#:export (%test-vnstat))


(define (run-vnstat-test)
"Run tests in a vm which has vnstat running."

(define vnstat-config
(vnstat-configuration
(max-bandwidth 0)
(time-sync-wait 0)
(bandwidth-detection-interval 0)))

(define os
(marionette-operating-system
(simple-operating-system
(service dhcp-client-service-type)
(service vnstat-service-type
vnstat-config)
(service inetd-service-type
(inetd-configuration
(entries
(list (inetd-entry
(name "discard")
(socket-type 'stream)
(protocol "tcp") ;; FIXME: originally this was UDP but port-forwardings hardcodes TCP
(wait? #t)
(user "nobody")))))))
#:imported-modules '((gnu services herd))))

(define forwarded-port 9999)

(define vm
(virtual-machine
(operating-system os)
;; Note: port 9 corresponds to "discard" service.
(port-forwardings `((,forwarded-port . 9))))) ;; FIXME: Allow UDP forward.

(define test-timeout (* 60 2)) ; wait for 2 minutes tops.

(define test
(with-imported-modules '((gnu build marionette))
#~(begin
(use-modules (gnu build marionette)
(srfi srfi-64))

(let ((marionette (make-marionette (list #$vm)))
(pid-file #$(vnstat-configuration-pid-file vnstat-config)))

(test-runner-current (system-test-runner #$output))
(test-begin "vnstat")

(test-assert "service is running"
(marionette-eval
'(begin
(use-modules (gnu services herd))
(start-service 'vnstatd))
marionette))

(test-assert "vnstatd ready"
(wait-for-file pid-file marionette))

(test-assert "vnstatd is logging"
;; pump garbage into the "discard" service within the vm
;; TODO: guile socket client instead? Is it feasible?
(let* ((socat #$(file-append socat "/bin/socat"))
(dest-addr #$(format #f "TCP4:localhost:~d"
forwarded-port))
(args `("socat" "-u" "/dev/zero" ,dest-addr))
;; XXX: Guile bug (22/03/2023, Guile 3.0.9)
;; Fixed in main: <https://issues.guix.gnu.org/61073>
#;(output-port (%make-void-port "w"))
(garbage-pump-pid (spawn socat args)))

(let ((retval
(marionette-eval
'(begin
(use-modules (ice-9 popen)
;(ice-9 rdelim)
(ice-9 match)
(sxml simple)
(sxml xpath))

(define selector
(let ((xpath '(vnstat interface traffic total)))
(compose (node-pos 1) (sxpath xpath))))

(let loop ((i 0))
(let* ((vnstat #$(file-append vnstat "/bin/vnstat"))
(query-cmd (format #f "~a --xml") vnstat)
(result
#;(call-with-port
(open-input-pipe query-cmd) read-line)
(call-with-port
(open-input-pipe query-cmd) xml->sxml))
(iface-stats (selector result)))
(match iface-stats
((('total ('rx "0") ('tx "0")))
(sleep 1)
(if (< i #$test-timeout)
(loop (+ i 1))
#f))
((('total ('rx rx) ('tx tx)))
#t)
(_ #f)))))
marionette)))
;; shutdown garbage pump
(kill garbage-pump-pid SIGTERM)
retval)))

(test-end)))))

(gexp->derivation "vnstat-test" test))

(define %test-vnstat
(system-test
(name "vnstat")
(description "Basic tests for vnstat service.")
(value (run-vnstat-test))))


Cheers,
Bruno
L
L
Ludovic Courtès wrote on 20 Apr 2023 12:03
Policy for system tests?
(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)
87bkjix44n.fsf_-_@gnu.org
Hi,

Maxim Cournoyer <maxim.cournoyer@gmail.com> skribis:

Toggle quote (2 lines)
> Ludovic Courtès <ludo@gnu.org> writes:

[...]

Toggle quote (12 lines)
>> I think a system test would be nice, we generally require it upfront,
>> but since Maxim wrote it can come later, let’s not let it block this
>> patch any longer.
>
> I didn't mean to lower our standards; I wasn't sure if that policy of
> ours was strict, since a few system services do not have corresponding
> tests, IIRC. I wary a bit that demanding a system test for each added
> service may cause scalability problems in the long run, as each demand a
> disk-heavy image to be generated and the test to run in a VM, which
> makes it expensive/slow. On the other hand, it's nice to know about any
> regressions when they happen rather than on a reboot...

Yeah, it’s an unwritten policy; I think we’ve consistently required it
for some time now. It’s useful because otherwise it’s hard to tell what
the status is for a service.

(Speaking of which, we do *not* have that policy for Home services,
because we don’t even have a test strategy, and that’s something we
should fix before it’s too late.)

Toggle quote (3 lines)
> If we have such a policy, perhaps we should explicit it in
> our documented contribution guidelines?

Yes!

Also, we should split the submission guidelines into different
categories: packages, services, doc, core, etc.

Ludo’.
L
L
Ludovic Courtès wrote on 20 Apr 2023 12:09
Re: bug#60788: [PATCH] services: Add vnstat-service-type.
(name . Bruno Victal)(address . mirai@makinata.eu)
877cu6x3t9.fsf@gnu.org
Hello!

Bruno Victal <mirai@makinata.eu> skribis:

Toggle quote (17 lines)
>>> +@item @code{database-dir} (default: @code{"/var/lib/vnstat"}) (type: string)
>>
>> [...]
>>
>>> +@item @code{create-dirs?} (default: @code{#t}) (type: maybe-boolean)
>>
>> For consistency, both within this record and with the rest of Guix, I
>> suggest avoiding abbreviations. Since this will be part of the API,
>> better fix it now than later.
>
> I should mention that almost all of the field names here are near verbatim
> vnstat config-file directives, i.e. a near 1-1 Scheme translation of vnstat config.
> This has the benefit that it makes serialization pretty much straightforward.
>
> It's possible to override their names by the use of the custom serializer parameter
> but would it be acceptable to leave them as-is?

Hmm, I’d say that if the cost of using “nice names” is “really high”,
then yes. But perhaps we can make that cost low by having a map for the
few cases where we use a name different from upstream?

(define field-name-mapping
'((database-directory . "database_dir") …))

Toggle quote (2 lines)
> (define-module (gnu tests vnstat)

Woohoo, you rock!

Toggle quote (12 lines)
> (test-assert "vnstatd is logging"
> ;; pump garbage into the "discard" service within the vm
> ;; TODO: guile socket client instead? Is it feasible?
> (let* ((socat #$(file-append socat "/bin/socat"))
> (dest-addr #$(format #f "TCP4:localhost:~d"
> forwarded-port))
> (args `("socat" "-u" "/dev/zero" ,dest-addr))
> ;; XXX: Guile bug (22/03/2023, Guile 3.0.9)
> ;; Fixed in main: <https://issues.guix.gnu.org/61073>
> #;(output-port (%make-void-port "w"))
> (garbage-pump-pid (spawn socat args)))

You can probably connect directly to DEST-ADDR from Guile instead of
going through ‘socat’?

If not, you can either pass ‘#:guile guile-3.0-latest’ to
‘gexp->derivation’ so you get ‘spawn’ (3.0.9 is the default in
‘core-updates’ anyway), or use ‘primitive-fork’.

HTH!

Ludo’.
B
B
Bruno Victal wrote on 5 May 2023 02:18
[PATCH v10 1/3] services: Add vnstat-service-type.
(address . 60788@debbugs.gnu.org)
4e67d41880a44306c5b5d0a39c776083c180cd15.1683245610.git.mirai@makinata.eu
* gnu/services/monitoring.scm (vnstat-service-type): New variable.
* doc/guix.texi (Monitoring Services): Document it.
---

Notable changes since v9:
* Fields create-dirs? and database-dir were renamed to create-directories? and database-directory.
* Field maxbw description asks that interface names be supplied as strings instead.
* Test suite was refactored and included in this series.
* Exports accessors for inetd service.

Notes:
Regarding the MaxBW field, I don't understand this option enough to decide on a different naming for it.

doc/guix.texi | 237 ++++++++++++++++++
gnu/services/monitoring.scm | 472 ++++++++++++++++++++++++++++++++++++
2 files changed, 709 insertions(+)

Toggle diff (433 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 55221a10c3..bedc38cb73 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -28656,6 +28656,243 @@ 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-directory} (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-directories?} (default: @code{#t}) (type: maybe-boolean)
+Enable or disable the creation of directories when a configured path
+doesn't exist. This includes @var{database-directory}.
+
+@item @code{daemon-group} (type: maybe-user-group)
+Specify the group to which the daemon process should switch during
+startup. Set to @code{%unset-value} to disable group switching.
+
+@item @code{daemon-user} (type: maybe-user-account)
+Specify the user to which the daemon process should switch during
+startup. Set to @code{%unset-value} to disable user switching.
+
+@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 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. Accepted values are: @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 bbf8b10f8b..e698040078 100644
--- a/gnu/services/monitoring.scm
+++ b/gnu/services/monitoring.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018, 2019 Gábor Boskovits <boskovits@gmail.com>
;;; Copyright © 2018, 2019, 2020 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2022 Marius Bakke <marius@gnu.org>
+;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;;
;;; 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-directory
+ 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-directories?
+ 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,435 @@ (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 (vnstat-serialize-user-account field-name value)
+ (vnstat-serialize-string field-name (user-account-name value)))
+
+(define (vnstat-serialize-user-group field-name value)
+ (vnstat-serialize-string field-name (user-group-name value)))
+
+(define-maybe string (prefix vnstat-))
+(define-maybe integer (prefix vnstat-))
+(define-maybe boolean (prefix vnstat-))
+(define-maybe alist (prefix vnstat-))
+(define-maybe user-account (prefix vnstat-))
+(define-maybe user-group (prefix vnstat-))
+
+(define %vnstat-user
+ (user-account
+ (name "vnstat")
+ (group "vnstat")
+ (system? #t)
+ (home-directory "/var/empty")
+ (shell (file-append shadow "/sbin/nologin"))))
+
+(define %vnstat-group
+ (user-group
+ (name "vnstat")
+ (system? #t)))
+
+;; 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-directory
+ (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."
+ (serializer
+ (lambda (_ value)
+ (vnstat-serialize-string 'database-dir value))))
+
+ (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
This message was truncated. Download the full message here.
B
B
Bruno Victal wrote on 5 May 2023 02:18
[PATCH v10 3/3] tests: Add vnstat tests.
(address . 60788@debbugs.gnu.org)
2b1c8fa1c767cb2bcdec87109402fc42be17753d.1683245610.git.mirai@makinata.eu
* gnu/tests/vnstat.scm: New file.
* gnu/local.mk: Register it.
---
gnu/local.mk | 1 +
gnu/tests/vnstat.scm | 159 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 160 insertions(+)
create mode 100644 gnu/tests/vnstat.scm

Toggle diff (179 lines)
diff --git a/gnu/local.mk b/gnu/local.mk
index 5f5de953d7..c462c41b9d 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -795,6 +795,7 @@ GNU_SYSTEM_MODULES = \
%D%/tests/version-control.scm \
%D%/tests/virtualization.scm \
%D%/tests/vnc.scm \
+ %D%/tests/vnstat.scm \
%D%/tests/web.scm
INSTALLER_MODULES = \
diff --git a/gnu/tests/vnstat.scm b/gnu/tests/vnstat.scm
new file mode 100644
index 0000000000..d1be98e342
--- /dev/null
+++ b/gnu/tests/vnstat.scm
@@ -0,0 +1,159 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>.
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu tests vnstat)
+ #:use-module (gnu tests)
+ #:use-module ((gnu packages networking) #:select (socat vnstat))
+ #:use-module (gnu services)
+ #:use-module (gnu services networking)
+ #:use-module (gnu services monitoring)
+ #:use-module (gnu system)
+ #:use-module (gnu system vm)
+ #:use-module (guix gexp)
+ #:use-module (ice-9 format)
+ #:export (%test-vnstat))
+
+
+(define (run-vnstat-test)
+ "Run tests in a vm which has vnstat running."
+
+ (define vnstat-config
+ (vnstat-configuration
+ (max-bandwidth 0)
+ (time-sync-wait 0)
+ (bandwidth-detection-interval 0)))
+
+ (define inetd-service-entry-config
+ (inetd-entry
+ (name "discard")
+ (socket-type 'stream)
+ (protocol "tcp")
+ (wait? #t)
+ (user "nobody")))
+
+ (define os
+ (marionette-operating-system
+ (simple-operating-system
+ (service dhcp-client-service-type)
+ (service vnstat-service-type
+ vnstat-config)
+ (service inetd-service-type
+ (inetd-configuration
+ (entries
+ (list inetd-service-entry-config)))))
+ #:imported-modules '((gnu services herd))))
+
+ (define forwarded-port 9999)
+
+ (define vm
+ (let* ((inetd-service-name "discard")
+ (inetd-service-proto
+ (inetd-entry-protocol inetd-service-entry-config))
+ (guest-port
+ (servent:port (getservbyname inetd-service-name
+ inetd-service-proto))))
+ (virtual-machine
+ (operating-system os)
+ (port-forwardings `((,forwarded-port . ,guest-port))))))
+
+ ;; The test duration is inconsistent, at times a test may complete under
+ ;; 2 minutes and at times it may take up to 5 minutes.
+ (define test-timeout (* 60 5))
+
+ (define test
+ (with-imported-modules '((gnu build marionette))
+ #~(begin
+ (use-modules (gnu build marionette)
+ (srfi srfi-64))
+
+ (let ((marionette (make-marionette (list #$vm)))
+ (pid-file #$(vnstat-configuration-pid-file vnstat-config)))
+
+ (test-runner-current (system-test-runner #$output))
+ (test-begin "vnstat")
+
+ (test-assert "service is running"
+ (marionette-eval
+ '(begin
+ (use-modules (gnu services herd))
+ (start-service 'vnstatd))
+ marionette))
+
+ (test-assert "vnstatd ready"
+ (wait-for-file pid-file marionette))
+
+ ;; Pump garbage into the 'discard' inetd service within the vm.
+ (let* ((socat #$(file-append socat "/bin/socat"))
+ (dest-addr #$(format #f "TCP4:localhost:~d"
+ forwarded-port))
+ (args `("socat" "-u" "/dev/zero" ,dest-addr))
+ ;; XXX: Guile bug (22/03/2023, Guile 3.0.9)
+ ;; Fixed in main: <https://issues.guix.gnu.org/61073>
+ ;; FIXME: re-add #:output (%make-void-port "w") below on
+ ;; next Guile release.
+ (garbage-pump-pid
+ (spawn socat args)))
+ (test-group-with-cleanup "Logging"
+ ;; To aid debugging, this test returns #t on success
+ ;; and either #f or 'timed-out otherwise.
+ (test-eq "vnstatd is logging"
+ #t
+ (marionette-eval
+ '(begin
+ (use-modules (ice-9 popen)
+ (ice-9 match)
+ (sxml simple)
+ (sxml xpath))
+
+ (define selector
+ (let ((xpath '(vnstat interface traffic total)))
+ (compose (node-pos 1) (sxpath xpath))))
+
+ (let loop ((i 0))
+ (let* ((vnstat #$(file-append vnstat "/bin/vnstat"))
+ (query-cmd (format #f "~a --xml" vnstat))
+ (proc (compose selector xml->sxml))
+ (result
+ (call-with-port
+ (open-input-pipe query-cmd) proc)))
+ (match result
+ ;; Counter still warming up.
+ ((('total ('rx "0") ('tx "0")))
+ (sleep 1)
+ (if (< i #$test-timeout)
+ (loop (+ i 1))
+ 'timed-out))
+ ;; Count of bytes on iface was non-zero.
+ ((('total ('rx rx) ('tx tx)))
+ #t)
+ ;; Unknown data encountered, perhaps the
+ ;; data format changed?
+ (_ #f)))))
+ marionette))
+ ;; Cleanup: shutdown garbage pump.
+ (kill garbage-pump-pid SIGTERM)))
+
+ (test-end)))))
+
+ (gexp->derivation "vnstat-test" test))
+
+(define %test-vnstat
+ (system-test
+ (name "vnstat")
+ (description "Basic tests for vnstat service.")
+ (value (run-vnstat-test))))
--
2.39.2
B
B
Bruno Victal wrote on 5 May 2023 02:18
[PATCH v10 2/3] services: inetd: Export accessors.
(address . 60788@debbugs.gnu.org)
0053c04412e34c5f9a6a28acc87560be8b8e6ff9.1683245610.git.mirai@makinata.eu
* gnu/services/networking.scm: Export inetd-configuration?,
inetd-configuration-program, inetd-configuration-entries, inetd-entry?,
inetd-entry-node, inetd-entry-name, inetd-entry-socket-type,
inetd-entry-protocol, inetd-entry-wait?, inetd-entry-user, inetd-entry-program
and inetd-entry-arguments.
---
gnu/services/networking.scm | 12 ++++++++++++
1 file changed, 12 insertions(+)

Toggle diff (26 lines)
diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm
index 866368aa90..554ab18234 100644
--- a/gnu/services/networking.scm
+++ b/gnu/services/networking.scm
@@ -121,7 +121,19 @@ (define-module (gnu services networking)
openntpd-service-type
inetd-configuration
+ inetd-configuration?
+ inetd-configuration-program
+ inetd-configuration-entries
inetd-entry
+ inetd-entry?
+ inetd-entry-node
+ inetd-entry-name
+ inetd-entry-socket-type
+ inetd-entry-protocol
+ inetd-entry-wait?
+ inetd-entry-user
+ inetd-entry-program
+ inetd-entry-arguments
inetd-service-type
opendht-configuration
--
2.39.2
L
L
Ludovic Courtès wrote on 11 May 2023 16:33
Re: [PATCH v10 1/3] services: Add vnstat-service-type.
(name . Bruno Victal)(address . mirai@makinata.eu)
87cz372b06.fsf@gnu.org
Hi,

Bruno Victal <mirai@makinata.eu> skribis:

Toggle quote (3 lines)
> * gnu/services/monitoring.scm (vnstat-service-type): New variable.
> * doc/guix.texi (Monitoring Services): Document it.

[...]

Toggle quote (3 lines)
> * gnu/tests/vnstat.scm: New file.
> * gnu/local.mk: Register it.

[...]

Toggle quote (6 lines)
> * gnu/services/networking.scm: Export inetd-configuration?,
> inetd-configuration-program, inetd-configuration-entries, inetd-entry?,
> inetd-entry-node, inetd-entry-name, inetd-entry-socket-type,
> inetd-entry-protocol, inetd-entry-wait?, inetd-entry-user, inetd-entry-program
> and inetd-entry-arguments.

Applied all three patches. Pheww, that was a long ride! Thanks for
your patience and for your quality work!

Ludo’.
Closed
?