Files
archived-teslamate/module.nix
T
JakobLichterfeldandscottbot95 fdf8185ce2 ci: add treefmt as code formatting multiplexer, refactor CI to avoid duplication, reorg CI into DevOps workflow (#4219)
* ci: add treefmt as code formatting multiplexer

* style: linter findings in entrypoint.sh script

* style: linter findings for yaml and yml

* style: linter findings for json files

* style: linter findings for nix files

* style: linter findings for js files

* style: linter findings for dashboards.sh

* style: linter findings for md and mdx files

* chore: remove unused clang formatter in treefmt config

* style: linter findings for mdx files

* ci: exclude Grafana dashboard JSON files from prettier formatting

* Revert "style: linter findings for json files"

This reverts commit f40c2e1759.

* ci: exclude Grafana dashboard JSON files from all formatting as we use the grafana export style

* style: linter findings for json files

* doc: update changelog

* ci(refactor): use composite action to avoid duplication in elixir workflow

* doc: update changelog

* ci: prevent workflow runs for certain conditions and allow scheduled runs

* ci(refactor): use reusable workflow to check paths

* ci(fix): correct output syntax for check_paths workflow and setting base branch

* ci(refactor): use reusable workflows for streamlined DevOps pipeline

* ci(fix): add write permission for packages in DevOps workflow

* ci(test): test DevOps workflow

* ci(test): test DevOps workflow

* ci(fix): Update condition for spell_check, ensure_linting, elixir, and ghcr_build workflows to reflect empty result instead of false

* ci: revert test DevOps

* ci(refactor): allow ghcr_build parallel to elixir test

* ci(refactor): Remove redundant check_paths job from elixir.yml, elixir_test.yml, and spell_check.yml workflows, check is done in devops.yml

* feat: add treefmt-nix to nix flake (#4219 - @JakobLichterfeld)

* ci: ensure proper linting via treefmt

* ci(test): test ensure_linting workflow

* ci(fix): checkout code for spell_checker to access file to check

* ci(fix): allow impure in ensure_linting workflow

* Revert "ci(test): test ensure_linting workflow"

This reverts commit a67b17ec09.

* ci(fix): correct use of flake-utils for formatter and checks

Co-authored-by: scottbot95 <scottbot95@gmail.com>

* ci(fix): correct use of flake-utils for treefmt

Co-authored-by: scottbot95 <scottbot95@gmail.com>

* refactor: Remove unnecessary imports in flake

* ci(fix): correct syntax in flake

* ci(refactor): Remove unused code in flake.nix

* style: standardised style for input url in flake

* ci(fix): treefmt-nix config with existing options

* ci(feat): Add Nix binary cache and update treefmt command in CI workflow

* ci(refactor): Remove unused code in flake.nix

* fix: include devShell packages only on supported platforms

* fix: update hash for mix-deps package in flake.nix

* ci(fix): Update treefmt command in CI workflow

* ci(test): test ensure_linting workflow

* feat: ensure mix deps are present in devShell

* ci(feat): use flake-parts to enable treefmt-nix

* feat: use flake-parts

* fix: correct use of flake-parts for package build

* doc: update CI badge URL for devops workflow

* ci(fix): handle empty path filter output

* ci: remove --impure flag from treefmt command in CI workflow

* fix: correct treefmt.config settings in formatter.nix

* fix: correct flake-parts inputs, avoid with in imports

* fix: correct program name for mix-format in formatter.nix

* feat: devenv via flake-parts

* fix: correct use of legacy nix code with flake-parts

* ci(fix): correct nix develop command in ensure_linting.yml

* refactor: list imports explicitly in flake, rename folder to flake-modules to be precise

* style: use tabs for indent size to format sh

* style: use nixfmt-rfc-style

* Revert "style: use nixfmt-rfc-style"

This reverts commit 082056159e.

* style: use nixfmt style

* fix: remove glibcLocales from optional dependencies to avoid  "A definition for option `packages."[definition 4-entry 16]"' is not of type `package'."

* fix: remove inotify-tools from optional dependencies to avoid  "A definition for option `packages."[definition 4-entry 16]"' is not of type `package'."

* fix: Remove inotify-tools and glibcLocales from optional dependencie

* fix: correct file paths in flake.nix to version

* fix: add ELIXIR_ERL_OPTIONS to shell environment to force utf8 locale

* fix: add LOCALE_ARCHIVE to shell environment in flake.nix

* Revert "fix: add LOCALE_ARCHIVE to shell environment in flake.nix"

This reverts commit d45f6e32ee.

* ci(refactor): rename workflow to elixir_dep_verification_and_static_analysis.yml to better reflect the intention,, remove duplicate checks

* ci(debug): debug locale settings

* Revert "ci(debug): debug locale settings"

This reverts commit 9b402f3c5f.

* Revert "fix: add ELIXIR_ERL_OPTIONS to shell environment to force utf8 locale"

This reverts commit d02419cba4.

* fix: add LOCALE_ARCHIVE to shell environment in flake.nix

* Revert "fix: add LOCALE_ARCHIVE to shell environment in flake.nix"

This reverts commit 761b437e69.

* fix: add LANG=C.UTF-8 to shell environment in flake.nix

* fix: add mix local.rebar and mix local.hex commands to flake.nix

* fix: pin devenv to version without unix socket bug

* chore: update nixpkgs to nixos-24.05 and update dependencies

* doc: add treefmt config comments

* ci: do not expose treefmt formatter programs in devshell

* fix: correct use of module option to enable PostgreSQL server in flake.nix

* Revert "chore: update nixpkgs to nixos-24.05 and update dependencies"

This reverts commit a6ea3f25aa.

* feat: consistent use of erlang 26 and elixir 1_16 in flake

* ci: switch to macOS runner for linting workflow

* Revert "ci: do not expose treefmt formatter programs in devshell"

This reverts commit 1ecfa451dc.

* Revert "ci: switch to macOS runner for linting workflow"

This reverts commit 7b430667d8.

* ci: Remove nixpkgs channel specification in ensure_linting workflow

* ci(debug): Add debug output for PATH and NIX_PATH in flake.nix

* Revert "ci(debug): Add debug output for PATH and NIX_PATH in flake.nix"

This reverts commit 07faec5ddf.

* fix: avoid the need for impure for devenv

see #4245

* fix: remove invalid custom build.check for formatter and use default

* style: linter findings

* fix: Add emptyTest to avoid nix flake check test execution on non-Linux systems

* chore: Remove LANG=C.UTF-8 from enterShell in flake.nix

* ci(fix): Remove --impure flag from treefmt command in CI mode

* ci(fix): avoid impure mode in ensure_linting workflow

* style: linter findings

* ci(debug): debug elixir version and locale

* chore: Update flake.lock dependencies

* feat: use newer devenv as unix socket bug is fixed in upstream

https://github.com/cachix/devenv/issues/1497

* fix: set rebar3 path in devenv

* Revert "ci(debug): debug elixir version and locale"

This reverts commit 7ecdc77c16.

* ci: re-enable path check in DevOps workflow

* doc: update Development and Contributing guide with nix and treefmt

* ci: use PostgreSQL 17

* style: linter findings

* ci(fix): ensure cache name in build action does not contain invalid characters to avoid invalid reference format

* doc: update changelog

* Revert "ci(fix): ensure cache name in build action does not contain invalid characters to avoid invalid reference format"

This reverts commit 02abb0359d.

* ci: remove branch restriction for check_paths workflow to increase sec

* ci(fix): run ghcr build workflow only for specific conditions

- Ensure workflow only run if there are no changes to the .github folder
- Allow workflow to run on workflow call or PRs from forks
- Prevent duplicate runs for PRs from non-forks
- Avoid invalid reference format for cache name in PRs from our repository

* doc: update changelog

* fix: update hash for mix-deps package in flake.nix

* fix: disable flakeCheck for formatter, as mix format need the dep to be fetched beforehand

* ci(fix): run ghcr build workflow only for specific conditions

* fix: move nixosModules.default to top-level attribute set

* refactor: remove unnecessary config nesting in formatter.nix

* ci(fix): ensure version for buildx is set to correct name

---------

Co-authored-by: scottbot95 <scottbot95@gmail.com>
2024-10-14 08:54:10 +02:00

318 lines
9.2 KiB
Nix

{ self }:
{ config
, lib
, pkgs
, ...
}:
let
teslamate = self.packages.${pkgs.system}.default;
cfg = config.services.teslamate;
inherit (lib)
mkPackageOption
mkEnableOption
mkOption
types
mkIf
mkMerge
getExe
literalExpression
;
in
{
options.services.teslamate = {
enable = mkEnableOption "Teslamate";
secretsFile = mkOption {
type = types.str;
example = "/run/secrets/teslamate.env";
description = lib.mdDoc ''
Path to an env file containing the secrets used by TeslaMate.
Must contain at least:
- `ENCRYPTION_KEY` - encryption key used to encrypt database
- `DATABASE_PASS` - password used to authenticate to database
- `RELEASE_COOKIE` - unique value used by elixir for clustering
'';
};
autoStart = mkOption {
type = types.bool;
default = true;
description = "Whether to start teslamate on boot.";
};
listenAddress = mkOption {
type = with types; nullOr str;
default = null;
example = "127.0.0.1";
description = "IP address where the web interface is exposed or `null` for all addresses";
};
port = mkOption {
type = types.port;
default = 4000;
description = "Port the TeslaMate service will listen on";
};
virtualHost = mkOption {
type = types.str;
default = if config.networking.domain == null then "localhost" else config.networking.fqdn;
defaultText = literalExpression ''
if config.networking.domain == null then "localhost" else config.networking.fqdn
'';
description = "Host part used for generating URLs throughout the app. Will be combined with urlPath";
};
urlPath = mkOption {
type = types.str;
default = "/";
description = "Path prefix used for generating URLs throughout the app. Will be combined with virtualHost";
};
postgres = {
enable_server = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Whether to create a postgres server with the recommended configuration.
Other settings will still be used even if `enable` is false to configure
database connection.
'';
};
package = mkPackageOption pkgs "postgresql_16" {
# 17 is not yet available in nixpkgs
extraDescription = ''
The postgresql package to use.
'';
};
user = mkOption {
type = types.str;
default = "teslamate";
description = "PostgresQL database user";
};
database = mkOption {
type = types.str;
default = "teslamate";
description = "PostgresQL database to connect to";
};
host = mkOption {
type = types.str;
default = "127.0.0.1";
description = "Hostname of the database server";
};
port = mkOption {
type = types.port;
default = 5432;
description = "Postgresql database port. Must be correct even if `services.teslamate.postgres.enable` is false";
};
};
grafana = {
enable = mkOption {
type = types.bool;
default = false;
description = "Whether to create and provision grafana with the TeslaMate dashboards";
};
listenAddress = mkOption {
type = types.str;
default = "0.0.0.0";
description = "IP address for grafana to listen to.";
};
port = mkOption {
type = types.port;
default = 3000;
description = "Port for grafana web service";
};
urlPath = mkOption {
type = types.str;
default = "/";
description = "Path that grafana is mounted on. Useful if using a reverse proxy to vend teslamate and grafana on the same port";
};
};
mqtt = {
enable = mkEnableOption "TeslaMate MQTT integration";
host = mkOption {
type = types.str;
default = "127.0.0.1";
description = "MQTT host";
};
port = mkOption {
type = with types; nullOr port;
default = null;
example = 1883;
description = "MQTT port.";
};
};
};
config = mkIf cfg.enable (mkMerge [
{
users.users.teslamate = {
isSystemUser = true;
group = "teslamate";
home = "/var/lib/teslamate";
createHome = true;
};
users.groups.teslamate = { };
systemd.services.teslamate = {
description = "TeslaMate";
after = [
"network.target"
"postgresql.service"
];
wantedBy = mkIf cfg.autoStart [ "multi-user.target" ];
serviceConfig = {
User = "teslamate";
Restart = "on-failure";
RestartSec = 5;
WorkingDirectory = "/var/lib/teslamate";
ExecStartPre = ''${getExe teslamate} eval "TeslaMate.Release.migrate"'';
ExecStart = "${getExe teslamate} start";
ExecStop = "${getExe teslamate} stop";
EnvironmentFile = cfg.secretsFile;
};
environment = mkMerge [
{
PORT = toString cfg.port;
DATABASE_USER = cfg.postgres.user;
DATABASE_NAME = cfg.postgres.database;
DATABASE_HOST = cfg.postgres.host;
DATABASE_PORT = toString cfg.postgres.port;
VIRTUAL_HOST = cfg.virtualHost;
URL_PATH = cfg.urlPath;
HTTP_BINDING_ADDRESS = mkIf (cfg.listenAddress != null) cfg.listenAddress;
DISABLE_MQTT = mkIf (!cfg.mqtt.enable) "true";
}
(mkIf cfg.mqtt.enable {
MQTT_HOST = cfg.mqtt.host;
MQTT_PORT = mkIf (cfg.mqtt.port != null) (toString cfg.mqtt.port);
})
];
};
}
(mkIf cfg.postgres.enable_server {
services.postgresql = {
enable = true;
inherit (cfg.postgres) port package;
initialScript = pkgs.writeText "teslamate-psql-init" ''
\set password `echo $DATABASE_PASS`
CREATE DATABASE ${cfg.postgres.database};
CREATE USER ${cfg.postgres.user} with encrypted password :'password';
GRANT ALL PRIVILEGES ON DATABASE ${cfg.postgres.database} TO ${cfg.postgres.user};
ALTER USER ${cfg.postgres.user} WITH SUPERUSER;
'';
};
# Include secrets in postgres as well
systemd.services.postgresql = {
serviceConfig = {
EnvironmentFile = cfg.secretsFile;
};
};
})
(mkIf cfg.grafana.enable {
services.grafana = {
enable = true;
settings = {
server = {
domain = cfg.virtualHost;
http_port = cfg.grafana.port;
http_addr = cfg.grafana.listenAddress;
root_url = "http://%(domain)s${cfg.grafana.urlPath}";
serve_from_sub_path = cfg.grafana.urlPath != "/";
};
security = {
allow_embedding = true;
disable_gravatr = true;
};
users = {
allow_sign_up = false;
};
"auth.anonymous".enabled = false;
"auth.basic".enabled = false;
analytics.reporting_enabled = false;
};
provision = {
enable = true;
datasources.path = ./grafana/datasource.yml;
# Need to duplicate dashboards.yml since it contains absolute paths
# which are incompatible with NixOS
dashboards.settings = {
apiVersion = 1;
providers = [
{
name = "teslamate";
orgId = 1;
folder = "TeslaMate";
folderUid = "Nr4ofiDZk";
type = "file";
disableDeletion = false;
editable = true;
updateIntervalSeconds = 86400;
options.path = lib.sources.sourceFilesBySuffices
./grafana/dashboards
[ ".json" ];
}
{
name = "teslamate_internal";
orgId = 1;
folder = "Internal";
folderUid = "Nr5ofiDZk";
type = "file";
disableDeletion = false;
editable = true;
updateIntervalSeconds = 86400;
options.path = lib.sources.sourceFilesBySuffices
./grafana/dashboards/internal
[ ".json" ];
}
{
name = "teslamate_reports";
orgId = 1;
folder = "Reports";
folderUid = "Nr6ofiDZk";
type = "file";
disableDeletion = false;
editable = true;
updateIntervalSeconds = 86400;
options.path = lib.sources.sourceFilesBySuffices
./grafana/dashboards/reports
[ ".json" ];
}
];
};
};
};
systemd.services.grafana = {
serviceConfig.EnvironmentFile = cfg.secretsFile;
environment = {
DATABASE_USER = cfg.postgres.user;
DATABASE_NAME = cfg.postgres.database;
DATABASE_HOST = cfg.postgres.host;
DATABASE_PORT = toString cfg.postgres.port;
DATABASE_SSL_MODE = "disable";
};
};
})
]);
}