2023-12-05 02:42:28 +00:00
|
|
|
{ config, pkgs, lib, ... }:
|
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.services.windmill;
|
|
|
|
in
|
|
|
|
{
|
|
|
|
options.services.windmill = {
|
2024-04-13 12:54:15 +00:00
|
|
|
enable = lib.mkEnableOption "windmill service";
|
2023-12-05 02:42:28 +00:00
|
|
|
|
|
|
|
serverPort = lib.mkOption {
|
|
|
|
type = lib.types.port;
|
|
|
|
default = 8001;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Port the windmill server listens on.";
|
2023-12-05 02:42:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
lspPort = lib.mkOption {
|
|
|
|
type = lib.types.port;
|
|
|
|
default = 3001;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Port the windmill lsp listens on.";
|
2023-12-05 02:42:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
database = {
|
|
|
|
name = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
|
|
|
# the simplest database setup is to have the database named like the user.
|
|
|
|
default = "windmill";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Database name.";
|
2023-12-05 02:42:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
user = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
|
|
|
# the simplest database setup is to have the database user like the name.
|
|
|
|
default = "windmill";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Database user.";
|
2023-12-05 02:42:28 +00:00
|
|
|
};
|
|
|
|
|
2024-09-13 21:36:55 +00:00
|
|
|
url = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
|
|
|
default = "postgres://${config.services.windmill.database.name}?host=/var/run/postgresql";
|
|
|
|
defaultText = lib.literalExpression ''
|
|
|
|
"postgres://\$\{config.services.windmill.database.name}?host=/var/run/postgresql";
|
|
|
|
'';
|
|
|
|
description = "Database url. Note that any secret here would be world-readable. Use `services.windmill.database.urlPath` unstead to include secrets in the url.";
|
|
|
|
};
|
|
|
|
|
2023-12-05 02:42:28 +00:00
|
|
|
urlPath = lib.mkOption {
|
2024-09-13 21:36:55 +00:00
|
|
|
type = lib.types.nullOr lib.types.path;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = ''
|
2023-12-05 02:42:28 +00:00
|
|
|
Path to the file containing the database url windmill should connect to. This is not deducted from database user and name as it might contain a secret
|
|
|
|
'';
|
2024-09-13 21:36:55 +00:00
|
|
|
default = null;
|
2023-12-05 02:42:28 +00:00
|
|
|
example = "config.age.secrets.DATABASE_URL_FILE.path";
|
|
|
|
};
|
2024-09-13 21:36:55 +00:00
|
|
|
|
2023-12-05 02:42:28 +00:00
|
|
|
createLocally = lib.mkOption {
|
|
|
|
type = lib.types.bool;
|
|
|
|
default = true;
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Whether to create a local database automatically.";
|
2023-12-05 02:42:28 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
baseUrl = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
2024-09-13 21:36:55 +00:00
|
|
|
default = "https://localhost:${toString config.services.windmill.serverPort}";
|
|
|
|
defaultText = lib.literalExpression ''
|
|
|
|
"https://localhost:\$\{toString config.services.windmill.serverPort}";
|
|
|
|
'';
|
2024-04-13 12:54:15 +00:00
|
|
|
description = ''
|
2023-12-05 02:42:28 +00:00
|
|
|
The base url that windmill will be served on.
|
|
|
|
'';
|
|
|
|
example = "https://windmill.example.com";
|
|
|
|
};
|
|
|
|
|
|
|
|
logLevel = lib.mkOption {
|
|
|
|
type = lib.types.enum [ "error" "warn" "info" "debug" "trace" ];
|
|
|
|
default = "info";
|
2024-04-13 12:54:15 +00:00
|
|
|
description = "Log level";
|
2023-12-05 02:42:28 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
|
|
|
|
|
|
services.postgresql = lib.optionalAttrs (cfg.database.createLocally) {
|
|
|
|
enable = lib.mkDefault true;
|
|
|
|
|
|
|
|
ensureDatabases = [ cfg.database.name ];
|
|
|
|
ensureUsers = [
|
|
|
|
{ name = cfg.database.user;
|
|
|
|
ensureDBOwnership = true;
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd.services =
|
|
|
|
let
|
2024-09-13 21:36:55 +00:00
|
|
|
useUrlPath = (cfg.database.urlPath != null);
|
2023-12-05 02:42:28 +00:00
|
|
|
serviceConfig = {
|
|
|
|
DynamicUser = true;
|
|
|
|
# using the same user to simplify db connection
|
|
|
|
User = cfg.database.user;
|
|
|
|
ExecStart = "${pkgs.windmill}/bin/windmill";
|
|
|
|
|
|
|
|
Restart = "always";
|
2024-09-13 21:36:55 +00:00
|
|
|
} // lib.optionalAttrs useUrlPath {
|
2023-12-05 02:42:28 +00:00
|
|
|
LoadCredential = [
|
|
|
|
"DATABASE_URL_FILE:${cfg.database.urlPath}"
|
|
|
|
];
|
|
|
|
};
|
2024-09-13 21:36:55 +00:00
|
|
|
db_url_envs = lib.optionalAttrs useUrlPath {
|
|
|
|
DATABASE_URL_FILE = "%d/DATABASE_URL_FILE";
|
|
|
|
} // lib.optionalAttrs (!useUrlPath) {
|
|
|
|
DATABASE_URL = cfg.database.url;
|
|
|
|
};
|
2023-12-05 02:42:28 +00:00
|
|
|
in
|
|
|
|
{
|
|
|
|
|
|
|
|
# coming from https://github.com/windmill-labs/windmill/blob/main/init-db-as-superuser.sql
|
|
|
|
# modified to not grant priviledges on all tables
|
|
|
|
# create role windmill_user and windmill_admin only if they don't exist
|
|
|
|
postgresql.postStart = lib.mkIf cfg.database.createLocally (lib.mkAfter ''
|
|
|
|
$PSQL -tA <<"EOF"
|
|
|
|
DO $$
|
|
|
|
BEGIN
|
|
|
|
IF NOT EXISTS (
|
|
|
|
SELECT FROM pg_catalog.pg_roles
|
|
|
|
WHERE rolname = 'windmill_user'
|
|
|
|
) THEN
|
|
|
|
CREATE ROLE windmill_user;
|
|
|
|
GRANT ALL PRIVILEGES ON DATABASE ${cfg.database.name} TO windmill_user;
|
|
|
|
ELSE
|
|
|
|
RAISE NOTICE 'Role "windmill_user" already exists. Skipping.';
|
|
|
|
END IF;
|
|
|
|
IF NOT EXISTS (
|
|
|
|
SELECT FROM pg_catalog.pg_roles
|
|
|
|
WHERE rolname = 'windmill_admin'
|
|
|
|
) THEN
|
|
|
|
CREATE ROLE windmill_admin WITH BYPASSRLS;
|
|
|
|
GRANT windmill_user TO windmill_admin;
|
|
|
|
ELSE
|
|
|
|
RAISE NOTICE 'Role "windmill_admin" already exists. Skipping.';
|
|
|
|
END IF;
|
|
|
|
GRANT windmill_admin TO windmill;
|
|
|
|
END
|
|
|
|
$$;
|
|
|
|
EOF
|
|
|
|
'');
|
|
|
|
|
|
|
|
windmill-server = {
|
|
|
|
description = "Windmill server";
|
|
|
|
after = [ "network.target" ] ++ lib.optional cfg.database.createLocally "postgresql.service";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
|
|
|
|
serviceConfig = serviceConfig // { StateDirectory = "windmill";};
|
|
|
|
|
|
|
|
environment = {
|
|
|
|
PORT = builtins.toString cfg.serverPort;
|
|
|
|
WM_BASE_URL = cfg.baseUrl;
|
|
|
|
RUST_LOG = cfg.logLevel;
|
|
|
|
MODE = "server";
|
2024-09-13 21:36:55 +00:00
|
|
|
} // db_url_envs;
|
2023-12-05 02:42:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
windmill-worker = {
|
|
|
|
description = "Windmill worker";
|
|
|
|
after = [ "network.target" ] ++ lib.optional cfg.database.createLocally "postgresql.service";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
|
|
|
|
serviceConfig = serviceConfig // { StateDirectory = "windmill-worker";};
|
|
|
|
|
|
|
|
environment = {
|
|
|
|
WM_BASE_URL = cfg.baseUrl;
|
|
|
|
RUST_LOG = cfg.logLevel;
|
|
|
|
MODE = "worker";
|
|
|
|
WORKER_GROUP = "default";
|
|
|
|
KEEP_JOB_DIR = "false";
|
2024-09-13 21:36:55 +00:00
|
|
|
} // db_url_envs;
|
2023-12-05 02:42:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
windmill-worker-native = {
|
|
|
|
description = "Windmill worker native";
|
|
|
|
after = [ "network.target" ] ++ lib.optional cfg.database.createLocally "postgresql.service";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
|
|
|
|
serviceConfig = serviceConfig // { StateDirectory = "windmill-worker-native";};
|
|
|
|
|
|
|
|
environment = {
|
|
|
|
WM_BASE_URL = cfg.baseUrl;
|
|
|
|
RUST_LOG = cfg.logLevel;
|
|
|
|
MODE = "worker";
|
|
|
|
WORKER_GROUP = "native";
|
2024-09-13 21:36:55 +00:00
|
|
|
} // db_url_envs;
|
2023-12-05 02:42:28 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|