aboutsummaryrefslogtreecommitdiffstats
path: root/modules/by-name/mo/monitoring/components/grafana.nix
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--modules/by-name/mo/monitoring/components/grafana.nix296
1 files changed, 296 insertions, 0 deletions
diff --git a/modules/by-name/mo/monitoring/components/grafana.nix b/modules/by-name/mo/monitoring/components/grafana.nix
new file mode 100644
index 0000000..5459878
--- /dev/null
+++ b/modules/by-name/mo/monitoring/components/grafana.nix
@@ -0,0 +1,296 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}: let
+ cfg = config.vhack.monitoring.grafana;
+in {
+ options.vhack.monitoring.grafana = {
+ enable = lib.mkEnableOption "grafana";
+
+ orgId = lib.mkOption {
+ type = lib.types.int;
+ description = "Org ID where all vhack related config will be stored.";
+ default = 1;
+ };
+
+ contactPoints = lib.mkOption {
+ type = lib.types.listOf lib.types.str;
+ description = "List of email addresses to send alerts to";
+ default = [];
+ };
+
+ dashboards = lib.mkOption {
+ type = lib.types.listOf lib.types.path;
+ description = "dashboards to provision under 'Vhack' folder.";
+ default = [];
+ };
+
+ fqdn = lib.mkOption {
+ type = lib.types.str;
+ description = "Domain under which Grafana will be served.";
+ example = "grafana.example.org";
+ };
+
+ adminPassword = lib.mkOption {
+ type = lib.types.path;
+ description = "The age-encrypted initial admin password; passed to agenix";
+ };
+
+ secretKey = lib.mkOption {
+ type = lib.types.path;
+ description = "The age-encrypted secret key, used for signing; passed to agenix";
+ };
+
+ port = lib.mkOption {
+ type = lib.types.port;
+ description = "Port where Grafana listens to HTTP requests.";
+ default = 3000;
+ };
+
+ debugLog = lib.mkOption {
+ type = lib.types.bool;
+ description = "Set to true to enable debug logging of the infrastructure serving Grafana.";
+ default = false;
+ example = true;
+ };
+
+ smtp = lib.mkOption {
+ description = "SMTP options.";
+ default = null;
+ type = lib.types.nullOr (
+ lib.types.submodule {
+ options = {
+ from_address = lib.mkOption {
+ type = lib.types.str;
+ description = "SMTP address from which the emails originate.";
+ example = "vaultwarden@mydomain.com";
+ };
+ from_name = lib.mkOption {
+ type = lib.types.str;
+ description = "SMTP name from which the emails originate.";
+ default = "Grafana";
+ };
+ host = lib.mkOption {
+ type = lib.types.str;
+ description = "SMTP host to send the emails to.";
+ };
+ port = lib.mkOption {
+ type = lib.types.port;
+ description = "SMTP port to send the emails to.";
+ default = 25;
+ };
+ username = lib.mkOption {
+ type = lib.types.str;
+ description = "Username to connect to the SMTP host.";
+ };
+ passwordFile = lib.mkOption {
+ type = lib.types.str;
+ description = "File containing the password to connect to the SMTP host.";
+ };
+ };
+ }
+ );
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = builtins.length cfg.contactPoints > 0;
+ message = "Must have at least one contact point for alerting";
+ }
+ ];
+
+ age.secrets = {
+ grafanaInitialAdminPw = {
+ file = cfg.adminPassword;
+ mode = "0700";
+ owner = "grafana";
+ group = "grafana";
+ };
+ grafanaSecretKey = {
+ file = cfg.secretKey;
+ mode = "0700";
+ owner = "grafana";
+ group = "grafana";
+ };
+ };
+
+ vhack = {
+ postgresql.enable = true;
+ monitoring.grafana.dashboards = [
+ ../dashboards/Errors.json
+ ../dashboards/Performance.json
+ ../dashboards/Scraping_Jobs.json
+ ];
+ };
+
+ services = {
+ nginx = {
+ virtualHosts.${cfg.fqdn} = {
+ locations."/" = {
+ proxyPass = "http://${toString config.services.grafana.settings.server.http_addr}:${toString config.services.grafana.settings.server.http_port}";
+ proxyWebsockets = true;
+ extraConfig = ''
+ proxy_set_header Host $host;
+ '';
+ };
+
+ forceSSL = true;
+ enableACME = true;
+ };
+ };
+
+ postgresql = {
+ ensureUsers = [
+ {
+ name = "grafana";
+ ensureDBOwnership = true;
+ }
+ ];
+ ensureDatabases = [
+ "grafana"
+ ];
+ };
+
+ grafana = {
+ enable = true;
+
+ settings = {
+ database = {
+ host = "/run/postgresql";
+ user = "grafana";
+ name = "grafana";
+ type = "postgres";
+ };
+
+ security = {
+ secret_key = "$__file{${config.age.secrets.grafanaSecretKey.path}}";
+
+ disable_initial_admin_creation = false;
+ admin_password = "$__file{${config.age.secrets.grafanaInitialAdminPw.path}}";
+ };
+
+ server = {
+ http_addr = "127.0.0.1";
+ http_port = cfg.port;
+ domain = cfg.fqdn;
+ root_url = "https://${cfg.fqdn}";
+ router_logging = cfg.debugLog;
+ };
+
+ smtp = lib.mkIf (!(isNull cfg.smtp)) {
+ enabled = true;
+ inherit (cfg.smtp) from_address from_name;
+ host = "${cfg.smtp.host}:${toString cfg.smtp.port}";
+ user = cfg.smtp.username;
+ password = "$__file{${cfg.smtp.passwordFile}}";
+ };
+ };
+
+ provision = {
+ dashboards.settings = lib.mkIf (cfg.dashboards != []) {
+ apiVersion = 1;
+ providers = [
+ {
+ folder = "Vhack";
+ options.path = pkgs.symlinkJoin {
+ name = "dashboards";
+ paths = map (p: pkgs.runCommand "davhackoard" {} "mkdir $out; cp ${p} $out") cfg.dashboards;
+ };
+ allowUiUpdates = true;
+ disableDeletion = true;
+ }
+ ];
+ };
+ datasources.settings = {
+ apiVersion = 1;
+ datasources = [
+ {
+ inherit (cfg) orgId;
+ name = "Prometheus";
+ type = "prometheus";
+ url = "http://127.0.0.1:${toString config.services.prometheus.port}";
+ uid = "df80f9f5-97d7-4112-91d8-72f523a02b09";
+ isDefault = true;
+ version = 1;
+ }
+ {
+ inherit (cfg) orgId;
+ name = "Loki";
+ type = "loki";
+ url = "http://127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}";
+ uid = "cd6cc53e-840c-484d-85f7-96fede324006";
+ version = 1;
+ }
+ ];
+ deleteDatasources = [
+ {
+ inherit (cfg) orgId;
+ name = "Prometheus";
+ }
+ {
+ inherit (cfg) orgId;
+ name = "Loki";
+ }
+ ];
+ };
+ alerting = {
+ contactPoints.settings = {
+ apiVersion = 1;
+ contactPoints = [
+ {
+ inherit (cfg) orgId;
+ name = "grafana-default-email";
+ receivers = lib.optionals ((builtins.length cfg.contactPoints) > 0) [
+ {
+ uid = "sysadmin";
+ type = "email";
+ settings.addresses = lib.concatStringsSep ";" cfg.contactPoints;
+ }
+ ];
+ }
+ ];
+ };
+ policies.settings = {
+ apiVersion = 1;
+ policies = [
+ {
+ inherit (cfg) orgId;
+ receiver = "grafana-default-email";
+ group_by = [
+ "grafana_folder"
+ "alertname"
+ ];
+ group_wait = "30s";
+ group_interval = "5m";
+ repeat_interval = "4h";
+ }
+ ];
+ # resetPolicies seems to happen after setting the above policies, effectively rolling back
+ # any updates.
+ };
+ rules.settings = let
+ rules = builtins.fromJSON (builtins.readFile ../rules.json);
+ in {
+ apiVersion = 1;
+ groups = [
+ {
+ inherit (cfg) orgId;
+ name = "SysAdmin";
+ folder = "Vhack";
+ interval = "10m";
+ inherit rules;
+ }
+ ];
+ # deleteRules seems to happen after creating the above rules, effectively rolling back
+ # any updates.
+ };
+ };
+ };
+ };
+ };
+ };
+}