at 25.11-pre 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/misc/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 { 404 # basic configs 405 "user" = cfg.user; 406 "own_hostname" = cfg.hostname; 407 "base_url" = lib.mkDefault "/"; 408 "auth_mechanism" = lib.mkDefault "mysql"; 409 410 # disable auto update function (won't work with NixOS) 411 "update" = false; 412 413 # enable fast ping by default 414 "ping_rrd_step" = 60; 415 416 # set default memory limit to 1G 417 "php_memory_limit" = lib.mkDefault 1024; 418 419 # one minute polling 420 "rrd.step" = if cfg.enableOneMinutePolling then 60 else 300; 421 "rrd.heartbeat" = if cfg.enableOneMinutePolling then 120 else 600; 422 } 423 // (lib.optionalAttrs cfg.distributedPoller.enable { 424 "distributed_poller" = true; 425 "distributed_poller_name" = lib.mkIf ( 426 cfg.distributedPoller.name != null 427 ) cfg.distributedPoller.name; 428 "distributed_poller_group" = cfg.distributedPoller.group; 429 "distributed_billing" = cfg.distributedPoller.distributedBilling; 430 "distributed_poller_memcached_host" = cfg.distributedPoller.memcachedHost; 431 "distributed_poller_memcached_port" = cfg.distributedPoller.memcachedPort; 432 "rrdcached" = 433 "${cfg.distributedPoller.rrdcachedHost}:${toString cfg.distributedPoller.rrdcachedPort}"; 434 }) 435 // (lib.optionalAttrs cfg.useDistributedPollers { 436 "distributed_poller" = true; 437 # still enable a local poller with distributed polling 438 "distributed_poller_group" = lib.mkDefault "0"; 439 "distributed_billing" = lib.mkDefault true; 440 "distributed_poller_memcached_host" = "localhost"; 441 "distributed_poller_memcached_port" = 11211; 442 "rrdcached" = "localhost:42217"; 443 }); 444 445 services.memcached = lib.mkIf cfg.useDistributedPollers { 446 enable = true; 447 listen = "0.0.0.0"; 448 }; 449 450 systemd.services.rrdcached = lib.mkIf cfg.useDistributedPollers { 451 description = "rrdcached"; 452 after = [ "librenms-setup.service" ]; 453 wantedBy = [ "multi-user.target" ]; 454 serviceConfig = { 455 Type = "forking"; 456 User = cfg.user; 457 Group = cfg.group; 458 LimitNOFILE = 16384; 459 RuntimeDirectory = "rrdcached"; 460 PidFile = "/run/rrdcached/rrdcached.pid"; 461 # rrdcached params from https://docs.librenms.org/Extensions/Distributed-Poller/#config-sample 462 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"; 463 }; 464 }; 465 466 services.mysql = lib.mkIf cfg.database.createLocally { 467 enable = true; 468 package = lib.mkDefault pkgs.mariadb; 469 settings.mysqld = 470 { 471 innodb_file_per_table = 1; 472 lower_case_table_names = 0; 473 } 474 // (lib.optionalAttrs cfg.useDistributedPollers { 475 bind-address = "0.0.0.0"; 476 }); 477 ensureDatabases = [ cfg.database.database ]; 478 ensureUsers = [ 479 { 480 name = cfg.database.username; 481 ensurePermissions = { 482 "${cfg.database.database}.*" = "ALL PRIVILEGES"; 483 }; 484 } 485 ]; 486 initialScript = lib.mkIf cfg.useDistributedPollers ( 487 pkgs.writeText "mysql-librenms-init" '' 488 CREATE USER IF NOT EXISTS '${cfg.database.username}'@'%'; 489 GRANT ALL PRIVILEGES ON ${cfg.database.database}.* TO '${cfg.database.username}'@'%'; 490 '' 491 ); 492 }; 493 494 services.nginx = lib.mkIf (!cfg.distributedPoller.enable) { 495 enable = true; 496 virtualHosts."${cfg.hostname}" = lib.mkMerge [ 497 cfg.nginx 498 { 499 root = lib.mkForce "${package}/html"; 500 locations."/" = { 501 index = "index.php"; 502 tryFiles = "$uri $uri/ /index.php?$query_string"; 503 }; 504 locations."~ .php$".extraConfig = '' 505 fastcgi_pass unix:${config.services.phpfpm.pools."librenms".socket}; 506 fastcgi_split_path_info ^(.+\.php)(/.+)$; 507 ''; 508 } 509 ]; 510 }; 511 512 services.phpfpm.pools.librenms = lib.mkIf (!cfg.distributedPoller.enable) { 513 user = cfg.user; 514 group = cfg.group; 515 inherit (package) phpPackage; 516 inherit phpOptions; 517 settings = { 518 "listen.mode" = "0660"; 519 "listen.owner" = config.services.nginx.user; 520 "listen.group" = config.services.nginx.group; 521 } // cfg.poolConfig; 522 }; 523 524 systemd.services.librenms-scheduler = { 525 description = "LibreNMS Scheduler"; 526 path = [ pkgs.unixtools.whereis ]; 527 serviceConfig = { 528 Type = "oneshot"; 529 WorkingDirectory = package; 530 User = cfg.user; 531 Group = cfg.group; 532 ExecStart = "${artisanWrapper}/bin/librenms-artisan schedule:run"; 533 }; 534 }; 535 536 systemd.timers.librenms-scheduler = { 537 description = "LibreNMS Scheduler"; 538 wantedBy = [ "timers.target" ]; 539 timerConfig = { 540 OnCalendar = "minutely"; 541 AccuracySec = "1second"; 542 }; 543 }; 544 545 systemd.services.librenms-setup = { 546 description = "Preparation tasks for LibreNMS"; 547 before = [ "phpfpm-librenms.service" ]; 548 after = [ 549 "systemd-tmpfiles-setup.service" 550 "network.target" 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 '' 592 set -euo pipefail 593 594 # config setup 595 ln -sf ${configFile} ${cfg.dataDir}/config.php 596 ${pkgs.envsubst}/bin/envsubst -i ${configJson} -o ${cfg.dataDir}/config.json 597 export PHPRC=${phpIni} 598 599 INIT=false 600 if [[ ! -s ${cfg.dataDir}/.env ]]; then 601 INIT=true 602 # init .env file 603 echo "APP_KEY=" > ${cfg.dataDir}/.env 604 ${artisanWrapper}/bin/librenms-artisan key:generate --ansi 605 ${artisanWrapper}/bin/librenms-artisan webpush:vapid 606 echo "" >> ${cfg.dataDir}/.env 607 echo -n "NODE_ID=" >> ${cfg.dataDir}/.env 608 ${package.phpPackage}/bin/php -r "echo uniqid();" >> ${cfg.dataDir}/.env 609 echo "" >> ${cfg.dataDir}/.env 610 else 611 # .env file already exists --> only update database and cache config 612 ${pkgs.gnused}/bin/sed -i /^DB_/d ${cfg.dataDir}/.env 613 ${pkgs.gnused}/bin/sed -i /^CACHE_DRIVER/d ${cfg.dataDir}/.env 614 fi 615 ${lib.optionalString (cfg.useDistributedPollers || cfg.distributedPoller.enable) '' 616 echo "CACHE_DRIVER=memcached" >> ${cfg.dataDir}/.env 617 ''} 618 echo "DB_DATABASE=${cfg.database.database}" >> ${cfg.dataDir}/.env 619 '' 620 + ( 621 if !isNull cfg.database.socket then 622 '' 623 # use socket connection 624 echo "DB_SOCKET=${cfg.database.socket}" >> ${cfg.dataDir}/.env 625 echo "DB_PASSWORD=null" >> ${cfg.dataDir}/.env 626 '' 627 else 628 '' 629 # use TCP connection 630 echo "DB_HOST=${cfg.database.host}" >> ${cfg.dataDir}/.env 631 echo "DB_PORT=${toString cfg.database.port}" >> ${cfg.dataDir}/.env 632 echo "DB_USERNAME=${cfg.database.username}" >> ${cfg.dataDir}/.env 633 echo -n "DB_PASSWORD=" >> ${cfg.dataDir}/.env 634 cat ${cfg.database.passwordFile} >> ${cfg.dataDir}/.env 635 '' 636 ) 637 + '' 638 # clear cache if package has changed (cache may contain cached paths 639 # to the old package) 640 OLD_PACKAGE=$(cat ${cfg.dataDir}/package) 641 if [[ $OLD_PACKAGE != "${package}" ]]; then 642 rm -r ${cfg.dataDir}/cache/* 643 fi 644 645 # convert rrd files when the oneMinutePolling option is changed 646 OLD_ENABLED=$(cat ${cfg.dataDir}/one_minute_enabled) 647 if [[ $OLD_ENABLED != "${lib.boolToString cfg.enableOneMinutePolling}" ]]; then 648 ${package}/scripts/rrdstep.php -h all 649 echo "${lib.boolToString cfg.enableOneMinutePolling}" > ${cfg.dataDir}/one_minute_enabled 650 fi 651 652 # migrate db if package version has changed 653 # not necessary for every package change 654 OLD_VERSION=$(cat ${cfg.dataDir}/version) 655 if [[ $OLD_VERSION != "${package.version}" ]]; then 656 ${artisanWrapper}/bin/librenms-artisan migrate --force --no-interaction 657 echo "${package.version}" > ${cfg.dataDir}/version 658 fi 659 660 if [[ $INIT == "true" ]]; then 661 ${artisanWrapper}/bin/librenms-artisan db:seed --force --no-interaction 662 fi 663 664 # regenerate cache if package has changed 665 if [[ $OLD_PACKAGE != "${package}" ]]; then 666 ${artisanWrapper}/bin/librenms-artisan view:clear 667 ${artisanWrapper}/bin/librenms-artisan optimize:clear 668 ${artisanWrapper}/bin/librenms-artisan view:cache 669 ${artisanWrapper}/bin/librenms-artisan optimize 670 echo "${package}" > ${cfg.dataDir}/package 671 fi 672 ''; 673 }; 674 675 programs.mtr.enable = true; 676 677 services.logrotate = { 678 enable = true; 679 settings."${cfg.logDir}/librenms.log" = { 680 su = "${cfg.user} ${cfg.group}"; 681 create = "0640 ${cfg.user} ${cfg.group}"; 682 rotate = 6; 683 frequency = "weekly"; 684 compress = true; 685 delaycompress = true; 686 missingok = true; 687 notifempty = true; 688 }; 689 }; 690 691 services.cron = { 692 enable = true; 693 systemCronJobs = 694 let 695 env = "PHPRC=${phpIni}"; 696 in 697 [ 698 # based on crontab provided by LibreNMS 699 "33 */6 * * * ${cfg.user} ${env} ${package}/cronic ${package}/discovery-wrapper.py 1" 700 "*/5 * * * * ${cfg.user} ${env} ${package}/discovery.php -h new >> /dev/null 2>&1" 701 702 "${ 703 if cfg.enableOneMinutePolling then "*" else "*/5" 704 } * * * * ${cfg.user} ${env} ${package}/cronic ${package}/poller-wrapper.py ${toString cfg.pollerThreads}" 705 "* * * * * ${cfg.user} ${env} ${package}/alerts.php >> /dev/null 2>&1" 706 707 "*/5 * * * * ${cfg.user} ${env} ${package}/check-services.php >> /dev/null 2>&1" 708 709 # extra: fast ping 710 "* * * * * ${cfg.user} ${env} ${package}/ping.php >> /dev/null 2>&1" 711 712 # daily.sh tasks are split to exclude update 713 "19 0 * * * ${cfg.user} ${env} ${package}/daily.sh cleanup >> /dev/null 2>&1" 714 "19 0 * * * ${cfg.user} ${env} ${package}/daily.sh notifications >> /dev/null 2>&1" 715 "19 0 * * * ${cfg.user} ${env} ${package}/daily.sh peeringdb >> /dev/null 2>&1" 716 "19 0 * * * ${cfg.user} ${env} ${package}/daily.sh mac_oui >> /dev/null 2>&1" 717 ] 718 ++ lib.optionals cfg.enableLocalBilling [ 719 "*/5 * * * * ${cfg.user} ${env} ${package}/poll-billing.php >> /dev/null 2>&1" 720 "01 * * * * ${cfg.user} ${env} ${package}/billing-calculate.php >> /dev/null 2>&1" 721 ]; 722 }; 723 724 security.wrappers = { 725 fping = { 726 setuid = true; 727 owner = "root"; 728 group = "root"; 729 source = "${pkgs.fping}/bin/fping"; 730 }; 731 }; 732 733 environment.systemPackages = [ 734 artisanWrapper 735 lnmsWrapper 736 ]; 737 738 systemd.tmpfiles.rules = 739 [ 740 "d ${cfg.logDir} 0750 ${cfg.user} ${cfg.group} - -" 741 "f ${cfg.logDir}/librenms.log 0640 ${cfg.user} ${cfg.group} - -" 742 "d ${cfg.dataDir} 0750 ${cfg.user} ${cfg.group} - -" 743 "f ${cfg.dataDir}/.env 0600 ${cfg.user} ${cfg.group} - -" 744 "f ${cfg.dataDir}/version 0600 ${cfg.user} ${cfg.group} - -" 745 "f ${cfg.dataDir}/package 0600 ${cfg.user} ${cfg.group} - -" 746 "f ${cfg.dataDir}/one_minute_enabled 0600 ${cfg.user} ${cfg.group} - -" 747 "f ${cfg.dataDir}/config.json 0600 ${cfg.user} ${cfg.group} - -" 748 "d ${cfg.dataDir}/storage 0700 ${cfg.user} ${cfg.group} - -" 749 "d ${cfg.dataDir}/storage/app 0700 ${cfg.user} ${cfg.group} - -" 750 "d ${cfg.dataDir}/storage/debugbar 0700 ${cfg.user} ${cfg.group} - -" 751 "d ${cfg.dataDir}/storage/framework 0700 ${cfg.user} ${cfg.group} - -" 752 "d ${cfg.dataDir}/storage/framework/cache 0700 ${cfg.user} ${cfg.group} - -" 753 "d ${cfg.dataDir}/storage/framework/sessions 0700 ${cfg.user} ${cfg.group} - -" 754 "d ${cfg.dataDir}/storage/framework/views 0700 ${cfg.user} ${cfg.group} - -" 755 "d ${cfg.dataDir}/storage/logs 0700 ${cfg.user} ${cfg.group} - -" 756 "d ${cfg.dataDir}/rrd 0700 ${cfg.user} ${cfg.group} - -" 757 "d ${cfg.dataDir}/cache 0700 ${cfg.user} ${cfg.group} - -" 758 ] 759 ++ lib.optionals cfg.useDistributedPollers [ 760 "d ${cfg.dataDir}/rrdcached-journal 0700 ${cfg.user} ${cfg.group} - -" 761 ]; 762 763 }; 764 765 meta.maintainers = with lib.maintainers; [ netali ] ++ lib.teams.wdz.members; 766}