at 23.11-pre 13 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4let 5 6 cfg = config.services.smokeping; 7 smokepingHome = "/var/lib/smokeping"; 8 smokepingPidDir = "/run"; 9 configFile = 10 if cfg.config == null 11 then 12 '' 13 *** General *** 14 cgiurl = ${cfg.cgiUrl} 15 contact = ${cfg.ownerEmail} 16 datadir = ${smokepingHome}/data 17 imgcache = ${smokepingHome}/cache 18 imgurl = ${cfg.imgUrl} 19 linkstyle = ${cfg.linkStyle} 20 ${lib.optionalString (cfg.mailHost != "") "mailhost = ${cfg.mailHost}"} 21 owner = ${cfg.owner} 22 pagedir = ${smokepingHome}/cache 23 piddir = ${smokepingPidDir} 24 ${lib.optionalString (cfg.sendmail != null) "sendmail = ${cfg.sendmail}"} 25 smokemail = ${cfg.smokeMailTemplate} 26 *** Presentation *** 27 template = ${cfg.presentationTemplate} 28 ${cfg.presentationConfig} 29 *** Alerts *** 30 ${cfg.alertConfig} 31 *** Database *** 32 ${cfg.databaseConfig} 33 *** Probes *** 34 ${cfg.probeConfig} 35 *** Targets *** 36 ${cfg.targetConfig} 37 ${cfg.extraConfig} 38 '' 39 else 40 cfg.config; 41 42 configPath = pkgs.writeText "smokeping.conf" configFile; 43 cgiHome = pkgs.writeScript "smokeping.fcgi" '' 44 #!${pkgs.bash}/bin/bash 45 ${cfg.package}/bin/smokeping_cgi /etc/smokeping.conf 46 ''; 47in 48 49{ 50 options = { 51 services.smokeping = { 52 enable = mkEnableOption (lib.mdDoc "smokeping service"); 53 54 alertConfig = mkOption { 55 type = types.lines; 56 default = '' 57 to = root@localhost 58 from = smokeping@localhost 59 ''; 60 example = '' 61 to = alertee@address.somewhere 62 from = smokealert@company.xy 63 64 +someloss 65 type = loss 66 # in percent 67 pattern = >0%,*12*,>0%,*12*,>0% 68 comment = loss 3 times in a row; 69 ''; 70 description = lib.mdDoc "Configuration for alerts."; 71 }; 72 cgiUrl = mkOption { 73 type = types.str; 74 default = "http://${cfg.hostName}:${toString cfg.port}/smokeping.cgi"; 75 defaultText = literalExpression ''"http://''${hostName}:''${toString port}/smokeping.cgi"''; 76 example = "https://somewhere.example.com/smokeping.cgi"; 77 description = lib.mdDoc "URL to the smokeping cgi."; 78 }; 79 config = mkOption { 80 type = types.nullOr types.lines; 81 default = null; 82 description = lib.mdDoc '' 83 Full smokeping config supplied by the user. Overrides 84 and replaces any other configuration supplied. 85 ''; 86 }; 87 databaseConfig = mkOption { 88 type = types.lines; 89 default = '' 90 step = 300 91 pings = 20 92 # consfn mrhb steps total 93 AVERAGE 0.5 1 1008 94 AVERAGE 0.5 12 4320 95 MIN 0.5 12 4320 96 MAX 0.5 12 4320 97 AVERAGE 0.5 144 720 98 MAX 0.5 144 720 99 MIN 0.5 144 720 100 101 ''; 102 example = '' 103 # near constant pings. 104 step = 30 105 pings = 20 106 # consfn mrhb steps total 107 AVERAGE 0.5 1 10080 108 AVERAGE 0.5 12 43200 109 MIN 0.5 12 43200 110 MAX 0.5 12 43200 111 AVERAGE 0.5 144 7200 112 MAX 0.5 144 7200 113 MIN 0.5 144 7200 114 ''; 115 description = lib.mdDoc ''Configure the ping frequency and retention of the rrd files. 116 Once set, changing the interval will require deletion or migration of all 117 the collected data.''; 118 }; 119 extraConfig = mkOption { 120 type = types.lines; 121 default = ""; 122 description = lib.mdDoc "Any additional customization not already included."; 123 }; 124 hostName = mkOption { 125 type = types.str; 126 default = config.networking.fqdn; 127 defaultText = literalExpression "config.networking.fqdn"; 128 example = "somewhere.example.com"; 129 description = lib.mdDoc "DNS name for the urls generated in the cgi."; 130 }; 131 imgUrl = mkOption { 132 type = types.str; 133 default = "cache"; 134 defaultText = literalExpression ''"cache"''; 135 example = "https://somewhere.example.com/cache"; 136 description = lib.mdDoc '' 137 Base url for images generated in the cgi. 138 139 The default is a relative URL to ensure it works also when e.g. forwarding 140 the GUI port via SSH. 141 ''; 142 }; 143 linkStyle = mkOption { 144 type = types.enum ["original" "absolute" "relative"]; 145 default = "relative"; 146 example = "absolute"; 147 description = lib.mdDoc "DNS name for the urls generated in the cgi."; 148 }; 149 mailHost = mkOption { 150 type = types.str; 151 default = ""; 152 example = "localhost"; 153 description = lib.mdDoc "Use this SMTP server to send alerts"; 154 }; 155 owner = mkOption { 156 type = types.str; 157 default = "nobody"; 158 example = "Bob Foobawr"; 159 description = lib.mdDoc "Real name of the owner of the instance"; 160 }; 161 ownerEmail = mkOption { 162 type = types.str; 163 default = "no-reply@${cfg.hostName}"; 164 defaultText = literalExpression ''"no-reply@''${hostName}"''; 165 example = "no-reply@yourdomain.com"; 166 description = lib.mdDoc "Email contact for owner"; 167 }; 168 package = mkOption { 169 type = types.package; 170 default = pkgs.smokeping; 171 defaultText = literalExpression "pkgs.smokeping"; 172 description = lib.mdDoc "Specify a custom smokeping package"; 173 }; 174 host = mkOption { 175 type = types.nullOr types.str; 176 default = "localhost"; 177 example = "192.0.2.1"; # rfc5737 example IP for documentation 178 description = lib.mdDoc '' 179 Host/IP to bind to for the web server. 180 181 Setting it to `null` skips passing the -h option to thttpd, 182 which makes it bind to all interfaces. 183 ''; 184 }; 185 port = mkOption { 186 type = types.port; 187 default = 8081; 188 description = lib.mdDoc "TCP port to use for the web server."; 189 }; 190 presentationConfig = mkOption { 191 type = types.lines; 192 default = '' 193 + charts 194 menu = Charts 195 title = The most interesting destinations 196 ++ stddev 197 sorter = StdDev(entries=>4) 198 title = Top Standard Deviation 199 menu = Std Deviation 200 format = Standard Deviation %f 201 ++ max 202 sorter = Max(entries=>5) 203 title = Top Max Roundtrip Time 204 menu = by Max 205 format = Max Roundtrip Time %f seconds 206 ++ loss 207 sorter = Loss(entries=>5) 208 title = Top Packet Loss 209 menu = Loss 210 format = Packets Lost %f 211 ++ median 212 sorter = Median(entries=>5) 213 title = Top Median Roundtrip Time 214 menu = by Median 215 format = Median RTT %f seconds 216 + overview 217 width = 600 218 height = 50 219 range = 10h 220 + detail 221 width = 600 222 height = 200 223 unison_tolerance = 2 224 "Last 3 Hours" 3h 225 "Last 30 Hours" 30h 226 "Last 10 Days" 10d 227 "Last 360 Days" 360d 228 ''; 229 description = lib.mdDoc "presentation graph style"; 230 }; 231 presentationTemplate = mkOption { 232 type = types.str; 233 default = "${pkgs.smokeping}/etc/basepage.html.dist"; 234 defaultText = literalExpression ''"''${pkgs.smokeping}/etc/basepage.html.dist"''; 235 description = lib.mdDoc "Default page layout for the web UI."; 236 }; 237 probeConfig = mkOption { 238 type = types.lines; 239 default = '' 240 + FPing 241 binary = ${config.security.wrapperDir}/fping 242 ''; 243 defaultText = literalExpression '' 244 ''' 245 + FPing 246 binary = ''${config.security.wrapperDir}/fping 247 ''' 248 ''; 249 description = lib.mdDoc "Probe configuration"; 250 }; 251 sendmail = mkOption { 252 type = types.nullOr types.path; 253 default = null; 254 example = "/run/wrappers/bin/sendmail"; 255 description = lib.mdDoc "Use this sendmail compatible script to deliver alerts"; 256 }; 257 smokeMailTemplate = mkOption { 258 type = types.str; 259 default = "${cfg.package}/etc/smokemail.dist"; 260 defaultText = literalExpression ''"''${package}/etc/smokemail.dist"''; 261 description = lib.mdDoc "Specify the smokemail template for alerts."; 262 }; 263 targetConfig = mkOption { 264 type = types.lines; 265 default = '' 266 probe = FPing 267 menu = Top 268 title = Network Latency Grapher 269 remark = Welcome to the SmokePing website of xxx Company. \ 270 Here you will learn all about the latency of our network. 271 + Local 272 menu = Local 273 title = Local Network 274 ++ LocalMachine 275 menu = Local Machine 276 title = This host 277 host = localhost 278 ''; 279 description = lib.mdDoc "Target configuration"; 280 }; 281 user = mkOption { 282 type = types.str; 283 default = "smokeping"; 284 description = lib.mdDoc "User that runs smokeping and (optionally) thttpd. A group of the same name will be created as well."; 285 }; 286 webService = mkOption { 287 type = types.bool; 288 default = true; 289 description = lib.mdDoc "Enable a smokeping web interface"; 290 }; 291 }; 292 293 }; 294 295 config = mkIf cfg.enable { 296 assertions = [ 297 { 298 assertion = !(cfg.sendmail != null && cfg.mailHost != ""); 299 message = "services.smokeping: sendmail and Mailhost cannot both be enabled."; 300 } 301 ]; 302 security.wrappers = { 303 fping = 304 { setuid = true; 305 owner = "root"; 306 group = "root"; 307 source = "${pkgs.fping}/bin/fping"; 308 }; 309 }; 310 environment.etc."smokeping.conf".source = configPath; 311 environment.systemPackages = [ pkgs.fping ]; 312 users.users.${cfg.user} = { 313 isNormalUser = false; 314 isSystemUser = true; 315 group = cfg.user; 316 description = "smokeping daemon user"; 317 home = smokepingHome; 318 createHome = true; 319 # When `cfg.webService` is enabled, `thttpd` makes SmokePing available 320 # under `${cfg.host}:${cfg.port}/smokeping.fcgi` as per the `ln -s` below. 321 # We also want that going to `${cfg.host}:${cfg.port}` without `smokeping.fcgi` 322 # makes it easy for the user to find SmokePing. 323 # However `thttpd` does not seem to support easy redirections from `/` to `smokeping.fcgi` 324 # and only allows directory listings or `/` -> `index.html` resolution if the directory 325 # has `chmod 755` (see https://acme.com/software/thttpd/thttpd_man.html#PERMISSIONS, 326 # " directories should be 755 if you want to allow indexing"). 327 # Otherwise it shows `403 Forbidden` on `/`. 328 # Thus, we need to make `smokepingHome` (which is given to `thttpd -d` below) `755`. 329 homeMode = "755"; 330 }; 331 users.groups.${cfg.user} = { }; 332 systemd.services.smokeping = { 333 reloadTriggers = [ configPath ]; 334 requiredBy = [ "multi-user.target" ]; 335 serviceConfig = { 336 User = cfg.user; 337 Restart = "on-failure"; 338 ExecStart = "${cfg.package}/bin/smokeping --config=/etc/smokeping.conf --nodaemon"; 339 }; 340 preStart = '' 341 mkdir -m 0755 -p ${smokepingHome}/cache ${smokepingHome}/data 342 ln -sf ${cfg.package}/htdocs/css ${smokepingHome}/css 343 ln -sf ${cfg.package}/htdocs/js ${smokepingHome}/js 344 ln -sf ${cgiHome} ${smokepingHome}/smokeping.fcgi 345 ${cfg.package}/bin/smokeping --check --config=${configPath} 346 ${cfg.package}/bin/smokeping --static --config=${configPath} 347 ''; 348 }; 349 systemd.services.thttpd = mkIf cfg.webService { 350 requiredBy = [ "multi-user.target"]; 351 requires = [ "smokeping.service"]; 352 path = with pkgs; [ bash rrdtool smokeping thttpd ]; 353 serviceConfig = { 354 Restart = "always"; 355 ExecStart = lib.concatStringsSep " " (lib.concatLists [ 356 [ "${pkgs.thttpd}/bin/thttpd" ] 357 [ "-u ${cfg.user}" ] 358 [ ''-c "**.fcgi"'' ] 359 [ "-d ${smokepingHome}" ] 360 (lib.optional (cfg.host != null) "-h ${cfg.host}") 361 [ "-p ${builtins.toString cfg.port}" ] 362 [ "-D -nos" ] 363 ]); 364 }; 365 }; 366 }; 367 368 meta.maintainers = with lib.maintainers; [ 369 erictapen 370 nh2 371 ]; 372} 373