nginx: expose generated config and allow nginx reloads (#57429)
* nginx: expose generated config and allow nginx reloads Fixes: https://github.com/NixOS/nixpkgs/issues/15906 Another try was done, but not yet merged in https://github.com/NixOS/nixpkgs/pull/24476 This add 2 new features: ability to review generated Nginx config (and NixOS has sophisticated generation!) and reloading of nginx on config changes. This preserves nginx restart on package updates. I've modified nginx test to use this new feature and check reload/restart behavior. * rename to enableReload * add sleep(1) in ETag test (race condition) and rewrite rebuild-switch using `nesting.clone`
This commit is contained in:
parent
9f237fe444
commit
855be67358
|
@ -162,6 +162,10 @@ let
|
||||||
${cfg.appendConfig}
|
${cfg.appendConfig}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
configPath = if cfg.enableReload
|
||||||
|
then "/etc/nginx/nginx.conf"
|
||||||
|
else configFile;
|
||||||
|
|
||||||
vhosts = concatStringsSep "\n" (mapAttrsToList (vhostName: vhost:
|
vhosts = concatStringsSep "\n" (mapAttrsToList (vhostName: vhost:
|
||||||
let
|
let
|
||||||
onlySSL = vhost.onlySSL || vhost.enableSSL;
|
onlySSL = vhost.onlySSL || vhost.enableSSL;
|
||||||
|
@ -431,6 +435,16 @@ in
|
||||||
";
|
";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enableReload = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Reload nginx when configuration file changes (instead of restart).
|
||||||
|
The configuration file is exposed at <filename>/etc/nginx/nginx.conf</filename>.
|
||||||
|
See also <literal>systemd.services.*.restartIfChanged</literal>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
stateDir = mkOption {
|
stateDir = mkOption {
|
||||||
default = "/var/spool/nginx";
|
default = "/var/spool/nginx";
|
||||||
description = "
|
description = "
|
||||||
|
@ -638,10 +652,10 @@ in
|
||||||
preStart =
|
preStart =
|
||||||
''
|
''
|
||||||
${cfg.preStart}
|
${cfg.preStart}
|
||||||
${cfg.package}/bin/nginx -c ${configFile} -p ${cfg.stateDir} -t
|
${cfg.package}/bin/nginx -c ${configPath} -p ${cfg.stateDir} -t
|
||||||
'';
|
'';
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${cfg.package}/bin/nginx -c ${configFile} -p ${cfg.stateDir}";
|
ExecStart = "${cfg.package}/bin/nginx -c ${configPath} -p ${cfg.stateDir}";
|
||||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
RestartSec = "10s";
|
RestartSec = "10s";
|
||||||
|
@ -649,6 +663,21 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
environment.etc."nginx/nginx.conf" = mkIf cfg.enableReload {
|
||||||
|
source = configFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.nginx-config-reload = mkIf cfg.enableReload {
|
||||||
|
wantedBy = [ "nginx.service" ];
|
||||||
|
restartTriggers = [ configFile ];
|
||||||
|
script = ''
|
||||||
|
if ${pkgs.systemd}/bin/systemctl -q is-active nginx.service ; then
|
||||||
|
${pkgs.systemd}/bin/systemctl reload nginx.service
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
serviceConfig.RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
|
||||||
security.acme.certs = filterAttrs (n: v: v != {}) (
|
security.acme.certs = filterAttrs (n: v: v != {}) (
|
||||||
let
|
let
|
||||||
vhostsConfigs = mapAttrsToList (vhostName: vhostConfig: vhostConfig) virtualHosts;
|
vhostsConfigs = mapAttrsToList (vhostName: vhostConfig: vhostConfig) virtualHosts;
|
||||||
|
|
|
@ -3,15 +3,15 @@
|
||||||
# generated virtual hosts config.
|
# generated virtual hosts config.
|
||||||
# 2. whether the ETag header is properly generated whenever we're serving
|
# 2. whether the ETag header is properly generated whenever we're serving
|
||||||
# files in Nix store paths
|
# files in Nix store paths
|
||||||
|
# 3. nginx doesn't restart on configuration changes (only reloads)
|
||||||
import ./make-test.nix ({ pkgs, ... }: {
|
import ./make-test.nix ({ pkgs, ... }: {
|
||||||
name = "nginx";
|
name = "nginx";
|
||||||
meta = with pkgs.stdenv.lib.maintainers; {
|
meta = with pkgs.stdenv.lib.maintainers; {
|
||||||
maintainers = [ mbbx6spp ];
|
maintainers = [ mbbx6spp ];
|
||||||
};
|
};
|
||||||
|
|
||||||
nodes = let
|
nodes = {
|
||||||
commonConfig = { pkgs, ... }: {
|
webserver = { pkgs, lib, ... }: {
|
||||||
services.nginx.enable = true;
|
services.nginx.enable = true;
|
||||||
services.nginx.commonHttpConfig = ''
|
services.nginx.commonHttpConfig = ''
|
||||||
log_format ceeformat '@cee: {"status":"$status",'
|
log_format ceeformat '@cee: {"status":"$status",'
|
||||||
|
@ -32,30 +32,42 @@ import ./make-test.nix ({ pkgs, ... }: {
|
||||||
location /favicon.ico { allow all; access_log off; log_not_found off; }
|
location /favicon.ico { allow all; access_log off; log_not_found off; }
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
services.nginx.virtualHosts.localhost = {
|
services.nginx.virtualHosts.localhost = {
|
||||||
root = pkgs.runCommand "testdir" {} ''
|
root = pkgs.runCommand "testdir" {} ''
|
||||||
mkdir "$out"
|
mkdir "$out"
|
||||||
echo hello world > "$out/index.html"
|
echo hello world > "$out/index.html"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
|
||||||
in {
|
|
||||||
webserver = commonConfig;
|
|
||||||
|
|
||||||
newwebserver = { pkgs, lib, ... }: {
|
services.nginx.enableReload = true;
|
||||||
imports = [ commonConfig ];
|
|
||||||
services.nginx.virtualHosts.localhost = {
|
nesting.clone = [
|
||||||
root = lib.mkForce (pkgs.runCommand "testdir2" {} ''
|
{
|
||||||
mkdir "$out"
|
services.nginx.virtualHosts.localhost = {
|
||||||
echo hello world > "$out/index.html"
|
root = lib.mkForce (pkgs.runCommand "testdir2" {} ''
|
||||||
'');
|
mkdir "$out"
|
||||||
};
|
echo content changed > "$out/index.html"
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
services.nginx.virtualHosts."1.my.test".listen = [ { addr = "127.0.0.1"; port = 8080; }];
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
services.nginx.package = pkgs.nginxUnstable;
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = { nodes, ... }: let
|
testScript = { nodes, ... }: let
|
||||||
newServerSystem = nodes.newwebserver.config.system.build.toplevel;
|
etagSystem = "${nodes.webserver.config.system.build.toplevel}/fine-tune/child-1";
|
||||||
switch = "${newServerSystem}/bin/switch-to-configuration test";
|
justReloadSystem = "${nodes.webserver.config.system.build.toplevel}/fine-tune/child-2";
|
||||||
|
reloadRestartSystem = "${nodes.webserver.config.system.build.toplevel}/fine-tune/child-3";
|
||||||
in ''
|
in ''
|
||||||
my $url = 'http://localhost/index.html';
|
my $url = 'http://localhost/index.html';
|
||||||
|
|
||||||
|
@ -77,9 +89,23 @@ import ./make-test.nix ({ pkgs, ... }: {
|
||||||
|
|
||||||
subtest "check ETag if serving Nix store paths", sub {
|
subtest "check ETag if serving Nix store paths", sub {
|
||||||
my $oldEtag = checkEtag;
|
my $oldEtag = checkEtag;
|
||||||
$webserver->succeed('${switch}');
|
$webserver->succeed("${etagSystem}/bin/switch-to-configuration test >&2");
|
||||||
|
$webserver->sleep(1); # race condition
|
||||||
my $newEtag = checkEtag;
|
my $newEtag = checkEtag;
|
||||||
die "Old ETag $oldEtag is the same as $newEtag" if $oldEtag eq $newEtag;
|
die "Old ETag $oldEtag is the same as $newEtag" if $oldEtag eq $newEtag;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
subtest "config is reloaded on nixos-rebuild switch", sub {
|
||||||
|
$webserver->succeed("${justReloadSystem}/bin/switch-to-configuration test >&2");
|
||||||
|
$webserver->waitForOpenPort("8080");
|
||||||
|
$webserver->fail("journalctl -u nginx | grep -q -i stopped");
|
||||||
|
$webserver->succeed("journalctl -u nginx | grep -q -i reloaded");
|
||||||
|
};
|
||||||
|
|
||||||
|
subtest "restart when nginx package changes", sub {
|
||||||
|
$webserver->succeed("${reloadRestartSystem}/bin/switch-to-configuration test >&2");
|
||||||
|
$webserver->waitForUnit("nginx");
|
||||||
|
$webserver->succeed("journalctl -u nginx | grep -q -i stopped");
|
||||||
|
};
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue