diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md index c58985132be0..d77f63d8b124 100644 --- a/nixos/doc/manual/release-notes/rl-2311.section.md +++ b/nixos/doc/manual/release-notes/rl-2311.section.md @@ -78,6 +78,8 @@ - `services.prometheus.exporters` has a new exporter to monitor electrical power consumption based on PowercapRAPL sensor called [Scaphandre](https://github.com/hubblo-org/scaphandre), see [#239803](https://github.com/NixOS/nixpkgs/pull/239803) for more details. +- The module `services.calibre-server` has new options to configure the `host`, `port`, `auth.enable`, `auth.mode` and `auth.userDb` path, see [#216497](https://github.com/NixOS/nixpkgs/pull/216497/) for more details. + ## Nixpkgs internals {#sec-release-23.11-nixpkgs-internals} - The `qemu-vm.nix` module by default now identifies block devices via diff --git a/nixos/modules/services/misc/calibre-server.nix b/nixos/modules/services/misc/calibre-server.nix index 77c60381a312..e1ddae1de1f8 100644 --- a/nixos/modules/services/misc/calibre-server.nix +++ b/nixos/modules/services/misc/calibre-server.nix @@ -6,6 +6,17 @@ let cfg = config.services.calibre-server; + documentationLink = "https://manual.calibre-ebook.com"; + generatedDocumentationLink = documentationLink + "/generated/en/calibre-server.html"; + + execFlags = (concatStringsSep " " + (mapAttrsToList (k: v: "${k} ${toString v}") (filterAttrs (name: value: value != null) { + "--listen-on" = cfg.host; + "--port" = cfg.port; + "--auth-mode" = cfg.auth.mode; + "--userdb" = cfg.auth.userDb; + }) ++ [(optionalString (cfg.auth.enable == true) "--enable-auth")]) + ); in { @@ -18,52 +29,100 @@ in ) ]; - ###### interface - options = { services.calibre-server = { enable = mkEnableOption (lib.mdDoc "calibre-server"); + package = lib.mkPackageOptionMD pkgs "calibre" { }; libraries = mkOption { - description = lib.mdDoc '' - The directories of the libraries to serve. They must be readable for the user under which the server runs. - ''; type = types.listOf types.path; + default = [ "/var/lib/calibre-server" ]; + description = lib.mdDoc '' + Make sure each library path is initialized before service startup. + The directories of the libraries to serve. They must be readable for the user under which the server runs. + See the [calibredb documentation](${documentationLink}/generated/en/calibredb.html#add) for details. + ''; }; user = mkOption { - description = lib.mdDoc "The user under which calibre-server runs."; type = types.str; default = "calibre-server"; + description = lib.mdDoc "The user under which calibre-server runs."; }; group = mkOption { - description = lib.mdDoc "The group under which calibre-server runs."; type = types.str; default = "calibre-server"; + description = lib.mdDoc "The group under which calibre-server runs."; }; + host = mkOption { + type = types.str; + default = "0.0.0.0"; + example = "::1"; + description = lib.mdDoc '' + The interface on which to listen for connections. + See the [calibre-server documentation](${generatedDocumentationLink}#cmdoption-calibre-server-listen-on) for details. + ''; + }; + + port = mkOption { + default = 8080; + type = types.port; + description = lib.mdDoc '' + The port on which to listen for connections. + See the [calibre-server documentation](${generatedDocumentationLink}#cmdoption-calibre-server-port) for details. + ''; + }; + + auth = { + enable = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Password based authentication to access the server. + See the [calibre-server documentation](${generatedDocumentationLink}#cmdoption-calibre-server-enable-auth) for details. + ''; + }; + + mode = mkOption { + type = types.enum [ "auto" "basic" "digest" ]; + default = "auto"; + description = lib.mdDoc '' + Choose the type of authentication used. + Set the HTTP authentication mode used by the server. + See the [calibre-server documentation](${generatedDocumentationLink}#cmdoption-calibre-server-auth-mode) for details. + ''; + }; + + userDb = mkOption { + default = null; + type = types.nullOr types.path; + description = lib.mdDoc '' + Choose users database file to use for authentication. + Make sure users database file is initialized before service startup. + See the [calibre-server documentation](${documentationLink}/server.html#managing-user-accounts-from-the-command-line-only) for details. + ''; + }; + }; }; }; - - ###### implementation - config = mkIf cfg.enable { systemd.services.calibre-server = { - description = "Calibre Server"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = cfg.user; - Restart = "always"; - ExecStart = "${pkgs.calibre}/bin/calibre-server ${lib.concatStringsSep " " cfg.libraries}"; - }; - + description = "Calibre Server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = cfg.user; + Restart = "always"; + ExecStart = "${cfg.package}/bin/calibre-server ${lib.concatStringsSep " " cfg.libraries} ${execFlags}"; }; + }; + environment.systemPackages = [ pkgs.calibre ]; users.users = optionalAttrs (cfg.user == "calibre-server") { @@ -83,4 +142,5 @@ in }; + meta.maintainers = with lib.maintainers; [ gaelreyrol ]; } diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 371546fe60e6..1b90b3e13807 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -151,6 +151,7 @@ in { cage = handleTest ./cage.nix {}; cagebreak = handleTest ./cagebreak.nix {}; calibre-web = handleTest ./calibre-web.nix {}; + calibre-server = handleTest ./calibre-server.nix {}; cassandra_3_0 = handleTest ./cassandra.nix { testPackage = pkgs.cassandra_3_0; }; cassandra_3_11 = handleTest ./cassandra.nix { testPackage = pkgs.cassandra_3_11; }; cassandra_4 = handleTest ./cassandra.nix { testPackage = pkgs.cassandra_4; }; diff --git a/nixos/tests/calibre-server.nix b/nixos/tests/calibre-server.nix new file mode 100644 index 000000000000..4b1753aaa704 --- /dev/null +++ b/nixos/tests/calibre-server.nix @@ -0,0 +1,104 @@ +{ system ? builtins.currentSystem +, config ? { } +, pkgs ? import ../.. { inherit system config; } +}: + +let + inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest; + inherit (pkgs.lib) concatStringsSep maintainers mapAttrs mkMerge + removeSuffix splitString; + + tests = { + default = { + calibreConfig = {}; + calibreScript = '' + wait_for_unit("calibre-server.service") + ''; + }; + customLibrary = { + calibreConfig = { + libraries = [ "/var/lib/calibre-data" ]; + }; + calibreScript = '' + succeed("ls -la /var/lib/calibre-data") + wait_for_unit("calibre-server.service") + ''; + }; + multipleLibraries = { + calibreConfig = { + libraries = [ "/var/lib/calibre-data" "/var/lib/calibre-server" ]; + }; + calibreScript = '' + succeed("ls -la /var/lib/calibre-data") + succeed("ls -la /var/lib/calibre-server") + wait_for_unit("calibre-server.service") + ''; + }; + hostAndPort = { + calibreConfig = { + host = "127.0.0.1"; + port = 8888; + }; + calibreScript = '' + wait_for_unit("calibre-server.service") + wait_for_open_port(8888) + succeed("curl --fail http://127.0.0.1:8888") + ''; + }; + basicAuth = { + calibreConfig = { + host = "127.0.0.1"; + port = 8888; + auth = { + enable = true; + mode = "basic"; + }; + }; + calibreScript = '' + wait_for_unit("calibre-server.service") + wait_for_open_port(8888) + fail("curl --fail http://127.0.0.1:8888") + ''; + }; + }; +in +mapAttrs + (test: testConfig: (makeTest ( + let + nodeName = testConfig.nodeName or test; + calibreConfig = { + enable = true; + libraries = [ "/var/lib/calibre-server" ]; + } // testConfig.calibreConfig or {}; + librariesInitScript = path: '' + ${nodeName}.execute("touch /tmp/test.epub") + ${nodeName}.execute("zip -r /tmp/test.zip /tmp/test.epub") + ${nodeName}.execute("mkdir -p ${path}") + ${nodeName}.execute("calibredb add -d --with-library ${path} /tmp/test.zip") + ''; + in + { + name = "calibre-server-${test}"; + + nodes.${nodeName} = mkMerge [{ + environment.systemPackages = [ pkgs.zip ]; + services.calibre-server = calibreConfig; + } testConfig.calibreProvider or { }]; + + testScript = '' + ${nodeName}.start() + ${concatStringsSep "\n" (map librariesInitScript calibreConfig.libraries)} + ${concatStringsSep "\n" (map (line: + if (builtins.substring 0 1 line == " " || builtins.substring 0 1 line == ")") + then line + else "${nodeName}.${line}" + ) (splitString "\n" (removeSuffix "\n" testConfig.calibreScript)))} + ${nodeName}.shutdown() + ''; + + meta = with maintainers; { + maintainers = [ gaelreyrol ]; + }; + } + ))) + tests