at 25.11-pre 57 kB view raw
1{ 2 system ? builtins.currentSystem, 3 config ? { }, 4 pkgs ? import ../.. { inherit system config; }, 5}: 6 7let 8 inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest; 9 inherit (pkgs.lib) 10 concatStringsSep 11 maintainers 12 mapAttrs 13 mkMerge 14 removeSuffix 15 replaceStrings 16 singleton 17 splitString 18 makeBinPath 19 ; 20 21 /* 22 * The attrset `exporterTests` contains one attribute 23 * for each exporter test. Each of these attributes 24 * is expected to be an attrset containing: 25 * 26 * `exporterConfig`: 27 * this attribute set contains config for the exporter itself 28 * 29 * `exporterTest` 30 * this attribute set contains test instructions 31 * 32 * `metricProvider` (optional) 33 * this attribute contains additional machine config 34 * 35 * `nodeName` (optional) 36 * override an incompatible testnode name 37 * 38 * Example: 39 * exporterTests.<exporterName> = { 40 * exporterConfig = { 41 * enable = true; 42 * }; 43 * metricProvider = { 44 * services.<metricProvider>.enable = true; 45 * }; 46 * exporterTest = '' 47 * wait_for_unit("prometheus-<exporterName>-exporter.service") 48 * wait_for_open_port(1234) 49 * succeed("curl -sSf 'localhost:1234/metrics'") 50 * ''; 51 * }; 52 * 53 * # this would generate the following test config: 54 * 55 * nodes.<exporterName> = { 56 * services.prometheus.<exporterName> = { 57 * enable = true; 58 * }; 59 * services.<metricProvider>.enable = true; 60 * }; 61 * 62 * testScript = '' 63 * <exporterName>.start() 64 * <exporterName>.wait_for_unit("prometheus-<exporterName>-exporter.service") 65 * <exporterName>.wait_for_open_port(1234) 66 * <exporterName>.succeed("curl -sSf 'localhost:1234/metrics'") 67 * <exporterName>.shutdown() 68 * ''; 69 */ 70 71 exporterTests = { 72 apcupsd = { 73 exporterConfig = { 74 enable = true; 75 }; 76 metricProvider = { 77 services.apcupsd.enable = true; 78 }; 79 exporterTest = '' 80 wait_for_unit("apcupsd.service") 81 wait_for_open_port(3551) 82 wait_for_unit("prometheus-apcupsd-exporter.service") 83 wait_for_open_port(9162) 84 succeed("curl -sSf http://localhost:9162/metrics | grep 'apcupsd_info'") 85 ''; 86 }; 87 88 artifactory = { 89 exporterConfig = { 90 enable = true; 91 artiUsername = "artifactory-username"; 92 artiPassword = "artifactory-password"; 93 }; 94 exporterTest = '' 95 wait_for_unit("prometheus-artifactory-exporter.service") 96 wait_for_open_port(9531) 97 succeed( 98 "curl -sSf http://localhost:9531/metrics | grep 'artifactory_up'" 99 ) 100 ''; 101 }; 102 103 bind = { 104 exporterConfig = { 105 enable = true; 106 }; 107 metricProvider = { 108 services.bind.enable = true; 109 services.bind.extraConfig = '' 110 statistics-channels { 111 inet 127.0.0.1 port 8053 allow { localhost; }; 112 }; 113 ''; 114 }; 115 exporterTest = '' 116 wait_for_unit("prometheus-bind-exporter.service") 117 wait_for_open_port(9119) 118 succeed( 119 "curl -sSf http://localhost:9119/metrics | grep 'bind_query_recursions_total 0'" 120 ) 121 ''; 122 }; 123 124 bird = { 125 exporterConfig = { 126 enable = true; 127 }; 128 metricProvider = { 129 services.bird.enable = true; 130 services.bird.config = '' 131 router id 127.0.0.1; 132 133 protocol kernel MyObviousTestString { 134 ipv4 { 135 import all; 136 export none; 137 }; 138 } 139 140 protocol device { 141 } 142 ''; 143 }; 144 exporterTest = '' 145 wait_for_unit("prometheus-bird-exporter.service") 146 wait_for_open_port(9324) 147 wait_until_succeeds( 148 "curl -sSf http://localhost:9324/metrics | grep 'MyObviousTestString'" 149 ) 150 ''; 151 }; 152 153 bitcoin = { 154 exporterConfig = { 155 enable = true; 156 rpcUser = "bitcoinrpc"; 157 rpcPasswordFile = pkgs.writeText "password" "hunter2"; 158 }; 159 metricProvider = { 160 services.bitcoind.default.enable = true; 161 services.bitcoind.default.rpc.users.bitcoinrpc.passwordHMAC = 162 "e8fe33f797e698ac258c16c8d7aadfbe$872bdb8f4d787367c26bcfd75e6c23c4f19d44a69f5d1ad329e5adf3f82710f7"; 163 }; 164 exporterTest = '' 165 wait_for_unit("prometheus-bitcoin-exporter.service") 166 wait_for_unit("bitcoind-default.service") 167 wait_for_open_port(9332) 168 succeed("curl -sSf http://localhost:9332/metrics | grep '^bitcoin_blocks '") 169 ''; 170 }; 171 172 blackbox = { 173 exporterConfig = { 174 enable = true; 175 configFile = pkgs.writeText "config.yml" ( 176 builtins.toJSON { 177 modules.icmp_v6 = { 178 prober = "icmp"; 179 icmp.preferred_ip_protocol = "ip6"; 180 }; 181 } 182 ); 183 }; 184 exporterTest = '' 185 wait_for_unit("prometheus-blackbox-exporter.service") 186 wait_for_open_port(9115) 187 succeed( 188 "curl -sSf 'http://localhost:9115/probe?target=localhost&module=icmp_v6' | grep 'probe_success 1'" 189 ) 190 ''; 191 }; 192 193 borgmatic = { 194 exporterConfig = { 195 enable = true; 196 user = "root"; 197 }; 198 metricProvider = { 199 services.borgmatic.enable = true; 200 services.borgmatic.settings.source_directories = [ "/home" ]; 201 services.borgmatic.settings.repositories = [ 202 { 203 label = "local"; 204 path = "/var/backup"; 205 } 206 ]; 207 services.borgmatic.settings.keep_daily = 10; 208 }; 209 exporterTest = '' 210 succeed("borgmatic rcreate -e none") 211 succeed("borgmatic") 212 wait_for_unit("prometheus-borgmatic-exporter.service") 213 wait_for_open_port(9996) 214 succeed("curl -sSf localhost:9996/metrics | grep 'borg_total_backups{repository=\"/var/backup\"} 1'") 215 ''; 216 }; 217 218 collectd = { 219 exporterConfig = { 220 enable = true; 221 extraFlags = [ "--web.collectd-push-path /collectd" ]; 222 }; 223 exporterTest = 224 let 225 postData = replaceStrings [ "\n" ] [ "" ] '' 226 [{ 227 "values":[23], 228 "dstypes":["gauge"], 229 "type":"gauge", 230 "interval":1000, 231 "host":"testhost", 232 "plugin":"testplugin", 233 "time":DATE 234 }] 235 ''; 236 in 237 '' 238 wait_for_unit("prometheus-collectd-exporter.service") 239 wait_for_open_port(9103) 240 succeed( 241 'echo \'${postData}\'> /tmp/data.json' 242 ) 243 succeed('sed -i -e "s DATE $(date +%s) " /tmp/data.json') 244 succeed( 245 "curl -sSfH 'Content-Type: application/json' -X POST --data @/tmp/data.json localhost:9103/collectd" 246 ) 247 succeed( 248 "curl -sSf localhost:9103/metrics | grep 'collectd_testplugin_gauge{instance=\"testhost\"} 23'" 249 ) 250 ''; 251 }; 252 253 deluge = { 254 exporterConfig = { 255 enable = true; 256 port = 1234; 257 listenAddress = "127.0.0.1"; 258 259 delugeUser = "user"; 260 delugePort = 2345; 261 delugePasswordFile = pkgs.writeText "password" "weak_password"; 262 }; 263 metricProvider = { 264 services.deluge.enable = true; 265 services.deluge.declarative = true; 266 services.deluge.config.daemon_port = 2345; 267 services.deluge.authFile = pkgs.writeText "authFile" '' 268 localclient:abcdef:10 269 user:weak_password:10 270 ''; 271 }; 272 exporterTest = '' 273 wait_for_unit("deluged.service") 274 wait_for_open_port(2345) 275 wait_for_unit("prometheus-deluge-exporter.service") 276 wait_for_open_port(1234) 277 succeed("curl -sSf http://localhost:1234 | grep 'deluge_torrents'") 278 ''; 279 }; 280 281 dnsmasq = { 282 exporterConfig = { 283 enable = true; 284 leasesPath = "/var/lib/dnsmasq/dnsmasq.leases"; 285 }; 286 metricProvider = { 287 services.dnsmasq.enable = true; 288 }; 289 exporterTest = '' 290 wait_for_unit("dnsmasq.service") 291 wait_for_open_port(53) 292 wait_for_file("/var/lib/dnsmasq/dnsmasq.leases") 293 wait_for_unit("prometheus-dnsmasq-exporter.service") 294 wait_for_open_port(9153) 295 succeed("curl -sSf http://localhost:9153/metrics | grep 'dnsmasq_leases 0'") 296 ''; 297 }; 298 299 dnssec = { 300 exporterConfig = { 301 enable = true; 302 configuration = { 303 records = [ 304 { 305 zone = "example.com"; 306 record = "@"; 307 type = "SOA"; 308 } 309 ]; 310 }; 311 resolvers = [ "127.0.0.1:53" ]; 312 }; 313 metricProvider = { 314 services.knot = { 315 enable = true; 316 settingsFile = pkgs.writeText "knot.conf" '' 317 server: 318 listen: 127.0.0.1@53 319 template: 320 - id: default 321 storage: ${ 322 pkgs.buildEnv { 323 name = "zones"; 324 paths = [ 325 (pkgs.writeTextDir "example.com.zone" '' 326 @ SOA ns1.example.com. noc.example.com. 2024032401 86400 7200 3600000 172800 327 @ NS ns1 328 ns1 A 192.168.0.1 329 '') 330 ]; 331 } 332 } 333 zonefile-load: difference 334 zonefile-sync: -1 335 zone: 336 - domain: example.com 337 file: example.com.zone 338 dnssec-signing: on 339 ''; 340 }; 341 }; 342 exporterTest = '' 343 wait_for_unit("knot.service") 344 wait_for_open_port(53) 345 wait_for_unit("prometheus-dnssec-exporter.service") 346 wait_for_open_port(9204) 347 succeed("curl -sSf http://localhost:9204/metrics | grep 'example.com'") 348 ''; 349 }; 350 351 # Access to WHOIS server is required to properly test this exporter, so 352 # just perform basic sanity check that the exporter is running and returns 353 # a failure. 354 domain = { 355 exporterConfig = { 356 enable = true; 357 }; 358 exporterTest = '' 359 wait_for_unit("prometheus-domain-exporter.service") 360 wait_for_open_port(9222) 361 succeed("curl -sSf 'http://localhost:9222/probe?target=nixos.org'") 362 ''; 363 }; 364 365 dovecot = { 366 exporterConfig = { 367 enable = true; 368 scopes = [ "global" ]; 369 socketPath = "/var/run/dovecot2/old-stats"; 370 user = "root"; # <- don't use user root in production 371 }; 372 metricProvider = { 373 services.dovecot2.enable = true; 374 }; 375 exporterTest = '' 376 wait_for_unit("prometheus-dovecot-exporter.service") 377 wait_for_open_port(9166) 378 succeed( 379 "curl -sSf http://localhost:9166/metrics | grep 'dovecot_up{scope=\"global\"} 1'" 380 ) 381 ''; 382 }; 383 384 exportarr-sonarr = 385 let 386 apikey = "eccff6a992bc2e4b88e46d064b26bb4e"; 387 in 388 { 389 nodeName = "exportarr_sonarr"; 390 exporterConfig = { 391 enable = true; 392 url = "http://127.0.0.1:8989"; 393 apiKeyFile = pkgs.writeText "dummy-api-key" apikey; 394 }; 395 metricProvider = { 396 services.sonarr = { 397 enable = true; 398 environmentFiles = [ (pkgs.writeText "sonarr-env" "SONARR__AUTH__APIKEY=${apikey}") ]; 399 }; 400 }; 401 exporterTest = '' 402 wait_for_unit("sonarr.service") 403 wait_for_open_port(8989) 404 wait_for_unit("prometheus-exportarr-sonarr-exporter.service") 405 wait_for_open_port(9708) 406 succeed("curl -sSf http://localhost:9708/metrics | grep sonarr_series_total") 407 ''; 408 }; 409 410 ebpf = { 411 exporterConfig = { 412 enable = true; 413 names = [ "timers" ]; 414 }; 415 exporterTest = '' 416 wait_for_unit("prometheus-ebpf-exporter.service") 417 wait_for_open_port(9435) 418 succeed( 419 "curl -sSf http://localhost:9435/metrics | grep 'ebpf_exporter_enabled_configs{name=\"timers\"} 1'" 420 ) 421 ''; 422 }; 423 424 fastly = { 425 exporterConfig = { 426 enable = true; 427 environmentFile = pkgs.writeText "fastly-exporter-env" "FASTLY_API_TOKEN=abc123"; 428 }; 429 430 exporterTest = '' 431 wait_for_unit("prometheus-fastly-exporter.service") 432 wait_for_open_port(9118) 433 ''; 434 }; 435 436 fritzbox = { 437 # TODO add proper test case 438 exporterConfig = { 439 enable = true; 440 }; 441 exporterTest = '' 442 wait_for_unit("prometheus-fritzbox-exporter.service") 443 wait_for_open_port(9133) 444 succeed( 445 "curl -sSf http://localhost:9133/metrics | grep 'fritzbox_exporter_collect_errors 0'" 446 ) 447 ''; 448 }; 449 450 graphite = { 451 exporterConfig = { 452 enable = true; 453 port = 9108; 454 graphitePort = 9109; 455 mappingSettings.mappings = [ 456 { 457 match = "test.*.*"; 458 name = "testing"; 459 labels = { 460 protocol = "$1"; 461 author = "$2"; 462 }; 463 } 464 ]; 465 }; 466 exporterTest = '' 467 wait_for_unit("prometheus-graphite-exporter.service") 468 wait_for_open_port(9108) 469 wait_for_open_port(9109) 470 succeed("echo test.tcp.foo-bar 1234 $(date +%s) | nc -w1 localhost 9109") 471 succeed("curl -sSf http://localhost:9108/metrics | grep 'testing{author=\"foo-bar\",protocol=\"tcp\"} 1234'") 472 ''; 473 }; 474 475 idrac = { 476 exporterConfig = { 477 enable = true; 478 port = 9348; 479 configuration = { 480 hosts = { 481 default = { 482 username = "username"; 483 password = "password"; 484 }; 485 }; 486 }; 487 }; 488 exporterTest = '' 489 wait_for_unit("prometheus-idrac-exporter.service") 490 wait_for_open_port(9348) 491 wait_until_succeeds("curl localhost:9348") 492 ''; 493 }; 494 495 influxdb = { 496 exporterConfig = { 497 enable = true; 498 sampleExpiry = "3s"; 499 }; 500 exporterTest = '' 501 wait_for_unit("prometheus-influxdb-exporter.service") 502 wait_for_open_port(9122) 503 succeed( 504 "curl -XPOST http://localhost:9122/write --data-binary 'influxdb_exporter,distro=nixos,added_in=21.09 value=1'" 505 ) 506 succeed( 507 "curl -sSf http://localhost:9122/metrics | grep 'nixos'" 508 ) 509 execute("sleep 5") 510 fail( 511 "curl -sSf http://localhost:9122/metrics | grep 'nixos'" 512 ) 513 ''; 514 }; 515 516 ipmi = { 517 exporterConfig = { 518 enable = true; 519 }; 520 exporterTest = '' 521 wait_for_unit("prometheus-ipmi-exporter.service") 522 wait_for_open_port(9290) 523 succeed( 524 "curl -sSf http://localhost:9290/metrics | grep 'ipmi_scrape_duration_seconds'" 525 ) 526 ''; 527 }; 528 529 jitsi = { 530 exporterConfig = { 531 enable = true; 532 }; 533 metricProvider = { 534 systemd.services.prometheus-jitsi-exporter.after = [ "jitsi-videobridge2.service" ]; 535 services.jitsi-videobridge = { 536 enable = true; 537 colibriRestApi = true; 538 }; 539 }; 540 exporterTest = '' 541 wait_for_unit("jitsi-videobridge2.service") 542 wait_for_open_port(8080) 543 wait_for_unit("prometheus-jitsi-exporter.service") 544 wait_for_open_port(9700) 545 wait_until_succeeds( 546 'journalctl -eu prometheus-jitsi-exporter.service -o cat | grep "key=participants"' 547 ) 548 succeed("curl -sSf 'localhost:9700/metrics' | grep 'jitsi_participants 0'") 549 ''; 550 }; 551 552 json = { 553 exporterConfig = { 554 enable = true; 555 configFile = pkgs.writeText "json-exporter-conf.json" ( 556 builtins.toJSON { 557 modules = { 558 default = { 559 metrics = [ 560 { 561 name = "json_test_metric"; 562 path = "{ .test }"; 563 } 564 ]; 565 }; 566 }; 567 } 568 ); 569 }; 570 metricProvider = { 571 systemd.services.prometheus-json-exporter.after = [ "nginx.service" ]; 572 services.nginx = { 573 enable = true; 574 virtualHosts.localhost.locations."/".extraConfig = '' 575 return 200 "{\"test\":1}"; 576 ''; 577 }; 578 }; 579 exporterTest = '' 580 wait_for_unit("nginx.service") 581 wait_for_open_port(80) 582 wait_for_unit("prometheus-json-exporter.service") 583 wait_for_open_port(7979) 584 succeed( 585 "curl -sSf 'localhost:7979/probe?target=http://localhost' | grep 'json_test_metric 1'" 586 ) 587 ''; 588 }; 589 590 knot = { 591 exporterConfig = { 592 enable = true; 593 }; 594 metricProvider = { 595 services.knot = { 596 enable = true; 597 extraArgs = [ "-v" ]; 598 settingsFile = pkgs.writeText "knot.conf" '' 599 server: 600 listen: 127.0.0.1@53 601 602 template: 603 - id: default 604 global-module: mod-stats 605 dnssec-signing: off 606 zonefile-sync: -1 607 zonefile-load: difference 608 storage: ${ 609 pkgs.buildEnv { 610 name = "foo"; 611 paths = [ 612 (pkgs.writeTextDir "test.zone" '' 613 @ SOA ns.example.com. noc.example.com. 2019031301 86400 7200 3600000 172800 614 @ NS ns1 615 @ NS ns2 616 ns1 A 192.168.0.1 617 '') 618 ]; 619 } 620 } 621 622 mod-stats: 623 - id: custom 624 edns-presence: on 625 query-type: on 626 627 zone: 628 - domain: test 629 file: test.zone 630 module: mod-stats/custom 631 ''; 632 }; 633 }; 634 exporterTest = '' 635 wait_for_unit("knot.service") 636 wait_for_unit("prometheus-knot-exporter.service") 637 wait_for_open_port(9433) 638 succeed("curl -sSf 'localhost:9433' | grep '2\.019031301'") 639 ''; 640 }; 641 642 keylight = { 643 # A hardware device is required to properly test this exporter, so just 644 # perform a couple of basic sanity checks that the exporter is running 645 # and requires a target, but cannot reach a specified target. 646 exporterConfig = { 647 enable = true; 648 }; 649 exporterTest = '' 650 wait_for_unit("prometheus-keylight-exporter.service") 651 wait_for_open_port(9288) 652 succeed( 653 "curl -sS --write-out '%{http_code}' -o /dev/null http://localhost:9288/metrics | grep '400'" 654 ) 655 succeed( 656 "curl -sS --write-out '%{http_code}' -o /dev/null http://localhost:9288/metrics?target=nosuchdevice | grep '500'" 657 ) 658 ''; 659 }; 660 661 lnd = { 662 exporterConfig = { 663 enable = true; 664 lndTlsPath = "/var/lib/lnd/tls.cert"; 665 lndMacaroonDir = "/var/lib/lnd"; 666 extraFlags = [ "--lnd.network=regtest" ]; 667 }; 668 metricProvider = { 669 systemd.services.prometheus-lnd-exporter.serviceConfig.RestartSec = 15; 670 systemd.services.prometheus-lnd-exporter.after = [ "lnd.service" ]; 671 services.bitcoind.regtest = { 672 enable = true; 673 extraConfig = '' 674 rpcauth=bitcoinrpc:e8fe33f797e698ac258c16c8d7aadfbe$872bdb8f4d787367c26bcfd75e6c23c4f19d44a69f5d1ad329e5adf3f82710f7 675 zmqpubrawblock=tcp://127.0.0.1:28332 676 zmqpubrawtx=tcp://127.0.0.1:28333 677 # https://github.com/lightningnetwork/lnd/issues/9163 678 deprecatedrpc=warnings 679 ''; 680 extraCmdlineOptions = [ "-regtest" ]; 681 }; 682 systemd.services.lnd = { 683 serviceConfig.ExecStart = '' 684 ${pkgs.lnd}/bin/lnd \ 685 --datadir=/var/lib/lnd \ 686 --tlscertpath=/var/lib/lnd/tls.cert \ 687 --tlskeypath=/var/lib/lnd/tls.key \ 688 --logdir=/var/log/lnd \ 689 --bitcoin.active \ 690 --bitcoin.regtest \ 691 --bitcoin.node=bitcoind \ 692 --bitcoind.rpcuser=bitcoinrpc \ 693 --bitcoind.rpcpass=hunter2 \ 694 --bitcoind.zmqpubrawblock=tcp://127.0.0.1:28332 \ 695 --bitcoind.zmqpubrawtx=tcp://127.0.0.1:28333 \ 696 --readonlymacaroonpath=/var/lib/lnd/readonly.macaroon 697 ''; 698 serviceConfig.StateDirectory = "lnd"; 699 wantedBy = [ "multi-user.target" ]; 700 after = [ "network.target" ]; 701 }; 702 # initialize wallet, creates macaroon needed by exporter 703 systemd.services.lnd.postStart = '' 704 ${pkgs.curl}/bin/curl \ 705 --retry 20 \ 706 --retry-delay 1 \ 707 --retry-connrefused \ 708 --cacert /var/lib/lnd/tls.cert \ 709 -X GET \ 710 https://localhost:8080/v1/genseed | ${pkgs.jq}/bin/jq -c '.cipher_seed_mnemonic' > /tmp/seed 711 ${pkgs.curl}/bin/curl \ 712 --retry 20 \ 713 --retry-delay 1 \ 714 --retry-connrefused \ 715 --cacert /var/lib/lnd/tls.cert \ 716 -X POST \ 717 -d "{\"wallet_password\": \"asdfasdfasdf\", \"cipher_seed_mnemonic\": $(cat /tmp/seed | tr -d '\n')}" \ 718 https://localhost:8080/v1/initwallet 719 ''; 720 }; 721 exporterTest = '' 722 wait_for_unit("lnd.service") 723 wait_for_open_port(10009) 724 wait_for_unit("prometheus-lnd-exporter.service") 725 wait_for_open_port(9092) 726 succeed("curl -sSf localhost:9092/metrics | grep '^lnd_peer_count'") 727 ''; 728 }; 729 730 mail = { 731 exporterConfig = { 732 enable = true; 733 configuration = { 734 monitoringInterval = "2s"; 735 mailCheckTimeout = "10s"; 736 servers = [ 737 { 738 name = "testserver"; 739 server = "localhost"; 740 port = 25; 741 from = "mail-exporter@localhost"; 742 to = "mail-exporter@localhost"; 743 detectionDir = "/var/spool/mail/mail-exporter/new"; 744 } 745 ]; 746 }; 747 }; 748 metricProvider = { 749 services.postfix.enable = true; 750 systemd.services.prometheus-mail-exporter = { 751 after = [ "postfix.service" ]; 752 requires = [ "postfix.service" ]; 753 serviceConfig = { 754 ExecStartPre = [ 755 "${pkgs.writeShellScript "create-maildir" '' 756 mkdir -p -m 0700 mail-exporter/new 757 ''}" 758 ]; 759 ProtectHome = true; 760 ReadOnlyPaths = "/"; 761 ReadWritePaths = "/var/spool/mail"; 762 WorkingDirectory = "/var/spool/mail"; 763 }; 764 }; 765 users.users.mailexporter = { 766 isSystemUser = true; 767 group = "mailexporter"; 768 }; 769 users.groups.mailexporter = { }; 770 }; 771 exporterTest = '' 772 wait_for_unit("postfix.service") 773 wait_for_unit("prometheus-mail-exporter.service") 774 wait_for_open_port(9225) 775 wait_until_succeeds( 776 "curl -sSf http://localhost:9225/metrics | grep 'mail_deliver_success{configname=\"testserver\"} 1'" 777 ) 778 ''; 779 }; 780 781 mikrotik = { 782 exporterConfig = { 783 enable = true; 784 extraFlags = [ "-timeout=1s" ]; 785 configuration = { 786 devices = [ 787 { 788 name = "router"; 789 address = "192.168.42.48"; 790 user = "prometheus"; 791 password = "shh"; 792 } 793 ]; 794 features = { 795 bgp = true; 796 dhcp = true; 797 dhcpl = true; 798 dhcpv6 = true; 799 health = true; 800 routes = true; 801 poe = true; 802 pools = true; 803 optics = true; 804 w60g = true; 805 wlansta = true; 806 wlanif = true; 807 monitor = true; 808 ipsec = true; 809 }; 810 }; 811 }; 812 exporterTest = '' 813 wait_for_unit("prometheus-mikrotik-exporter.service") 814 wait_for_open_port(9436) 815 succeed( 816 "curl -sSf http://localhost:9436/metrics | grep 'mikrotik_scrape_collector_success{device=\"router\"} 0'" 817 ) 818 ''; 819 }; 820 821 modemmanager = { 822 exporterConfig = { 823 enable = true; 824 refreshRate = "10s"; 825 }; 826 metricProvider = { 827 # ModemManager is installed when NetworkManager is enabled. Ensure it is 828 # started and is wanted by NM and the exporter to start everything up 829 # in the right order. 830 networking.networkmanager.enable = true; 831 systemd.services.ModemManager = { 832 enable = true; 833 wantedBy = [ 834 "NetworkManager.service" 835 "prometheus-modemmanager-exporter.service" 836 ]; 837 }; 838 }; 839 exporterTest = '' 840 wait_for_unit("ModemManager.service") 841 wait_for_unit("prometheus-modemmanager-exporter.service") 842 wait_for_open_port(9539) 843 succeed( 844 "curl -sSf http://localhost:9539/metrics | grep 'modemmanager_info'" 845 ) 846 ''; 847 }; 848 849 mqtt = { 850 exporterConfig = { 851 enable = true; 852 environmentFile = pkgs.writeText "mqtt-exporter-envfile" '' 853 MQTT_PASSWORD=testpassword 854 ''; 855 }; 856 metricProvider = { 857 services.mosquitto = { 858 enable = true; 859 listeners = [ 860 { 861 users.exporter = { 862 acl = [ "read #" ]; 863 passwordFile = pkgs.writeText "mosquitto-password" "testpassword"; 864 }; 865 } 866 ]; 867 }; 868 systemd.services.prometheus-mqtt-exporter = { 869 wants = [ "mosquitto.service" ]; 870 after = [ "mosquitto.service" ]; 871 }; 872 }; 873 exporterTest = '' 874 wait_for_unit("mosquitto.service") 875 wait_for_unit("prometheus-mqtt-exporter.service") 876 wait_for_open_port(9000) 877 succeed( 878 "curl -sSf http://localhost:9000/metrics | grep '^python_info'" 879 ) 880 ''; 881 }; 882 883 mysqld = { 884 exporterConfig = { 885 enable = true; 886 runAsLocalSuperUser = true; 887 configFile = pkgs.writeText "test-prometheus-exporter-mysqld-config.my-cnf" '' 888 [client] 889 user = exporter 890 password = snakeoilpassword 891 ''; 892 }; 893 metricProvider = { 894 services.mysql = { 895 enable = true; 896 package = pkgs.mariadb; 897 initialScript = pkgs.writeText "mysql-init-script.sql" '' 898 CREATE USER 'exporter'@'localhost' 899 IDENTIFIED BY 'snakeoilpassword' 900 WITH MAX_USER_CONNECTIONS 3; 901 GRANT PROCESS, REPLICATION CLIENT, SLAVE MONITOR, SELECT ON *.* TO 'exporter'@'localhost'; 902 ''; 903 }; 904 }; 905 exporterTest = '' 906 wait_for_unit("prometheus-mysqld-exporter.service") 907 wait_for_open_port(9104) 908 wait_for_unit("mysql.service") 909 succeed("curl -sSf http://localhost:9104/metrics | grep 'mysql_up 1'") 910 systemctl("stop mysql.service") 911 succeed("curl -sSf http://localhost:9104/metrics | grep 'mysql_up 0'") 912 systemctl("start mysql.service") 913 wait_for_unit("mysql.service") 914 succeed("curl -sSf http://localhost:9104/metrics | grep 'mysql_up 1'") 915 ''; 916 }; 917 918 nextcloud = { 919 exporterConfig = { 920 enable = true; 921 passwordFile = "/var/nextcloud-pwfile"; 922 url = "http://localhost"; 923 }; 924 metricProvider = { 925 systemd.services.nc-pwfile = 926 let 927 passfile = (pkgs.writeText "pwfile" "snakeoilpw"); 928 in 929 { 930 requiredBy = [ "prometheus-nextcloud-exporter.service" ]; 931 before = [ "prometheus-nextcloud-exporter.service" ]; 932 serviceConfig.ExecStart = '' 933 ${pkgs.coreutils}/bin/install -o nextcloud-exporter -m 0400 ${passfile} /var/nextcloud-pwfile 934 ''; 935 }; 936 services.nginx = { 937 enable = true; 938 virtualHosts."localhost" = { 939 basicAuth.nextcloud-exporter = "snakeoilpw"; 940 locations."/" = { 941 root = "${pkgs.prometheus-nextcloud-exporter.src}/serverinfo/testdata"; 942 tryFiles = "/negative-space.json =404"; 943 }; 944 }; 945 }; 946 }; 947 exporterTest = '' 948 wait_for_unit("nginx.service") 949 wait_for_unit("prometheus-nextcloud-exporter.service") 950 wait_for_open_port(9205) 951 succeed("curl -sSf http://localhost:9205/metrics | grep 'nextcloud_up 1'") 952 ''; 953 }; 954 955 nginx = { 956 exporterConfig = { 957 enable = true; 958 constLabels = [ "foo=bar" ]; 959 }; 960 metricProvider = { 961 services.nginx = { 962 enable = true; 963 statusPage = true; 964 virtualHosts."test".extraConfig = "return 204;"; 965 }; 966 }; 967 exporterTest = '' 968 wait_for_unit("nginx.service") 969 wait_for_unit("prometheus-nginx-exporter.service") 970 wait_for_open_port(9113) 971 succeed("curl -sSf http://localhost:9113/metrics | grep 'nginx_up{foo=\"bar\"} 1'") 972 ''; 973 }; 974 975 nginxlog = { 976 exporterConfig = { 977 enable = true; 978 group = "nginx"; 979 settings = { 980 namespaces = [ 981 { 982 name = "filelogger"; 983 source = { 984 files = [ "/var/log/nginx/filelogger.access.log" ]; 985 }; 986 } 987 { 988 name = "syslogger"; 989 source = { 990 syslog = { 991 listen_address = "udp://127.0.0.1:10000"; 992 format = "rfc3164"; 993 tags = [ "nginx" ]; 994 }; 995 }; 996 } 997 ]; 998 }; 999 }; 1000 metricProvider = { 1001 services.nginx = { 1002 enable = true; 1003 httpConfig = '' 1004 server { 1005 listen 80; 1006 server_name filelogger.local; 1007 access_log /var/log/nginx/filelogger.access.log; 1008 } 1009 server { 1010 listen 81; 1011 server_name syslogger.local; 1012 access_log syslog:server=127.0.0.1:10000,tag=nginx,severity=info; 1013 } 1014 ''; 1015 }; 1016 }; 1017 exporterTest = '' 1018 wait_for_unit("nginx.service") 1019 wait_for_unit("prometheus-nginxlog-exporter.service") 1020 wait_for_open_port(9117) 1021 wait_for_open_port(80) 1022 wait_for_open_port(81) 1023 succeed("curl http://localhost") 1024 execute("sleep 1") 1025 succeed( 1026 "curl -sSf http://localhost:9117/metrics | grep 'filelogger_http_response_count_total' | grep 1" 1027 ) 1028 succeed("curl http://localhost:81") 1029 execute("sleep 1") 1030 succeed( 1031 "curl -sSf http://localhost:9117/metrics | grep 'syslogger_http_response_count_total' | grep 1" 1032 ) 1033 ''; 1034 }; 1035 1036 node = { 1037 exporterConfig = { 1038 enable = true; 1039 }; 1040 exporterTest = '' 1041 wait_for_unit("prometheus-node-exporter.service") 1042 wait_for_open_port(9100) 1043 succeed( 1044 "curl -sSf http://localhost:9100/metrics | grep 'node_exporter_build_info{.\\+} 1'" 1045 ) 1046 ''; 1047 }; 1048 1049 node-cert = { 1050 nodeName = "node_cert"; 1051 exporterConfig = { 1052 enable = true; 1053 paths = [ "/run/certs" ]; 1054 }; 1055 exporterTest = '' 1056 wait_for_unit("prometheus-node-cert-exporter.service") 1057 wait_for_open_port(9141) 1058 wait_until_succeeds( 1059 "curl -sSf http://localhost:9141/metrics | grep 'ssl_certificate_expiry_seconds{.\\+path=\"/run/certs/node-cert\\.cert\".\\+}'" 1060 ) 1061 ''; 1062 1063 metricProvider = { 1064 system.activationScripts.cert.text = '' 1065 mkdir -p /run/certs 1066 cd /run/certs 1067 1068 cat >ca.template <<EOF 1069 organization = "prometheus-node-cert-exporter" 1070 cn = "prometheus-node-cert-exporter" 1071 expiration_days = 365 1072 ca 1073 cert_signing_key 1074 crl_signing_key 1075 EOF 1076 1077 ${pkgs.gnutls}/bin/certtool \ 1078 --generate-privkey \ 1079 --key-type rsa \ 1080 --sec-param High \ 1081 --outfile node-cert.key 1082 1083 ${pkgs.gnutls}/bin/certtool \ 1084 --generate-self-signed \ 1085 --load-privkey node-cert.key \ 1086 --template ca.template \ 1087 --outfile node-cert.cert 1088 ''; 1089 }; 1090 }; 1091 1092 pgbouncer = { 1093 exporterConfig = { 1094 enable = true; 1095 connectionEnvFile = "${pkgs.writeText "connstr-env" '' 1096 PGBOUNCER_EXPORTER_CONNECTION_STRING=postgres://admin@localhost:6432/pgbouncer?sslmode=disable 1097 ''}"; 1098 }; 1099 1100 metricProvider = { 1101 services.postgresql.enable = true; 1102 services.pgbouncer = { 1103 enable = true; 1104 settings = { 1105 pgbouncer = { 1106 listen_addr = "*"; 1107 auth_type = "any"; 1108 max_client_conn = 99; 1109 # https://github.com/prometheus-community/pgbouncer_exporter#pgbouncer-configuration 1110 ignore_startup_parameters = "extra_float_digits"; 1111 }; 1112 databases = { 1113 postgres = concatStringsSep " " [ 1114 "host=/run/postgresql" 1115 "port=5432" 1116 "auth_user=postgres" 1117 "dbname=postgres" 1118 ]; 1119 }; 1120 }; 1121 }; 1122 }; 1123 exporterTest = '' 1124 wait_for_unit("postgresql.service") 1125 wait_for_unit("pgbouncer.service") 1126 wait_for_unit("prometheus-pgbouncer-exporter.service") 1127 wait_for_open_port(9127) 1128 succeed("curl -sSf http://localhost:9127/metrics | grep 'pgbouncer_up 1'") 1129 succeed( 1130 "curl -sSf http://localhost:9127/metrics | grep 'pgbouncer_config_max_client_connections 99'" 1131 ) 1132 ''; 1133 }; 1134 1135 php-fpm = { 1136 nodeName = "php_fpm"; 1137 exporterConfig = { 1138 enable = true; 1139 environmentFile = pkgs.writeTextFile { 1140 name = "/tmp/prometheus-php-fpm-exporter.env"; 1141 text = '' 1142 PHP_FPM_SCRAPE_URI="tcp://127.0.0.1:9000/status" 1143 ''; 1144 }; 1145 }; 1146 metricProvider = { 1147 users.users."php-fpm-exporter" = { 1148 isSystemUser = true; 1149 group = "php-fpm-exporter"; 1150 }; 1151 users.groups."php-fpm-exporter" = { }; 1152 services.phpfpm.pools."php-fpm-exporter" = { 1153 user = "php-fpm-exporter"; 1154 group = "php-fpm-exporter"; 1155 settings = { 1156 "pm" = "dynamic"; 1157 "pm.max_children" = 32; 1158 "pm.max_requests" = 500; 1159 "pm.start_servers" = 2; 1160 "pm.min_spare_servers" = 2; 1161 "pm.max_spare_servers" = 5; 1162 "pm.status_path" = "/status"; 1163 "listen" = "127.0.0.1:9000"; 1164 "listen.allowed_clients" = "127.0.0.1"; 1165 }; 1166 phpEnv."PATH" = makeBinPath [ pkgs.php ]; 1167 }; 1168 }; 1169 exporterTest = '' 1170 wait_for_unit("phpfpm-php-fpm-exporter.service") 1171 wait_for_unit("prometheus-php-fpm-exporter.service") 1172 succeed("curl -sSf http://localhost:9253/metrics | grep 'phpfpm_up{.*} 1'") 1173 ''; 1174 }; 1175 1176 ping = { 1177 exporterConfig = { 1178 enable = true; 1179 1180 settings = { 1181 targets = [ 1182 { 1183 "localhost" = { 1184 alias = "local machine"; 1185 env = "prod"; 1186 type = "domain"; 1187 }; 1188 } 1189 { 1190 "127.0.0.1" = { 1191 alias = "local machine"; 1192 type = "v4"; 1193 }; 1194 } 1195 { 1196 "::1" = { 1197 alias = "local machine"; 1198 type = "v6"; 1199 }; 1200 } 1201 { 1202 "google.com" = { }; 1203 } 1204 ]; 1205 dns = { }; 1206 ping = { 1207 interval = "2s"; 1208 timeout = "3s"; 1209 history-size = 42; 1210 payload-size = 56; 1211 }; 1212 log = { 1213 level = "warn"; 1214 }; 1215 }; 1216 }; 1217 1218 exporterTest = '' 1219 wait_for_unit("prometheus-ping-exporter.service") 1220 wait_for_open_port(9427) 1221 succeed("curl -sSf http://localhost:9427/metrics | grep 'ping_up{.*} 1'") 1222 ''; 1223 }; 1224 1225 postfix = { 1226 exporterConfig = { 1227 enable = true; 1228 }; 1229 metricProvider = { 1230 services.postfix.enable = true; 1231 }; 1232 exporterTest = '' 1233 wait_for_unit("prometheus-postfix-exporter.service") 1234 wait_for_file("/var/lib/postfix/queue/public/showq") 1235 wait_for_open_port(9154) 1236 wait_until_succeeds( 1237 "curl -sSf http://localhost:9154/metrics | grep 'postfix_up{path=\"/var/lib/postfix/queue/public/showq\"} 1'" 1238 ) 1239 succeed( 1240 "curl -sSf http://localhost:9154/metrics | grep 'postfix_smtpd_connects_total 0'" 1241 ) 1242 succeed("curl -sSf http://localhost:9154/metrics | grep 'postfix_up{.*} 1'") 1243 ''; 1244 }; 1245 1246 postgres = { 1247 exporterConfig = { 1248 enable = true; 1249 runAsLocalSuperUser = true; 1250 }; 1251 metricProvider = { 1252 services.postgresql.enable = true; 1253 }; 1254 exporterTest = '' 1255 wait_for_unit("prometheus-postgres-exporter.service") 1256 wait_for_open_port(9187) 1257 wait_for_unit("postgresql.service") 1258 succeed( 1259 "curl -sSf http://localhost:9187/metrics | grep 'pg_exporter_last_scrape_error 0'" 1260 ) 1261 succeed("curl -sSf http://localhost:9187/metrics | grep 'pg_up 1'") 1262 systemctl("stop postgresql.service") 1263 succeed( 1264 "curl -sSf http://localhost:9187/metrics | grep -v 'pg_exporter_last_scrape_error 0'" 1265 ) 1266 succeed("curl -sSf http://localhost:9187/metrics | grep 'pg_up 0'") 1267 systemctl("start postgresql.service") 1268 wait_for_unit("postgresql.service") 1269 succeed( 1270 "curl -sSf http://localhost:9187/metrics | grep 'pg_exporter_last_scrape_error 0'" 1271 ) 1272 succeed("curl -sSf http://localhost:9187/metrics | grep 'pg_up 1'") 1273 ''; 1274 }; 1275 1276 process = { 1277 exporterConfig = { 1278 enable = true; 1279 settings.process_names = [ 1280 # Remove nix store path from process name 1281 { 1282 name = "{{.Matches.Wrapped}} {{ .Matches.Args }}"; 1283 cmdline = [ "^/nix/store[^ ]*/(?P<Wrapped>[^ /]*) (?P<Args>.*)" ]; 1284 } 1285 ]; 1286 }; 1287 exporterTest = '' 1288 wait_for_unit("prometheus-process-exporter.service") 1289 wait_for_open_port(9256) 1290 wait_until_succeeds( 1291 "curl -sSf localhost:9256/metrics | grep -q '{}'".format( 1292 'namedprocess_namegroup_cpu_seconds_total{groupname="process-exporter ' 1293 ) 1294 ) 1295 ''; 1296 }; 1297 1298 pve = 1299 let 1300 pveExporterEnvFile = pkgs.writeTextFile { 1301 name = "pve.env"; 1302 text = '' 1303 PVE_USER="test_user@pam" 1304 PVE_PASSWORD="hunter3" 1305 PVE_VERIFY_SSL="false" 1306 ''; 1307 }; 1308 in 1309 { 1310 exporterConfig = { 1311 enable = true; 1312 environmentFile = pveExporterEnvFile; 1313 }; 1314 exporterTest = '' 1315 wait_for_unit("prometheus-pve-exporter.service") 1316 wait_for_open_port(9221) 1317 wait_until_succeeds("curl localhost:9221") 1318 ''; 1319 }; 1320 1321 py-air-control = { 1322 nodeName = "py_air_control"; 1323 exporterConfig = { 1324 enable = true; 1325 deviceHostname = "127.0.0.1"; 1326 }; 1327 exporterTest = '' 1328 wait_for_unit("prometheus-py-air-control-exporter.service") 1329 wait_for_open_port(9896) 1330 succeed( 1331 "curl -sSf http://localhost:9896/metrics | grep 'py_air_control_sampling_error_total'" 1332 ) 1333 ''; 1334 }; 1335 1336 redis = { 1337 exporterConfig = { 1338 enable = true; 1339 }; 1340 metricProvider.services.redis.servers."".enable = true; 1341 exporterTest = '' 1342 wait_for_unit("redis.service") 1343 wait_for_unit("prometheus-redis-exporter.service") 1344 wait_for_open_port(6379) 1345 wait_for_open_port(9121) 1346 wait_until_succeeds("curl -sSf localhost:9121/metrics | grep 'redis_up 1'") 1347 ''; 1348 }; 1349 1350 restic = 1351 let 1352 repository = "rest:http://127.0.0.1:8000"; 1353 passwordFile = pkgs.writeText "restic-test-password" "test-password"; 1354 in 1355 { 1356 exporterConfig = { 1357 enable = true; 1358 inherit repository passwordFile; 1359 }; 1360 metricProvider = { 1361 services.restic.server = { 1362 enable = true; 1363 extraFlags = [ "--no-auth" ]; 1364 }; 1365 environment.systemPackages = [ pkgs.restic ]; 1366 }; 1367 exporterTest = '' 1368 # prometheus-restic-exporter.service fails without initialised repository 1369 systemctl("stop prometheus-restic-exporter.service") 1370 1371 # Initialise the repository 1372 wait_for_unit("restic-rest-server.service") 1373 wait_for_open_port(8000) 1374 succeed("restic init --repo ${repository} --password-file ${passwordFile}") 1375 1376 systemctl("start prometheus-restic-exporter.service") 1377 wait_for_unit("prometheus-restic-exporter.service") 1378 wait_for_open_port(9753) 1379 wait_until_succeeds("curl -sSf localhost:9753/metrics | grep 'restic_check_success 1.0'") 1380 ''; 1381 }; 1382 1383 rspamd = { 1384 exporterConfig = { 1385 enable = true; 1386 }; 1387 metricProvider = { 1388 services.rspamd.enable = true; 1389 }; 1390 exporterTest = '' 1391 wait_for_unit("rspamd.service") 1392 wait_for_unit("prometheus-rspamd-exporter.service") 1393 wait_for_open_port(11334) 1394 wait_for_open_port(7980) 1395 wait_until_succeeds( 1396 "curl -sSf 'localhost:7980/probe?target=http://localhost:11334/stat' | grep 'rspamd_scanned{host=\"rspamd\"} 0'" 1397 ) 1398 ''; 1399 }; 1400 1401 rtl_433 = { 1402 exporterConfig = { 1403 enable = true; 1404 }; 1405 metricProvider = { 1406 # Mock rtl_433 binary to return a dummy metric stream. 1407 nixpkgs.overlays = [ 1408 (self: super: { 1409 rtl_433 = self.runCommand "rtl_433" { } '' 1410 mkdir -p "$out/bin" 1411 cat <<EOF > "$out/bin/rtl_433" 1412 #!/bin/sh 1413 while true; do 1414 printf '{"time" : "2020-04-26 13:37:42", "model" : "zopieux", "id" : 55, "channel" : 3, "temperature_C" : 18.000}\n' 1415 sleep 4 1416 done 1417 EOF 1418 chmod +x "$out/bin/rtl_433" 1419 ''; 1420 }) 1421 ]; 1422 }; 1423 exporterTest = '' 1424 wait_for_unit("prometheus-rtl_433-exporter.service") 1425 wait_for_open_port(9550) 1426 wait_until_succeeds( 1427 "curl -sSf localhost:9550/metrics | grep '{}'".format( 1428 'rtl_433_temperature_celsius{channel="3",id="55",location="",model="zopieux"} 18' 1429 ) 1430 ) 1431 ''; 1432 }; 1433 1434 sabnzbd = { 1435 exporterConfig = { 1436 enable = true; 1437 servers = [ 1438 { 1439 baseUrl = "http://localhost:8080"; 1440 apiKeyFile = "/var/sabnzbd-apikey"; 1441 } 1442 ]; 1443 }; 1444 1445 metricProvider = { 1446 services.sabnzbd.enable = true; 1447 1448 # unrar is required for sabnzbd 1449 nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (pkgs.lib.getName pkg) [ "unrar" ]; 1450 1451 # extract the generated api key before starting 1452 systemd.services.sabnzbd-apikey = { 1453 requires = [ "sabnzbd.service" ]; 1454 after = [ "sabnzbd.service" ]; 1455 requiredBy = [ "prometheus-sabnzbd-exporter.service" ]; 1456 before = [ "prometheus-sabnzbd-exporter.service" ]; 1457 script = '' 1458 grep -Po '^api_key = \K.+' /var/lib/sabnzbd/sabnzbd.ini > /var/sabnzbd-apikey 1459 ''; 1460 }; 1461 }; 1462 1463 exporterTest = '' 1464 wait_for_unit("sabnzbd.service") 1465 wait_for_unit("prometheus-sabnzbd-exporter.service") 1466 wait_for_open_port(8080) 1467 wait_for_open_port(9387) 1468 wait_until_succeeds( 1469 "curl -sSf 'localhost:9387/metrics' | grep 'sabnzbd_queue_size{sabnzbd_instance=\"http://localhost:8080\"} 0.0'" 1470 ) 1471 ''; 1472 }; 1473 1474 scaphandre = { 1475 exporterConfig = { 1476 enable = true; 1477 }; 1478 metricProvider = { 1479 boot.kernelModules = [ "intel_rapl_common" ]; 1480 }; 1481 exporterTest = '' 1482 wait_for_unit("prometheus-scaphandre-exporter.service") 1483 wait_for_open_port(8080) 1484 wait_until_succeeds( 1485 "curl -sSf 'localhost:8080/metrics'" 1486 ) 1487 ''; 1488 }; 1489 1490 shelly = { 1491 exporterConfig = { 1492 enable = true; 1493 metrics-file = "${pkgs.writeText "test.json" ''{}''}"; 1494 }; 1495 exporterTest = '' 1496 wait_for_unit("prometheus-shelly-exporter.service") 1497 wait_for_open_port(9784) 1498 wait_until_succeeds( 1499 "curl -sSf 'localhost:9784/metrics'" 1500 ) 1501 ''; 1502 }; 1503 1504 script = { 1505 exporterConfig = { 1506 enable = true; 1507 settings.scripts = [ 1508 { 1509 name = "success"; 1510 script = "sleep 1"; 1511 } 1512 ]; 1513 }; 1514 exporterTest = '' 1515 wait_for_unit("prometheus-script-exporter.service") 1516 wait_for_open_port(9172) 1517 wait_until_succeeds( 1518 "curl -sSf 'localhost:9172/probe?name=success' | grep -q '{}'".format( 1519 'script_success{script="success"} 1' 1520 ) 1521 ) 1522 ''; 1523 }; 1524 1525 smartctl = { 1526 exporterConfig = { 1527 enable = true; 1528 devices = [ 1529 "/dev/vda" 1530 ]; 1531 }; 1532 exporterTest = '' 1533 wait_until_succeeds( 1534 'journalctl -eu prometheus-smartctl-exporter.service -o cat | grep "Unable to detect device type"' 1535 ) 1536 ''; 1537 }; 1538 1539 smokeping = { 1540 exporterConfig = { 1541 enable = true; 1542 hosts = [ "127.0.0.1" ]; 1543 }; 1544 exporterTest = '' 1545 wait_for_unit("prometheus-smokeping-exporter.service") 1546 wait_for_open_port(9374) 1547 wait_until_succeeds( 1548 "curl -sSf localhost:9374/metrics | grep '{}' | grep -v ' 0$'".format( 1549 'smokeping_requests_total{host="127.0.0.1",ip="127.0.0.1",source=""} ' 1550 ) 1551 ) 1552 wait_until_succeeds( 1553 "curl -sSf localhost:9374/metrics | grep '{}'".format( 1554 'smokeping_response_ttl{host="127.0.0.1",ip="127.0.0.1",source=""}' 1555 ) 1556 ) 1557 ''; 1558 }; 1559 1560 snmp = { 1561 exporterConfig = { 1562 enable = true; 1563 configuration = { 1564 auths.public_v2 = { 1565 community = "public"; 1566 version = 2; 1567 }; 1568 }; 1569 }; 1570 exporterTest = '' 1571 wait_for_unit("prometheus-snmp-exporter.service") 1572 wait_for_open_port(9116) 1573 succeed("curl -sSf localhost:9116/metrics | grep 'snmp_request_errors_total 0'") 1574 ''; 1575 }; 1576 1577 sql = { 1578 exporterConfig = { 1579 configuration.jobs.points = { 1580 interval = "1m"; 1581 connections = [ 1582 "postgres://prometheus-sql-exporter@/data?host=/run/postgresql&sslmode=disable" 1583 ]; 1584 queries = { 1585 points = { 1586 labels = [ "name" ]; 1587 help = "Amount of points accumulated per person"; 1588 values = [ "amount" ]; 1589 query = "SELECT SUM(amount) as amount, name FROM points GROUP BY name"; 1590 }; 1591 }; 1592 }; 1593 enable = true; 1594 user = "prometheus-sql-exporter"; 1595 }; 1596 metricProvider = { 1597 services.postgresql = { 1598 enable = true; 1599 initialScript = builtins.toFile "init.sql" '' 1600 CREATE DATABASE data; 1601 \c data; 1602 CREATE TABLE points (amount INT, name TEXT); 1603 INSERT INTO points(amount, name) VALUES (1, 'jack'); 1604 INSERT INTO points(amount, name) VALUES (2, 'jill'); 1605 INSERT INTO points(amount, name) VALUES (3, 'jack'); 1606 1607 CREATE USER "prometheus-sql-exporter"; 1608 GRANT ALL PRIVILEGES ON DATABASE data TO "prometheus-sql-exporter"; 1609 GRANT SELECT ON points TO "prometheus-sql-exporter"; 1610 ''; 1611 }; 1612 systemd.services.prometheus-sql-exporter.after = [ "postgresql.service" ]; 1613 }; 1614 exporterTest = '' 1615 wait_for_unit("prometheus-sql-exporter.service") 1616 wait_for_open_port(9237) 1617 succeed("curl http://localhost:9237/metrics | grep -c 'sql_points{' | grep 2") 1618 ''; 1619 }; 1620 1621 statsd = { 1622 exporterConfig = { 1623 enable = true; 1624 }; 1625 exporterTest = '' 1626 wait_for_unit("prometheus-statsd-exporter.service") 1627 wait_for_open_port(9102) 1628 succeed("curl http://localhost:9102/metrics | grep 'statsd_exporter_build_info{'") 1629 wait_until_succeeds( 1630 "echo 'test.udp:1|c' > /dev/udp/localhost/9125 && \ 1631 curl http://localhost:9102/metrics | grep 'test_udp 1'", 1632 timeout=10 1633 ) 1634 wait_until_succeeds( 1635 "echo 'test.tcp:1|c' > /dev/tcp/localhost/9125 && \ 1636 curl http://localhost:9102/metrics | grep 'test_tcp 1'", 1637 timeout=10 1638 ) 1639 ''; 1640 }; 1641 1642 surfboard = { 1643 exporterConfig = { 1644 enable = true; 1645 modemAddress = "localhost"; 1646 }; 1647 metricProvider = { 1648 systemd.services.prometheus-surfboard-exporter.after = [ "nginx.service" ]; 1649 services.nginx = { 1650 enable = true; 1651 virtualHosts.localhost.locations."/cgi-bin/status".extraConfig = '' 1652 return 204; 1653 ''; 1654 }; 1655 }; 1656 exporterTest = '' 1657 wait_for_unit("nginx.service") 1658 wait_for_open_port(80) 1659 wait_for_unit("prometheus-surfboard-exporter.service") 1660 wait_for_open_port(9239) 1661 succeed("curl -sSf localhost:9239/metrics | grep 'surfboard_up 1'") 1662 ''; 1663 }; 1664 1665 systemd = { 1666 exporterConfig = { 1667 enable = true; 1668 1669 extraFlags = [ 1670 "--systemd.collector.enable-restart-count" 1671 ]; 1672 }; 1673 metricProvider = { }; 1674 exporterTest = '' 1675 wait_for_unit("prometheus-systemd-exporter.service") 1676 wait_for_open_port(9558) 1677 wait_until_succeeds( 1678 "curl -sSf localhost:9558/metrics | grep '{}'".format( 1679 'systemd_unit_state{name="basic.target",state="active",type="target"} 1' 1680 ) 1681 ) 1682 succeed( 1683 "curl -sSf localhost:9558/metrics | grep '{}'".format( 1684 'systemd_service_restart_total{name="prometheus-systemd-exporter.service"} 0' 1685 ) 1686 ) 1687 ''; 1688 }; 1689 1690 unpoller = { 1691 nodeName = "unpoller"; 1692 exporterConfig.enable = true; 1693 exporterConfig.controllers = [ { } ]; 1694 exporterTest = '' 1695 wait_until_succeeds( 1696 'journalctl -eu prometheus-unpoller-exporter.service -o cat | grep "Connection Error"' 1697 ) 1698 ''; 1699 }; 1700 1701 unbound = { 1702 exporterConfig = { 1703 enable = true; 1704 unbound.host = "unix:///run/unbound/unbound.ctl"; 1705 }; 1706 metricProvider = { 1707 services.unbound = { 1708 enable = true; 1709 localControlSocketPath = "/run/unbound/unbound.ctl"; 1710 }; 1711 systemd.services.prometheus-unbound-exporter.serviceConfig = { 1712 SupplementaryGroups = [ "unbound" ]; 1713 }; 1714 }; 1715 exporterTest = '' 1716 wait_for_unit("unbound.service") 1717 wait_for_unit("prometheus-unbound-exporter.service") 1718 wait_for_open_port(9167) 1719 wait_until_succeeds("curl -sSf localhost:9167/metrics | grep 'unbound_up 1'") 1720 ''; 1721 }; 1722 1723 v2ray = { 1724 exporterConfig = { 1725 enable = true; 1726 }; 1727 1728 metricProvider = { 1729 systemd.services.prometheus-nginx-exporter.after = [ "v2ray.service" ]; 1730 services.v2ray = { 1731 enable = true; 1732 config = { 1733 stats = { }; 1734 api = { 1735 tag = "api"; 1736 services = [ "StatsService" ]; 1737 }; 1738 inbounds = [ 1739 { 1740 port = 1080; 1741 listen = "127.0.0.1"; 1742 protocol = "http"; 1743 } 1744 { 1745 listen = "127.0.0.1"; 1746 port = 54321; 1747 protocol = "dokodemo-door"; 1748 settings = { 1749 address = "127.0.0.1"; 1750 }; 1751 tag = "api"; 1752 } 1753 ]; 1754 outbounds = [ 1755 { 1756 protocol = "freedom"; 1757 } 1758 { 1759 protocol = "freedom"; 1760 settings = { }; 1761 tag = "api"; 1762 } 1763 ]; 1764 routing = { 1765 strategy = "rules"; 1766 settings = { 1767 rules = [ 1768 { 1769 inboundTag = [ "api" ]; 1770 outboundTag = "api"; 1771 type = "field"; 1772 } 1773 ]; 1774 }; 1775 }; 1776 }; 1777 }; 1778 }; 1779 exporterTest = '' 1780 wait_for_unit("prometheus-v2ray-exporter.service") 1781 wait_for_open_port(9299) 1782 succeed("curl -sSf localhost:9299/scrape | grep 'v2ray_up 1'") 1783 ''; 1784 }; 1785 1786 varnish = { 1787 exporterConfig = { 1788 enable = true; 1789 instance = "/run/varnish/varnish"; 1790 group = "varnish"; 1791 }; 1792 metricProvider = { 1793 systemd.services.prometheus-varnish-exporter.after = [ 1794 "varnish.service" 1795 ]; 1796 services.varnish = { 1797 enable = true; 1798 stateDir = "/run/varnish/varnish"; 1799 config = '' 1800 vcl 4.0; 1801 backend default { 1802 .host = "127.0.0.1"; 1803 .port = "80"; 1804 } 1805 ''; 1806 }; 1807 }; 1808 exporterTest = '' 1809 wait_for_unit("prometheus-varnish-exporter.service") 1810 wait_for_open_port(6081) 1811 wait_for_open_port(9131) 1812 succeed("curl -sSf http://localhost:9131/metrics | grep 'varnish_up 1'") 1813 ''; 1814 }; 1815 1816 wireguard = 1817 let 1818 snakeoil = import ./wireguard/snakeoil-keys.nix; 1819 publicKeyWithoutNewlines = replaceStrings [ "\n" ] [ "" ] snakeoil.peer1.publicKey; 1820 in 1821 { 1822 exporterConfig.enable = true; 1823 metricProvider = { 1824 networking.wireguard.interfaces.wg0 = { 1825 ips = [ 1826 "10.23.42.1/32" 1827 "fc00::1/128" 1828 ]; 1829 listenPort = 23542; 1830 1831 inherit (snakeoil.peer0) privateKey; 1832 1833 peers = singleton { 1834 allowedIPs = [ 1835 "10.23.42.2/32" 1836 "fc00::2/128" 1837 ]; 1838 1839 inherit (snakeoil.peer1) publicKey; 1840 }; 1841 }; 1842 systemd.services.prometheus-wireguard-exporter.after = [ "wireguard-wg0.service" ]; 1843 }; 1844 exporterTest = '' 1845 wait_for_unit("prometheus-wireguard-exporter.service") 1846 wait_for_open_port(9586) 1847 wait_until_succeeds( 1848 "curl -sSf http://localhost:9586/metrics | grep '${publicKeyWithoutNewlines}'" 1849 ) 1850 ''; 1851 }; 1852 1853 zfs = { 1854 exporterConfig = { 1855 enable = true; 1856 }; 1857 metricProvider = { 1858 boot.supportedFilesystems = [ "zfs" ]; 1859 networking.hostId = "7327ded7"; 1860 }; 1861 exporterTest = '' 1862 wait_for_unit("prometheus-zfs-exporter.service") 1863 wait_for_unit("zfs.target") 1864 wait_for_open_port(9134) 1865 wait_until_succeeds("curl -f localhost:9134/metrics | grep 'zfs_scrape_collector_success{.*} 1'") 1866 ''; 1867 }; 1868 }; 1869in 1870mapAttrs ( 1871 exporter: testConfig: 1872 (makeTest ( 1873 let 1874 nodeName = testConfig.nodeName or exporter; 1875 1876 in 1877 { 1878 name = "prometheus-${exporter}-exporter"; 1879 1880 nodes.${nodeName} = mkMerge [ 1881 { 1882 services.prometheus.exporters.${exporter} = testConfig.exporterConfig; 1883 } 1884 testConfig.metricProvider or { } 1885 ]; 1886 1887 testScript = '' 1888 ${nodeName}.start() 1889 ${concatStringsSep "\n" ( 1890 map ( 1891 line: 1892 if 1893 builtins.any (b: b) [ 1894 (builtins.match "^[[:space:]]*$" line != null) 1895 (builtins.substring 0 1 line == "#") 1896 (builtins.substring 0 1 line == " ") 1897 (builtins.substring 0 1 line == ")") 1898 ] 1899 then 1900 line 1901 else 1902 "${nodeName}.${line}" 1903 ) (splitString "\n" (removeSuffix "\n" testConfig.exporterTest)) 1904 )} 1905 ${nodeName}.shutdown() 1906 ''; 1907 1908 meta = with maintainers; { 1909 maintainers = [ willibutz ]; 1910 }; 1911 } 1912 )) 1913) exporterTests