1{ lib, ... }:
2{
3 name = "anubis";
4 meta.maintainers = with lib.maintainers; [
5 soopyc
6 nullcube
7 ];
8
9 nodes.machine =
10 {
11 config,
12 pkgs,
13 ...
14 }:
15 {
16 services.anubis = {
17 defaultOptions.settings = {
18 DIFFICULTY = 3;
19 USER_DEFINED_DEFAULT = true;
20 };
21 instances = {
22 "".settings = {
23 TARGET = "http://localhost:8080";
24 DIFFICULTY = 5;
25 USER_DEFINED_INSTANCE = true;
26 };
27
28 "tcp" = {
29 user = "anubis-tcp";
30 group = "anubis-tcp";
31 settings = {
32 TARGET = "http://localhost:8080";
33 BIND = ":9000";
34 BIND_NETWORK = "tcp";
35 METRICS_BIND = ":9001";
36 METRICS_BIND_NETWORK = "tcp";
37 };
38 };
39
40 "unix-upstream" = {
41 group = "nginx";
42 settings.TARGET = "unix:///run/nginx/nginx.sock";
43 };
44 };
45 };
46
47 # support
48 users.users.nginx.extraGroups = [ config.users.groups.anubis.name ];
49 services.nginx = {
50 enable = true;
51 recommendedProxySettings = true;
52 virtualHosts."basic.localhost".locations = {
53 "/".proxyPass = "http://unix:${config.services.anubis.instances."".settings.BIND}";
54 "/metrics".proxyPass = "http://unix:${config.services.anubis.instances."".settings.METRICS_BIND}";
55 };
56
57 virtualHosts."tcp.localhost".locations = {
58 "/".proxyPass = "http://localhost:9000";
59 "/metrics".proxyPass = "http://localhost:9001";
60 };
61
62 virtualHosts."unix.localhost".locations = {
63 "/".proxyPass = "http://unix:${config.services.anubis.instances.unix-upstream.settings.BIND}";
64 };
65
66 # emulate an upstream with nginx, listening on tcp and unix sockets.
67 virtualHosts."upstream.localhost" = {
68 default = true; # make nginx match this vhost for `localhost`
69 listen = [
70 { addr = "unix:/run/nginx/nginx.sock"; }
71 {
72 addr = "localhost";
73 port = 8080;
74 }
75 ];
76 locations."/" = {
77 tryFiles = "$uri $uri/index.html =404";
78 root = pkgs.runCommand "anubis-test-upstream" { } ''
79 mkdir $out
80 echo "it works" >> $out/index.html
81 '';
82 };
83 };
84 };
85 };
86
87 testScript = ''
88 for unit in ["nginx", "anubis", "anubis-tcp", "anubis-unix-upstream"]:
89 machine.wait_for_unit(unit + ".service")
90
91 for port in [9000, 9001]:
92 machine.wait_for_open_port(port)
93
94 for instance in ["anubis", "anubis-unix-upstream"]:
95 machine.wait_for_open_unix_socket(f"/run/anubis/{instance}.sock")
96 machine.wait_for_open_unix_socket(f"/run/anubis/{instance}-metrics.sock")
97
98 # Default unix socket mode
99 machine.succeed('curl -f http://basic.localhost | grep "it works"')
100 machine.succeed('curl -f http://basic.localhost -H "User-Agent: Mozilla" | grep anubis')
101 machine.succeed('curl -f http://basic.localhost/metrics | grep anubis_challenges_issued')
102 machine.succeed('curl -f -X POST http://basic.localhost/.within.website/x/cmd/anubis/api/make-challenge | grep challenge')
103
104 # TCP mode
105 machine.succeed('curl -f http://tcp.localhost -H "User-Agent: Mozilla" | grep anubis')
106 machine.succeed('curl -f http://tcp.localhost/metrics | grep anubis_challenges_issued')
107
108 # Upstream is a unix socket mode
109 machine.succeed('curl -f http://unix.localhost/index.html | grep "it works"')
110
111 # Default user-defined environment variables
112 machine.succeed('cat /run/current-system/etc/systemd/system/anubis.service | grep "USER_DEFINED_DEFAULT"')
113 machine.succeed('cat /run/current-system/etc/systemd/system/anubis-tcp.service | grep "USER_DEFINED_DEFAULT"')
114
115 # Instance-specific user-specified environment variables
116 machine.succeed('cat /run/current-system/etc/systemd/system/anubis.service | grep "USER_DEFINED_INSTANCE"')
117 machine.fail('cat /run/current-system/etc/systemd/system/anubis-tcp.service | grep "USER_DEFINED_INSTANCE"')
118
119 # Make sure defaults don't overwrite themselves
120 machine.succeed('cat /run/current-system/etc/systemd/system/anubis.service | grep "DIFFICULTY=5"')
121 machine.succeed('cat /run/current-system/etc/systemd/system/anubis-tcp.service | grep "DIFFICULTY=3"')
122 '';
123}