2020-04-24 23:36:52 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
let
|
|
|
|
|
|
|
|
cfg = config.services.smokeping;
|
|
|
|
smokepingHome = "/var/lib/smokeping";
|
|
|
|
smokepingPidDir = "/run";
|
|
|
|
configFile =
|
|
|
|
if cfg.config == null
|
|
|
|
then
|
|
|
|
''
|
|
|
|
*** General ***
|
|
|
|
cgiurl = ${cfg.cgiUrl}
|
|
|
|
contact = ${cfg.ownerEmail}
|
|
|
|
datadir = ${smokepingHome}/data
|
|
|
|
imgcache = ${smokepingHome}/cache
|
|
|
|
imgurl = ${cfg.imgUrl}
|
|
|
|
linkstyle = ${cfg.linkStyle}
|
|
|
|
${lib.optionalString (cfg.mailHost != "") "mailhost = ${cfg.mailHost}"}
|
|
|
|
owner = ${cfg.owner}
|
|
|
|
pagedir = ${smokepingHome}/cache
|
|
|
|
piddir = ${smokepingPidDir}
|
|
|
|
${lib.optionalString (cfg.sendmail != null) "sendmail = ${cfg.sendmail}"}
|
|
|
|
smokemail = ${cfg.smokeMailTemplate}
|
|
|
|
*** Presentation ***
|
|
|
|
template = ${cfg.presentationTemplate}
|
|
|
|
${cfg.presentationConfig}
|
|
|
|
*** Alerts ***
|
|
|
|
${cfg.alertConfig}
|
|
|
|
*** Database ***
|
|
|
|
${cfg.databaseConfig}
|
|
|
|
*** Probes ***
|
|
|
|
${cfg.probeConfig}
|
|
|
|
*** Targets ***
|
|
|
|
${cfg.targetConfig}
|
|
|
|
${cfg.extraConfig}
|
|
|
|
''
|
|
|
|
else
|
|
|
|
cfg.config;
|
|
|
|
|
|
|
|
configPath = pkgs.writeText "smokeping.conf" configFile;
|
|
|
|
cgiHome = pkgs.writeScript "smokeping.fcgi" ''
|
|
|
|
#!${pkgs.bash}/bin/bash
|
|
|
|
${cfg.package}/bin/smokeping_cgi ${configPath}
|
|
|
|
'';
|
|
|
|
in
|
|
|
|
|
|
|
|
{
|
|
|
|
options = {
|
|
|
|
services.smokeping = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Enable the smokeping service";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
alertConfig = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
default = ''
|
|
|
|
to = root@localhost
|
|
|
|
from = smokeping@localhost
|
|
|
|
'';
|
2021-10-06 13:57:05 +00:00
|
|
|
example = ''
|
2020-04-24 23:36:52 +00:00
|
|
|
to = alertee@address.somewhere
|
|
|
|
from = smokealert@company.xy
|
|
|
|
|
|
|
|
+someloss
|
|
|
|
type = loss
|
|
|
|
# in percent
|
|
|
|
pattern = >0%,*12*,>0%,*12*,>0%
|
|
|
|
comment = loss 3 times in a row;
|
|
|
|
'';
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Configuration for alerts.";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
cgiUrl = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "http://${cfg.hostName}:${toString cfg.port}/smokeping.cgi";
|
2021-10-06 13:57:05 +00:00
|
|
|
defaultText = literalExpression ''"http://''${hostName}:''${toString port}/smokeping.cgi"'';
|
2020-04-24 23:36:52 +00:00
|
|
|
example = "https://somewhere.example.com/smokeping.cgi";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "URL to the smokeping cgi.";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
config = mkOption {
|
|
|
|
type = types.nullOr types.lines;
|
|
|
|
default = null;
|
2022-09-09 14:08:57 +00:00
|
|
|
description = lib.mdDoc ''
|
|
|
|
Full smokeping config supplied by the user. Overrides
|
|
|
|
and replaces any other configuration supplied.
|
|
|
|
'';
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
databaseConfig = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
default = ''
|
|
|
|
step = 300
|
|
|
|
pings = 20
|
|
|
|
# consfn mrhb steps total
|
|
|
|
AVERAGE 0.5 1 1008
|
|
|
|
AVERAGE 0.5 12 4320
|
|
|
|
MIN 0.5 12 4320
|
|
|
|
MAX 0.5 12 4320
|
|
|
|
AVERAGE 0.5 144 720
|
|
|
|
MAX 0.5 144 720
|
|
|
|
MIN 0.5 144 720
|
|
|
|
|
|
|
|
'';
|
2021-10-06 13:57:05 +00:00
|
|
|
example = ''
|
2020-04-24 23:36:52 +00:00
|
|
|
# near constant pings.
|
|
|
|
step = 30
|
|
|
|
pings = 20
|
|
|
|
# consfn mrhb steps total
|
|
|
|
AVERAGE 0.5 1 10080
|
|
|
|
AVERAGE 0.5 12 43200
|
|
|
|
MIN 0.5 12 43200
|
|
|
|
MAX 0.5 12 43200
|
|
|
|
AVERAGE 0.5 144 7200
|
|
|
|
MAX 0.5 144 7200
|
|
|
|
MIN 0.5 144 7200
|
|
|
|
'';
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc ''Configure the ping frequency and retention of the rrd files.
|
2020-04-24 23:36:52 +00:00
|
|
|
Once set, changing the interval will require deletion or migration of all
|
|
|
|
the collected data.'';
|
|
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
default = "";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Any additional customization not already included.";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
hostName = mkOption {
|
|
|
|
type = types.str;
|
2021-02-05 17:12:51 +00:00
|
|
|
default = config.networking.fqdn;
|
2021-10-06 13:57:05 +00:00
|
|
|
defaultText = literalExpression "config.networking.fqdn";
|
2020-04-24 23:36:52 +00:00
|
|
|
example = "somewhere.example.com";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "DNS name for the urls generated in the cgi.";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
imgUrl = mkOption {
|
|
|
|
type = types.str;
|
2021-12-06 16:07:01 +00:00
|
|
|
default = "cache";
|
|
|
|
defaultText = literalExpression ''"cache"'';
|
2020-04-24 23:36:52 +00:00
|
|
|
example = "https://somewhere.example.com/cache";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc ''
|
2021-12-06 16:07:01 +00:00
|
|
|
Base url for images generated in the cgi.
|
|
|
|
|
|
|
|
The default is a relative URL to ensure it works also when e.g. forwarding
|
|
|
|
the GUI port via SSH.
|
|
|
|
'';
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
linkStyle = mkOption {
|
|
|
|
type = types.enum ["original" "absolute" "relative"];
|
|
|
|
default = "relative";
|
|
|
|
example = "absolute";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "DNS name for the urls generated in the cgi.";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
mailHost = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "";
|
|
|
|
example = "localhost";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Use this SMTP server to send alerts";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
owner = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "nobody";
|
2022-08-12 12:06:08 +00:00
|
|
|
example = "Bob Foobawr";
|
|
|
|
description = lib.mdDoc "Real name of the owner of the instance";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
ownerEmail = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "no-reply@${cfg.hostName}";
|
2021-10-06 13:57:05 +00:00
|
|
|
defaultText = literalExpression ''"no-reply@''${hostName}"'';
|
2020-04-24 23:36:52 +00:00
|
|
|
example = "no-reply@yourdomain.com";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Email contact for owner";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
package = mkOption {
|
|
|
|
type = types.package;
|
|
|
|
default = pkgs.smokeping;
|
2021-10-06 13:57:05 +00:00
|
|
|
defaultText = literalExpression "pkgs.smokeping";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Specify a custom smokeping package";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
2021-12-06 16:07:01 +00:00
|
|
|
host = mkOption {
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = "localhost";
|
|
|
|
example = "192.0.2.1"; # rfc5737 example IP for documentation
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc ''
|
2021-12-06 16:07:01 +00:00
|
|
|
Host/IP to bind to for the web server.
|
|
|
|
|
2022-08-12 12:06:08 +00:00
|
|
|
Setting it to `null` skips passing the -h option to thttpd,
|
2021-12-06 16:07:01 +00:00
|
|
|
which makes it bind to all interfaces.
|
|
|
|
'';
|
|
|
|
};
|
2020-04-24 23:36:52 +00:00
|
|
|
port = mkOption {
|
|
|
|
type = types.int;
|
|
|
|
default = 8081;
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "TCP port to use for the web server.";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
presentationConfig = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
default = ''
|
|
|
|
+ charts
|
|
|
|
menu = Charts
|
|
|
|
title = The most interesting destinations
|
|
|
|
++ stddev
|
|
|
|
sorter = StdDev(entries=>4)
|
|
|
|
title = Top Standard Deviation
|
|
|
|
menu = Std Deviation
|
|
|
|
format = Standard Deviation %f
|
|
|
|
++ max
|
|
|
|
sorter = Max(entries=>5)
|
|
|
|
title = Top Max Roundtrip Time
|
|
|
|
menu = by Max
|
|
|
|
format = Max Roundtrip Time %f seconds
|
|
|
|
++ loss
|
|
|
|
sorter = Loss(entries=>5)
|
|
|
|
title = Top Packet Loss
|
|
|
|
menu = Loss
|
|
|
|
format = Packets Lost %f
|
|
|
|
++ median
|
|
|
|
sorter = Median(entries=>5)
|
|
|
|
title = Top Median Roundtrip Time
|
|
|
|
menu = by Median
|
|
|
|
format = Median RTT %f seconds
|
|
|
|
+ overview
|
|
|
|
width = 600
|
|
|
|
height = 50
|
|
|
|
range = 10h
|
|
|
|
+ detail
|
|
|
|
width = 600
|
|
|
|
height = 200
|
|
|
|
unison_tolerance = 2
|
|
|
|
"Last 3 Hours" 3h
|
|
|
|
"Last 30 Hours" 30h
|
|
|
|
"Last 10 Days" 10d
|
|
|
|
"Last 360 Days" 360d
|
|
|
|
'';
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "presentation graph style";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
presentationTemplate = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${pkgs.smokeping}/etc/basepage.html.dist";
|
2021-10-06 13:57:05 +00:00
|
|
|
defaultText = literalExpression ''"''${pkgs.smokeping}/etc/basepage.html.dist"'';
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Default page layout for the web UI.";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
probeConfig = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
default = ''
|
|
|
|
+ FPing
|
|
|
|
binary = ${config.security.wrapperDir}/fping
|
|
|
|
'';
|
2021-12-06 16:07:01 +00:00
|
|
|
defaultText = literalExpression ''
|
|
|
|
'''
|
|
|
|
+ FPing
|
|
|
|
binary = ''${config.security.wrapperDir}/fping
|
|
|
|
'''
|
|
|
|
'';
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Probe configuration";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
sendmail = mkOption {
|
|
|
|
type = types.nullOr types.path;
|
|
|
|
default = null;
|
|
|
|
example = "/run/wrappers/bin/sendmail";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Use this sendmail compatible script to deliver alerts";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
smokeMailTemplate = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.package}/etc/smokemail.dist";
|
2021-10-06 13:57:05 +00:00
|
|
|
defaultText = literalExpression ''"''${package}/etc/smokemail.dist"'';
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Specify the smokemail template for alerts.";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
targetConfig = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
default = ''
|
2021-02-05 17:12:51 +00:00
|
|
|
probe = FPing
|
|
|
|
menu = Top
|
|
|
|
title = Network Latency Grapher
|
|
|
|
remark = Welcome to the SmokePing website of xxx Company. \
|
|
|
|
Here you will learn all about the latency of our network.
|
|
|
|
+ Local
|
|
|
|
menu = Local
|
|
|
|
title = Local Network
|
|
|
|
++ LocalMachine
|
|
|
|
menu = Local Machine
|
|
|
|
title = This host
|
|
|
|
host = localhost
|
2020-04-24 23:36:52 +00:00
|
|
|
'';
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Target configuration";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
user = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "smokeping";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "User that runs smokeping and (optionally) thttpd. A group of the same name will be created as well.";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
webService = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Enable a smokeping web interface";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
assertions = [
|
|
|
|
{
|
|
|
|
assertion = !(cfg.sendmail != null && cfg.mailHost != "");
|
|
|
|
message = "services.smokeping: sendmail and Mailhost cannot both be enabled.";
|
|
|
|
}
|
|
|
|
];
|
|
|
|
security.wrappers = {
|
2021-09-22 15:38:15 +00:00
|
|
|
fping =
|
|
|
|
{ setuid = true;
|
|
|
|
owner = "root";
|
|
|
|
group = "root";
|
|
|
|
source = "${pkgs.fping}/bin/fping";
|
|
|
|
};
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
environment.systemPackages = [ pkgs.fping ];
|
|
|
|
users.users.${cfg.user} = {
|
|
|
|
isNormalUser = false;
|
|
|
|
isSystemUser = true;
|
2021-09-18 10:52:07 +00:00
|
|
|
group = cfg.user;
|
2020-04-24 23:36:52 +00:00
|
|
|
description = "smokeping daemon user";
|
|
|
|
home = smokepingHome;
|
|
|
|
createHome = true;
|
2022-10-30 15:09:59 +00:00
|
|
|
# When `cfg.webService` is enabled, `thttpd` makes SmokePing available
|
|
|
|
# under `${cfg.host}:${cfg.port}/smokeping.fcgi` as per the `ln -s` below.
|
|
|
|
# We also want that going to `${cfg.host}:${cfg.port}` without `smokeping.fcgi`
|
|
|
|
# makes it easy for the user to find SmokePing.
|
|
|
|
# However `thttpd` does not seem to support easy redirections from `/` to `smokeping.fcgi`
|
|
|
|
# and only allows directory listings or `/` -> `index.html` resolution if the directory
|
|
|
|
# has `chmod 755` (see https://acme.com/software/thttpd/thttpd_man.html#PERMISSIONS,
|
|
|
|
# " directories should be 755 if you want to allow indexing").
|
|
|
|
# Otherwise it shows `403 Forbidden` on `/`.
|
|
|
|
# Thus, we need to make `smokepingHome` (which is given to `thttpd -d` below) `755`.
|
|
|
|
homeMode = "755";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
2021-09-18 10:52:07 +00:00
|
|
|
users.groups.${cfg.user} = {};
|
2020-04-24 23:36:52 +00:00
|
|
|
systemd.services.smokeping = {
|
2021-12-06 16:07:01 +00:00
|
|
|
requiredBy = [ "multi-user.target"];
|
2020-04-24 23:36:52 +00:00
|
|
|
serviceConfig = {
|
|
|
|
User = cfg.user;
|
|
|
|
Restart = "on-failure";
|
2021-12-06 16:07:01 +00:00
|
|
|
ExecStart = "${cfg.package}/bin/smokeping --config=${configPath} --nodaemon";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
preStart = ''
|
|
|
|
mkdir -m 0755 -p ${smokepingHome}/cache ${smokepingHome}/data
|
|
|
|
rm -f ${smokepingHome}/cropper
|
|
|
|
ln -s ${cfg.package}/htdocs/cropper ${smokepingHome}/cropper
|
|
|
|
rm -f ${smokepingHome}/smokeping.fcgi
|
|
|
|
ln -s ${cgiHome} ${smokepingHome}/smokeping.fcgi
|
|
|
|
${cfg.package}/bin/smokeping --check --config=${configPath}
|
|
|
|
${cfg.package}/bin/smokeping --static --config=${configPath}
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
systemd.services.thttpd = mkIf cfg.webService {
|
2021-12-06 16:07:01 +00:00
|
|
|
requiredBy = [ "multi-user.target"];
|
2020-04-24 23:36:52 +00:00
|
|
|
requires = [ "smokeping.service"];
|
|
|
|
path = with pkgs; [ bash rrdtool smokeping thttpd ];
|
2021-12-06 16:07:01 +00:00
|
|
|
serviceConfig = {
|
|
|
|
Restart = "always";
|
|
|
|
ExecStart = lib.concatStringsSep " " (lib.concatLists [
|
|
|
|
[ "${pkgs.thttpd}/bin/thttpd" ]
|
|
|
|
[ "-u ${cfg.user}" ]
|
|
|
|
[ ''-c "**.fcgi"'' ]
|
|
|
|
[ "-d ${smokepingHome}" ]
|
|
|
|
(lib.optional (cfg.host != null) "-h ${cfg.host}")
|
|
|
|
[ "-p ${builtins.toString cfg.port}" ]
|
|
|
|
[ "-D -nos" ]
|
|
|
|
]);
|
|
|
|
};
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2021-12-06 16:07:01 +00:00
|
|
|
meta.maintainers = with lib.maintainers; [
|
|
|
|
erictapen
|
|
|
|
nh2
|
|
|
|
];
|
2020-04-24 23:36:52 +00:00
|
|
|
}
|
|
|
|
|