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