1
0
Fork 0

add test for monitoring that checks provisioning goes well

This commit is contained in:
ibizaman 2023-11-26 09:30:45 -08:00
parent bd8f36a555
commit a4a8a2adad
3 changed files with 101 additions and 39 deletions

View file

@ -49,6 +49,13 @@
flattenAttrs = root: attrset: pkgs.lib.attrsets.foldlAttrs (acc: name: value: acc // { flattenAttrs = root: attrset: pkgs.lib.attrsets.foldlAttrs (acc: name: value: acc // {
"${root}_${name}" = value; "${root}_${name}" = value;
}) {} attrset; }) {} attrset;
vm_test = name: path: flattenAttrs "vm_${name}" (
import path {
inherit pkgs;
inherit (pkgs) lib;
}
);
in (rec { in (rec {
all = mergeTests [ all = mergeTests [
modules modules
@ -64,7 +71,8 @@
]); ]);
}; };
} }
// (flattenAttrs "vm_postgresql" (import ./test/vm/postgresql.nix {inherit pkgs; inherit (pkgs) lib;})) // (vm_test "postgresql" ./test/vm/postgresql.nix)
// (vm_test "monitoring" ./test/vm/monitoring.nix)
); );
} }
); );

View file

@ -9,12 +9,6 @@ in
options.shb.monitoring = { options.shb.monitoring = {
enable = lib.mkEnableOption "selfhostblocks.monitoring"; enable = lib.mkEnableOption "selfhostblocks.monitoring";
# sopsFile = lib.mkOption {
# type = lib.types.path;
# description = "Sops file location";
# example = "secrets/monitoring.yaml";
# };
subdomain = lib.mkOption { subdomain = lib.mkOption {
type = lib.types.str; type = lib.types.str;
description = "Subdomain under which home-assistant will be served."; description = "Subdomain under which home-assistant will be served.";
@ -27,6 +21,24 @@ in
example = "mydomain.com"; example = "mydomain.com";
}; };
grafanaPort = lib.mkOption {
type = lib.types.port;
description = "Port where Grafana listens to HTTP requests.";
default = 3000;
};
prometheusPort = lib.mkOption {
type = lib.types.port;
description = "Port where Prometheus listens to HTTP requests.";
default = 3001;
};
lokiPort = lib.mkOption {
type = lib.types.port;
description = "Port where Loki listens to HTTP requests.";
default = 3002;
};
debugLog = lib.mkOption { debugLog = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
description = "Set to true to enable debug logging of the infrastructure serving Grafana."; description = "Set to true to enable debug logging of the infrastructure serving Grafana.";
@ -49,10 +61,22 @@ in
contactPoints = lib.mkOption { contactPoints = lib.mkOption {
type = lib.types.listOf lib.types.str; type = lib.types.listOf lib.types.str;
description = "List of email addresses to send alerts to"; description = "List of email addresses to send alerts to";
default = [];
};
adminPasswordFile = lib.mkOption {
type = lib.types.path;
description = "File containing the initial admin password.";
};
secretKeyFile = lib.mkOption {
type = lib.types.path;
description = "File containing the secret key used for signing.";
}; };
smtp = lib.mkOption { smtp = lib.mkOption {
type = lib.types.submodule { default = null;
type = lib.types.nullOr (lib.types.submodule {
options = { options = {
from_address = lib.mkOption { from_address = lib.mkOption {
type = lib.types.str; type = lib.types.str;
@ -82,14 +106,14 @@ in
description = "File containing the password to connect to the SMTP host."; description = "File containing the password to connect to the SMTP host.";
}; };
}; };
}; });
}; };
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
assertions = [ assertions = [
{ {
assertion = builtins.length cfg.contactPoints > 0; assertion = (!(isNull cfg.smtp)) -> builtins.length cfg.contactPoints > 0;
message = "Must have at least one contact point for alerting"; message = "Must have at least one contact point for alerting";
} }
]; ];
@ -115,15 +139,21 @@ in
# password = "$__file{/run/secrets/homeassistant/dbpass}"; # password = "$__file{/run/secrets/homeassistant/dbpass}";
}; };
security = {
secret_key = "$__file{${cfg.secretKeyFile}}";
disable_initial_admin_creation = false; # Enable when LDAP support is configured.
admin_password = "$__file{${cfg.adminPasswordFile}}"; # Remove when LDAP support is configured.
};
server = { server = {
http_addr = "127.0.0.1"; http_addr = "127.0.0.1";
http_port = 3000; http_port = cfg.grafanaPort;
domain = fqdn; domain = fqdn;
root_url = "https://${fqdn}"; root_url = "https://${fqdn}";
router_logging = cfg.debugLog; router_logging = cfg.debugLog;
}; };
smtp = { smtp = lib.mkIf (!(isNull cfg.smtp)) {
enabled = true; enabled = true;
inherit (cfg.smtp) from_address from_name; inherit (cfg.smtp) from_address from_name;
host = "${cfg.smtp.host}:${toString cfg.smtp.port}"; host = "${cfg.smtp.host}:${toString cfg.smtp.port}";
@ -175,33 +205,24 @@ in
} }
]; ];
}; };
alerting.contactPoints.settings = lib.mkIf ((builtins.length cfg.contactPoints) > 0) { alerting.contactPoints.settings = {
apiVersion = 1; apiVersion = 1;
contactPoints = [{ contactPoints = [{
inherit (cfg) orgId; inherit (cfg) orgId;
name = "selfhostblocks-sysadmin"; name = "grafana-default-email";
receivers = [{ receivers = lib.optionals ((builtins.length cfg.contactPoints) > 0) [{
uid = "sysadmin"; uid = "sysadmin";
type = "email"; type = "email";
settings.addresses = lib.concatStringsSep ";" cfg.contactPoints; settings.addresses = lib.concatStringsSep ";" cfg.contactPoints;
}]; }];
}]; }];
deleteContactPoints = [
{
inherit (cfg) orgId;
uid = "grafana-default-email";
}
];
}; };
alerting.policies.settings = { alerting.policies.settings = {
apiVersion = 1; apiVersion = 1;
policies = [{ policies = [{
inherit (cfg) orgId; inherit (cfg) orgId;
receiver = "selfhostblocks-sysadmin"; receiver = "grafana-default-email";
group_by = [ "grafana_folder" "alertname" ]; group_by = [ "grafana_folder" "alertname" ];
object_matchers = [
[ "role" "=" "sysadmin" ]
];
group_wait = "30s"; group_wait = "30s";
group_interval = "5m"; group_interval = "5m";
repeat_interval = "4h"; repeat_interval = "4h";
@ -230,7 +251,7 @@ in
services.prometheus = { services.prometheus = {
enable = true; enable = true;
port = 3001; port = cfg.prometheusPort;
}; };
services.loki = { services.loki = {
@ -239,7 +260,7 @@ in
configuration = { configuration = {
auth_enabled = false; auth_enabled = false;
server.http_listen_port = 3002; server.http_listen_port = cfg.lokiPort;
ingester = { ingester = {
lifecycler = { lifecycler = {
@ -340,9 +361,9 @@ in
enable = true; enable = true;
virtualHosts.${fqdn} = { virtualHosts.${fqdn} = {
forceSSL = true; forceSSL = lib.mkIf config.shb.ssl.enable true;
sslCertificate = "/var/lib/acme/${cfg.domain}/cert.pem"; sslCertificate = lib.mkIf config.shb.ssl.enable "/var/lib/acme/${cfg.domain}/cert.pem";
sslCertificateKey = "/var/lib/acme/${cfg.domain}/key.pem"; sslCertificateKey = lib.mkIf config.shb.ssl.enable "/var/lib/acme/${cfg.domain}/key.pem";
locations."/" = { locations."/" = {
proxyPass = "http://${toString config.services.grafana.settings.server.http_addr}:${toString config.services.grafana.settings.server.http_port}"; proxyPass = "http://${toString config.services.grafana.settings.server.http_addr}:${toString config.services.grafana.settings.server.http_port}";
proxyWebsockets = true; proxyWebsockets = true;
@ -439,14 +460,5 @@ in
listenAddress = "127.0.0.1"; listenAddress = "127.0.0.1";
}; };
services.nginx.statusPage = lib.mkDefault config.services.nginx.enable; services.nginx.statusPage = lib.mkDefault config.services.nginx.enable;
# sops.secrets."grafana" = {
# inherit (cfg) sopsFile;
# mode = "0440";
# owner = "grafana";
# group = "grafana";
# # path = "${config.services.home-assistant.configDir}/secrets.yaml";
# restartUnits = [ "grafana.service" ];
# };
}; };
} }

42
test/vm/monitoring.nix Normal file
View file

@ -0,0 +1,42 @@
{ pkgs, lib, ... }:
{
# This test, although simple, makes sure all provisioning went fine.
auth = pkgs.nixosTest {
name = "monitoring-basic";
nodes.machine = { config, pkgs, ... }: {
imports = [
{
options = {
shb.ssl.enable = lib.mkEnableOption "ssl";
};
}
../../modules/blocks/postgresql.nix
../../modules/blocks/monitoring.nix
];
shb.monitoring = {
enable = true;
subdomain = "grafana";
domain = "example.com";
grafanaPort = 3000;
adminPasswordFile = pkgs.writeText "admin_password" "securepw";
secretKeyFile = pkgs.writeText "secret_key" "secret_key";
};
};
testScript = { nodes, ... }: ''
start_all()
machine.wait_for_unit("grafana.service")
def curl_req(password, wantStatus, endpoint):
response = machine.wait_until_succeeds("curl -i http://admin:{password}@localhost:3000{endpoint}".format(password=password, endpoint=endpoint), timeout=10)
if not response.startswith("HTTP/1.1 {wantStatus}".format(wantStatus=wantStatus)):
raise Exception("Wrong status, expected {}, got {}".format(wantStatus, response[9:12]))
return response
curl_req("securepw", 200, "/api/org")
curl_req("wrong", 401, "/api/org")
'';
};
}