diff --git a/infra/machines/fedi201/fedipanel.nix b/infra/machines/fedi201/fedipanel.nix index 5312eafb..4f90c473 100644 --- a/infra/machines/fedi201/fedipanel.nix +++ b/infra/machines/fedi201/fedipanel.nix @@ -4,15 +4,10 @@ }: let name = "panel"; - panel = (import ../../../panel/default.nix { }).package; in { imports = [ - ../../../panel/nix/configuration.nix - ]; - - environment.systemPackages = [ - panel + (import ../../../panel { }).module ]; security.acme = { @@ -22,18 +17,11 @@ in services.${name} = { enable = true; - package = panel; production = true; domain = "demo.fediversity.eu"; - host = "0.0.0.0"; secrets = { SECRET_KEY = config.age.secrets.panel-secret-key.path; }; port = 8000; - settings = { - DATABASE_URL = "sqlite:///var/lib/${name}/db.sqlite3"; - CREDENTIALS_DIRECTORY = "/var/lib/${name}/.credentials"; - STATIC_ROOT = "/var/lib/${name}/static"; - }; }; } diff --git a/panel/default.nix b/panel/default.nix index b0ec435e..c5bc5fe4 100644 --- a/panel/default.nix +++ b/panel/default.nix @@ -8,17 +8,13 @@ }, }: let - package = pkgs.callPackage ./nix/package.nix { }; - - pkgs' = pkgs.extend (_final: _prev: { panel = package; }); - manage = pkgs.writeScriptBin "manage" '' exec ${pkgs.lib.getExe pkgs.python3} ${toString ./src/manage.py} $@ ''; in { shell = pkgs.mkShellNoCC { - inputsFrom = [ package ]; + inputsFrom = [ (pkgs.callPackage ./nix/package.nix { }) ]; packages = [ pkgs.npins manage @@ -36,8 +32,8 @@ in ''; }; - tests = pkgs'.callPackage ./nix/tests.nix { }; - inherit package; + module = import ./nix/configuration.nix; + tests = pkgs.callPackage ./nix/tests.nix { }; # re-export inputs so they can be overridden granularly # (they can't be accessed from the outside any other way) diff --git a/panel/nix/configuration.nix b/panel/nix/configuration.nix index e261fd95..21ac9d7c 100644 --- a/panel/nix/configuration.nix +++ b/panel/nix/configuration.nix @@ -12,7 +12,6 @@ let mkEnableOption mkIf mkOption - mkPackageOption optionalString types ; @@ -22,23 +21,15 @@ let name = "panel"; cfg = config.services.${name}; + package = pkgs.callPackage ./package.nix { }; database-url = "sqlite:////var/lib/${name}/db.sqlite3"; python-environment = pkgs.python3.withPackages ( - ps: - with ps; - [ + ps: with ps; [ + package uvicorn - cfg.package - dj-database-url - django-compressor - django-debug-toolbar - django-libsass - django_4 - setuptools ] - ++ cfg.package.propagatedBuildInputs ); configFile = pkgs.concatText "configuration.py" [ @@ -48,7 +39,7 @@ let manage-service = writeShellApplication { name = "manage"; - text = ''exec ${cfg.package}/bin/manage.py "$@"''; + text = ''exec ${package}/bin/manage.py "$@"''; }; manage-admin = writeShellApplication { @@ -83,8 +74,6 @@ in { options.services.${name} = { enable = mkEnableOption "Service configuration for `${name}`"; - # NOTE: this requires that the package is present in `pkgs` - package = mkPackageOption pkgs name { }; production = mkOption { type = types.bool; default = true; @@ -145,6 +134,8 @@ in }; config = mkIf cfg.enable { + nixpkgs.overlays = [ (import ./overlay.nix) ]; + environment.systemPackages = [ manage-admin ]; services = { @@ -181,16 +172,15 @@ in preStart = '' # Auto-migrate on first run or if the package has changed versionFile="/var/lib/${name}/package-version" - if [[ $(cat "$versionFile" 2>/dev/null) != ${cfg.package} ]]; then + if [[ $(cat "$versionFile" 2>/dev/null) != ${package} ]]; then manage migrate --no-input manage collectstatic --no-input --clear manage compress --force - echo ${cfg.package} > "$versionFile" + echo ${package} > "$versionFile" fi ''; script = '' - export PYTHONPATH=$PYTHONPATH:${cfg.package}/lib/python3.12/site-packages - ${python-environment}/bin/python -m uvicorn ${name}.asgi:application --host ${cfg.host} --port ${toString cfg.port} + uvicorn ${name}.asgi:application --host ${cfg.host} --port ${toString cfg.port} ''; serviceConfig = { Restart = "always"; diff --git a/panel/nix/tests.nix b/panel/nix/tests.nix index a8259384..ea5ebd94 100644 --- a/panel/nix/tests.nix +++ b/panel/nix/tests.nix @@ -3,6 +3,8 @@ let # TODO: specify project/service name globally name = "panel"; defaults = { + # XXX: we have to duplicate this here despite it being defined in the service module, otherwise the test framework will error out + nixpkgs.overlays = lib.mkForce [ (import ./overlay.nix) ]; services.${name} = { enable = true; production = false; @@ -26,6 +28,7 @@ lib.mapAttrs (name: test: pkgs.testers.runNixOSTest (test // { inherit name; })) # run all application-level tests managed by Django # https://docs.djangoproject.com/en/5.0/topics/testing/overview/ testScript = '' + server.wait_for_unit("${name}.service") server.succeed("manage test ${name}") ''; }; @@ -34,7 +37,6 @@ lib.mapAttrs (name: test: pkgs.testers.runNixOSTest (test // { inherit name; })) nodes.server = _: { imports = [ ./configuration.nix ]; }; # check that the admin interface is served testScript = '' - server.wait_for_unit("multi-user.target") server.wait_for_unit("${name}.service") server.wait_for_open_port(8000) server.succeed("curl --fail -L -H 'Host: example.org' http://localhost/admin") @@ -45,11 +47,11 @@ lib.mapAttrs (name: test: pkgs.testers.runNixOSTest (test // { inherit name; })) inherit defaults; nodes.server = _: { imports = [ ./configuration.nix ]; }; extraPythonPackages = ps: with ps; [ beautifulsoup4 ]; + # type checking on `beautifulsoup4` will error out skipTypeCheck = true; # check that stylesheets are pre-processed and served testScript = '' from bs4 import BeautifulSoup - server.wait_for_unit("multi-user.target") server.wait_for_unit("${name}.service") server.wait_for_open_port(8000) stdout = server.succeed("curl --fail -H 'Host: example.org' http://localhost") diff --git a/panel/src/panel/settings.py b/panel/src/panel/settings.py index fc32a36b..4209f80a 100644 --- a/panel/src/panel/settings.py +++ b/panel/src/panel/settings.py @@ -26,6 +26,8 @@ BASE_DIR = Path(__file__).resolve().parent.parent # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ def get_secret(name: str, encoding: str = "utf-8") -> str: + # In the NixOS deployment, this variable is set by `systemd` via `LoadCredential` + # https://systemd.io/CREDENTIALS/ credentials_dir = env.get("CREDENTIALS_DIRECTORY") if credentials_dir is None: