nixos/librenms: init

authored by Jennifer Graul and committed by Yureka e94820df 63288740

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