at master 5.5 kB view raw
1# verifies: 2# 1. nginx generates config file with shared http context definitions above 3# generated virtual hosts config. 4# 2. whether the ETag header is properly generated whenever we're serving 5# files in Nix store paths 6# 3. nginx doesn't restart on configuration changes (only reloads) 7{ pkgs, ... }: 8{ 9 name = "nginx"; 10 meta = with pkgs.lib.maintainers; { 11 maintainers = [ 12 mbbx6spp 13 danbst 14 ]; 15 }; 16 17 nodes = { 18 webserver = 19 { pkgs, lib, ... }: 20 { 21 services.nginx.enable = true; 22 services.nginx.commonHttpConfig = '' 23 log_format ceeformat '@cee: {"status":"$status",' 24 '"request_time":$request_time,' 25 '"upstream_response_time":$upstream_response_time,' 26 '"pipe":"$pipe","bytes_sent":$bytes_sent,' 27 '"connection":"$connection",' 28 '"remote_addr":"$remote_addr",' 29 '"host":"$host",' 30 '"timestamp":"$time_iso8601",' 31 '"request":"$request",' 32 '"http_referer":"$http_referer",' 33 '"upstream_addr":"$upstream_addr"}'; 34 ''; 35 services.nginx.virtualHosts."0.my.test" = { 36 extraConfig = '' 37 access_log syslog:server=unix:/dev/log,facility=user,tag=mytag,severity=info ceeformat; 38 location /favicon.ico { allow all; access_log off; log_not_found off; } 39 ''; 40 }; 41 42 services.nginx.virtualHosts.localhost = { 43 root = pkgs.runCommand "testdir" { } '' 44 mkdir "$out" 45 echo hello world > "$out/index.html" 46 ''; 47 }; 48 49 services.nginx.enableReload = true; 50 51 specialisation.etagSystem.configuration = { 52 services.nginx.virtualHosts.localhost = { 53 root = lib.mkForce ( 54 pkgs.runCommand "testdir2" { } '' 55 mkdir "$out" 56 echo content changed > "$out/index.html" 57 '' 58 ); 59 }; 60 }; 61 62 specialisation.justReloadSystem.configuration = { 63 services.nginx.virtualHosts."1.my.test".listen = [ 64 { 65 addr = "127.0.0.1"; 66 port = 8080; 67 } 68 ]; 69 }; 70 71 specialisation.reloadRestartSystem.configuration = { 72 services.nginx.package = pkgs.nginxMainline; 73 }; 74 75 specialisation.reloadWithErrorsSystem.configuration = { 76 services.nginx.package = pkgs.nginxMainline; 77 services.nginx.virtualHosts."!@$$(#*%".locations."~@#*$*!)".proxyPass = ";;;"; 78 }; 79 }; 80 }; 81 82 testScript = 83 { nodes, ... }: 84 let 85 etagSystem = "${nodes.webserver.system.build.toplevel}/specialisation/etagSystem"; 86 justReloadSystem = "${nodes.webserver.system.build.toplevel}/specialisation/justReloadSystem"; 87 reloadRestartSystem = "${nodes.webserver.system.build.toplevel}/specialisation/reloadRestartSystem"; 88 reloadWithErrorsSystem = "${nodes.webserver.system.build.toplevel}/specialisation/reloadWithErrorsSystem"; 89 in 90 '' 91 url = "http://localhost/index.html" 92 93 94 def check_etag(): 95 etag = webserver.succeed( 96 f'curl -v {url} 2>&1 | sed -n -e "s/^< etag: *//ip"' 97 ).rstrip() 98 http_code = webserver.succeed( 99 f"curl -w '%{{http_code}}' --head --fail -H 'If-None-Match: {etag}' {url}" 100 ) 101 assert http_code.split("\n")[-1] == "304" 102 103 return etag 104 105 106 def wait_for_nginx_on_port(port): 107 webserver.wait_for_unit("nginx") 108 webserver.wait_for_open_port(port) 109 110 111 # nginx can be ready before multi-user.target, in which case switching to 112 # a different configuration might not realize it needs to restart nginx. 113 webserver.wait_for_unit("multi-user.target") 114 115 wait_for_nginx_on_port(80) 116 117 with subtest("check ETag if serving Nix store paths"): 118 old_etag = check_etag() 119 webserver.succeed( 120 "${etagSystem}/bin/switch-to-configuration test >&2" 121 ) 122 wait_for_nginx_on_port(80) 123 new_etag = check_etag() 124 assert old_etag != new_etag 125 126 with subtest("config is reloaded on nixos-rebuild switch"): 127 webserver.succeed( 128 "${justReloadSystem}/bin/switch-to-configuration test >&2" 129 ) 130 wait_for_nginx_on_port(8080) 131 webserver.fail("journalctl -u nginx | grep -q -i stopped") 132 webserver.succeed("journalctl -u nginx | grep -q -i reloaded") 133 134 with subtest("restart when nginx package changes"): 135 webserver.succeed( 136 "${reloadRestartSystem}/bin/switch-to-configuration test >&2" 137 ) 138 wait_for_nginx_on_port(80) 139 webserver.succeed("journalctl -u nginx | grep -q -i stopped") 140 141 with subtest("nixos-rebuild --switch should fail when there are configuration errors"): 142 webserver.fail( 143 "${reloadWithErrorsSystem}/bin/switch-to-configuration test >&2" 144 ) 145 webserver.succeed("[[ $(systemctl is-failed nginx-config-reload) == failed ]]") 146 webserver.succeed("[[ $(systemctl is-failed nginx) == active ]]") 147 # just to make sure operation is idempotent. During development I had a situation 148 # when first time it shows error, but stops showing it on subsequent rebuilds 149 webserver.fail( 150 "${reloadWithErrorsSystem}/bin/switch-to-configuration test >&2" 151 ) 152 ''; 153}