Unverified Commit 9d7e9c59 authored by Maximilian Bosch's avatar Maximilian Bosch
Browse files

nixos/grafana: allow using both directories or single YAML files for non-Nix provisioning

parent 2f1dfb0d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1300,7 +1300,7 @@ services.github-runner.serviceOverrides.SupplementaryGroups = [
                <para>
                  Instead of declaring datasources and dashboards in
                  pure Nix, it’s also possible to specify configuration
                  files with YAML instead using
                  files (or directories) with YAML instead using
                  <xref linkend="opt-services.grafana.provision.datasources.path" />
                  (or
                  <xref linkend="opt-services.grafana.provision.dashboards.path" />.
+1 −1
Original line number Diff line number Diff line
@@ -420,7 +420,7 @@ Available as [services.patroni](options.html#opt-services.patroni.enable).
      [](#opt-services.grafana.provision.dashboards.settings.apiVersion)).

    - Instead of declaring datasources and dashboards in pure Nix, it's also possible
      to specify configuration files with YAML instead using
      to specify configuration files (or directories) with YAML instead using
      [](#opt-services.grafana.provision.datasources.path) (or
      [](#opt-services.grafana.provision.dashboards.path). This is useful when having
      provisioning files from non-NixOS Grafana instances that you also want to
+36 −32
Original line number Diff line number Diff line
@@ -25,42 +25,51 @@ let
            ${attr} = [];
          });

  datasourceFile = mkProvisionCfg "datasource" "datasources" cfg.provision.datasources;
  dashboardFile = mkProvisionCfg "dashboard" "providers" cfg.provision.dashboards;
  datasourceFileOrDir = mkProvisionCfg "datasource" "datasources" cfg.provision.datasources;
  dashboardFileOrDir = mkProvisionCfg "dashboard" "providers" cfg.provision.dashboards;

  notifierConfiguration = {
    apiVersion = 1;
    notifiers = cfg.provision.notifiers;
  };

  notifierFile = pkgs.writeText "notifier.yaml" (builtins.toJSON notifierConfiguration);
  notifierFileOrDir = pkgs.writeText "notifier.yaml" (builtins.toJSON notifierConfiguration);

  generateAlertingProvisioningYaml = x: if (cfg.provision.alerting."${x}".path == null)
                                        then provisioningSettingsFormat.generate "${x}.yaml" cfg.provision.alerting."${x}".settings
                                        else cfg.provision.alerting."${x}".path;
  rulesFile = generateAlertingProvisioningYaml "rules";
  contactPointsFile = generateAlertingProvisioningYaml "contactPoints";
  policiesFile = generateAlertingProvisioningYaml "policies";
  templatesFile = generateAlertingProvisioningYaml "templates";
  muteTimingsFile = generateAlertingProvisioningYaml "muteTimings";

  provisionConfDir =  pkgs.runCommand "grafana-provisioning" { } ''
  rulesFileOrDir = generateAlertingProvisioningYaml "rules";
  contactPointsFileOrDir = generateAlertingProvisioningYaml "contactPoints";
  policiesFileOrDir = generateAlertingProvisioningYaml "policies";
  templatesFileOrDir = generateAlertingProvisioningYaml "templates";
  muteTimingsFileOrDir = generateAlertingProvisioningYaml "muteTimings";

  ln = { src, dir, filename }: ''
    if [[ -d "${src}" ]]; then
      pushd $out/${dir} &>/dev/null
        lndir "${src}"
      popd &>/dev/null
    else
      ln -sf ${src} $out/${dir}/${filename}.yaml
    fi
  '';
  provisionConfDir = pkgs.runCommand "grafana-provisioning" { nativeBuildInputs = [ pkgs.xorg.lndir ]; } ''
    mkdir -p $out/{datasources,dashboards,notifiers,alerting}
    ln -sf ${datasourceFile} $out/datasources/datasource.yaml
    ln -sf ${dashboardFile} $out/dashboards/dashboard.yaml
    ln -sf ${notifierFile} $out/notifiers/notifier.yaml
    ln -sf ${rulesFile} $out/alerting/rules.yaml
    ln -sf ${contactPointsFile} $out/alerting/contactPoints.yaml
    ln -sf ${policiesFile} $out/alerting/policies.yaml
    ln -sf ${templatesFile} $out/alerting/templates.yaml
    ln -sf ${muteTimingsFile} $out/alerting/muteTimings.yaml
    ${ln { src = datasourceFileOrDir;    dir = "datasources"; filename = "datasource"; }}
    ${ln { src = dashboardFileOrDir;     dir = "dashboards";  filename = "dashbaord"; }}
    ${ln { src = notifierFileOrDir;      dir = "notifiers";   filename = "notifier"; }}
    ${ln { src = rulesFileOrDir;         dir = "alerting";    filename = "rules"; }}
    ${ln { src = contactPointsFileOrDir; dir = "alerting";    filename = "contactPoints"; }}
    ${ln { src = policiesFileOrDir;      dir = "alerting";    filename = "policies"; }}
    ${ln { src = templatesFileOrDir;     dir = "alerting";    filename = "templates"; }}
    ${ln { src = muteTimingsFileOrDir;   dir = "alerting";    filename = "muteTimings"; }}
  '';

  # Get a submodule without any embedded metadata:
  _filter = x: filterAttrs (k: v: k != "_module") x;

  # FIXME(@Ma27) remove before 23.05. This is just a helper-type
  # because `mkRenamedOptionModule` doesn't work if `foo.bar` is renamed
  # because `mkRenamedOptionMthere's there's odule` doesn't work if `foo.bar` is renamed
  # to `foo.bar.baz`.
  submodule' = module: types.coercedTo
    (mkOptionType {
@@ -342,19 +351,7 @@ in {
                Don't change the value of this option if you are planning to use `services.grafana.provision` options.
              '';
              default = provisionConfDir;
              defaultText = literalExpression ''
                pkgs.runCommand "grafana-provisioning" { } \'\'
                  mkdir -p $out/{datasources,dashboards,notifiers,alerting}
                  ln -sf ''${datasourceFile} $out/datasources/datasource.yaml
                  ln -sf ''${dashboardFile} $out/dashboards/dashboard.yaml
                  ln -sf ''${notifierFile} $out/notifiers/notifier.yaml
                  ln -sf ''${rulesFile} $out/alerting/rules.yaml
                  ln -sf ''${contactPointsFile} $out/alerting/contactPoints.yaml
                  ln -sf ''${policiesFile} $out/alerting/policies.yaml
                  ln -sf ''${templatesFile} $out/alerting/templates.yaml
                  ln -sf ''${muteTimingsFile} $out/alerting/muteTimings.yaml
                  \'\'
              '';
              defaultText = "directory with all provisioning files linked together";
              type = types.path;
            };
          };
@@ -641,6 +638,7 @@ in {
            description = lib.mdDoc ''
              Path to YAML datasource configuration. Can't be used with
              [](#opt-services.grafana.provision.datasources.settings) simultaneously.
              Can be either a directory or a single YAML file. Will end up in the store.
            '';
            default = null;
            type = types.nullOr types.path;
@@ -692,6 +690,7 @@ in {
            description = lib.mdDoc ''
              Path to YAML dashboard configuration. Can't be used with
              [](#opt-services.grafana.provision.dashboards.settings) simultaneously.
              Can be either a directory or a single YAML file. Will end up in the store.
            '';
            default = null;
            type = types.nullOr types.path;
@@ -714,6 +713,7 @@ in {
            description = lib.mdDoc ''
              Path to YAML rules configuration. Can't be used with
              [](#opt-services.grafana.provision.alerting.rules.settings) simultaneously.
              Can be either a directory or a single YAML file. Will end up in the store.
            '';
            default = null;
            type = types.nullOr types.path;
@@ -837,6 +837,7 @@ in {
            description = lib.mdDoc ''
              Path to YAML contact points configuration. Can't be used with
              [](#opt-services.grafana.provision.alerting.contactPoints.settings) simultaneously.
              Can be either a directory or a single YAML file. Will end up in the store.
            '';
            default = null;
            type = types.nullOr types.path;
@@ -917,6 +918,7 @@ in {
            description = lib.mdDoc ''
              Path to YAML notification policies configuration. Can't be used with
              [](#opt-services.grafana.provision.alerting.policies.settings) simultaneously.
              Can be either a directory or a single YAML file. Will end up in the store.
            '';
            default = null;
            type = types.nullOr types.path;
@@ -986,6 +988,7 @@ in {
            description = lib.mdDoc ''
              Path to YAML templates configuration. Can't be used with
              [](#opt-services.grafana.provision.alerting.templates.settings) simultaneously.
              Can be either a directory or a single YAML file. Will end up in the store.
            '';
            default = null;
            type = types.nullOr types.path;
@@ -1067,6 +1070,7 @@ in {
            description = lib.mdDoc ''
              Path to YAML mute timings configuration. Can't be used with
              [](#opt-services.grafana.provision.alerting.muteTimings.settings) simultaneously.
              Can be either a directory or a single YAML file. Will end up in the store.
            '';
            default = null;
            type = types.nullOr types.path;
+18 −1
Original line number Diff line number Diff line
@@ -163,6 +163,22 @@ let
        };
      };
    };

    provisionYamlDirs = let
      mkdir = p: pkgs.writeTextDir (baseNameOf p) (builtins.readFile p);
    in {
      services.grafana.provision = {
        datasources.path = mkdir ./datasources.yaml;
        dashboards.path = mkdir ./dashboards.yaml;
        alerting = {
          rules.path = mkdir ./rules.yaml;
          contactPoints.path = mkdir ./contact-points.yaml;
          policies.path = mkdir ./policies.yaml;
          templates.path = mkdir ./templates.yaml;
          muteTimings.path = mkdir ./mute-timings.yaml;
        };
      };
    };
  };

  nodes = builtins.mapAttrs (_: val: mkMerge [ val baseGrafanaConf ]) extraNodeConfs;
@@ -180,8 +196,9 @@ in {

    nodeNix = ("Nix (new format)", provisionNix)
    nodeYaml = ("Nix (YAML)", provisionYaml)
    nodeYamlDir = ("Nix (YAML in dirs)", provisionYamlDirs)

    for description, machine in [nodeNix, nodeYaml]:
    for description, machine in [nodeNix, nodeYaml, nodeYamlDir]:
        with subtest(f"Should start provision node: {description}"):
            machine.wait_for_unit("grafana.service")
            machine.wait_for_open_port(3000)