at 23.11-pre 45 kB view raw
1{ system ? builtins.currentSystem 2, config ? { } 3, pkgs ? import ../.. { inherit system config; } 4}: 5 6let 7 inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest; 8 inherit (pkgs.lib) concatStringsSep maintainers mapAttrs mkMerge 9 removeSuffix replaceStrings singleton splitString; 10 11 /* 12 * The attrset `exporterTests` contains one attribute 13 * for each exporter test. Each of these attributes 14 * is expected to be an attrset containing: 15 * 16 * `exporterConfig`: 17 * this attribute set contains config for the exporter itself 18 * 19 * `exporterTest` 20 * this attribute set contains test instructions 21 * 22 * `metricProvider` (optional) 23 * this attribute contains additional machine config 24 * 25 * `nodeName` (optional) 26 * override an incompatible testnode name 27 * 28 * Example: 29 * exporterTests.<exporterName> = { 30 * exporterConfig = { 31 * enable = true; 32 * }; 33 * metricProvider = { 34 * services.<metricProvider>.enable = true; 35 * }; 36 * exporterTest = '' 37 * wait_for_unit("prometheus-<exporterName>-exporter.service") 38 * wait_for_open_port(1234) 39 * succeed("curl -sSf 'localhost:1234/metrics'") 40 * ''; 41 * }; 42 * 43 * # this would generate the following test config: 44 * 45 * nodes.<exporterName> = { 46 * services.prometheus.<exporterName> = { 47 * enable = true; 48 * }; 49 * services.<metricProvider>.enable = true; 50 * }; 51 * 52 * testScript = '' 53 * <exporterName>.start() 54 * <exporterName>.wait_for_unit("prometheus-<exporterName>-exporter.service") 55 * <exporterName>.wait_for_open_port(1234) 56 * <exporterName>.succeed("curl -sSf 'localhost:1234/metrics'") 57 * <exporterName>.shutdown() 58 * ''; 59 */ 60 61 exporterTests = { 62 apcupsd = { 63 exporterConfig = { 64 enable = true; 65 }; 66 metricProvider = { 67 services.apcupsd.enable = true; 68 }; 69 exporterTest = '' 70 wait_for_unit("apcupsd.service") 71 wait_for_open_port(3551) 72 wait_for_unit("prometheus-apcupsd-exporter.service") 73 wait_for_open_port(9162) 74 succeed("curl -sSf http://localhost:9162/metrics | grep 'apcupsd_info'") 75 ''; 76 }; 77 78 artifactory = { 79 exporterConfig = { 80 enable = true; 81 artiUsername = "artifactory-username"; 82 artiPassword = "artifactory-password"; 83 }; 84 exporterTest = '' 85 wait_for_unit("prometheus-artifactory-exporter.service") 86 wait_for_open_port(9531) 87 succeed( 88 "curl -sSf http://localhost:9531/metrics | grep 'artifactory_up'" 89 ) 90 ''; 91 }; 92 93 bind = { 94 exporterConfig = { 95 enable = true; 96 }; 97 metricProvider = { 98 services.bind.enable = true; 99 services.bind.extraConfig = '' 100 statistics-channels { 101 inet 127.0.0.1 port 8053 allow { localhost; }; 102 }; 103 ''; 104 }; 105 exporterTest = '' 106 wait_for_unit("prometheus-bind-exporter.service") 107 wait_for_open_port(9119) 108 succeed( 109 "curl -sSf http://localhost:9119/metrics | grep 'bind_query_recursions_total 0'" 110 ) 111 ''; 112 }; 113 114 bird = { 115 exporterConfig = { 116 enable = true; 117 }; 118 metricProvider = { 119 services.bird2.enable = true; 120 services.bird2.config = '' 121 router id 127.0.0.1; 122 123 protocol kernel MyObviousTestString { 124 ipv4 { 125 import all; 126 export none; 127 }; 128 } 129 130 protocol device { 131 } 132 ''; 133 }; 134 exporterTest = '' 135 wait_for_unit("prometheus-bird-exporter.service") 136 wait_for_open_port(9324) 137 wait_until_succeeds( 138 "curl -sSf http://localhost:9324/metrics | grep 'MyObviousTestString'" 139 ) 140 ''; 141 }; 142 143 bitcoin = { 144 exporterConfig = { 145 enable = true; 146 rpcUser = "bitcoinrpc"; 147 rpcPasswordFile = pkgs.writeText "password" "hunter2"; 148 }; 149 metricProvider = { 150 services.bitcoind.default.enable = true; 151 services.bitcoind.default.rpc.users.bitcoinrpc.passwordHMAC = "e8fe33f797e698ac258c16c8d7aadfbe$872bdb8f4d787367c26bcfd75e6c23c4f19d44a69f5d1ad329e5adf3f82710f7"; 152 }; 153 exporterTest = '' 154 wait_for_unit("prometheus-bitcoin-exporter.service") 155 wait_for_unit("bitcoind-default.service") 156 wait_for_open_port(9332) 157 succeed("curl -sSf http://localhost:9332/metrics | grep '^bitcoin_blocks '") 158 ''; 159 }; 160 161 blackbox = { 162 exporterConfig = { 163 enable = true; 164 configFile = pkgs.writeText "config.yml" (builtins.toJSON { 165 modules.icmp_v6 = { 166 prober = "icmp"; 167 icmp.preferred_ip_protocol = "ip6"; 168 }; 169 }); 170 }; 171 exporterTest = '' 172 wait_for_unit("prometheus-blackbox-exporter.service") 173 wait_for_open_port(9115) 174 succeed( 175 "curl -sSf 'http://localhost:9115/probe?target=localhost&module=icmp_v6' | grep 'probe_success 1'" 176 ) 177 ''; 178 }; 179 180 collectd = { 181 exporterConfig = { 182 enable = true; 183 extraFlags = [ "--web.collectd-push-path /collectd" ]; 184 }; 185 exporterTest = let postData = replaceStrings [ "\n" ] [ "" ] '' 186 [{ 187 "values":[23], 188 "dstypes":["gauge"], 189 "type":"gauge", 190 "interval":1000, 191 "host":"testhost", 192 "plugin":"testplugin", 193 "time":DATE 194 }] 195 ''; in 196 '' 197 wait_for_unit("prometheus-collectd-exporter.service") 198 wait_for_open_port(9103) 199 succeed( 200 'echo \'${postData}\'> /tmp/data.json' 201 ) 202 succeed('sed -ie "s DATE $(date +%s) " /tmp/data.json') 203 succeed( 204 "curl -sSfH 'Content-Type: application/json' -X POST --data @/tmp/data.json localhost:9103/collectd" 205 ) 206 succeed( 207 "curl -sSf localhost:9103/metrics | grep 'collectd_testplugin_gauge{instance=\"testhost\"} 23'" 208 ) 209 ''; 210 }; 211 212 dnsmasq = { 213 exporterConfig = { 214 enable = true; 215 leasesPath = "/var/lib/dnsmasq/dnsmasq.leases"; 216 }; 217 metricProvider = { 218 services.dnsmasq.enable = true; 219 }; 220 exporterTest = '' 221 wait_for_unit("prometheus-dnsmasq-exporter.service") 222 wait_for_open_port(9153) 223 succeed("curl -sSf http://localhost:9153/metrics | grep 'dnsmasq_leases 0'") 224 ''; 225 }; 226 227 # Access to WHOIS server is required to properly test this exporter, so 228 # just perform basic sanity check that the exporter is running and returns 229 # a failure. 230 domain = { 231 exporterConfig = { 232 enable = true; 233 }; 234 exporterTest = '' 235 wait_for_unit("prometheus-domain-exporter.service") 236 wait_for_open_port(9222) 237 succeed("curl -sSf 'http://localhost:9222/probe?target=nixos.org'") 238 ''; 239 }; 240 241 dovecot = { 242 exporterConfig = { 243 enable = true; 244 scopes = [ "global" ]; 245 socketPath = "/var/run/dovecot2/old-stats"; 246 user = "root"; # <- don't use user root in production 247 }; 248 metricProvider = { 249 services.dovecot2.enable = true; 250 }; 251 exporterTest = '' 252 wait_for_unit("prometheus-dovecot-exporter.service") 253 wait_for_open_port(9166) 254 succeed( 255 "curl -sSf http://localhost:9166/metrics | grep 'dovecot_up{scope=\"global\"} 1'" 256 ) 257 ''; 258 }; 259 260 fastly = { 261 exporterConfig = { 262 enable = true; 263 tokenPath = pkgs.writeText "token" "abc123"; 264 }; 265 266 # noop: fastly's exporter can't start without first talking to fastly 267 # see: https://github.com/peterbourgon/fastly-exporter/issues/87 268 exporterTest = '' 269 succeed("true"); 270 ''; 271 }; 272 273 fritzbox = { 274 # TODO add proper test case 275 exporterConfig = { 276 enable = true; 277 }; 278 exporterTest = '' 279 wait_for_unit("prometheus-fritzbox-exporter.service") 280 wait_for_open_port(9133) 281 succeed( 282 "curl -sSf http://localhost:9133/metrics | grep 'fritzbox_exporter_collect_errors 0'" 283 ) 284 ''; 285 }; 286 287 influxdb = { 288 exporterConfig = { 289 enable = true; 290 sampleExpiry = "3s"; 291 }; 292 exporterTest = '' 293 wait_for_unit("prometheus-influxdb-exporter.service") 294 wait_for_open_port(9122) 295 succeed( 296 "curl -XPOST http://localhost:9122/write --data-binary 'influxdb_exporter,distro=nixos,added_in=21.09 value=1'" 297 ) 298 succeed( 299 "curl -sSf http://localhost:9122/metrics | grep 'nixos'" 300 ) 301 execute("sleep 5") 302 fail( 303 "curl -sSf http://localhost:9122/metrics | grep 'nixos'" 304 ) 305 ''; 306 }; 307 308 ipmi = { 309 exporterConfig = { 310 enable = true; 311 }; 312 exporterTest = '' 313 wait_for_unit("prometheus-ipmi-exporter.service") 314 wait_for_open_port(9290) 315 succeed( 316 "curl -sSf http://localhost:9290/metrics | grep 'ipmi_scrape_duration_seconds'" 317 ) 318 ''; 319 }; 320 321 jitsi = { 322 exporterConfig = { 323 enable = true; 324 }; 325 metricProvider = { 326 systemd.services.prometheus-jitsi-exporter.after = [ "jitsi-videobridge2.service" ]; 327 services.jitsi-videobridge = { 328 enable = true; 329 colibriRestApi = true; 330 }; 331 }; 332 exporterTest = '' 333 wait_for_unit("jitsi-videobridge2.service") 334 wait_for_open_port(8080) 335 wait_for_unit("prometheus-jitsi-exporter.service") 336 wait_for_open_port(9700) 337 wait_until_succeeds( 338 'journalctl -eu prometheus-jitsi-exporter.service -o cat | grep "key=participants"' 339 ) 340 succeed("curl -sSf 'localhost:9700/metrics' | grep 'jitsi_participants 0'") 341 ''; 342 }; 343 344 json = { 345 exporterConfig = { 346 enable = true; 347 url = "http://localhost"; 348 configFile = pkgs.writeText "json-exporter-conf.json" (builtins.toJSON { 349 modules = { 350 default = { 351 metrics = [ 352 { name = "json_test_metric"; path = "{ .test }"; } 353 ]; 354 }; 355 }; 356 }); 357 }; 358 metricProvider = { 359 systemd.services.prometheus-json-exporter.after = [ "nginx.service" ]; 360 services.nginx = { 361 enable = true; 362 virtualHosts.localhost.locations."/".extraConfig = '' 363 return 200 "{\"test\":1}"; 364 ''; 365 }; 366 }; 367 exporterTest = '' 368 wait_for_unit("nginx.service") 369 wait_for_open_port(80) 370 wait_for_unit("prometheus-json-exporter.service") 371 wait_for_open_port(7979) 372 succeed( 373 "curl -sSf 'localhost:7979/probe?target=http://localhost' | grep 'json_test_metric 1'" 374 ) 375 ''; 376 }; 377 378 kea = let 379 controlSocketPathV4 = "/run/kea/dhcp4.sock"; 380 controlSocketPathV6 = "/run/kea/dhcp6.sock"; 381 in 382 { 383 exporterConfig = { 384 enable = true; 385 controlSocketPaths = [ 386 controlSocketPathV4 387 controlSocketPathV6 388 ]; 389 }; 390 metricProvider = { 391 services.kea = { 392 dhcp4 = { 393 enable = true; 394 settings = { 395 control-socket = { 396 socket-type = "unix"; 397 socket-name = controlSocketPathV4; 398 }; 399 }; 400 }; 401 dhcp6 = { 402 enable = true; 403 settings = { 404 control-socket = { 405 socket-type = "unix"; 406 socket-name = controlSocketPathV6; 407 }; 408 }; 409 }; 410 }; 411 }; 412 413 exporterTest = '' 414 wait_for_unit("kea-dhcp4-server.service") 415 wait_for_unit("kea-dhcp6-server.service") 416 wait_for_file("${controlSocketPathV4}") 417 wait_for_file("${controlSocketPathV6}") 418 wait_for_unit("prometheus-kea-exporter.service") 419 wait_for_open_port(9547) 420 succeed( 421 "curl --fail localhost:9547/metrics | grep 'packets_received_total'" 422 ) 423 ''; 424 }; 425 426 knot = { 427 exporterConfig = { 428 enable = true; 429 }; 430 metricProvider = { 431 services.knot = { 432 enable = true; 433 extraArgs = [ "-v" ]; 434 extraConfig = '' 435 server: 436 listen: 127.0.0.1@53 437 438 template: 439 - id: default 440 global-module: mod-stats 441 dnssec-signing: off 442 zonefile-sync: -1 443 journal-db: /var/lib/knot/journal 444 kasp-db: /var/lib/knot/kasp 445 timer-db: /var/lib/knot/timer 446 zonefile-load: difference 447 storage: ${pkgs.buildEnv { 448 name = "foo"; 449 paths = [ 450 (pkgs.writeTextDir "test.zone" '' 451 @ SOA ns.example.com. noc.example.com. 2019031301 86400 7200 3600000 172800 452 @ NS ns1 453 @ NS ns2 454 ns1 A 192.168.0.1 455 '') 456 ]; 457 }} 458 459 mod-stats: 460 - id: custom 461 edns-presence: on 462 query-type: on 463 464 zone: 465 - domain: test 466 file: test.zone 467 module: mod-stats/custom 468 ''; 469 }; 470 }; 471 exporterTest = '' 472 wait_for_unit("knot.service") 473 wait_for_unit("prometheus-knot-exporter.service") 474 wait_for_open_port(9433) 475 succeed("curl -sSf 'localhost:9433' | grep 'knot_server_zone_count 1.0'") 476 ''; 477 }; 478 479 keylight = { 480 # A hardware device is required to properly test this exporter, so just 481 # perform a couple of basic sanity checks that the exporter is running 482 # and requires a target, but cannot reach a specified target. 483 exporterConfig = { 484 enable = true; 485 }; 486 exporterTest = '' 487 wait_for_unit("prometheus-keylight-exporter.service") 488 wait_for_open_port(9288) 489 succeed( 490 "curl -sS --write-out '%{http_code}' -o /dev/null http://localhost:9288/metrics | grep '400'" 491 ) 492 succeed( 493 "curl -sS --write-out '%{http_code}' -o /dev/null http://localhost:9288/metrics?target=nosuchdevice | grep '500'" 494 ) 495 ''; 496 }; 497 498 lnd = { 499 exporterConfig = { 500 enable = true; 501 lndTlsPath = "/var/lib/lnd/tls.cert"; 502 lndMacaroonDir = "/var/lib/lnd"; 503 extraFlags = [ "--lnd.network=regtest" ]; 504 }; 505 metricProvider = { 506 systemd.services.prometheus-lnd-exporter.serviceConfig.RestartSec = 15; 507 systemd.services.prometheus-lnd-exporter.after = [ "lnd.service" ]; 508 services.bitcoind.regtest = { 509 enable = true; 510 extraConfig = '' 511 rpcauth=bitcoinrpc:e8fe33f797e698ac258c16c8d7aadfbe$872bdb8f4d787367c26bcfd75e6c23c4f19d44a69f5d1ad329e5adf3f82710f7 512 zmqpubrawblock=tcp://127.0.0.1:28332 513 zmqpubrawtx=tcp://127.0.0.1:28333 514 ''; 515 extraCmdlineOptions = [ "-regtest" ]; 516 }; 517 systemd.services.lnd = { 518 serviceConfig.ExecStart = '' 519 ${pkgs.lnd}/bin/lnd \ 520 --datadir=/var/lib/lnd \ 521 --tlscertpath=/var/lib/lnd/tls.cert \ 522 --tlskeypath=/var/lib/lnd/tls.key \ 523 --logdir=/var/log/lnd \ 524 --bitcoin.active \ 525 --bitcoin.regtest \ 526 --bitcoin.node=bitcoind \ 527 --bitcoind.rpcuser=bitcoinrpc \ 528 --bitcoind.rpcpass=hunter2 \ 529 --bitcoind.zmqpubrawblock=tcp://127.0.0.1:28332 \ 530 --bitcoind.zmqpubrawtx=tcp://127.0.0.1:28333 \ 531 --readonlymacaroonpath=/var/lib/lnd/readonly.macaroon 532 ''; 533 serviceConfig.StateDirectory = "lnd"; 534 wantedBy = [ "multi-user.target" ]; 535 after = [ "network.target" ]; 536 }; 537 # initialize wallet, creates macaroon needed by exporter 538 systemd.services.lnd.postStart = '' 539 ${pkgs.curl}/bin/curl \ 540 --retry 20 \ 541 --retry-delay 1 \ 542 --retry-connrefused \ 543 --cacert /var/lib/lnd/tls.cert \ 544 -X GET \ 545 https://localhost:8080/v1/genseed | ${pkgs.jq}/bin/jq -c '.cipher_seed_mnemonic' > /tmp/seed 546 ${pkgs.curl}/bin/curl \ 547 --retry 20 \ 548 --retry-delay 1 \ 549 --retry-connrefused \ 550 --cacert /var/lib/lnd/tls.cert \ 551 -X POST \ 552 -d "{\"wallet_password\": \"asdfasdfasdf\", \"cipher_seed_mnemonic\": $(cat /tmp/seed | tr -d '\n')}" \ 553 https://localhost:8080/v1/initwallet 554 ''; 555 }; 556 exporterTest = '' 557 wait_for_unit("lnd.service") 558 wait_for_open_port(10009) 559 wait_for_unit("prometheus-lnd-exporter.service") 560 wait_for_open_port(9092) 561 succeed("curl -sSf localhost:9092/metrics | grep '^lnd_peer_count'") 562 ''; 563 }; 564 565 mail = { 566 exporterConfig = { 567 enable = true; 568 configuration = { 569 monitoringInterval = "2s"; 570 mailCheckTimeout = "10s"; 571 servers = [{ 572 name = "testserver"; 573 server = "localhost"; 574 port = 25; 575 from = "mail-exporter@localhost"; 576 to = "mail-exporter@localhost"; 577 detectionDir = "/var/spool/mail/mail-exporter/new"; 578 }]; 579 }; 580 }; 581 metricProvider = { 582 services.postfix.enable = true; 583 systemd.services.prometheus-mail-exporter = { 584 after = [ "postfix.service" ]; 585 requires = [ "postfix.service" ]; 586 serviceConfig = { 587 ExecStartPre = [ 588 "${pkgs.writeShellScript "create-maildir" '' 589 mkdir -p -m 0700 mail-exporter/new 590 ''}" 591 ]; 592 ProtectHome = true; 593 ReadOnlyPaths = "/"; 594 ReadWritePaths = "/var/spool/mail"; 595 WorkingDirectory = "/var/spool/mail"; 596 }; 597 }; 598 users.users.mailexporter = { 599 isSystemUser = true; 600 group = "mailexporter"; 601 }; 602 users.groups.mailexporter = {}; 603 }; 604 exporterTest = '' 605 wait_for_unit("postfix.service") 606 wait_for_unit("prometheus-mail-exporter.service") 607 wait_for_open_port(9225) 608 wait_until_succeeds( 609 "curl -sSf http://localhost:9225/metrics | grep 'mail_deliver_success{configname=\"testserver\"} 1'" 610 ) 611 ''; 612 }; 613 614 mikrotik = { 615 exporterConfig = { 616 enable = true; 617 extraFlags = [ "-timeout=1s" ]; 618 configuration = { 619 devices = [ 620 { 621 name = "router"; 622 address = "192.168.42.48"; 623 user = "prometheus"; 624 password = "shh"; 625 } 626 ]; 627 features = { 628 bgp = true; 629 dhcp = true; 630 dhcpl = true; 631 dhcpv6 = true; 632 health = true; 633 routes = true; 634 poe = true; 635 pools = true; 636 optics = true; 637 w60g = true; 638 wlansta = true; 639 wlanif = true; 640 monitor = true; 641 ipsec = true; 642 }; 643 }; 644 }; 645 exporterTest = '' 646 wait_for_unit("prometheus-mikrotik-exporter.service") 647 wait_for_open_port(9436) 648 succeed( 649 "curl -sSf http://localhost:9436/metrics | grep 'mikrotik_scrape_collector_success{device=\"router\"} 0'" 650 ) 651 ''; 652 }; 653 654 modemmanager = { 655 exporterConfig = { 656 enable = true; 657 refreshRate = "10s"; 658 }; 659 metricProvider = { 660 # ModemManager is installed when NetworkManager is enabled. Ensure it is 661 # started and is wanted by NM and the exporter to start everything up 662 # in the right order. 663 networking.networkmanager.enable = true; 664 systemd.services.ModemManager = { 665 enable = true; 666 wantedBy = [ "NetworkManager.service" "prometheus-modemmanager-exporter.service" ]; 667 }; 668 }; 669 exporterTest = '' 670 wait_for_unit("ModemManager.service") 671 wait_for_unit("prometheus-modemmanager-exporter.service") 672 wait_for_open_port(9539) 673 succeed( 674 "curl -sSf http://localhost:9539/metrics | grep 'modemmanager_info'" 675 ) 676 ''; 677 }; 678 679 nextcloud = { 680 exporterConfig = { 681 enable = true; 682 passwordFile = "/var/nextcloud-pwfile"; 683 url = "http://localhost"; 684 }; 685 metricProvider = { 686 systemd.services.nc-pwfile = 687 let 688 passfile = (pkgs.writeText "pwfile" "snakeoilpw"); 689 in 690 { 691 requiredBy = [ "prometheus-nextcloud-exporter.service" ]; 692 before = [ "prometheus-nextcloud-exporter.service" ]; 693 serviceConfig.ExecStart = '' 694 ${pkgs.coreutils}/bin/install -o nextcloud-exporter -m 0400 ${passfile} /var/nextcloud-pwfile 695 ''; 696 }; 697 services.nginx = { 698 enable = true; 699 virtualHosts."localhost" = { 700 basicAuth.nextcloud-exporter = "snakeoilpw"; 701 locations."/" = { 702 root = "${pkgs.prometheus-nextcloud-exporter.src}/serverinfo/testdata"; 703 tryFiles = "/negative-space.json =404"; 704 }; 705 }; 706 }; 707 }; 708 exporterTest = '' 709 wait_for_unit("nginx.service") 710 wait_for_unit("prometheus-nextcloud-exporter.service") 711 wait_for_open_port(9205) 712 succeed("curl -sSf http://localhost:9205/metrics | grep 'nextcloud_up 1'") 713 ''; 714 }; 715 716 nginx = { 717 exporterConfig = { 718 enable = true; 719 }; 720 metricProvider = { 721 services.nginx = { 722 enable = true; 723 statusPage = true; 724 virtualHosts."test".extraConfig = "return 204;"; 725 }; 726 }; 727 exporterTest = '' 728 wait_for_unit("nginx.service") 729 wait_for_unit("prometheus-nginx-exporter.service") 730 wait_for_open_port(9113) 731 succeed("curl -sSf http://localhost:9113/metrics | grep 'nginx_up 1'") 732 ''; 733 }; 734 735 nginxlog = { 736 exporterConfig = { 737 enable = true; 738 group = "nginx"; 739 settings = { 740 namespaces = [ 741 { 742 name = "filelogger"; 743 source = { 744 files = [ "/var/log/nginx/filelogger.access.log" ]; 745 }; 746 } 747 { 748 name = "syslogger"; 749 source = { 750 syslog = { 751 listen_address = "udp://127.0.0.1:10000"; 752 format = "rfc3164"; 753 tags = [ "nginx" ]; 754 }; 755 }; 756 } 757 ]; 758 }; 759 }; 760 metricProvider = { 761 services.nginx = { 762 enable = true; 763 httpConfig = '' 764 server { 765 listen 80; 766 server_name filelogger.local; 767 access_log /var/log/nginx/filelogger.access.log; 768 } 769 server { 770 listen 81; 771 server_name syslogger.local; 772 access_log syslog:server=127.0.0.1:10000,tag=nginx,severity=info; 773 } 774 ''; 775 }; 776 }; 777 exporterTest = '' 778 wait_for_unit("nginx.service") 779 wait_for_unit("prometheus-nginxlog-exporter.service") 780 wait_for_open_port(9117) 781 wait_for_open_port(80) 782 wait_for_open_port(81) 783 succeed("curl http://localhost") 784 execute("sleep 1") 785 succeed( 786 "curl -sSf http://localhost:9117/metrics | grep 'filelogger_http_response_count_total' | grep 1" 787 ) 788 succeed("curl http://localhost:81") 789 execute("sleep 1") 790 succeed( 791 "curl -sSf http://localhost:9117/metrics | grep 'syslogger_http_response_count_total' | grep 1" 792 ) 793 ''; 794 }; 795 796 node = { 797 exporterConfig = { 798 enable = true; 799 }; 800 exporterTest = '' 801 wait_for_unit("prometheus-node-exporter.service") 802 wait_for_open_port(9100) 803 succeed( 804 "curl -sSf http://localhost:9100/metrics | grep 'node_exporter_build_info{.\\+} 1'" 805 ) 806 ''; 807 }; 808 809 openldap = { 810 exporterConfig = { 811 enable = true; 812 ldapCredentialFile = "${pkgs.writeText "exporter.yml" '' 813 ldapUser: "cn=root,dc=example" 814 ldapPass: "notapassword" 815 ''}"; 816 }; 817 metricProvider = { 818 services.openldap = { 819 enable = true; 820 settings.children = { 821 "cn=schema".includes = [ 822 "${pkgs.openldap}/etc/schema/core.ldif" 823 "${pkgs.openldap}/etc/schema/cosine.ldif" 824 "${pkgs.openldap}/etc/schema/inetorgperson.ldif" 825 "${pkgs.openldap}/etc/schema/nis.ldif" 826 ]; 827 "olcDatabase={1}mdb" = { 828 attrs = { 829 objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ]; 830 olcDatabase = "{1}mdb"; 831 olcDbDirectory = "/var/db/openldap"; 832 olcSuffix = "dc=example"; 833 olcRootDN = { 834 # cn=root,dc=example 835 base64 = "Y249cm9vdCxkYz1leGFtcGxl"; 836 }; 837 olcRootPW = { 838 path = "${pkgs.writeText "rootpw" "notapassword"}"; 839 }; 840 }; 841 }; 842 "olcDatabase={2}monitor".attrs = { 843 objectClass = [ "olcDatabaseConfig" ]; 844 olcDatabase = "{2}monitor"; 845 olcAccess = [ "to dn.subtree=cn=monitor by users read" ]; 846 }; 847 }; 848 declarativeContents."dc=example" = '' 849 dn: dc=example 850 objectClass: domain 851 dc: example 852 853 dn: ou=users,dc=example 854 objectClass: organizationalUnit 855 ou: users 856 ''; 857 }; 858 }; 859 exporterTest = '' 860 wait_for_unit("prometheus-openldap-exporter.service") 861 wait_for_open_port(389) 862 wait_for_open_port(9330) 863 wait_until_succeeds( 864 "curl -sSf http://localhost:9330/metrics | grep 'openldap_scrape{result=\"ok\"} 1'" 865 ) 866 ''; 867 }; 868 869 openvpn = { 870 exporterConfig = { 871 enable = true; 872 group = "openvpn"; 873 statusPaths = [ "/run/openvpn-test" ]; 874 }; 875 metricProvider = { 876 users.groups.openvpn = { }; 877 services.openvpn.servers.test = { 878 config = '' 879 dev tun 880 status /run/openvpn-test 881 status-version 3 882 ''; 883 up = "chmod g+r /run/openvpn-test"; 884 }; 885 systemd.services."openvpn-test".serviceConfig.Group = "openvpn"; 886 }; 887 exporterTest = '' 888 wait_for_unit("openvpn-test.service") 889 wait_for_unit("prometheus-openvpn-exporter.service") 890 succeed("curl -sSf http://localhost:9176/metrics | grep 'openvpn_up{.*} 1'") 891 ''; 892 }; 893 894 postfix = { 895 exporterConfig = { 896 enable = true; 897 }; 898 metricProvider = { 899 services.postfix.enable = true; 900 }; 901 exporterTest = '' 902 wait_for_unit("prometheus-postfix-exporter.service") 903 wait_for_file("/var/lib/postfix/queue/public/showq") 904 wait_for_open_port(9154) 905 wait_until_succeeds( 906 "curl -sSf http://localhost:9154/metrics | grep 'postfix_up{path=\"/var/lib/postfix/queue/public/showq\"} 1'" 907 ) 908 succeed( 909 "curl -sSf http://localhost:9154/metrics | grep 'postfix_smtpd_connects_total 0'" 910 ) 911 succeed("curl -sSf http://localhost:9154/metrics | grep 'postfix_up{.*} 1'") 912 ''; 913 }; 914 915 postgres = { 916 exporterConfig = { 917 enable = true; 918 runAsLocalSuperUser = true; 919 }; 920 metricProvider = { 921 services.postgresql.enable = true; 922 }; 923 exporterTest = '' 924 wait_for_unit("prometheus-postgres-exporter.service") 925 wait_for_open_port(9187) 926 wait_for_unit("postgresql.service") 927 succeed( 928 "curl -sSf http://localhost:9187/metrics | grep 'pg_exporter_last_scrape_error 0'" 929 ) 930 succeed("curl -sSf http://localhost:9187/metrics | grep 'pg_up 1'") 931 systemctl("stop postgresql.service") 932 succeed( 933 "curl -sSf http://localhost:9187/metrics | grep -v 'pg_exporter_last_scrape_error 0'" 934 ) 935 succeed("curl -sSf http://localhost:9187/metrics | grep 'pg_up 0'") 936 systemctl("start postgresql.service") 937 wait_for_unit("postgresql.service") 938 succeed( 939 "curl -sSf http://localhost:9187/metrics | grep 'pg_exporter_last_scrape_error 0'" 940 ) 941 succeed("curl -sSf http://localhost:9187/metrics | grep 'pg_up 1'") 942 ''; 943 }; 944 945 process = { 946 exporterConfig = { 947 enable = true; 948 settings.process_names = [ 949 # Remove nix store path from process name 950 { name = "{{.Matches.Wrapped}} {{ .Matches.Args }}"; cmdline = [ "^/nix/store[^ ]*/(?P<Wrapped>[^ /]*) (?P<Args>.*)" ]; } 951 ]; 952 }; 953 exporterTest = '' 954 wait_for_unit("prometheus-process-exporter.service") 955 wait_for_open_port(9256) 956 wait_until_succeeds( 957 "curl -sSf localhost:9256/metrics | grep -q '{}'".format( 958 'namedprocess_namegroup_cpu_seconds_total{groupname="process-exporter ' 959 ) 960 ) 961 ''; 962 }; 963 964 pve = let 965 pveExporterEnvFile = pkgs.writeTextFile { 966 name = "pve.env"; 967 text = '' 968 PVE_USER="test_user@pam" 969 PVE_PASSWORD="hunter3" 970 PVE_VERIFY_SSL="false" 971 ''; 972 }; 973 in { 974 exporterConfig = { 975 enable = true; 976 environmentFile = pveExporterEnvFile; 977 }; 978 exporterTest = '' 979 wait_for_unit("prometheus-pve-exporter.service") 980 wait_for_open_port(9221) 981 wait_until_succeeds("curl localhost:9221") 982 ''; 983 }; 984 985 py-air-control = { 986 nodeName = "py_air_control"; 987 exporterConfig = { 988 enable = true; 989 deviceHostname = "127.0.0.1"; 990 }; 991 exporterTest = '' 992 wait_for_unit("prometheus-py-air-control-exporter.service") 993 wait_for_open_port(9896) 994 succeed( 995 "curl -sSf http://localhost:9896/metrics | grep 'py_air_control_sampling_error_total'" 996 ) 997 ''; 998 }; 999 1000 redis = { 1001 exporterConfig = { 1002 enable = true; 1003 }; 1004 metricProvider.services.redis.servers."".enable = true; 1005 exporterTest = '' 1006 wait_for_unit("redis.service") 1007 wait_for_unit("prometheus-redis-exporter.service") 1008 wait_for_open_port(6379) 1009 wait_for_open_port(9121) 1010 wait_until_succeeds("curl -sSf localhost:9121/metrics | grep 'redis_up 1'") 1011 ''; 1012 }; 1013 1014 rspamd = { 1015 exporterConfig = { 1016 enable = true; 1017 }; 1018 metricProvider = { 1019 services.rspamd.enable = true; 1020 }; 1021 exporterTest = '' 1022 wait_for_unit("rspamd.service") 1023 wait_for_unit("prometheus-rspamd-exporter.service") 1024 wait_for_open_port(11334) 1025 wait_for_open_port(7980) 1026 wait_until_succeeds( 1027 "curl -sSf 'localhost:7980/probe?target=http://localhost:11334/stat' | grep 'rspamd_scanned{host=\"rspamd\"} 0'" 1028 ) 1029 ''; 1030 }; 1031 1032 rtl_433 = { 1033 exporterConfig = { 1034 enable = true; 1035 }; 1036 metricProvider = { 1037 # Mock rtl_433 binary to return a dummy metric stream. 1038 nixpkgs.overlays = [ 1039 (self: super: { 1040 rtl_433 = self.runCommand "rtl_433" { } '' 1041 mkdir -p "$out/bin" 1042 cat <<EOF > "$out/bin/rtl_433" 1043 #!/bin/sh 1044 while true; do 1045 printf '{"time" : "2020-04-26 13:37:42", "model" : "zopieux", "id" : 55, "channel" : 3, "temperature_C" : 18.000}\n' 1046 sleep 4 1047 done 1048 EOF 1049 chmod +x "$out/bin/rtl_433" 1050 ''; 1051 }) 1052 ]; 1053 }; 1054 exporterTest = '' 1055 wait_for_unit("prometheus-rtl_433-exporter.service") 1056 wait_for_open_port(9550) 1057 wait_until_succeeds( 1058 "curl -sSf localhost:9550/metrics | grep '{}'".format( 1059 'rtl_433_temperature_celsius{channel="3",id="55",location="",model="zopieux"} 18' 1060 ) 1061 ) 1062 ''; 1063 }; 1064 1065 shelly = { 1066 exporterConfig = { 1067 enable = true; 1068 metrics-file = "${pkgs.writeText "test.json" ''{}''}"; 1069 }; 1070 exporterTest = '' 1071 wait_for_unit("prometheus-shelly-exporter.service") 1072 wait_for_open_port(9784) 1073 wait_until_succeeds( 1074 "curl -sSf 'localhost:9784/metrics'" 1075 ) 1076 ''; 1077 }; 1078 1079 script = { 1080 exporterConfig = { 1081 enable = true; 1082 settings.scripts = [ 1083 { name = "success"; script = "sleep 1"; } 1084 ]; 1085 }; 1086 exporterTest = '' 1087 wait_for_unit("prometheus-script-exporter.service") 1088 wait_for_open_port(9172) 1089 wait_until_succeeds( 1090 "curl -sSf 'localhost:9172/probe?name=success' | grep -q '{}'".format( 1091 'script_success{script="success"} 1' 1092 ) 1093 ) 1094 ''; 1095 }; 1096 1097 smartctl = { 1098 exporterConfig = { 1099 enable = true; 1100 devices = [ 1101 "/dev/vda" 1102 ]; 1103 }; 1104 exporterTest = '' 1105 wait_until_succeeds( 1106 'journalctl -eu prometheus-smartctl-exporter.service -o cat | grep "Device unavailable"' 1107 ) 1108 ''; 1109 }; 1110 1111 smokeping = { 1112 exporterConfig = { 1113 enable = true; 1114 hosts = [ "127.0.0.1" ]; 1115 }; 1116 exporterTest = '' 1117 wait_for_unit("prometheus-smokeping-exporter.service") 1118 wait_for_open_port(9374) 1119 wait_until_succeeds( 1120 "curl -sSf localhost:9374/metrics | grep '{}' | grep -v ' 0$'".format( 1121 'smokeping_requests_total{host="127.0.0.1",ip="127.0.0.1"} ' 1122 ) 1123 ) 1124 wait_until_succeeds( 1125 "curl -sSf localhost:9374/metrics | grep '{}'".format( 1126 'smokeping_response_ttl{host="127.0.0.1",ip="127.0.0.1"}' 1127 ) 1128 ) 1129 ''; 1130 }; 1131 1132 snmp = { 1133 exporterConfig = { 1134 enable = true; 1135 configuration.default = { 1136 version = 2; 1137 auth.community = "public"; 1138 }; 1139 }; 1140 exporterTest = '' 1141 wait_for_unit("prometheus-snmp-exporter.service") 1142 wait_for_open_port(9116) 1143 succeed("curl -sSf localhost:9116/metrics | grep 'snmp_request_errors_total 0'") 1144 ''; 1145 }; 1146 1147 sql = { 1148 exporterConfig = { 1149 configuration.jobs.points = { 1150 interval = "1m"; 1151 connections = [ 1152 "postgres://prometheus-sql-exporter@/data?host=/run/postgresql&sslmode=disable" 1153 ]; 1154 queries = { 1155 points = { 1156 labels = [ "name" ]; 1157 help = "Amount of points accumulated per person"; 1158 values = [ "amount" ]; 1159 query = "SELECT SUM(amount) as amount, name FROM points GROUP BY name"; 1160 }; 1161 }; 1162 }; 1163 enable = true; 1164 user = "prometheus-sql-exporter"; 1165 }; 1166 metricProvider = { 1167 services.postgresql = { 1168 enable = true; 1169 initialScript = builtins.toFile "init.sql" '' 1170 CREATE DATABASE data; 1171 \c data; 1172 CREATE TABLE points (amount INT, name TEXT); 1173 INSERT INTO points(amount, name) VALUES (1, 'jack'); 1174 INSERT INTO points(amount, name) VALUES (2, 'jill'); 1175 INSERT INTO points(amount, name) VALUES (3, 'jack'); 1176 1177 CREATE USER "prometheus-sql-exporter"; 1178 GRANT ALL PRIVILEGES ON DATABASE data TO "prometheus-sql-exporter"; 1179 GRANT SELECT ON points TO "prometheus-sql-exporter"; 1180 ''; 1181 }; 1182 systemd.services.prometheus-sql-exporter.after = [ "postgresql.service" ]; 1183 }; 1184 exporterTest = '' 1185 wait_for_unit("prometheus-sql-exporter.service") 1186 wait_for_open_port(9237) 1187 succeed("curl http://localhost:9237/metrics | grep -c 'sql_points{' | grep 2") 1188 ''; 1189 }; 1190 1191 statsd = { 1192 exporterConfig = { 1193 enable = true; 1194 }; 1195 exporterTest = '' 1196 wait_for_unit("prometheus-statsd-exporter.service") 1197 wait_for_open_port(9102) 1198 succeed("curl http://localhost:9102/metrics | grep 'statsd_exporter_build_info{'") 1199 wait_until_succeeds( 1200 "echo 'test.udp:1|c' > /dev/udp/localhost/9125 && \ 1201 curl http://localhost:9102/metrics | grep 'test_udp 1'", 1202 timeout=10 1203 ) 1204 wait_until_succeeds( 1205 "echo 'test.tcp:1|c' > /dev/tcp/localhost/9125 && \ 1206 curl http://localhost:9102/metrics | grep 'test_tcp 1'", 1207 timeout=10 1208 ) 1209 ''; 1210 }; 1211 1212 surfboard = { 1213 exporterConfig = { 1214 enable = true; 1215 modemAddress = "localhost"; 1216 }; 1217 metricProvider = { 1218 systemd.services.prometheus-surfboard-exporter.after = [ "nginx.service" ]; 1219 services.nginx = { 1220 enable = true; 1221 virtualHosts.localhost.locations."/cgi-bin/status".extraConfig = '' 1222 return 204; 1223 ''; 1224 }; 1225 }; 1226 exporterTest = '' 1227 wait_for_unit("nginx.service") 1228 wait_for_open_port(80) 1229 wait_for_unit("prometheus-surfboard-exporter.service") 1230 wait_for_open_port(9239) 1231 succeed("curl -sSf localhost:9239/metrics | grep 'surfboard_up 1'") 1232 ''; 1233 }; 1234 1235 systemd = { 1236 exporterConfig = { 1237 enable = true; 1238 1239 extraFlags = [ 1240 "--systemd.collector.enable-restart-count" 1241 ]; 1242 }; 1243 metricProvider = { }; 1244 exporterTest = '' 1245 wait_for_unit("prometheus-systemd-exporter.service") 1246 wait_for_open_port(9558) 1247 wait_until_succeeds( 1248 "curl -sSf localhost:9558/metrics | grep '{}'".format( 1249 'systemd_unit_state{name="basic.target",state="active",type="target"} 1' 1250 ) 1251 ) 1252 succeed( 1253 "curl -sSf localhost:9558/metrics | grep '{}'".format( 1254 'systemd_service_restart_total{name="prometheus-systemd-exporter.service"} 0' 1255 ) 1256 ) 1257 ''; 1258 }; 1259 1260 tor = { 1261 exporterConfig = { 1262 enable = true; 1263 }; 1264 metricProvider = { 1265 # Note: this does not connect the test environment to the Tor network. 1266 # Client, relay, bridge or exit connectivity are disabled by default. 1267 services.tor.enable = true; 1268 services.tor.settings.ControlPort = 9051; 1269 }; 1270 exporterTest = '' 1271 wait_for_unit("tor.service") 1272 wait_for_open_port(9051) 1273 wait_for_unit("prometheus-tor-exporter.service") 1274 wait_for_open_port(9130) 1275 succeed("curl -sSf localhost:9130/metrics | grep 'tor_version{.\\+} 1'") 1276 ''; 1277 }; 1278 1279 unpoller = { 1280 nodeName = "unpoller"; 1281 exporterConfig.enable = true; 1282 exporterConfig.controllers = [{ }]; 1283 exporterTest = '' 1284 wait_until_succeeds( 1285 'journalctl -eu prometheus-unpoller-exporter.service -o cat | grep "Connection Error"' 1286 ) 1287 ''; 1288 }; 1289 1290 unbound = { 1291 exporterConfig = { 1292 enable = true; 1293 fetchType = "uds"; 1294 controlInterface = "/run/unbound/unbound.ctl"; 1295 }; 1296 metricProvider = { 1297 services.unbound = { 1298 enable = true; 1299 localControlSocketPath = "/run/unbound/unbound.ctl"; 1300 }; 1301 systemd.services.prometheus-unbound-exporter.serviceConfig = { 1302 SupplementaryGroups = [ "unbound" ]; 1303 }; 1304 }; 1305 exporterTest = '' 1306 wait_for_unit("unbound.service") 1307 wait_for_unit("prometheus-unbound-exporter.service") 1308 wait_for_open_port(9167) 1309 succeed("curl -sSf localhost:9167/metrics | grep 'unbound_up 1'") 1310 ''; 1311 }; 1312 1313 v2ray = { 1314 exporterConfig = { 1315 enable = true; 1316 }; 1317 1318 metricProvider = { 1319 systemd.services.prometheus-nginx-exporter.after = [ "v2ray.service" ]; 1320 services.v2ray = { 1321 enable = true; 1322 config = { 1323 stats = {}; 1324 api = { 1325 tag = "api"; 1326 services = [ "StatsService" ]; 1327 }; 1328 inbounds = [ 1329 { 1330 port = 1080; 1331 listen = "127.0.0.1"; 1332 protocol = "http"; 1333 } 1334 { 1335 listen = "127.0.0.1"; 1336 port = 54321; 1337 protocol = "dokodemo-door"; 1338 settings = { address = "127.0.0.1"; }; 1339 tag = "api"; 1340 } 1341 ]; 1342 outbounds = [ 1343 { 1344 protocol = "freedom"; 1345 } 1346 { 1347 protocol = "freedom"; 1348 settings = {}; 1349 tag = "api"; 1350 } 1351 ]; 1352 routing = { 1353 strategy = "rules"; 1354 settings = { 1355 rules = [ 1356 { 1357 inboundTag = [ "api" ]; 1358 outboundTag = "api"; 1359 type = "field"; 1360 } 1361 ]; 1362 }; 1363 }; 1364 }; 1365 }; 1366 }; 1367 exporterTest = '' 1368 wait_for_unit("prometheus-v2ray-exporter.service") 1369 wait_for_open_port(9299) 1370 succeed("curl -sSf localhost:9299/scrape | grep 'v2ray_up 1'") 1371 ''; 1372 }; 1373 1374 varnish = { 1375 exporterConfig = { 1376 enable = true; 1377 instance = "/var/spool/varnish/varnish"; 1378 group = "varnish"; 1379 }; 1380 metricProvider = { 1381 systemd.services.prometheus-varnish-exporter.after = [ 1382 "varnish.service" 1383 ]; 1384 services.varnish = { 1385 enable = true; 1386 config = '' 1387 vcl 4.0; 1388 backend default { 1389 .host = "127.0.0.1"; 1390 .port = "80"; 1391 } 1392 ''; 1393 }; 1394 }; 1395 exporterTest = '' 1396 wait_for_unit("prometheus-varnish-exporter.service") 1397 wait_for_open_port(6081) 1398 wait_for_open_port(9131) 1399 succeed("curl -sSf http://localhost:9131/metrics | grep 'varnish_up 1'") 1400 ''; 1401 }; 1402 1403 wireguard = let 1404 snakeoil = import ./wireguard/snakeoil-keys.nix; 1405 publicKeyWithoutNewlines = replaceStrings [ "\n" ] [ "" ] snakeoil.peer1.publicKey; 1406 in 1407 { 1408 exporterConfig.enable = true; 1409 metricProvider = { 1410 networking.wireguard.interfaces.wg0 = { 1411 ips = [ "10.23.42.1/32" "fc00::1/128" ]; 1412 listenPort = 23542; 1413 1414 inherit (snakeoil.peer0) privateKey; 1415 1416 peers = singleton { 1417 allowedIPs = [ "10.23.42.2/32" "fc00::2/128" ]; 1418 1419 inherit (snakeoil.peer1) publicKey; 1420 }; 1421 }; 1422 systemd.services.prometheus-wireguard-exporter.after = [ "wireguard-wg0.service" ]; 1423 }; 1424 exporterTest = '' 1425 wait_for_unit("prometheus-wireguard-exporter.service") 1426 wait_for_open_port(9586) 1427 wait_until_succeeds( 1428 "curl -sSf http://localhost:9586/metrics | grep '${publicKeyWithoutNewlines}'" 1429 ) 1430 ''; 1431 }; 1432 1433 zfs = { 1434 exporterConfig = { 1435 enable = true; 1436 }; 1437 metricProvider = { 1438 boot.supportedFilesystems = [ "zfs" ]; 1439 networking.hostId = "7327ded7"; 1440 }; 1441 exporterTest = '' 1442 wait_for_unit("prometheus-zfs-exporter.service") 1443 wait_for_unit("zfs.target") 1444 wait_for_open_port(9134) 1445 wait_until_succeeds("curl -f localhost:9134/metrics | grep 'zfs_scrape_collector_success{.*} 1'") 1446 ''; 1447 }; 1448 }; 1449in 1450mapAttrs 1451 (exporter: testConfig: (makeTest ( 1452 let 1453 nodeName = testConfig.nodeName or exporter; 1454 1455 in 1456 { 1457 name = "prometheus-${exporter}-exporter"; 1458 1459 nodes.${nodeName} = mkMerge [{ 1460 services.prometheus.exporters.${exporter} = testConfig.exporterConfig; 1461 } testConfig.metricProvider or { }]; 1462 1463 testScript = '' 1464 ${nodeName}.start() 1465 ${concatStringsSep "\n" (map (line: 1466 if (builtins.substring 0 1 line == " " || builtins.substring 0 1 line == ")") 1467 then line 1468 else "${nodeName}.${line}" 1469 ) (splitString "\n" (removeSuffix "\n" testConfig.exporterTest)))} 1470 ${nodeName}.shutdown() 1471 ''; 1472 1473 meta = with maintainers; { 1474 maintainers = [ willibutz ]; 1475 }; 1476 } 1477 ))) 1478 exporterTests