Merge pull request #76723 from jokogr/u/traefik-2.1.1

Traefik: 1.7.14 -> 2.2.0

Changed files
+192 -60
nixos
modules
services
web-servers
tests
pkgs
servers
traefik
+85 -40
nixos/modules/services/web-servers/traefik.nix
···
let
cfg = config.services.traefik;
-
configFile =
-
if cfg.configFile == null then
-
pkgs.runCommand "config.toml" {
-
buildInputs = [ pkgs.remarshal ];
-
preferLocalBuild = true;
-
} ''
-
remarshal -if json -of toml \
-
< ${pkgs.writeText "config.json" (builtins.toJSON cfg.configOptions)} \
-
> $out
-
''
-
else cfg.configFile;
-
+
jsonValue = with types;
+
let
+
valueType = nullOr (oneOf [
+
bool
+
int
+
float
+
str
+
(lazyAttrsOf valueType)
+
(listOf valueType)
+
]) // {
+
description = "JSON value";
+
emptyValue.value = { };
+
};
+
in valueType;
+
dynamicConfigFile = if cfg.dynamicConfigFile == null then
+
pkgs.runCommand "config.toml" {
+
buildInputs = [ pkgs.remarshal ];
+
preferLocalBuild = true;
+
} ''
+
remarshal -if json -of toml \
+
< ${
+
pkgs.writeText "dynamic_config.json"
+
(builtins.toJSON cfg.dynamicConfigOptions)
+
} \
+
> $out
+
''
+
else
+
cfg.dynamicConfigFile;
+
staticConfigFile = if cfg.staticConfigFile == null then
+
pkgs.runCommand "config.toml" {
+
buildInputs = [ pkgs.yj ];
+
preferLocalBuild = true;
+
} ''
+
yj -jt -i \
+
< ${
+
pkgs.writeText "static_config.json" (builtins.toJSON
+
(recursiveUpdate cfg.staticConfigOptions {
+
providers.file.filename = "${dynamicConfigFile}";
+
}))
+
} \
+
> $out
+
''
+
else
+
cfg.staticConfigFile;
in {
options.services.traefik = {
enable = mkEnableOption "Traefik web server";
-
configFile = mkOption {
+
staticConfigFile = mkOption {
default = null;
-
example = literalExample "/path/to/config.toml";
+
example = literalExample "/path/to/static_config.toml";
type = types.nullOr types.path;
description = ''
-
Path to verbatim traefik.toml to use.
-
(Using that option has precedence over <literal>configOptions</literal>)
+
Path to traefik's static configuration to use.
+
(Using that option has precedence over <literal>staticConfigOptions</literal> and <literal>dynamicConfigOptions</literal>)
'';
};
-
configOptions = mkOption {
+
staticConfigOptions = mkOption {
description = ''
-
Config for Traefik.
+
Static configuration for Traefik.
'';
-
type = types.attrs;
-
default = {
-
defaultEntryPoints = ["http"];
+
type = jsonValue;
+
default = { entryPoints.http.address = ":80"; };
+
example = {
+
entryPoints.web.address = ":8080";
entryPoints.http.address = ":80";
+
+
api = { };
};
-
example = {
-
defaultEntrypoints = [ "http" ];
-
web.address = ":8080";
-
entryPoints.http.address = ":80";
+
};
-
file = {};
-
frontends = {
-
frontend1 = {
-
backend = "backend1";
-
routes.test_1.rule = "Host:localhost";
-
};
-
};
-
backends.backend1 = {
-
servers.server1.url = "http://localhost:8000";
+
dynamicConfigFile = mkOption {
+
default = null;
+
example = literalExample "/path/to/dynamic_config.toml";
+
type = types.nullOr types.path;
+
description = ''
+
Path to traefik's dynamic configuration to use.
+
(Using that option has precedence over <literal>dynamicConfigOptions</literal>)
+
'';
+
};
+
+
dynamicConfigOptions = mkOption {
+
description = ''
+
Dynamic configuration for Traefik.
+
'';
+
type = jsonValue;
+
default = { };
+
example = {
+
http.routers.router1 = {
+
rule = "Host(`localhost`)";
+
service = "service1";
};
+
+
http.services.service1.loadBalancer.servers =
+
[{ url = "http://localhost:8080"; }];
};
};
···
default = "/var/lib/traefik";
type = types.path;
description = ''
-
Location for any persistent data traefik creates, ie. acme
+
Location for any persistent data traefik creates, ie. acme
'';
};
···
};
config = mkIf cfg.enable {
-
systemd.tmpfiles.rules = [
-
"d '${cfg.dataDir}' 0700 traefik traefik - -"
-
];
+
systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0700 traefik traefik - -" ];
systemd.services.traefik = {
description = "Traefik web server";
after = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
-
ExecStart = ''${cfg.package.bin}/bin/traefik --configfile=${configFile}'';
+
ExecStart =
+
"${cfg.package}/bin/traefik --configfile=${staticConfigFile}";
Type = "simple";
User = "traefik";
Group = cfg.group;
···
isSystemUser = true;
};
-
users.groups.traefik = {};
+
users.groups.traefik = { };
};
}
+2
nixos/tests/all-tests.nix
···
timezone = handleTest ./timezone.nix {};
tinydns = handleTest ./tinydns.nix {};
tor = handleTest ./tor.nix {};
+
# traefik test relies on docker-containers
+
traefik = handleTestOn ["x86_64-linux"] ./traefik.nix {};
transmission = handleTest ./transmission.nix {};
trac = handleTest ./trac.nix {};
trilium-server = handleTestOn ["x86_64-linux"] ./trilium-server.nix {};
+87
nixos/tests/traefik.nix
···
+
# Test Traefik as a reverse proxy of a local web service
+
# and a Docker container.
+
import ./make-test-python.nix ({ pkgs, ... }: {
+
name = "traefik";
+
meta = with pkgs.stdenv.lib.maintainers; {
+
maintainers = [ joko ];
+
};
+
+
nodes = {
+
client = { config, pkgs, ... }: {
+
environment.systemPackages = [ pkgs.curl ];
+
};
+
traefik = { config, pkgs, ... }: {
+
docker-containers.nginx = {
+
extraDockerOptions = [
+
"-l" "traefik.enable=true"
+
"-l" "traefik.http.routers.nginx.entrypoints=web"
+
"-l" "traefik.http.routers.nginx.rule=Host(`nginx.traefik.test`)"
+
];
+
image = "nginx-container";
+
imageFile = pkgs.dockerTools.examples.nginx;
+
};
+
+
networking.firewall.allowedTCPPorts = [ 80 ];
+
+
services.traefik = {
+
enable = true;
+
+
dynamicConfigOptions = {
+
http.routers.simplehttp = {
+
rule = "Host(`simplehttp.traefik.test`)";
+
entryPoints = [ "web" ];
+
service = "simplehttp";
+
};
+
+
http.services.simplehttp = {
+
loadBalancer.servers = [{
+
url = "http://127.0.0.1:8000";
+
}];
+
};
+
};
+
+
staticConfigOptions = {
+
global = {
+
checkNewVersion = false;
+
sendAnonymousUsage = false;
+
};
+
+
entryPoints.web.address = ":80";
+
+
providers.docker.exposedByDefault = false;
+
};
+
};
+
+
systemd.services.simplehttp = {
+
script = "${pkgs.python3}/bin/python -m http.server 8000";
+
serviceConfig.Type = "simple";
+
wantedBy = [ "multi-user.target" ];
+
};
+
+
users.users.traefik.extraGroups = [ "docker" ];
+
};
+
};
+
+
testScript = ''
+
start_all()
+
+
traefik.wait_for_unit("docker-nginx.service")
+
traefik.wait_until_succeeds("docker ps | grep nginx-container")
+
traefik.wait_for_unit("simplehttp.service")
+
traefik.wait_for_unit("traefik.service")
+
traefik.wait_for_open_port(80)
+
traefik.wait_for_unit("multi-user.target")
+
+
client.wait_for_unit("multi-user.target")
+
+
with subtest("Check that a container can be reached via Traefik"):
+
assert "Hello from NGINX" in client.succeed(
+
"curl -sSf -H Host:nginx.traefik.test http://traefik/"
+
)
+
+
with subtest("Check that dynamic configuration works"):
+
assert "Directory listing for " in client.succeed(
+
"curl -sSf -H Host:simplehttp.traefik.test http://traefik/"
+
)
+
'';
+
})
+18 -20
pkgs/servers/traefik/default.nix
···
-
{ stdenv, buildGoPackage, fetchFromGitHub, bash, go-bindata}:
+
{ stdenv, buildGoModule, fetchFromGitHub, go-bindata, nixosTests }:
-
buildGoPackage rec {
+
buildGoModule rec {
pname = "traefik";
-
version = "1.7.14";
-
-
goPackagePath = "github.com/containous/traefik";
+
version = "2.2.0";
src = fetchFromGitHub {
owner = "containous";
repo = "traefik";
rev = "v${version}";
-
sha256 = "1j3p09j8rpdkp8v4d4mz224ddakkvhzchvccm9qryrqc2fq4022v";
+
sha256 = "1dcazssabqxr9wv3dds3z7ks3y628qa07vgnn3hpdwxzm2b2ma92";
};
-
nativeBuildInputs = [ go-bindata bash ];
+
modSha256 = "0w3ssxvsmq8i6hbfmn4ig2x13i2nlqy5q1khcblf9pq5vhk202qx";
+
subPackages = [ "cmd/traefik" ];
-
buildPhase = ''
-
runHook preBuild
-
(
-
cd go/src/github.com/containous/traefik
-
bash ./script/make.sh generate
+
nativeBuildInputs = [ go-bindata ];
-
CODENAME=$(awk -F "=" '/CODENAME=/ { print $2}' script/binary)
-
go build -ldflags "\
-
-X github.com/containous/traefik/version.Version=${version} \
-
-X github.com/containous/traefik/version.Codename=$CODENAME \
-
" -a -o $bin/bin/traefik ./cmd/traefik
-
)
-
runHook postBuild
+
passthru.tests = { inherit (nixosTests) traefik; };
+
+
preBuild = ''
+
go generate
+
+
CODENAME=$(awk -F "=" '/CODENAME=/ { print $2}' script/binary)
+
+
makeFlagsArray+=("-ldflags=\
+
-X github.com/containous/traefik/version.Version=${version} \
+
-X github.com/containous/traefik/version.Codename=$CODENAME")
'';
meta = with stdenv.lib; {
homepage = "https://traefik.io";
description = "A modern reverse proxy";
license = licenses.mit;
-
maintainers = with maintainers; [ hamhut1066 vdemeester ];
+
maintainers = with maintainers; [ vdemeester ];
};
}