nixos/rss-bridge: fix pool, add package, add webserver + test (#379189)

This commit is contained in:
Felix Bühler
2025-02-13 19:40:23 +01:00
committed by GitHub
8 changed files with 154 additions and 63 deletions

View File

@@ -465,6 +465,8 @@
- `networking.wireguard` now has an optional networkd backend. It is enabled by default when `networking.useNetworkd` is enabled, and it can be enabled alongside scripted networking with `networking.wireguard.useNetworkd`. Some `networking.wireguard` options have slightly different behavior with the networkd and script-based backends, documented in each option.
- `services.rss-bridge` now has a `package` option as well as support for `caddy` as reverse proxy.
- `services.avahi.ipv6` now defaults to true.
- The Home Assistant module has new options {option}`services.home-assistant.blueprints.automation`, `services.home-assistant.blueprints.script`, and {option}`services.home-assistant.blueprints.template` that allow for the declarative installation of [blueprints](https://www.home-assistant.io/docs/blueprint/) into the appropriate configuration directories.

View File

@@ -4,33 +4,53 @@
pkgs,
...
}:
with lib;
let
inherit (lib)
literalExpression
mkDefault
mkEnableOption
mkIf
mkOption
mkPackageOption
mkRenamedOptionModule
types
;
cfg = config.services.rss-bridge;
poolName = "rss-bridge";
cfgHalf = lib.mapAttrsRecursive (
path: value:
let
envName = lib.toUpper ("RSSBRIDGE_" + lib.concatStringsSep "_" path);
envValue =
if lib.isList value then
lib.concatStringsSep "," value
else if lib.isBool value then
lib.boolToString value
else
toString value;
in
if (value != null) then "fastcgi_param \"${envName}\" \"${envValue}\";" else null
) cfg.config;
cfgEnv = lib.concatStringsSep "\n" (lib.collect lib.isString cfgHalf);
cfgEnv = lib.pipe cfg.config [
(lib.mapAttrsRecursive (
path: value:
lib.optionalAttrs (value != null) {
name = lib.toUpper "RSSBRIDGE_${lib.concatStringsSep "_" path}";
value =
if lib.isList value then
lib.concatStringsSep "," value
else if lib.isBool value then
lib.boolToString value
else
toString value;
}
))
(lib.collect (x: lib.isString x.name or false && lib.isString x.value or false))
lib.listToAttrs
];
in
{
imports = [
(mkRenamedOptionModule
[ "services" "rss-bridge" "whitelist" ]
[ "services" "rss-bridge" "config" "system" "enabled_bridges" ]
[
"services"
"rss-bridge"
"whitelist"
]
[
"services"
"rss-bridge"
"config"
"system"
"enabled_bridges"
]
)
];
@@ -40,27 +60,30 @@ in
user = mkOption {
type = types.str;
default = "nginx";
default = if cfg.webserver == null then "rss-bridge" else cfg.webserver;
defaultText = "{option}`config.services.rss-bridge.webserver` or \"rss-bridge\"";
description = ''
User account under which both the service and the web-application run.
The user account under which both the service and the web application run.
'';
};
group = mkOption {
type = types.str;
default = "nginx";
default = if cfg.webserver == null then "rss-bridge" else cfg.webserver;
defaultText = "{option}`config.services.rss-bridge.webserver` or \"rss-bridge\"";
description = ''
Group under which the web-application run.
The group under which the web application runs.
'';
};
package = mkPackageOption pkgs "rss-bridge" { };
pool = mkOption {
type = types.str;
default = poolName;
type = types.nullOr types.str;
default = "rss-bridge";
description = ''
Name of existing phpfpm pool that is used to run web-application.
If not specified a pool will be created automatically with
default values.
Name of phpfpm pool that is used to run web-application.
If `null` specified none will be created, otherwise automatically created with default values.
'';
};
@@ -77,7 +100,20 @@ in
type = types.nullOr types.str;
default = "rss-bridge";
description = ''
Name of the nginx virtualhost to use and setup. If null, do not setup any virtualhost.
Name of the nginx or caddy virtualhost to use and setup. If null, do not setup any virtualhost.
'';
};
webserver = mkOption {
type = types.nullOr (
types.enum [
"nginx"
"caddy"
]
);
default = "nginx";
description = ''
Type of virtualhost to use and setup. If null, do not setup any virtualhost.
'';
};
@@ -97,12 +133,12 @@ in
type = types.str;
description = "Directory where to store cache files (if cache.type = \"file\").";
default = "${cfg.dataDir}/cache/";
defaultText = options.literalExpression "\${config.services.rss-bridge.dataDir}/cache/";
defaultText = literalExpression "\${config.services.rss-bridge.dataDir}/cache/";
};
};
};
};
example = options.literalExpression ''
example = literalExpression ''
{
system.enabled_bridges = [ "*" ];
error = {
@@ -124,12 +160,12 @@ in
};
config = mkIf cfg.enable {
services.phpfpm.pools = mkIf (cfg.pool == poolName) {
${poolName} = {
services.phpfpm.pools = mkIf (cfg.pool != null) {
${cfg.pool} = {
user = cfg.user;
settings = mapAttrs (name: mkDefault) {
settings = lib.mapAttrs (name: mkDefault) {
"listen.owner" = cfg.user;
"listen.group" = cfg.user;
"listen.group" = cfg.group;
"listen.mode" = "0600";
"pm" = "dynamic";
"pm.max_children" = 75;
@@ -150,11 +186,11 @@ in
};
};
services.nginx = mkIf (cfg.virtualHost != null) {
services.nginx = mkIf (cfg.virtualHost != null && cfg.webserver == "nginx") {
enable = true;
virtualHosts = {
${cfg.virtualHost} = {
root = "${pkgs.rss-bridge}";
root = "${cfg.package}";
locations."/" = {
tryFiles = "$uri /index.php$is_args$args";
@@ -166,11 +202,26 @@ in
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:${config.services.phpfpm.pools.${cfg.pool}.socket};
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
${cfgEnv}
${lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: "fastcgi_param \"${n}\" \"${v}\";") cfgEnv)}
'';
};
};
};
};
services.caddy = mkIf (cfg.virtualHost != null && cfg.webserver == "caddy") {
enable = true;
virtualHosts.${cfg.virtualHost} = {
extraConfig = ''
root * ${cfg.package}
file_server
php_fastcgi unix/${config.services.phpfpm.pools.${cfg.pool}.socket} {
${lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: " env ${n} \"${v}\"") cfgEnv)}
}
'';
};
};
};
meta.maintainers = with lib.maintainers; [ quantenzitrone ];
}

View File

@@ -922,7 +922,7 @@ in {
rshim = handleTest ./rshim.nix {};
rspamd = handleTest ./rspamd.nix {};
rspamd-trainer = handleTest ./rspamd-trainer.nix {};
rss-bridge = handleTest ./web-apps/rss-bridge.nix {};
rss-bridge = handleTest ./web-apps/rss-bridge {};
rss2email = handleTest ./rss2email.nix {};
rstudio-server = handleTest ./rstudio-server.nix {};
rsyncd = handleTest ./rsyncd.nix {};

View File

@@ -1,22 +0,0 @@
{ pkgs, ... }:
{
name = "rss-bridge";
meta.maintainers = with pkgs.lib.maintainers; [ mynacol ];
nodes.machine =
{ ... }:
{
services.rss-bridge = {
enable = true;
};
};
testScript = ''
start_all()
machine.wait_for_unit("nginx.service")
machine.wait_for_unit("phpfpm-rss-bridge.service")
# check for successful feed download
machine.succeed("curl -sS -f 'http://localhost/?action=display&bridge=DemoBridge&context=testCheckbox&format=Atom'")
'';
}

View File

@@ -0,0 +1,28 @@
import ../../make-test-python.nix (
{ lib, pkgs, ... }:
{
name = "rss-bridge-caddy";
meta.maintainers = with lib.maintainers; [ mynacol ];
nodes.machine =
{ ... }:
{
services.rss-bridge = {
enable = true;
webserver = "caddy";
virtualHost = "localhost:80";
config.system.enabled_bridges = [ "DemoBridge" ];
};
};
testScript = ''
machine.wait_for_unit("caddy.service")
machine.wait_for_unit("phpfpm-rss-bridge.service")
machine.wait_for_open_port(80)
# check for successful feed download
response = machine.succeed("curl -f 'http://localhost:80/?action=display&bridge=DemoBridge&context=testCheckbox&format=Atom'")
assert '<title type="html">Test</title>' in response, "Feed didn't load successfully"
'';
}
)

View File

@@ -0,0 +1,5 @@
{ system, pkgs, ... }:
{
nginx = import ./nginx.nix { inherit system pkgs; };
caddy = import ./caddy.nix { inherit system pkgs; };
}

View File

@@ -0,0 +1,27 @@
import ../../make-test-python.nix (
{ lib, pkgs, ... }:
{
name = "rss-bridge-nginx";
meta.maintainers = with lib.maintainers; [ mynacol ];
nodes.machine =
{ ... }:
{
services.rss-bridge = {
enable = true;
webserver = "nginx";
config.system.enabled_bridges = [ "DemoBridge" ];
};
};
testScript = ''
machine.wait_for_unit("nginx.service")
machine.wait_for_unit("phpfpm-rss-bridge.service")
machine.wait_for_open_port(80)
# check for successful feed download
response = machine.succeed("curl -f 'http://localhost:80/?action=display&bridge=DemoBridge&context=testCheckbox&format=Atom'")
assert '<title type="html">Test</title>' in response, "Feed didn't load successfully"
'';
}
)

View File

@@ -24,7 +24,7 @@ stdenv.mkDerivation rec {
passthru = {
tests = {
basic-functionality = nixosTests.rss-bridge;
inherit (nixosTests.rss-bridge) caddy nginx;
};
updateScript = nix-update-script { };
};