nixos/varnish: turn listen addresses into structured config (#421481)

Changed files
+175 -6
nixos
doc
manual
release-notes
modules
services
web-servers
varnish
tests
+3
nixos/doc/manual/release-notes/rl-2511.section.md
···
- `amdgpu` kernel driver overdrive mode can now be enabled by setting [hardware.amdgpu.overdrive.enable](#opt-hardware.amdgpu.overdrive.enable) and customized through [hardware.amdgpu.overdrive.ppfeaturemask](#opt-hardware.amdgpu.overdrive.ppfeaturemask).
This allows for fine-grained control over the GPU's performance and maybe required by overclocking softwares like Corectrl and Lact. These new options replace old options such as {option}`programs.corectrl.gpuOverclock.enable` and {option}`programs.tuxclocker.enableAMD`.
+
- `services.varnish.http_address` has been superseeded by `services.varnish.listen` which is now
+
structured config for all of varnish's `-a` variations.
+
- [](#opt-services.gnome.gnome-keyring.enable) does not ship with an SSH agent anymore, as this is now handled by the `gcr_4` package instead of `gnome-keyring`. A new module has been added to support this, under [](#opt-services.gnome.gcr-ssh-agent.enable) (its default value has been set to [](#opt-services.gnome.gnome-keyring.enable) to ensure a smooth transition). See the [relevant upstream PR](https://gitlab.gnome.org/GNOME/gcr/-/merge_requests/67) for more details.
- The `nettools` package (ifconfig, arp, mii-tool, netstat, route) is not installed by default anymore. The suite is unmaintained and users should migrate to `iproute2` and `ethtool` instead.
+123 -3
nixos/modules/services/web-servers/varnish/default.nix
···
}:
let
+
inherit (lib)
+
types
+
mkOption
+
hasPrefix
+
concatMapStringsSep
+
optionalString
+
concatMap
+
;
+
inherit (builtins) isNull;
+
cfg = config.services.varnish;
# Varnish has very strong opinions and very complicated code around handling
···
else
"/var/run/varnishd";
+
# from --help:
+
# -a [<name>=]address[:port][,proto] # HTTP listen address and port
+
# [,user=<u>][,group=<g>] # Can be specified multiple times.
+
# [,mode=<m>] # default: ":80,HTTP"
+
# # Proto can be "PROXY" or "HTTP" (default)
+
# # user, group and mode set permissions for
+
# # a Unix domain socket.
+
commandLineAddresses =
+
(concatMapStringsSep " " (
+
a:
+
"-a "
+
+ optionalString (!isNull a.name) "${a.name}="
+
+ a.address
+
+ optionalString (!isNull a.port) ":${toString a.port}"
+
+ optionalString (!isNull a.proto) ",${a.proto}"
+
+ optionalString (!isNull a.user) ",user=${a.user}"
+
+ optionalString (!isNull a.group) ",group=${a.group}"
+
+ optionalString (!isNull a.mode) ",mode=${a.mode}"
+
) cfg.listen)
+
+ lib.optionalString (!isNull cfg.http_address) " -a ${cfg.http_address}";
+
addressSubmodule = types.submodule {
+
options = {
+
name = mkOption {
+
description = "Name is referenced in logs. If name is not specified, 'a0', 'a1', etc. is used.";
+
default = null;
+
type = with types; nullOr str;
+
};
+
address = mkOption {
+
description = ''
+
If given an IP address, it can be a host name ("localhost"), an IPv4 dotted-quad
+
("127.0.0.1") or an IPv6 address enclosed in square brackets ("[::1]").
+
+
(VCL4.1 and higher) If given an absolute Path ("/path/to/listen.sock") or "@"
+
followed by the name of an abstract socket ("@myvarnishd") accept connections
+
on a Unix domain socket.
+
+
The user, group and mode sub-arguments may be used to specify the permissions
+
of the socket file. These sub-arguments do not apply to abstract sockets.
+
'';
+
type = types.str;
+
};
+
port = mkOption {
+
description = "The port to use for IP sockets. If port is not specified, port 80 (http) is used.";
+
default = null;
+
type = with types; nullOr int;
+
};
+
proto = mkOption {
+
description = "PROTO can be 'HTTP' (the default) or 'PROXY'. Both version 1 and 2 of the proxy protocol can be used.";
+
type = types.enum [
+
"HTTP"
+
"PROXY"
+
];
+
default = "HTTP";
+
};
+
user = mkOption {
+
description = "User name who owns the socket file.";
+
default = null;
+
type = with lib.types; nullOr str;
+
};
+
group = mkOption {
+
description = "Group name who owns the socket file.";
+
default = null;
+
type = with lib.types; nullOr str;
+
};
+
mode = mkOption {
+
description = "Permission of the socket file (3-digit octal value).";
+
default = null;
+
type = with types; nullOr str;
+
};
+
};
+
};
+
checkedAddressModule = types.addCheck addressSubmodule (
+
m:
+
(
+
if ((hasPrefix "@" m.address) || (hasPrefix "/" m.address)) then
+
# this is a unix socket
+
(m.port != null)
+
else
+
# this is not a path-based unix socket
+
if !(hasPrefix "/" m.address) && (m.group != null) || (m.user != null) || (m.mode != null) then
+
false
+
else
+
true
+
)
+
);
commandLine =
"-f ${pkgs.writeText "default.vcl" cfg.config}"
+
···
package = lib.mkPackageOption pkgs "varnish" { };
http_address = lib.mkOption {
-
type = lib.types.str;
-
default = "*:6081";
+
type = with lib.types; nullOr str;
+
default = null;
description = ''
HTTP listen address and port.
'';
+
};
+
+
listen = lib.mkOption {
+
description = "Accept for client requests on the specified listen addresses.";
+
type = lib.types.listOf checkedAddressModule;
+
defaultText = lib.literalExpression ''[ { address="*"; port=6081; } ]'';
+
default = lib.optional (isNull cfg.http_address) {
+
address = "*";
+
port = 6081;
+
};
};
config = lib.mkOption {
···
serviceConfig = {
Type = "simple";
PermissionsStartOnly = true;
-
ExecStart = "${cfg.package}/sbin/varnishd -a ${cfg.http_address} -n ${stateDir} -F ${cfg.extraCommandLine} ${commandLine}";
+
ExecStart = "${cfg.package}/sbin/varnishd ${commandLineAddresses} -n ${stateDir} -F ${cfg.extraCommandLine} ${commandLine}";
Restart = "always";
RestartSec = "5s";
User = "varnish";
···
${cfg.package}/bin/varnishd -C ${commandLine} 2> $out || (cat $out; exit 1)
'')
];
+
+
assertions = concatMap (m: [
+
{
+
assertion = (hasPrefix "/" m.address) || (hasPrefix "@" m.address) -> m.port == null;
+
message = "Listen ports must not be specified with UNIX sockets: ${builtins.toJSON m}";
+
}
+
{
+
assertion = !(hasPrefix "/" m.address) -> m.user == null && m.group == null && m.mode == null;
+
message = "Abstract UNIX sockets or IP sockets can not be used with user, group, and mode settings: ${builtins.toJSON m}";
+
}
+
]) cfg.listen;
+
+
warnings =
+
lib.optional (!isNull cfg.http_address)
+
"The option `services.varnish.http_address` is deprecated. Use `services.varnish.listen` instead.";
users.users.varnish = {
group = "varnish";
+49 -3
nixos/tests/varnish.nix
···
nodes = {
varnish =
-
{ config, pkgs, ... }:
+
{
+
config,
+
pkgs,
+
lib,
+
...
+
}:
{
services.nix-serve = {
enable = true;
···
services.varnish = {
inherit package;
enable = true;
-
http_address = "0.0.0.0:80";
+
http_address = "0.0.0.0:81";
+
listen = [
+
{
+
address = "0.0.0.0";
+
port = 80;
+
proto = "HTTP";
+
}
+
{
+
name = "proxyport";
+
address = "0.0.0.0";
+
port = 8080;
+
proto = "PROXY";
+
}
+
{ address = "@asdf"; }
+
{
+
address = "/run/varnishd/client.http.sock";
+
user = "varnish";
+
group = "varnish";
+
mode = "660";
+
}
+
];
config = ''
-
vcl 4.0;
+
vcl 4.1;
backend nix-serve {
.host = "127.0.0.1";
···
networking.firewall.allowedTCPPorts = [ 80 ];
system.extraDependencies = [ testPath ];
+
+
assertions =
+
map
+
(
+
pattern:
+
let
+
cmdline = config.systemd.services.varnish.serviceConfig.ExecStart;
+
in
+
{
+
assertion = lib.hasInfix pattern cmdline;
+
message = "Address argument `${pattern}` missing in commandline `${cmdline}`.";
+
}
+
)
+
[
+
" -a 0.0.0.0:80,HTTP "
+
" -a proxyport=0.0.0.0:8080,PROXY "
+
" -a @asdf,HTTP "
+
" -a /run/varnishd/client.http.sock,HTTP,user=varnish,group=varnish,mode=660 "
+
" -a 0.0.0.0:81 "
+
];
};
client =
···
testScript = ''
start_all()
varnish.wait_for_open_port(80)
+
client.wait_until_succeeds("curl -f http://varnish/nix-cache-info");