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

This commit is contained in:
Maximilian Bosch 2022-11-14 11:44:08 +01:00
parent 2f1dfb0db3
commit 9d7e9c5965
No known key found for this signature in database
GPG key ID: 9A6EEA275CA5BE0A
4 changed files with 55 additions and 34 deletions

View file

@ -1300,7 +1300,7 @@ services.github-runner.serviceOverrides.SupplementaryGroups = [
<para> <para>
Instead of declaring datasources and dashboards in Instead of declaring datasources and dashboards in
pure Nix, its also possible to specify configuration pure Nix, its 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" /> <xref linkend="opt-services.grafana.provision.datasources.path" />
(or (or
<xref linkend="opt-services.grafana.provision.dashboards.path" />. <xref linkend="opt-services.grafana.provision.dashboards.path" />.

View file

@ -420,7 +420,7 @@ Available as [services.patroni](options.html#opt-services.patroni.enable).
[](#opt-services.grafana.provision.dashboards.settings.apiVersion)). [](#opt-services.grafana.provision.dashboards.settings.apiVersion)).
- Instead of declaring datasources and dashboards in pure Nix, it's also possible - 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.datasources.path) (or
[](#opt-services.grafana.provision.dashboards.path). This is useful when having [](#opt-services.grafana.provision.dashboards.path). This is useful when having
provisioning files from non-NixOS Grafana instances that you also want to provisioning files from non-NixOS Grafana instances that you also want to

View file

@ -25,42 +25,51 @@ let
${attr} = []; ${attr} = [];
}); });
datasourceFile = mkProvisionCfg "datasource" "datasources" cfg.provision.datasources; datasourceFileOrDir = mkProvisionCfg "datasource" "datasources" cfg.provision.datasources;
dashboardFile = mkProvisionCfg "dashboard" "providers" cfg.provision.dashboards; dashboardFileOrDir = mkProvisionCfg "dashboard" "providers" cfg.provision.dashboards;
notifierConfiguration = { notifierConfiguration = {
apiVersion = 1; apiVersion = 1;
notifiers = cfg.provision.notifiers; 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) generateAlertingProvisioningYaml = x: if (cfg.provision.alerting."${x}".path == null)
then provisioningSettingsFormat.generate "${x}.yaml" cfg.provision.alerting."${x}".settings then provisioningSettingsFormat.generate "${x}.yaml" cfg.provision.alerting."${x}".settings
else cfg.provision.alerting."${x}".path; else cfg.provision.alerting."${x}".path;
rulesFile = generateAlertingProvisioningYaml "rules"; rulesFileOrDir = generateAlertingProvisioningYaml "rules";
contactPointsFile = generateAlertingProvisioningYaml "contactPoints"; contactPointsFileOrDir = generateAlertingProvisioningYaml "contactPoints";
policiesFile = generateAlertingProvisioningYaml "policies"; policiesFileOrDir = generateAlertingProvisioningYaml "policies";
templatesFile = generateAlertingProvisioningYaml "templates"; templatesFileOrDir = generateAlertingProvisioningYaml "templates";
muteTimingsFile = generateAlertingProvisioningYaml "muteTimings"; muteTimingsFileOrDir = generateAlertingProvisioningYaml "muteTimings";
provisionConfDir = pkgs.runCommand "grafana-provisioning" { } '' 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} mkdir -p $out/{datasources,dashboards,notifiers,alerting}
ln -sf ${datasourceFile} $out/datasources/datasource.yaml ${ln { src = datasourceFileOrDir; dir = "datasources"; filename = "datasource"; }}
ln -sf ${dashboardFile} $out/dashboards/dashboard.yaml ${ln { src = dashboardFileOrDir; dir = "dashboards"; filename = "dashbaord"; }}
ln -sf ${notifierFile} $out/notifiers/notifier.yaml ${ln { src = notifierFileOrDir; dir = "notifiers"; filename = "notifier"; }}
ln -sf ${rulesFile} $out/alerting/rules.yaml ${ln { src = rulesFileOrDir; dir = "alerting"; filename = "rules"; }}
ln -sf ${contactPointsFile} $out/alerting/contactPoints.yaml ${ln { src = contactPointsFileOrDir; dir = "alerting"; filename = "contactPoints"; }}
ln -sf ${policiesFile} $out/alerting/policies.yaml ${ln { src = policiesFileOrDir; dir = "alerting"; filename = "policies"; }}
ln -sf ${templatesFile} $out/alerting/templates.yaml ${ln { src = templatesFileOrDir; dir = "alerting"; filename = "templates"; }}
ln -sf ${muteTimingsFile} $out/alerting/muteTimings.yaml ${ln { src = muteTimingsFileOrDir; dir = "alerting"; filename = "muteTimings"; }}
''; '';
# Get a submodule without any embedded metadata: # Get a submodule without any embedded metadata:
_filter = x: filterAttrs (k: v: k != "_module") x; _filter = x: filterAttrs (k: v: k != "_module") x;
# FIXME(@Ma27) remove before 23.05. This is just a helper-type # 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`. # to `foo.bar.baz`.
submodule' = module: types.coercedTo submodule' = module: types.coercedTo
(mkOptionType { (mkOptionType {
@ -342,19 +351,7 @@ in {
Don't change the value of this option if you are planning to use `services.grafana.provision` options. Don't change the value of this option if you are planning to use `services.grafana.provision` options.
''; '';
default = provisionConfDir; default = provisionConfDir;
defaultText = literalExpression '' defaultText = "directory with all provisioning files linked together";
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
\'\'
'';
type = types.path; type = types.path;
}; };
}; };
@ -641,6 +638,7 @@ in {
description = lib.mdDoc '' description = lib.mdDoc ''
Path to YAML datasource configuration. Can't be used with Path to YAML datasource configuration. Can't be used with
[](#opt-services.grafana.provision.datasources.settings) simultaneously. [](#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; default = null;
type = types.nullOr types.path; type = types.nullOr types.path;
@ -692,6 +690,7 @@ in {
description = lib.mdDoc '' description = lib.mdDoc ''
Path to YAML dashboard configuration. Can't be used with Path to YAML dashboard configuration. Can't be used with
[](#opt-services.grafana.provision.dashboards.settings) simultaneously. [](#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; default = null;
type = types.nullOr types.path; type = types.nullOr types.path;
@ -714,6 +713,7 @@ in {
description = lib.mdDoc '' description = lib.mdDoc ''
Path to YAML rules configuration. Can't be used with Path to YAML rules configuration. Can't be used with
[](#opt-services.grafana.provision.alerting.rules.settings) simultaneously. [](#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; default = null;
type = types.nullOr types.path; type = types.nullOr types.path;
@ -837,6 +837,7 @@ in {
description = lib.mdDoc '' description = lib.mdDoc ''
Path to YAML contact points configuration. Can't be used with Path to YAML contact points configuration. Can't be used with
[](#opt-services.grafana.provision.alerting.contactPoints.settings) simultaneously. [](#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; default = null;
type = types.nullOr types.path; type = types.nullOr types.path;
@ -917,6 +918,7 @@ in {
description = lib.mdDoc '' description = lib.mdDoc ''
Path to YAML notification policies configuration. Can't be used with Path to YAML notification policies configuration. Can't be used with
[](#opt-services.grafana.provision.alerting.policies.settings) simultaneously. [](#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; default = null;
type = types.nullOr types.path; type = types.nullOr types.path;
@ -986,6 +988,7 @@ in {
description = lib.mdDoc '' description = lib.mdDoc ''
Path to YAML templates configuration. Can't be used with Path to YAML templates configuration. Can't be used with
[](#opt-services.grafana.provision.alerting.templates.settings) simultaneously. [](#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; default = null;
type = types.nullOr types.path; type = types.nullOr types.path;
@ -1067,6 +1070,7 @@ in {
description = lib.mdDoc '' description = lib.mdDoc ''
Path to YAML mute timings configuration. Can't be used with Path to YAML mute timings configuration. Can't be used with
[](#opt-services.grafana.provision.alerting.muteTimings.settings) simultaneously. [](#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; default = null;
type = types.nullOr types.path; type = types.nullOr types.path;

View file

@ -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; nodes = builtins.mapAttrs (_: val: mkMerge [ val baseGrafanaConf ]) extraNodeConfs;
@ -180,8 +196,9 @@ in {
nodeNix = ("Nix (new format)", provisionNix) nodeNix = ("Nix (new format)", provisionNix)
nodeYaml = ("Nix (YAML)", provisionYaml) 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}"): with subtest(f"Should start provision node: {description}"):
machine.wait_for_unit("grafana.service") machine.wait_for_unit("grafana.service")
machine.wait_for_open_port(3000) machine.wait_for_open_port(3000)