diff --git a/nixos/modules/services/web-apps/windmill.nix b/nixos/modules/services/web-apps/windmill.nix index 80d246a9c6b2..e4aa0bf0ec77 100644 --- a/nixos/modules/services/web-apps/windmill.nix +++ b/nixos/modules/services/web-apps/windmill.nix @@ -91,6 +91,16 @@ in config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.database.createLocally -> cfg.database.name == cfg.database.user; + message = '' + Automatically provisioning the windmill database requires both database name and database user to be equal. '${cfg.database.name}' != '${cfg.database.user}' + To fix this problem, assign the same value to both options services.windmill.database.{name,user}. + ''; + } + ]; + services.postgresql = lib.optionalAttrs (cfg.database.createLocally) { enable = lib.mkDefault true; @@ -101,7 +111,18 @@ in ensureDBOwnership = true; } ]; + }; + systemd.targets.windmill = { + description = "Windmill"; + wantedBy = [ "multi-user.target" ]; + requires = + [ ] + ++ (lib.optionals config.systemd.services.windmill-server.enable [ "windmill-server.service" ]) + ++ (lib.optionals config.systemd.services.windmill-worker.enable [ "windmill-worker.service" ]) + ++ (lib.optionals config.systemd.services.windmill-worker-native.enable [ + "windmill-worker-native.service" + ]); }; systemd.services = @@ -112,7 +133,6 @@ in # using the same user to simplify db connection User = cfg.database.user; ExecStart = "${pkgs.windmill}/bin/windmill"; - Restart = "always"; } // lib.optionalAttrs useUrlPath { @@ -129,42 +149,72 @@ in }; in { + windmill-initdb = lib.mkIf cfg.database.createLocally { + description = "Windmill database setup"; + requires = [ "postgresql.target" ]; + after = [ "postgresql.target" ]; + requiredBy = + [ ] + ++ (lib.optionals config.systemd.services.windmill-server.enable [ "windmill-server.service" ]) + ++ (lib.optionals config.systemd.services.windmill-worker.enable [ "windmill-worker.service" ]) + ++ (lib.optionals config.systemd.services.windmill-worker-native.enable [ + "windmill-worker-native.service" + ]); + before = + [ ] + ++ (lib.optionals config.systemd.services.windmill-server.enable [ "windmill-server.service" ]) + ++ (lib.optionals config.systemd.services.windmill-worker.enable [ "windmill-worker.service" ]) + ++ (lib.optionals config.systemd.services.windmill-worker-native.enable [ + "windmill-worker-native.service" + ]); - # coming from https://github.com/windmill-labs/windmill/blob/main/init-db-as-superuser.sql - # modified to not grant privileges on all tables - # create role windmill_user and windmill_admin only if they don't exist - postgresql.postStart = lib.mkIf cfg.database.createLocally '' - 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 - ''; + path = [ config.services.postgresql.package ]; + # coming from https://github.com/windmill-labs/windmill/blob/main/init-db-as-superuser.sql + # modified to not grant privileges on all tables + # create role windmill_user and windmill_admin only if they don't exist + script = '' + 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 ${cfg.database.user}; + END + $$; + EOF + ''; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + # Superuser because of required permission CREATE ROLE + User = "postgres"; + + ProtectSystem = "strict"; + ProtectHome = "read-only"; + }; + }; windmill-server = { description = "Windmill server"; - after = [ "network.target" ] ++ lib.optional cfg.database.createLocally "postgresql.target"; - wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + partOf = [ "windmill.target" ]; serviceConfig = serviceConfig // { StateDirectory = "windmill"; @@ -181,8 +231,8 @@ in windmill-worker = { description = "Windmill worker"; - after = [ "network.target" ] ++ lib.optional cfg.database.createLocally "postgresql.target"; - wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + partOf = [ "windmill.target" ]; serviceConfig = serviceConfig // { StateDirectory = "windmill-worker"; @@ -200,8 +250,8 @@ in windmill-worker-native = { description = "Windmill worker native"; - after = [ "network.target" ] ++ lib.optional cfg.database.createLocally "postgresql.target"; - wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + partOf = [ "windmill.target" ]; serviceConfig = serviceConfig // { StateDirectory = "windmill-worker-native";