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