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