From a17f93fa84cf2ee39179f11c7f601fbbd0e54f14 Mon Sep 17 00:00:00 2001 From: niten Date: Sat, 22 Jul 2023 10:30:59 -0700 Subject: [PATCH] Initial checkin --- flake.nix | 17 ++++ tesla-mate-container.nix | 166 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 flake.nix create mode 100644 tesla-mate-container.nix diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..e8364dd --- /dev/null +++ b/flake.nix @@ -0,0 +1,17 @@ +{ + description = "TeslaMate running in a container"; + + inputs = { + nixpkgs.url = "nixpkgs/nixos-23.05"; + arion.url = "github:hercules-ci/arion"; + }; + + outputs = { self, nixpkgs, arion, ... }: { + nixosModules = rec { + default = teslaMateContainer; + teslaMateContainer = { ... }: { + imports = [ arion.nixosModules.arion ./tesla-mate-container.nix ]; + }; + }; + }; +} diff --git a/tesla-mate-container.nix b/tesla-mate-container.nix new file mode 100644 index 0000000..94caeb2 --- /dev/null +++ b/tesla-mate-container.nix @@ -0,0 +1,166 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = canfig.services.teslaMateContainer; + + 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); + + makeTeslaMateImage = + { teslaMateImage, postgresImage, grafanaImage, stateDirectory, ... }: + { pkgs, ... }: { + project.name = "teslamate"; + services = { + teslamate = { + image = teslaMateImage; + restart = "always"; + volumes = [ "${stateDirectory}/import:/opt/app/import" ]; + ports = [ "4000:4000" ]; + cap_drop = "all"; + }; + postgres = { + image = postgresImage; + restart = "always"; + volumes = [ "${stateDirectory}/postgres:/var/lib/postgresql/data" ]; + env_file = [ postgresEnvFile ]; + }; + grafana = { + image = grafanaImage; + restart = "always"; + volumes = [ "${stateDirectory}/grafana:/var/lib/grafana" ]; + env_file = [ grafanaEnvFile ]; + ports = [ "3000:3000" ]; + }; + }; + }; +in { + options.services.telsaMateContainer = with types; { + 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."; + }; + }; + }; + + 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"; + 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; + }; + }; + + virtualisation = { + arion = { + backend = "podman-socket"; + projects.teslamate.settings = let + teslaMateImage = makeTeslaMateImage { + teslaMateImage = cfg.images.tesla-mate; + postgresImage = cfg.images.postgres; + grafanaImage = cfg.images.grafana; + 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; + teslaMatePostgresUid = config.users.users.tesla-mate-postgres.uid; + teslaMateGrafanaUid = config.users.users.tesla-mate-grafana.uid; + }; + in { imports = [ teslaMateImage ]; }; + }; + }; + }; +}