at master 26 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 cfg = config.services.librenms; 10 settingsFormat = pkgs.formats.json { }; 11 configJson = settingsFormat.generate "librenms-config.json" cfg.settings; 12 13 package = cfg.package.override { 14 logDir = cfg.logDir; 15 dataDir = cfg.dataDir; 16 }; 17 18 phpOptions = '' 19 log_errors = on 20 post_max_size = 100M 21 upload_max_filesize = 100M 22 memory_limit = ${toString cfg.settings.php_memory_limit}M 23 date.timezone = "${config.time.timeZone}" 24 ''; 25 phpIni = 26 pkgs.runCommand "php.ini" 27 { 28 inherit (package) phpPackage; 29 inherit phpOptions; 30 preferLocalBuild = true; 31 passAsFile = [ "phpOptions" ]; 32 } 33 '' 34 cat $phpPackage/etc/php.ini $phpOptionsPath > $out 35 ''; 36 37 artisanWrapper = pkgs.writeShellScriptBin "librenms-artisan" '' 38 cd ${package} 39 sudo=exec 40 if [[ "$USER" != ${cfg.user} ]]; then 41 sudo='exec /run/wrappers/bin/sudo -u ${cfg.user}' 42 fi 43 $sudo ${package}/artisan "$@" 44 ''; 45 46 lnmsWrapper = pkgs.writeShellScriptBin "lnms" '' 47 cd ${package} 48 sudo=exec 49 if [[ "$USER" != ${cfg.user} ]]; then 50 sudo='exec /run/wrappers/bin/sudo -u ${cfg.user}' 51 fi 52 $sudo ${package}/lnms "$@" 53 ''; 54 55 configFile = pkgs.writeText "config.php" '' 56 <?php 57 $new_config = json_decode(file_get_contents("${cfg.dataDir}/config.json"), true); 58 $config = ($config == null) ? $new_config : array_merge($config, $new_config); 59 60 ${lib.optionalString (cfg.extraConfig != null) cfg.extraConfig} 61 ''; 62 63in 64{ 65 options.services.librenms = with lib; { 66 enable = mkEnableOption "LibreNMS network monitoring system"; 67 68 package = lib.mkPackageOption pkgs "librenms" { }; 69 70 finalPackage = lib.mkOption { 71 type = lib.types.package; 72 readOnly = true; 73 default = package; 74 defaultText = lib.literalExpression "package"; 75 description = '' 76 The final package used by the module. This is the package that has all overrides. 77 ''; 78 }; 79 80 user = mkOption { 81 type = types.str; 82 default = "librenms"; 83 description = '' 84 Name of the LibreNMS user. 85 ''; 86 }; 87 88 group = mkOption { 89 type = types.str; 90 default = "librenms"; 91 description = '' 92 Name of the LibreNMS group. 93 ''; 94 }; 95 96 hostname = mkOption { 97 type = types.str; 98 default = config.networking.fqdnOrHostName; 99 defaultText = literalExpression "config.networking.fqdnOrHostName"; 100 description = '' 101 The hostname to serve LibreNMS on. 102 ''; 103 }; 104 105 pollerThreads = mkOption { 106 type = types.int; 107 default = 16; 108 description = '' 109 Amount of threads of the cron-poller. 110 ''; 111 }; 112 113 enableOneMinutePolling = mkOption { 114 type = types.bool; 115 default = false; 116 description = '' 117 Enables the [1-Minute Polling](https://docs.librenms.org/Support/1-Minute-Polling/). 118 Changing this option will automatically convert your existing rrd files. 119 ''; 120 }; 121 122 enableLocalBilling = mkOption { 123 type = types.bool; 124 default = true; 125 description = '' 126 Enable billing Cron-Jobs on the local instance. Enabled by default, but you may disable it 127 on some nodes within a distributed poller setup. See [the docs](https://docs.librenms.org/Extensions/Distributed-Poller/#discovery) 128 for more informations about billing with distributed pollers. 129 ''; 130 }; 131 132 useDistributedPollers = mkOption { 133 type = types.bool; 134 default = false; 135 description = '' 136 Enables [distributed pollers](https://docs.librenms.org/Extensions/Distributed-Poller/) 137 for this LibreNMS instance. This will enable a local `rrdcached` and `memcached` server. 138 139 To use this feature, make sure to configure your firewall that the distributed pollers 140 can reach the local `mysql`, `rrdcached` and `memcached` ports. 141 ''; 142 }; 143 144 distributedPoller = { 145 enable = mkOption { 146 type = types.bool; 147 default = false; 148 description = '' 149 Configure this LibreNMS instance as a [distributed poller](https://docs.librenms.org/Extensions/Distributed-Poller/). 150 This will disable all web features and just configure the poller features. 151 Use the `mysql` database of your main LibreNMS instance in the database settings. 152 ''; 153 }; 154 155 name = mkOption { 156 type = types.nullOr types.str; 157 default = null; 158 description = '' 159 Custom name of this poller. 160 ''; 161 }; 162 163 group = mkOption { 164 type = types.str; 165 default = "0"; 166 example = "1,2"; 167 description = '' 168 Group(s) of this poller. 169 ''; 170 }; 171 172 distributedBilling = mkOption { 173 type = types.bool; 174 default = false; 175 description = '' 176 Enable distributed billing on this poller. 177 178 Note: according to [the docs](https://docs.librenms.org/Extensions/Distributed-Poller/#discovery), 179 billing should only be calculated on a single node per poller group. You can disable billing on 180 some nodes with the `services.librenms.enableLocalBilling` option. 181 ''; 182 }; 183 184 memcachedHost = mkOption { 185 type = types.str; 186 description = '' 187 Hostname or IP of the `memcached` server. 188 ''; 189 }; 190 191 memcachedPort = mkOption { 192 type = types.port; 193 default = 11211; 194 description = '' 195 Port of the `memcached` server. 196 ''; 197 }; 198 199 rrdcachedHost = mkOption { 200 type = types.str; 201 description = '' 202 Hostname or IP of the `rrdcached` server. 203 ''; 204 }; 205 206 rrdcachedPort = mkOption { 207 type = types.port; 208 default = 42217; 209 description = '' 210 Port of the `memcached` server. 211 ''; 212 }; 213 }; 214 215 poolConfig = mkOption { 216 type = 217 with types; 218 attrsOf (oneOf [ 219 str 220 int 221 bool 222 ]); 223 default = { 224 "pm" = "dynamic"; 225 "pm.max_children" = 32; 226 "pm.start_servers" = 2; 227 "pm.min_spare_servers" = 2; 228 "pm.max_spare_servers" = 4; 229 "pm.max_requests" = 500; 230 }; 231 description = '' 232 Options for the LibreNMS PHP pool. See the documentation on `php-fpm.conf` 233 for details on configuration directives. 234 ''; 235 }; 236 237 nginx = mkOption { 238 type = types.submodule ( 239 recursiveUpdate (import ../web-servers/nginx/vhost-options.nix { inherit config lib; }) { } 240 ); 241 default = { }; 242 example = literalExpression '' 243 { 244 serverAliases = [ 245 "librenms.''${config.networking.domain}" 246 ]; 247 # To enable encryption and let let's encrypt take care of certificate 248 forceSSL = true; 249 enableACME = true; 250 # To set the LibreNMS virtualHost as the default virtualHost; 251 default = true; 252 } 253 ''; 254 description = '' 255 With this option, you can customize the nginx virtualHost settings. 256 ''; 257 }; 258 259 dataDir = mkOption { 260 type = types.path; 261 default = "/var/lib/librenms"; 262 description = '' 263 Path of the LibreNMS state directory. 264 ''; 265 }; 266 267 logDir = mkOption { 268 type = types.path; 269 default = "/var/log/librenms"; 270 description = '' 271 Path of the LibreNMS logging directory. 272 ''; 273 }; 274 275 database = { 276 createLocally = mkOption { 277 type = types.bool; 278 default = false; 279 description = '' 280 Whether to create a local database automatically. 281 ''; 282 }; 283 284 host = mkOption { 285 default = "localhost"; 286 description = '' 287 Hostname or IP of the MySQL/MariaDB server. 288 Ignored if 'socket' is defined. 289 ''; 290 }; 291 292 port = mkOption { 293 type = types.port; 294 default = 3306; 295 description = '' 296 Port of the MySQL/MariaDB server. 297 Ignored if 'socket' is defined. 298 ''; 299 }; 300 301 database = mkOption { 302 type = types.str; 303 default = "librenms"; 304 description = '' 305 Name of the database on the MySQL/MariaDB server. 306 ''; 307 }; 308 309 username = mkOption { 310 type = types.str; 311 default = "librenms"; 312 description = '' 313 Name of the user on the MySQL/MariaDB server. 314 Ignored if 'socket' is defined. 315 ''; 316 }; 317 318 passwordFile = mkOption { 319 type = types.nullOr types.path; 320 default = null; 321 example = "/run/secrets/mysql.pass"; 322 description = '' 323 A file containing the password for the user of the MySQL/MariaDB server. 324 Must be readable for the LibreNMS user. 325 Ignored if 'socket' is defined, mandatory otherwise. 326 ''; 327 }; 328 329 socket = mkOption { 330 type = types.nullOr types.str; 331 default = null; 332 example = "/run/mysqld/mysqld.sock"; 333 description = '' 334 A unix socket to mysql, accessible by the librenms user. 335 Useful when mysql is on the localhost. 336 ''; 337 }; 338 }; 339 340 environmentFile = mkOption { 341 type = types.nullOr types.str; 342 default = null; 343 description = '' 344 File containing env-vars to be substituted into the final config. Useful for secrets. 345 Does not apply to settings defined in `extraConfig`. 346 ''; 347 }; 348 349 settings = mkOption { 350 type = types.submodule { 351 freeformType = settingsFormat.type; 352 options = { }; 353 }; 354 description = '' 355 Attrset of the LibreNMS configuration. 356 See <https://docs.librenms.org/Support/Configuration/> for reference. 357 All possible options are listed [here](https://github.com/librenms/librenms/blob/master/resources/definitions/config_definitions.json). 358 See <https://docs.librenms.org/Extensions/Authentication/> for setting other authentication methods. 359 ''; 360 default = { }; 361 example = { 362 base_url = "/librenms/"; 363 top_devices = true; 364 top_ports = false; 365 }; 366 }; 367 368 extraConfig = mkOption { 369 type = types.nullOr types.str; 370 default = null; 371 description = '' 372 Additional config for LibreNMS that will be appended to the `config.php`. See 373 <https://github.com/librenms/librenms/blob/master/misc/config_definitions.json> 374 for possible options. Useful if you want to use PHP-Functions in your config. 375 ''; 376 }; 377 }; 378 379 config = lib.mkIf cfg.enable { 380 assertions = [ 381 { 382 assertion = config.time.timeZone != null; 383 message = "You must set `time.timeZone` to use the LibreNMS module."; 384 } 385 { 386 assertion = cfg.database.createLocally -> cfg.database.host == "localhost"; 387 message = "The database host must be \"localhost\" if services.librenms.database.createLocally is set to true."; 388 } 389 { 390 assertion = !(cfg.useDistributedPollers && cfg.distributedPoller.enable); 391 message = "The LibreNMS instance can't be a distributed poller and a full instance at the same time."; 392 } 393 ]; 394 395 users.users.${cfg.user} = { 396 group = "${cfg.group}"; 397 isSystemUser = true; 398 }; 399 400 users.groups.${cfg.group} = { }; 401 402 services.librenms.settings = { 403 # basic configs 404 "user" = cfg.user; 405 "own_hostname" = cfg.hostname; 406 "base_url" = lib.mkDefault "/"; 407 "auth_mechanism" = lib.mkDefault "mysql"; 408 409 # disable auto update function (won't work with NixOS) 410 "update" = false; 411 412 # enable fast ping by default 413 "ping_rrd_step" = 60; 414 415 # set default memory limit to 1G 416 "php_memory_limit" = lib.mkDefault 1024; 417 418 # one minute polling 419 "rrd.step" = if cfg.enableOneMinutePolling then 60 else 300; 420 "rrd.heartbeat" = if cfg.enableOneMinutePolling then 120 else 600; 421 } 422 // (lib.optionalAttrs cfg.distributedPoller.enable { 423 "distributed_poller" = true; 424 "distributed_poller_name" = lib.mkIf ( 425 cfg.distributedPoller.name != null 426 ) cfg.distributedPoller.name; 427 "distributed_poller_group" = cfg.distributedPoller.group; 428 "distributed_billing" = cfg.distributedPoller.distributedBilling; 429 "distributed_poller_memcached_host" = cfg.distributedPoller.memcachedHost; 430 "distributed_poller_memcached_port" = cfg.distributedPoller.memcachedPort; 431 "rrdcached" = 432 "${cfg.distributedPoller.rrdcachedHost}:${toString cfg.distributedPoller.rrdcachedPort}"; 433 }) 434 // (lib.optionalAttrs cfg.useDistributedPollers { 435 "distributed_poller" = true; 436 # still enable a local poller with distributed polling 437 "distributed_poller_group" = lib.mkDefault "0"; 438 "distributed_billing" = lib.mkDefault true; 439 "distributed_poller_memcached_host" = "localhost"; 440 "distributed_poller_memcached_port" = 11211; 441 "rrdcached" = "localhost:42217"; 442 }); 443 444 services.memcached = lib.mkIf cfg.useDistributedPollers { 445 enable = true; 446 listen = "0.0.0.0"; 447 }; 448 449 systemd.services.rrdcached = lib.mkIf cfg.useDistributedPollers { 450 description = "rrdcached"; 451 after = [ "librenms-setup.service" ]; 452 wantedBy = [ "multi-user.target" ]; 453 serviceConfig = { 454 Type = "forking"; 455 User = cfg.user; 456 Group = cfg.group; 457 LimitNOFILE = 16384; 458 RuntimeDirectory = "rrdcached"; 459 PidFile = "/run/rrdcached/rrdcached.pid"; 460 # rrdcached params from https://docs.librenms.org/Extensions/Distributed-Poller/#config-sample 461 ExecStart = "${pkgs.rrdtool}/bin/rrdcached -l 0:42217 -R -j ${cfg.dataDir}/rrdcached-journal/ -F -b ${cfg.dataDir}/rrd -B -w 1800 -z 900 -p /run/rrdcached/rrdcached.pid"; 462 }; 463 }; 464 465 services.mysql = lib.mkIf cfg.database.createLocally { 466 enable = true; 467 package = lib.mkDefault pkgs.mariadb; 468 settings.mysqld = { 469 innodb_file_per_table = 1; 470 lower_case_table_names = 0; 471 } 472 // (lib.optionalAttrs cfg.useDistributedPollers { 473 bind-address = "0.0.0.0"; 474 }); 475 ensureDatabases = [ cfg.database.database ]; 476 ensureUsers = [ 477 { 478 name = cfg.database.username; 479 ensurePermissions = { 480 "${cfg.database.database}.*" = "ALL PRIVILEGES"; 481 }; 482 } 483 ]; 484 initialScript = lib.mkIf cfg.useDistributedPollers ( 485 pkgs.writeText "mysql-librenms-init" '' 486 CREATE USER IF NOT EXISTS '${cfg.database.username}'@'%'; 487 GRANT ALL PRIVILEGES ON ${cfg.database.database}.* TO '${cfg.database.username}'@'%'; 488 '' 489 ); 490 }; 491 492 services.nginx = lib.mkIf (!cfg.distributedPoller.enable) { 493 enable = true; 494 virtualHosts."${cfg.hostname}" = lib.mkMerge [ 495 cfg.nginx 496 { 497 root = lib.mkForce "${package}/html"; 498 locations."/" = { 499 index = "index.php"; 500 tryFiles = "$uri $uri/ /index.php?$query_string"; 501 }; 502 locations."~ .php$".extraConfig = '' 503 fastcgi_pass unix:${config.services.phpfpm.pools."librenms".socket}; 504 fastcgi_split_path_info ^(.+\.php)(/.+)$; 505 ''; 506 } 507 ]; 508 }; 509 510 services.phpfpm.pools.librenms = lib.mkIf (!cfg.distributedPoller.enable) { 511 user = cfg.user; 512 group = cfg.group; 513 inherit (package) phpPackage; 514 inherit phpOptions; 515 settings = { 516 "listen.mode" = "0660"; 517 "listen.owner" = config.services.nginx.user; 518 "listen.group" = config.services.nginx.group; 519 } 520 // cfg.poolConfig; 521 }; 522 523 systemd.services.librenms-scheduler = { 524 description = "LibreNMS Scheduler"; 525 path = [ pkgs.unixtools.whereis ]; 526 serviceConfig = { 527 Type = "oneshot"; 528 WorkingDirectory = package; 529 User = cfg.user; 530 Group = cfg.group; 531 ExecStart = "${artisanWrapper}/bin/librenms-artisan schedule:run"; 532 }; 533 }; 534 535 systemd.timers.librenms-scheduler = { 536 description = "LibreNMS Scheduler"; 537 wantedBy = [ "timers.target" ]; 538 timerConfig = { 539 OnCalendar = "minutely"; 540 AccuracySec = "1second"; 541 }; 542 }; 543 544 systemd.services.librenms-setup = { 545 description = "Preparation tasks for LibreNMS"; 546 before = [ "phpfpm-librenms.service" ]; 547 after = [ 548 "systemd-tmpfiles-setup.service" 549 "network.target" 550 ] 551 ++ (lib.optional (cfg.database.host == "localhost") "mysql.service"); 552 wantedBy = [ "multi-user.target" ]; 553 restartTriggers = [ 554 package 555 configFile 556 ]; 557 path = [ 558 pkgs.mariadb 559 pkgs.unixtools.whereis 560 pkgs.gnused 561 ]; 562 serviceConfig = { 563 Type = "oneshot"; 564 RemainAfterExit = true; 565 EnvironmentFile = lib.mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; 566 User = cfg.user; 567 Group = cfg.group; 568 ExecStartPre = lib.mkIf cfg.database.createLocally [ 569 "!${ 570 pkgs.writeShellScript "librenms-db-init" ( 571 if !isNull cfg.database.socket then 572 '' 573 echo "ALTER USER '${cfg.database.username}'@'localhost' IDENTIFIED VIA unix_socket;" | ${pkgs.mariadb}/bin/mysql --socket='${cfg.database.socket}' 574 ${lib.optionalString cfg.useDistributedPollers '' 575 echo "ALTER USER '${cfg.database.username}'@'%' IDENTIFIED VIA unix_socket;" | ${pkgs.mariadb}/bin/mysql --socket='${cfg.database.socket}' 576 ''} 577 '' 578 else 579 '' 580 DB_PASSWORD=$(cat ${cfg.database.passwordFile} | tr -d '\n') 581 echo "ALTER USER '${cfg.database.username}'@'localhost' IDENTIFIED BY '$DB_PASSWORD';" | ${pkgs.mariadb}/bin/mysql 582 ${lib.optionalString cfg.useDistributedPollers '' 583 echo "ALTER USER '${cfg.database.username}'@'%' IDENTIFIED BY '$DB_PASSWORD';" | ${pkgs.mariadb}/bin/mysql 584 ''} 585 '' 586 ) 587 }" 588 ]; 589 }; 590 script = '' 591 set -euo pipefail 592 593 # config setup 594 ln -sf ${configFile} ${cfg.dataDir}/config.php 595 ${pkgs.envsubst}/bin/envsubst -i ${configJson} -o ${cfg.dataDir}/config.json 596 export PHPRC=${phpIni} 597 598 INIT=false 599 if [[ ! -s ${cfg.dataDir}/.env ]]; then 600 INIT=true 601 # init .env file 602 echo "APP_KEY=" > ${cfg.dataDir}/.env 603 ${artisanWrapper}/bin/librenms-artisan key:generate --ansi 604 ${artisanWrapper}/bin/librenms-artisan webpush:vapid 605 echo "" >> ${cfg.dataDir}/.env 606 echo -n "NODE_ID=" >> ${cfg.dataDir}/.env 607 ${package.phpPackage}/bin/php -r "echo uniqid();" >> ${cfg.dataDir}/.env 608 echo "" >> ${cfg.dataDir}/.env 609 else 610 # .env file already exists --> only update database and cache config 611 ${pkgs.gnused}/bin/sed -i /^DB_/d ${cfg.dataDir}/.env 612 ${pkgs.gnused}/bin/sed -i /^CACHE_DRIVER/d ${cfg.dataDir}/.env 613 fi 614 ${lib.optionalString (cfg.useDistributedPollers || cfg.distributedPoller.enable) '' 615 echo "CACHE_DRIVER=memcached" >> ${cfg.dataDir}/.env 616 ''} 617 echo "DB_DATABASE=${cfg.database.database}" >> ${cfg.dataDir}/.env 618 '' 619 + ( 620 if !isNull cfg.database.socket then 621 '' 622 # use socket connection 623 echo "DB_SOCKET=${cfg.database.socket}" >> ${cfg.dataDir}/.env 624 echo "DB_PASSWORD=null" >> ${cfg.dataDir}/.env 625 '' 626 else 627 '' 628 # use TCP connection 629 echo "DB_HOST=${cfg.database.host}" >> ${cfg.dataDir}/.env 630 echo "DB_PORT=${toString cfg.database.port}" >> ${cfg.dataDir}/.env 631 echo "DB_USERNAME=${cfg.database.username}" >> ${cfg.dataDir}/.env 632 echo -n "DB_PASSWORD=" >> ${cfg.dataDir}/.env 633 cat ${cfg.database.passwordFile} >> ${cfg.dataDir}/.env 634 '' 635 ) 636 + '' 637 # clear cache if package has changed (cache may contain cached paths 638 # to the old package) 639 OLD_PACKAGE=$(cat ${cfg.dataDir}/package) 640 if [[ $OLD_PACKAGE != "${package}" ]]; then 641 rm -r ${cfg.dataDir}/cache/* 642 fi 643 644 # convert rrd files when the oneMinutePolling option is changed 645 OLD_ENABLED=$(cat ${cfg.dataDir}/one_minute_enabled) 646 if [[ $OLD_ENABLED != "${lib.boolToString cfg.enableOneMinutePolling}" ]]; then 647 ${package}/scripts/rrdstep.php -h all 648 echo "${lib.boolToString cfg.enableOneMinutePolling}" > ${cfg.dataDir}/one_minute_enabled 649 fi 650 651 # migrate db if package version has changed 652 # not necessary for every package change 653 OLD_VERSION=$(cat ${cfg.dataDir}/version) 654 if [[ $OLD_VERSION != "${package.version}" ]]; then 655 ${artisanWrapper}/bin/librenms-artisan migrate --force --no-interaction 656 echo "${package.version}" > ${cfg.dataDir}/version 657 fi 658 659 if [[ $INIT == "true" ]]; then 660 ${artisanWrapper}/bin/librenms-artisan db:seed --force --no-interaction 661 fi 662 663 # regenerate cache if package has changed 664 if [[ $OLD_PACKAGE != "${package}" ]]; then 665 ${artisanWrapper}/bin/librenms-artisan view:clear 666 ${artisanWrapper}/bin/librenms-artisan optimize:clear 667 ${artisanWrapper}/bin/librenms-artisan view:cache 668 ${artisanWrapper}/bin/librenms-artisan optimize 669 echo "${package}" > ${cfg.dataDir}/package 670 fi 671 ''; 672 }; 673 674 programs.mtr.enable = true; 675 676 services.logrotate = { 677 enable = true; 678 settings."${cfg.logDir}/librenms.log" = { 679 su = "${cfg.user} ${cfg.group}"; 680 create = "0640 ${cfg.user} ${cfg.group}"; 681 rotate = 6; 682 frequency = "weekly"; 683 compress = true; 684 delaycompress = true; 685 missingok = true; 686 notifempty = true; 687 }; 688 }; 689 690 services.cron = { 691 enable = true; 692 systemCronJobs = 693 let 694 env = "PHPRC=${phpIni}"; 695 in 696 [ 697 # based on crontab provided by LibreNMS 698 "33 */6 * * * ${cfg.user} ${env} ${package}/cronic ${package}/discovery-wrapper.py 1" 699 "*/5 * * * * ${cfg.user} ${env} ${package}/discovery.php -h new >> /dev/null 2>&1" 700 701 "${ 702 if cfg.enableOneMinutePolling then "*" else "*/5" 703 } * * * * ${cfg.user} ${env} ${package}/cronic ${package}/poller-wrapper.py ${toString cfg.pollerThreads}" 704 "* * * * * ${cfg.user} ${env} ${package}/alerts.php >> /dev/null 2>&1" 705 706 "*/5 * * * * ${cfg.user} ${env} ${package}/check-services.php >> /dev/null 2>&1" 707 708 # extra: fast ping 709 "* * * * * ${cfg.user} ${env} ${package}/ping.php >> /dev/null 2>&1" 710 711 # daily.sh tasks are split to exclude update 712 "19 0 * * * ${cfg.user} ${env} ${package}/daily.sh cleanup >> /dev/null 2>&1" 713 "19 0 * * * ${cfg.user} ${env} ${package}/daily.sh notifications >> /dev/null 2>&1" 714 "19 0 * * * ${cfg.user} ${env} ${package}/daily.sh peeringdb >> /dev/null 2>&1" 715 "19 0 * * * ${cfg.user} ${env} ${package}/daily.sh mac_oui >> /dev/null 2>&1" 716 ] 717 ++ lib.optionals cfg.enableLocalBilling [ 718 "*/5 * * * * ${cfg.user} ${env} ${package}/poll-billing.php >> /dev/null 2>&1" 719 "01 * * * * ${cfg.user} ${env} ${package}/billing-calculate.php >> /dev/null 2>&1" 720 ]; 721 }; 722 723 security.wrappers = { 724 fping = { 725 setuid = true; 726 owner = "root"; 727 group = "root"; 728 source = "${pkgs.fping}/bin/fping"; 729 }; 730 }; 731 732 environment.systemPackages = [ 733 artisanWrapper 734 lnmsWrapper 735 ]; 736 737 systemd.tmpfiles.rules = [ 738 "d ${cfg.logDir} 0750 ${cfg.user} ${cfg.group} - -" 739 "f ${cfg.logDir}/librenms.log 0640 ${cfg.user} ${cfg.group} - -" 740 "d ${cfg.dataDir} 0750 ${cfg.user} ${cfg.group} - -" 741 "f ${cfg.dataDir}/.env 0600 ${cfg.user} ${cfg.group} - -" 742 "f ${cfg.dataDir}/version 0600 ${cfg.user} ${cfg.group} - -" 743 "f ${cfg.dataDir}/package 0600 ${cfg.user} ${cfg.group} - -" 744 "f ${cfg.dataDir}/one_minute_enabled 0600 ${cfg.user} ${cfg.group} - -" 745 "f ${cfg.dataDir}/config.json 0600 ${cfg.user} ${cfg.group} - -" 746 "d ${cfg.dataDir}/storage 0700 ${cfg.user} ${cfg.group} - -" 747 "d ${cfg.dataDir}/storage/app 0700 ${cfg.user} ${cfg.group} - -" 748 "d ${cfg.dataDir}/storage/debugbar 0700 ${cfg.user} ${cfg.group} - -" 749 "d ${cfg.dataDir}/storage/framework 0700 ${cfg.user} ${cfg.group} - -" 750 "d ${cfg.dataDir}/storage/framework/cache 0700 ${cfg.user} ${cfg.group} - -" 751 "d ${cfg.dataDir}/storage/framework/sessions 0700 ${cfg.user} ${cfg.group} - -" 752 "d ${cfg.dataDir}/storage/framework/views 0700 ${cfg.user} ${cfg.group} - -" 753 "d ${cfg.dataDir}/storage/logs 0700 ${cfg.user} ${cfg.group} - -" 754 "d ${cfg.dataDir}/rrd 0700 ${cfg.user} ${cfg.group} - -" 755 "d ${cfg.dataDir}/cache 0700 ${cfg.user} ${cfg.group} - -" 756 ] 757 ++ lib.optionals cfg.useDistributedPollers [ 758 "d ${cfg.dataDir}/rrdcached-journal 0700 ${cfg.user} ${cfg.group} - -" 759 ]; 760 761 }; 762 763 meta.maintainers = with lib.maintainers; [ netali ] ++ lib.teams.wdz.members; 764}