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