Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)

Merge pull request #59262 from basvandijk/prometheus2-release-19.03

Backport prometheus2 to release-19.03

authored by

Bas van Dijk and committed by
GitHub
012e05a9 2db665b6

+346 -40
+33
nixos/doc/manual/release-notes/rl-1903.xml
··· 125 <option>security.pam.services.&lt;name?&gt;.duoSecurity.enable</option>. 126 </para> 127 </listitem> 128 <listitem><para><filename>config/appstream.nix</filename></para></listitem> 129 <listitem><para><filename>config/xdg/sounds.nix</filename></para></listitem> 130 <listitem><para><filename>hardware/acpilight.nix</filename></para></listitem> ··· 559 <literal>nodejs-6_x</literal>, <literal>nodejs-slim-6_x</literal> and 560 <literal>nodePackages_6_x</literal> are removed. 561 </para> 562 </listitem> 563 </itemizedlist> 564 </section>
··· 125 <option>security.pam.services.&lt;name?&gt;.duoSecurity.enable</option>. 126 </para> 127 </listitem> 128 + 129 + <listitem> 130 + <para> 131 + Besides the existing <option>services.prometheus</option> module which 132 + targets Prometheus-1 a new <option>services.prometheus2</option> module 133 + has been added which targets Prometheus-2. 134 + </para> 135 + <para> 136 + Both modules can be enabled at the same time. In fact 137 + <link xlink:href="https://prometheus.io/docs/prometheus/latest/migration/#storage"> 138 + this is needed for upgrading existing Prometheus-1 data to Prometheus-2 139 + </link>. 140 + </para> 141 + </listitem> 142 <listitem><para><filename>config/appstream.nix</filename></para></listitem> 143 <listitem><para><filename>config/xdg/sounds.nix</filename></para></listitem> 144 <listitem><para><filename>hardware/acpilight.nix</filename></para></listitem> ··· 573 <literal>nodejs-6_x</literal>, <literal>nodejs-slim-6_x</literal> and 574 <literal>nodePackages_6_x</literal> are removed. 575 </para> 576 + </listitem> 577 + <listitem> 578 + <para> 579 + The directory where Prometheus will store its metric data is now 580 + managed by systemd's StateDirectory mechanism. It still defaults 581 + to <literal>/var/lib/prometheus</literal>. 582 + </para> 583 + <para> 584 + Its location can be specified by the new 585 + <option>services.prometheus.stateDir</option> option which 586 + defaults to <literal>prometheus</literal>. Note that this should 587 + be a directory relative to <literal>/var/lib/</literal>. 588 + </para> 589 + <para> 590 + The option <option>services.prometheus.dataDir</option> has been 591 + deprecated. You can still set it but it's now required to have 592 + <literal>/var/lib/</literal> as a prefix and you can't set 593 + <option>services.prometheus.stateDir</option> at the same time. 594 + </para> 595 </listitem> 596 </itemizedlist> 597 </section>
+271 -31
nixos/modules/services/monitoring/prometheus/default.nix
··· 4 5 let 6 cfg = config.services.prometheus; 7 promUser = "prometheus"; 8 promGroup = "prometheus"; 9 10 # Get a submodule without any embedded metadata: 11 _filter = x: filterAttrs (k: v: k != "_module") x; 12 ··· 17 promtool ${what} $out 18 ''; 19 20 # Pretty-print JSON to a file 21 writePrettyJSON = name: x: 22 pkgs.runCommand name { preferLocalBuild = true; } '' 23 echo '${builtins.toJSON x}' | ${pkgs.jq}/bin/jq . > $out 24 ''; 25 26 - # This becomes the main config file 27 promConfig = { 28 global = cfg.globalConfig; 29 rule_files = map (promtoolCheck "check-rules" "rules") (cfg.ruleFiles ++ [ ··· 35 generatedPrometheusYml = writePrettyJSON "prometheus.yml" promConfig; 36 37 prometheusYml = let 38 - yml = if cfg.configText != null then 39 pkgs.writeText "prometheus.yml" cfg.configText 40 else generatedPrometheusYml; 41 in promtoolCheck "check-config" "prometheus.yml" yml; 42 43 cmdlineArgs = cfg.extraFlags ++ [ 44 - "-storage.local.path=${cfg.dataDir}/metrics" 45 "-config.file=${prometheusYml}" 46 "-web.listen-address=${cfg.listenAddress}" 47 "-alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}" 48 "-alertmanager.timeout=${toString cfg.alertmanagerTimeout}s" 49 - (optionalString (cfg.alertmanagerURL != []) "-alertmanager.url=${concatStringsSep "," cfg.alertmanagerURL}") 50 - (optionalString (cfg.webExternalUrl != null) "-web.external-url=${cfg.webExternalUrl}") 51 - ]; 52 53 promTypes.globalConfig = types.submodule { 54 options = { ··· 403 }; 404 405 dataDir = mkOption { 406 - type = types.path; 407 - default = "/var/lib/prometheus"; 408 description = '' 409 Directory to store Prometheus metrics data. 410 ''; 411 }; 412 ··· 497 ''; 498 }; 499 }; 500 - }; 501 502 - config = mkIf cfg.enable { 503 - users.groups.${promGroup}.gid = config.ids.gids.prometheus; 504 - users.users.${promUser} = { 505 - description = "Prometheus daemon user"; 506 - uid = config.ids.uids.prometheus; 507 - group = promGroup; 508 - home = cfg.dataDir; 509 - createHome = true; 510 - }; 511 - systemd.services.prometheus = { 512 - wantedBy = [ "multi-user.target" ]; 513 - after = [ "network.target" ]; 514 - script = '' 515 - #!/bin/sh 516 - exec ${cfg.package}/bin/prometheus \ 517 - ${concatStringsSep " \\\n " cmdlineArgs} 518 - ''; 519 - serviceConfig = { 520 - User = promUser; 521 - Restart = "always"; 522 - WorkingDirectory = cfg.dataDir; 523 }; 524 }; 525 - }; 526 }
··· 4 5 let 6 cfg = config.services.prometheus; 7 + cfg2 = config.services.prometheus2; 8 promUser = "prometheus"; 9 promGroup = "prometheus"; 10 11 + stateDir = 12 + if cfg.stateDir != null 13 + then cfg.stateDir 14 + else 15 + if cfg.dataDir != null 16 + then 17 + # This assumes /var/lib/ is a prefix of cfg.dataDir. 18 + # This is checked as an assertion below. 19 + removePrefix stateDirBase cfg.dataDir 20 + else "prometheus"; 21 + stateDirBase = "/var/lib/"; 22 + workingDir = stateDirBase + stateDir; 23 + workingDir2 = stateDirBase + cfg2.stateDir; 24 + 25 # Get a submodule without any embedded metadata: 26 _filter = x: filterAttrs (k: v: k != "_module") x; 27 ··· 32 promtool ${what} $out 33 ''; 34 35 + # a wrapper that verifies that the configuration is valid for 36 + # prometheus 2 37 + prom2toolCheck = what: name: file: 38 + pkgs.runCommand 39 + "${name}-${replaceStrings [" "] [""] what}-checked" 40 + { buildInputs = [ cfg2.package ]; } '' 41 + ln -s ${file} $out 42 + promtool ${what} $out 43 + ''; 44 + 45 # Pretty-print JSON to a file 46 writePrettyJSON = name: x: 47 pkgs.runCommand name { preferLocalBuild = true; } '' 48 echo '${builtins.toJSON x}' | ${pkgs.jq}/bin/jq . > $out 49 ''; 50 51 + # This becomes the main config file for Prometheus 1 52 promConfig = { 53 global = cfg.globalConfig; 54 rule_files = map (promtoolCheck "check-rules" "rules") (cfg.ruleFiles ++ [ ··· 60 generatedPrometheusYml = writePrettyJSON "prometheus.yml" promConfig; 61 62 prometheusYml = let 63 + yml = if cfg.configText != null then 64 pkgs.writeText "prometheus.yml" cfg.configText 65 else generatedPrometheusYml; 66 in promtoolCheck "check-config" "prometheus.yml" yml; 67 68 cmdlineArgs = cfg.extraFlags ++ [ 69 + "-storage.local.path=${workingDir}/metrics" 70 "-config.file=${prometheusYml}" 71 "-web.listen-address=${cfg.listenAddress}" 72 "-alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}" 73 "-alertmanager.timeout=${toString cfg.alertmanagerTimeout}s" 74 + ] ++ 75 + optional (cfg.alertmanagerURL != []) "-alertmanager.url=${concatStringsSep "," cfg.alertmanagerURL}" ++ 76 + optional (cfg.webExternalUrl != null) "-web.external-url=${cfg.webExternalUrl}"; 77 + 78 + # This becomes the main config file for Prometheus 2 79 + promConfig2 = { 80 + global = cfg2.globalConfig; 81 + rule_files = map (prom2toolCheck "check rules" "rules") (cfg2.ruleFiles ++ [ 82 + (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg2.rules)) 83 + ]); 84 + scrape_configs = cfg2.scrapeConfigs; 85 + alerting = optionalAttrs (cfg2.alertmanagerURL != []) { 86 + alertmanagers = [{ 87 + static_configs = [{ 88 + targets = cfg2.alertmanagerURL; 89 + }]; 90 + }]; 91 + }; 92 + }; 93 + 94 + generatedPrometheus2Yml = writePrettyJSON "prometheus.yml" promConfig2; 95 + 96 + prometheus2Yml = let 97 + yml = if cfg2.configText != null then 98 + pkgs.writeText "prometheus.yml" cfg2.configText 99 + else generatedPrometheus2Yml; 100 + in prom2toolCheck "check config" "prometheus.yml" yml; 101 + 102 + cmdlineArgs2 = cfg2.extraFlags ++ [ 103 + "--storage.tsdb.path=${workingDir2}/data/" 104 + "--config.file=${prometheus2Yml}" 105 + "--web.listen-address=${cfg2.listenAddress}" 106 + "--alertmanager.notification-queue-capacity=${toString cfg2.alertmanagerNotificationQueueCapacity}" 107 + "--alertmanager.timeout=${toString cfg2.alertmanagerTimeout}s" 108 + ] ++ 109 + optional (cfg2.webExternalUrl != null) "--web.external-url=${cfg2.webExternalUrl}"; 110 111 promTypes.globalConfig = types.submodule { 112 options = { ··· 461 }; 462 463 dataDir = mkOption { 464 + type = types.nullOr types.path; 465 + default = null; 466 description = '' 467 Directory to store Prometheus metrics data. 468 + This option is deprecated, please use <option>services.prometheus.stateDir</option>. 469 + ''; 470 + }; 471 + 472 + stateDir = mkOption { 473 + type = types.nullOr types.str; 474 + default = null; 475 + description = '' 476 + Directory below <literal>${stateDirBase}</literal> to store Prometheus metrics data. 477 + This directory will be created automatically using systemd's StateDirectory mechanism. 478 + Defaults to <literal>prometheus</literal>. 479 ''; 480 }; 481 ··· 566 ''; 567 }; 568 }; 569 + services.prometheus2 = { 570 571 + enable = mkOption { 572 + type = types.bool; 573 + default = false; 574 + description = '' 575 + Enable the Prometheus 2 monitoring daemon. 576 + ''; 577 + }; 578 + 579 + package = mkOption { 580 + type = types.package; 581 + default = pkgs.prometheus_2; 582 + defaultText = "pkgs.prometheus_2"; 583 + description = '' 584 + The prometheus2 package that should be used. 585 + ''; 586 + }; 587 + 588 + listenAddress = mkOption { 589 + type = types.str; 590 + default = "0.0.0.0:9090"; 591 + description = '' 592 + Address to listen on for the web interface, API, and telemetry. 593 + ''; 594 + }; 595 + 596 + stateDir = mkOption { 597 + type = types.str; 598 + default = "prometheus2"; 599 + description = '' 600 + Directory below <literal>${stateDirBase}</literal> to store Prometheus metrics data. 601 + This directory will be created automatically using systemd's StateDirectory mechanism. 602 + Defaults to <literal>prometheus2</literal>. 603 + ''; 604 + }; 605 + 606 + extraFlags = mkOption { 607 + type = types.listOf types.str; 608 + default = []; 609 + description = '' 610 + Extra commandline options when launching Prometheus 2. 611 + ''; 612 + }; 613 + 614 + configText = mkOption { 615 + type = types.nullOr types.lines; 616 + default = null; 617 + description = '' 618 + If non-null, this option defines the text that is written to 619 + prometheus.yml. If null, the contents of prometheus.yml is generated 620 + from the structured config options. 621 + ''; 622 + }; 623 + 624 + globalConfig = mkOption { 625 + type = promTypes.globalConfig; 626 + default = {}; 627 + apply = _filter; 628 + description = '' 629 + Parameters that are valid in all configuration contexts. They 630 + also serve as defaults for other configuration sections 631 + ''; 632 + }; 633 + 634 + rules = mkOption { 635 + type = types.listOf types.str; 636 + default = []; 637 + description = '' 638 + Alerting and/or Recording rules to evaluate at runtime. 639 + ''; 640 + }; 641 + 642 + ruleFiles = mkOption { 643 + type = types.listOf types.path; 644 + default = []; 645 + description = '' 646 + Any additional rules files to include in this configuration. 647 + ''; 648 + }; 649 + 650 + scrapeConfigs = mkOption { 651 + type = types.listOf promTypes.scrape_config; 652 + default = []; 653 + apply = x: map _filter x; 654 + description = '' 655 + A list of scrape configurations. 656 + ''; 657 + }; 658 + 659 + alertmanagerURL = mkOption { 660 + type = types.listOf types.str; 661 + default = []; 662 + description = '' 663 + List of Alertmanager URLs to send notifications to. 664 + ''; 665 + }; 666 + 667 + alertmanagerNotificationQueueCapacity = mkOption { 668 + type = types.int; 669 + default = 10000; 670 + description = '' 671 + The capacity of the queue for pending alert manager notifications. 672 + ''; 673 + }; 674 + 675 + alertmanagerTimeout = mkOption { 676 + type = types.int; 677 + default = 10; 678 + description = '' 679 + Alert manager HTTP API timeout (in seconds). 680 + ''; 681 + }; 682 + 683 + webExternalUrl = mkOption { 684 + type = types.nullOr types.str; 685 + default = null; 686 + example = "https://example.com/"; 687 + description = '' 688 + The URL under which Prometheus is externally reachable (for example, 689 + if Prometheus is served via a reverse proxy). 690 + ''; 691 }; 692 }; 693 + }; 694 + 695 + config = mkMerge [ 696 + (mkIf (cfg.enable || cfg2.enable) { 697 + users.groups.${promGroup}.gid = config.ids.gids.prometheus; 698 + users.users.${promUser} = { 699 + description = "Prometheus daemon user"; 700 + uid = config.ids.uids.prometheus; 701 + group = promGroup; 702 + }; 703 + }) 704 + (mkIf cfg.enable { 705 + warnings = 706 + optional (cfg.dataDir != null) '' 707 + The option services.prometheus.dataDir is deprecated, please use 708 + services.prometheus.stateDir. 709 + ''; 710 + assertions = [ 711 + { 712 + assertion = !(cfg.dataDir != null && cfg.stateDir != null); 713 + message = 714 + "The options services.prometheus.dataDir and services.prometheus.stateDir" + 715 + " can't both be set at the same time! It's recommended to only set the latter" + 716 + " since the former is deprecated."; 717 + } 718 + { 719 + assertion = cfg.dataDir != null -> hasPrefix stateDirBase cfg.dataDir; 720 + message = 721 + "The option services.prometheus.dataDir should have ${stateDirBase} as a prefix!"; 722 + } 723 + { 724 + assertion = cfg.stateDir != null -> !hasPrefix "/" cfg.stateDir; 725 + message = 726 + "The option services.prometheus.stateDir shouldn't be an absolute directory." + 727 + " It should be a directory relative to ${stateDirBase}."; 728 + } 729 + { 730 + assertion = cfg2.stateDir != null -> !hasPrefix "/" cfg2.stateDir; 731 + message = 732 + "The option services.prometheus2.stateDir shouldn't be an absolute directory." + 733 + " It should be a directory relative to ${stateDirBase}."; 734 + } 735 + ]; 736 + systemd.services.prometheus = { 737 + wantedBy = [ "multi-user.target" ]; 738 + after = [ "network.target" ]; 739 + serviceConfig = { 740 + ExecStart = "${cfg.package}/bin/prometheus" + 741 + optionalString (length cmdlineArgs != 0) (" \\\n " + 742 + concatStringsSep " \\\n " cmdlineArgs); 743 + User = promUser; 744 + Restart = "always"; 745 + WorkingDirectory = workingDir; 746 + StateDirectory = stateDir; 747 + }; 748 + }; 749 + }) 750 + (mkIf cfg2.enable { 751 + systemd.services.prometheus2 = { 752 + wantedBy = [ "multi-user.target" ]; 753 + after = [ "network.target" ]; 754 + serviceConfig = { 755 + ExecStart = "${cfg2.package}/bin/prometheus" + 756 + optionalString (length cmdlineArgs2 != 0) (" \\\n " + 757 + concatStringsSep " \\\n " cmdlineArgs2); 758 + User = promUser; 759 + Restart = "always"; 760 + WorkingDirectory = workingDir2; 761 + StateDirectory = cfg2.stateDir; 762 + }; 763 + }; 764 + }) 765 + ]; 766 }
+1
nixos/tests/all-tests.nix
··· 188 predictable-interface-names = handleTest ./predictable-interface-names.nix {}; 189 printing = handleTest ./printing.nix {}; 190 prometheus = handleTest ./prometheus.nix {}; 191 prometheus-exporters = handleTest ./prometheus-exporters.nix {}; 192 prosody = handleTest ./prosody.nix {}; 193 proxy = handleTest ./proxy.nix {};
··· 188 predictable-interface-names = handleTest ./predictable-interface-names.nix {}; 189 printing = handleTest ./printing.nix {}; 190 prometheus = handleTest ./prometheus.nix {}; 191 + prometheus2 = handleTest ./prometheus-2.nix {}; 192 prometheus-exporters = handleTest ./prometheus-exporters.nix {}; 193 prosody = handleTest ./prosody.nix {}; 194 proxy = handleTest ./proxy.nix {};
+34
nixos/tests/prometheus-2.nix
···
··· 1 + import ./make-test.nix { 2 + name = "prometheus-2"; 3 + 4 + nodes = { 5 + one = { pkgs, ... }: { 6 + services.prometheus2 = { 7 + enable = true; 8 + scrapeConfigs = [{ 9 + job_name = "prometheus"; 10 + static_configs = [{ 11 + targets = [ "127.0.0.1:9090" ]; 12 + labels = { instance = "localhost"; }; 13 + }]; 14 + }]; 15 + rules = [ 16 + '' 17 + groups: 18 + - name: test 19 + rules: 20 + - record: testrule 21 + expr: count(up{job="prometheus"}) 22 + '' 23 + ]; 24 + }; 25 + }; 26 + }; 27 + 28 + testScript = '' 29 + startAll; 30 + $one->waitForUnit("prometheus2.service"); 31 + $one->waitForOpenPort(9090); 32 + $one->succeed("curl -s http://127.0.0.1:9090/metrics"); 33 + ''; 34 + }
+7 -9
pkgs/servers/monitoring/prometheus/default.nix
··· 2 3 let 4 goPackagePath = "github.com/prometheus/prometheus"; 5 - 6 - generic = { version, sha256, ... }@attrs: 7 let attrs' = builtins.removeAttrs attrs ["version" "sha256"]; in 8 buildGoPackage ({ 9 name = "prometheus-${version}"; ··· 16 repo = "prometheus"; 17 inherit sha256; 18 }; 19 - 20 - doCheck = true; 21 22 buildFlagsArray = let t = "${goPackagePath}/vendor/github.com/prometheus/common/version"; in '' 23 -ldflags= ··· 43 platforms = platforms.unix; 44 }; 45 } // attrs'); 46 - in rec { 47 - prometheus_1 = generic { 48 version = "1.8.2"; 49 sha256 = "088flpg3qgnj9afl9vbaa19v2s1d21yxy38nrlv5m7cxwy2pi5pv"; 50 }; 51 52 - prometheus_2 = generic { 53 - version = "2.6.0"; 54 - sha256 = "1d9zwzs280pw9zspqwp7xx3ji04lfg2v9l5qhrfy3y633ghcmpxz"; 55 }; 56 }
··· 2 3 let 4 goPackagePath = "github.com/prometheus/prometheus"; 5 + in rec { 6 + buildPrometheus = { version, sha256, doCheck ? true, ... }@attrs: 7 let attrs' = builtins.removeAttrs attrs ["version" "sha256"]; in 8 buildGoPackage ({ 9 name = "prometheus-${version}"; ··· 16 repo = "prometheus"; 17 inherit sha256; 18 }; 19 20 buildFlagsArray = let t = "${goPackagePath}/vendor/github.com/prometheus/common/version"; in '' 21 -ldflags= ··· 41 platforms = platforms.unix; 42 }; 43 } // attrs'); 44 + 45 + prometheus_1 = buildPrometheus { 46 version = "1.8.2"; 47 sha256 = "088flpg3qgnj9afl9vbaa19v2s1d21yxy38nrlv5m7cxwy2pi5pv"; 48 }; 49 50 + prometheus_2 = buildPrometheus { 51 + version = "2.8.1"; 52 + sha256 = "0x8w0qdh4lcf19nmdlhvgzpy08c2a932d3k49cjwhi5npcsf858n"; 53 }; 54 }