283 lines
7.5 KiB
Nix
283 lines
7.5 KiB
Nix
# NOTE: this assumes that postgres is running locally.
|
|
|
|
{ config, lib, pkgs, ... }@toplevel:
|
|
|
|
with lib;
|
|
let
|
|
cfg = config.fudo.metrics.grafana;
|
|
|
|
hostname = config.instance.hostname;
|
|
domain-name = config.fudo.hosts.${hostname}.domain;
|
|
|
|
host-secrets = config.fudo.secrets.host-secrets.${hostname};
|
|
|
|
datasourceOpts = { name, ... }: {
|
|
options = with types; {
|
|
url = mkOption {
|
|
type = str;
|
|
description = "Datasource URL.";
|
|
};
|
|
|
|
type = mkOption {
|
|
type = enum [ "prometheus" "loki" ];
|
|
description = "Type of the datasource.";
|
|
};
|
|
|
|
name = mkOption {
|
|
type = str;
|
|
description = "Name of the datasource.";
|
|
default = name;
|
|
};
|
|
|
|
default = mkOption {
|
|
type = bool;
|
|
description = "Use this datasource as the default while querying.";
|
|
default = false;
|
|
};
|
|
};
|
|
};
|
|
|
|
ldapOpts = {
|
|
options = with types; {
|
|
hosts = mkOption {
|
|
type = listOf str;
|
|
description = "LDAP server hostnames.";
|
|
};
|
|
|
|
bind-dn = mkOption {
|
|
type = str;
|
|
description = "DN as which to bind with the LDAP server.";
|
|
};
|
|
|
|
bind-passwd = mkOption {
|
|
type = str;
|
|
description = "Password with which to bind to the LDAP server.";
|
|
};
|
|
|
|
base-dn = mkOption {
|
|
type = str;
|
|
description = "DN under which to search for users.";
|
|
};
|
|
};
|
|
};
|
|
|
|
in {
|
|
|
|
options.fudo.metrics.grafana = with types; {
|
|
enable = mkEnableOption "Fudo Metrics Display Service";
|
|
|
|
hostname = mkOption {
|
|
type = str;
|
|
description = "Grafana site hostname.";
|
|
example = "fancy-graphs.fudo.org";
|
|
};
|
|
|
|
smtp = {
|
|
username = mkOption {
|
|
type = str;
|
|
description = "Username with which to send email.";
|
|
default = "metrics";
|
|
};
|
|
|
|
password-file = mkOption {
|
|
type = str;
|
|
description = "Path to a file containing the email user's password.";
|
|
};
|
|
|
|
hostname = mkOption {
|
|
type = str;
|
|
description = "Mail server hostname.";
|
|
default = "mail.${domain-name}";
|
|
};
|
|
|
|
email = mkOption {
|
|
type = str;
|
|
description =
|
|
"Address from which mail will be sent (i.e. 'from' address).";
|
|
default =
|
|
"${toplevel.config.fudo.grafana.smtp.username}@${domain-name}";
|
|
};
|
|
|
|
domain = mkOption {
|
|
type = str;
|
|
description = "Domain of the SMTP server.";
|
|
default = toplevel.config.instance.local-domain;
|
|
};
|
|
};
|
|
|
|
database = {
|
|
name = mkOption {
|
|
type = str;
|
|
description = "Database name.";
|
|
default = "grafana";
|
|
};
|
|
hostname = mkOption {
|
|
type = str;
|
|
description = "Hostname of the database server.";
|
|
default = "localhost";
|
|
};
|
|
user = mkOption {
|
|
type = str;
|
|
description = "Database username.";
|
|
default = "grafana";
|
|
};
|
|
password-file = mkOption {
|
|
type = str;
|
|
description = "File containing the database user's password.";
|
|
};
|
|
};
|
|
|
|
ldap = mkOption {
|
|
type = nullOr (submodule ldapOpts);
|
|
description = "";
|
|
default = null;
|
|
};
|
|
|
|
admin-password-file = mkOption {
|
|
type = str;
|
|
description = "Path to a file containing the admin user's password.";
|
|
};
|
|
|
|
secret-key-file = mkOption {
|
|
type = str;
|
|
description =
|
|
"Path to a file containing the server's secret key, used for signatures.";
|
|
};
|
|
|
|
datasources = mkOption {
|
|
type = attrsOf (submodule datasourceOpts);
|
|
description = "A list of datasources supplied to Grafana.";
|
|
default = { };
|
|
};
|
|
|
|
state-directory = mkOption {
|
|
type = str;
|
|
description = "Directory at which to store Grafana state data.";
|
|
default = "/var/lib/grafana";
|
|
};
|
|
|
|
private-network = mkEnableOption "Network is private, no SSL.";
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
systemd = {
|
|
tmpfiles.rules =
|
|
let grafana-user = config.systemd.services.grafana.serviceConfig.User;
|
|
in [ "d ${cfg.state-directory} 0700 ${grafana-user} - - -" ];
|
|
|
|
services.grafana.serviceConfig = {
|
|
EnvironmentFile = host-secrets.grafana-environment-file.target-file;
|
|
};
|
|
};
|
|
|
|
fudo.secrets.host-secrets.${hostname}.grafana-environment-file = {
|
|
source-file = pkgs.writeText "grafana.env" ''
|
|
${optionalString (cfg.ldap != null)
|
|
''GRAFANA_LDAP_BIND_PASSWD="${cfg.ldap.bind-passwd}"''}
|
|
'';
|
|
target-file = "/run/metrics/grafana/auth-bind.passwd";
|
|
user = config.systemd.services.grafana.serviceConfig.User;
|
|
};
|
|
|
|
services = {
|
|
nginx = {
|
|
enable = true;
|
|
recommendedOptimisation = true;
|
|
recommendedProxySettings = true;
|
|
|
|
virtualHosts = {
|
|
"${cfg.hostname}" = {
|
|
enableACME = !cfg.private-network;
|
|
forceSSL = !cfg.private-network;
|
|
locations."/".proxyPass = "http://127.0.0.1:3000";
|
|
};
|
|
};
|
|
};
|
|
|
|
grafana = {
|
|
enable = true;
|
|
|
|
addr = "127.0.0.1";
|
|
protocol = "http";
|
|
port = 3000;
|
|
domain = cfg.hostname;
|
|
rootUrl = let scheme = if cfg.private-network then "http" else "https";
|
|
in "${scheme}://${cfg.hostname}/";
|
|
dataDir = cfg.state-directory;
|
|
|
|
settings = {
|
|
smtp = {
|
|
enable = true;
|
|
# TODO: create system user as necessary
|
|
from_address = "${cfg.smtp.username}@${cfg.smtp.domain}";
|
|
host = "${cfg.smtp.hostname}:25";
|
|
user = cfg.smtp.username;
|
|
password = "$__${cfg.smtp.password-file}}";
|
|
};
|
|
|
|
security = {
|
|
admin_password = "$__{${cfg.admin-password-file}}";
|
|
secret_key = "$__file{${cfg.secret-key-file}}";
|
|
};
|
|
|
|
database = {
|
|
host = cfg.database.hostname;
|
|
name = cfg.database.name;
|
|
user = cfg.database.user;
|
|
password = "$__{${cfg.database.password-file}}";
|
|
type = "postgres";
|
|
};
|
|
|
|
ldap.auth = mkIf (cfg.ldap != null) (let
|
|
base = cfg.ldap.base-dn;
|
|
|
|
config-file = pkgs.writeText "grafana-ldap.toml" ''
|
|
[[servers]]
|
|
host = "${concatStringsSep " " cfg.ldap.hosts}"
|
|
port = 389
|
|
start_tls = true
|
|
|
|
bind_dn = "uid=%s,ou=members,${base}"
|
|
|
|
search_filter = "(uid=%s)"
|
|
search_base_dns = [ "ou=members,${base}" ]
|
|
|
|
group_search_filter = "(&(objectClass=posixGroup)(memberUid=%s))"
|
|
group_search_base_dns = ["ou=groups,${base}"]
|
|
group_search_filter_user_attribute = "uid"
|
|
|
|
[[servers.group_mappings]]
|
|
group_dn = "cn=admin,ou=groups,${base}"
|
|
org_role = "Admin"
|
|
grafana_admin = true
|
|
|
|
[[servers.group_mappings]]
|
|
group_dn = "cn=*,ou=groups,${base}"
|
|
org_role = "Viewer"
|
|
'';
|
|
in {
|
|
enabled = true;
|
|
allow_sign_up = true;
|
|
config_file = config-file;
|
|
|
|
# AUTH_LDAP_ENABLED = "true";
|
|
# AUTH_LDAP_ALLOW_SIGN_UP = "true";
|
|
# AUTH_LDAP_CONFIG_FILE = config-file;
|
|
});
|
|
};
|
|
|
|
provision = {
|
|
enable = true;
|
|
datasources.settings.datasources = let
|
|
make-datasource = datasource: {
|
|
editable = false;
|
|
isDefault = datasource.default;
|
|
inherit (datasource) name type url;
|
|
};
|
|
in map make-datasource (attrValues cfg.datasources);
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|