tesla-mate-container/tesla-mate-container.nix

221 lines
6.9 KiB
Nix
Raw Normal View History

2023-07-22 10:30:59 -07:00
{ config, lib, pkgs, ... }:
with lib;
let
2023-07-22 11:03:07 -07:00
cfg = config.services.teslaMateContainer;
2023-07-22 10:30:59 -07:00
hostSecrets = config.fudo.secrets.host-secrets."${config.instance.hostname}";
makeEnvFile = envVars:
let
envLines =
mapAttrsToList (var: val: ''${var}="${toString val}"'') envVars;
in pkgs.writeText "envFile" (concatStringsSep "\n" envLines);
2023-07-22 11:37:57 -07:00
makeTeslaMateImage = { teslaMateImage, postgresImage, grafanaImage
2023-07-22 14:19:00 -07:00
, teslaMatePort, grafanaPort, teslaMateEnvFile, postgresEnvFile
, grafanaEnvFile, teslaMateUid, postgresUid, grafanaUid, stateDirectory, ...
}:
2023-07-22 10:30:59 -07:00
{ pkgs, ... }: {
project.name = "teslamate";
services = {
teslamate = {
2023-07-22 11:42:37 -07:00
service = {
image = teslaMateImage;
restart = "always";
volumes = [ "${stateDirectory}/import:/opt/app/import" ];
2023-07-22 14:19:00 -07:00
ports = [ "${toString teslaMatePort}:4000" ];
2023-07-22 11:58:05 -07:00
user = "${toString teslaMateUid}:${toString teslaMateUid}";
2023-07-22 11:42:37 -07:00
env_file = [ teslaMateEnvFile ];
2023-07-22 12:25:21 -07:00
capabilities.ALL = false;
2023-10-12 14:45:43 -07:00
depends_on = { postgres.condition = "service_healthy"; };
2023-07-22 11:42:37 -07:00
};
2023-07-22 10:30:59 -07:00
};
postgres = {
2023-07-22 11:42:37 -07:00
service = {
image = postgresImage;
restart = "always";
volumes = [ "${stateDirectory}/postgres:/var/lib/postgresql/data" ];
env_file = [ postgresEnvFile ];
2023-07-22 11:58:05 -07:00
user = "${toString postgresUid}:${toString postgresUid}";
2023-10-12 14:45:43 -07:00
healthcheck = {
2023-11-28 17:33:40 -08:00
test = [ "CMD" "pg_isready" "-U" "teslamate" "-d" "teslamate" ];
2023-10-12 14:45:43 -07:00
start_period = "20s";
interval = "30s";
retries = 5;
timeout = "3s";
};
2023-07-22 11:42:37 -07:00
};
2023-07-22 10:30:59 -07:00
};
grafana = {
2023-07-22 11:42:37 -07:00
service = {
image = grafanaImage;
restart = "always";
volumes = [ "${stateDirectory}/grafana:/var/lib/grafana" ];
env_file = [ grafanaEnvFile ];
2023-07-22 11:58:05 -07:00
user = "${toString grafanaUid}:${toString grafanaUid}";
2023-07-22 14:19:00 -07:00
ports = [ "${toString grafanaPort}:3000" ];
2023-10-12 14:45:43 -07:00
depends_on = [ "teslamate" ];
2023-07-22 11:42:37 -07:00
};
2023-07-22 10:30:59 -07:00
};
};
};
in {
2023-07-22 11:04:06 -07:00
options.services.teslaMateContainer = with types; {
2023-07-22 10:30:59 -07:00
enable = mkEnableOption "Enable TeslaMate in a PodMan container.";
images = {
tesla-mate = mkOption {
type = str;
description = "Docker image to use for Tesla Mate.";
default = "teslamate/teslamate:latest";
};
postgres = mkOption {
type = str;
description = "Docker image to use for Postgres DB.";
default = "postgres:15";
};
grafana = mkOption {
type = str;
description = "Docker image to use for Grafana.";
default = "teslamate/grafana:latest";
};
};
mqtt = {
host = mkOption {
type = str;
description = "Hostname of the MQTT server.";
};
port = mkOption {
type = port;
description = "Port of the MQTT server";
default = 1883;
};
user = mkOption {
type = str;
description = "User as which to connect to the MQTT server.";
default = "tesla-mate";
};
password = mkOption {
type = str;
description =
"Password with which to authenticate with the MQTT server.";
};
};
2023-07-22 12:13:48 -07:00
2023-07-22 14:19:00 -07:00
port = mkOption {
type = port;
description = "Local port on which to listen for TeslaMate requests.";
};
grafana-port = mkOption {
type = port;
description = "Local port on which to listen for Grafana requests.";
};
2023-07-22 12:13:48 -07:00
state-directory = mkOption {
type = str;
description = "Path at which to store service state.";
};
2023-07-22 10:30:59 -07:00
};
config = mkIf cfg.enable {
fudo.secrets.host-secrets."${config.instance.hostname}" = let
teslaMateDbPass = readFile
(pkgs.lib.passwd.stablerandom-passwd-file "teslaMateDbPasswd"
config.instance.build-seed);
teslaMateEncryptionKey = readFile
(pkgs.lib.passwd.stablerandom-passwd-file "teslaMateEncryptionKey"
config.instance.build-seed);
in {
teslaMateEnv = {
source-file = makeEnvFile {
ENCRYPTION_KEY = teslaMateEncryptionKey;
DATABASE_USER = "teslamate";
DATABASE_PASS = teslaMateDbPass;
DATABASE_HOST = "postgres";
2023-07-22 16:22:30 -07:00
DATABASE_NAME = "teslamate";
2023-07-22 10:30:59 -07:00
MQTT_HOST = cfg.mqtt.host;
MQTT_PORT = cfg.mqtt.port;
MQTT_USERNAME = cfg.mqtt.user;
MQTT_PASSWORD = cfg.mqtt.password;
};
target-file = "/run/tesla-mate/tesla-mate.env";
};
teslaMatePostgresEnv = {
source-file = makeEnvFile {
POSTGRES_USER = "teslamate";
POSTGRES_PASSWORD = teslaMateDbPass;
POSTGRES_DB = "teslamate";
};
target-file = "/run/tesla-mate/postgres.env";
};
teslaMateGrafanaEnv = {
source-file = makeEnvFile {
DATABASE_USER = "teslamate";
DATABASE_PASS = teslaMateDbPass;
DATABASE_NAME = "teslamate";
DATABASE_HOST = "postgres";
};
target-file = "/run/tesla-mate/grafana.env";
};
};
users.users = {
tesla-mate = {
isSystemUser = true;
group = "tesla-mate";
uid = 720;
};
tesla-mate-postgres = {
isSystemUser = true;
group = "tesla-mate";
uid = 721;
};
tesla-mate-grafana = {
isSystemUser = true;
group = "tesla-mate";
uid = 722;
};
};
2023-09-25 17:24:49 -07:00
systemd = {
tmpfiles.rules = [
"d ${cfg.state-directory}/import 0700 ${
toString config.users.users.tesla-mate.uid
} root - -"
"d ${cfg.state-directory}/postgres 0700 ${
toString config.users.users.tesla-mate-postgres.uid
} root - -"
"d ${cfg.state-directory}/grafana 0700 ${
toString config.users.users.tesla-mate-grafana.uid
} root - -"
];
services.arion-teslamate = {
after =
[ "fudo-secrets.target" "network-online.target" "podman.service" ];
requires = [ "network-online.target" "podman.service" ];
};
};
2023-07-22 10:38:50 -07:00
virtualisation.arion.projects.teslamate.settings = let
teslaMateImage = makeTeslaMateImage {
teslaMateImage = cfg.images.tesla-mate;
postgresImage = cfg.images.postgres;
grafanaImage = cfg.images.grafana;
2023-07-22 14:19:00 -07:00
teslaMatePort = cfg.port;
grafanaPort = cfg.grafana-port;
2023-07-22 10:38:50 -07:00
stateDirectory = cfg.state-directory;
teslaMateEnvFile = hostSecrets.teslaMateEnv.target-file;
postgresEnvFile = hostSecrets.teslaMatePostgresEnv.target-file;
grafanaEnvFile = hostSecrets.teslaMateGrafanaEnv.target-file;
teslaMateUid = config.users.users.tesla-mate.uid;
2023-07-22 11:40:20 -07:00
postgresUid = config.users.users.tesla-mate-postgres.uid;
grafanaUid = config.users.users.tesla-mate-grafana.uid;
2023-07-22 10:30:59 -07:00
};
2023-07-22 10:38:50 -07:00
in { imports = [ teslaMateImage ]; };
2023-07-22 10:30:59 -07:00
};
}