at 24.11-pre 6.2 kB view raw
1# verifies: 2# 1. Traffic Server is able to start 3# 2. Traffic Server spawns traffic_crashlog upon startup 4# 3. Traffic Server proxies HTTP requests according to URL remapping rules 5# in 'services.trafficserver.remap' 6# 4. Traffic Server applies per-map settings specified with the conf_remap 7# plugin 8# 5. Traffic Server caches HTTP responses 9# 6. Traffic Server processes HTTP PUSH requests 10# 7. Traffic Server can load the healthchecks plugin 11# 8. Traffic Server logs HTTP traffic as configured 12# 13# uses: 14# - bin/traffic_manager 15# - bin/traffic_server 16# - bin/traffic_crashlog 17# - bin/traffic_cache_tool 18# - bin/traffic_ctl 19# - bin/traffic_logcat 20# - bin/traffic_logstats 21# - bin/tspush 22import ./make-test-python.nix ({ pkgs, ... }: { 23 name = "trafficserver"; 24 meta = with pkgs.lib.maintainers; { 25 maintainers = [ midchildan ]; 26 }; 27 28 nodes = { 29 ats = { pkgs, lib, config, ... }: let 30 user = config.users.users.trafficserver.name; 31 group = config.users.groups.trafficserver.name; 32 healthchecks = pkgs.writeText "healthchecks.conf" '' 33 /status /tmp/ats.status text/plain 200 500 34 ''; 35 in { 36 services.trafficserver.enable = true; 37 38 services.trafficserver.records = { 39 proxy.config.http.server_ports = "80 80:ipv6"; 40 proxy.config.hostdb.host_file.path = "/etc/hosts"; 41 proxy.config.log.max_space_mb_headroom = 0; 42 proxy.config.http.push_method_enabled = 1; 43 44 # check that cache storage is usable before accepting traffic 45 proxy.config.http.wait_for_cache = 2; 46 }; 47 48 services.trafficserver.plugins = [ 49 { path = "healthchecks.so"; arg = toString healthchecks; } 50 { path = "xdebug.so"; } 51 ]; 52 53 services.trafficserver.remap = '' 54 map http://httpbin.test http://httpbin 55 map http://pristine-host-hdr.test http://httpbin \ 56 @plugin=conf_remap.so \ 57 @pparam=proxy.config.url_remap.pristine_host_hdr=1 58 map http://ats/tspush http://httpbin/cache \ 59 @plugin=conf_remap.so \ 60 @pparam=proxy.config.http.cache.required_headers=0 61 ''; 62 63 services.trafficserver.storage = '' 64 /dev/vdb volume=1 65 ''; 66 67 networking.firewall.allowedTCPPorts = [ 80 ]; 68 virtualisation.emptyDiskImages = [ 256 ]; 69 services.udev.extraRules = '' 70 KERNEL=="vdb", OWNER="${user}", GROUP="${group}" 71 ''; 72 }; 73 74 httpbin = { pkgs, lib, ... }: let 75 python = pkgs.python3.withPackages 76 (ps: with ps; [ httpbin gunicorn gevent ]); 77 in { 78 systemd.services.httpbin = { 79 enable = true; 80 after = [ "network.target" ]; 81 wantedBy = [ "multi-user.target" ]; 82 serviceConfig = { 83 ExecStart = "${python}/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k gevent"; 84 }; 85 }; 86 87 networking.firewall.allowedTCPPorts = [ 80 ]; 88 }; 89 90 client = { pkgs, lib, ... }: { 91 environment.systemPackages = with pkgs; [ curl ]; 92 }; 93 }; 94 95 testScript = { nodes, ... }: let 96 sampleFile = pkgs.writeText "sample.txt" '' 97 It's the season of White Album. 98 ''; 99 in '' 100 import json 101 import re 102 103 ats.wait_for_unit("trafficserver") 104 ats.wait_for_open_port(80) 105 httpbin.wait_for_unit("httpbin") 106 httpbin.wait_for_open_port(80) 107 client.systemctl("start network-online.target") 108 client.wait_for_unit("network-online.target") 109 110 with subtest("Traffic Server is running"): 111 out = ats.succeed("traffic_ctl server status") 112 assert out.strip() == "Proxy -- on" 113 114 with subtest("traffic_crashlog is running"): 115 ats.succeed("pgrep -f traffic_crashlog") 116 117 with subtest("basic remapping works"): 118 out = client.succeed("curl -vv -H 'Host: httpbin.test' http://ats/headers") 119 assert json.loads(out)["headers"]["Host"] == "httpbin" 120 121 with subtest("conf_remap plugin works"): 122 out = client.succeed( 123 "curl -vv -H 'Host: pristine-host-hdr.test' http://ats/headers" 124 ) 125 assert json.loads(out)["headers"]["Host"] == "pristine-host-hdr.test" 126 127 with subtest("caching works"): 128 out = client.succeed( 129 "curl -vv -D - -H 'Host: httpbin.test' -H 'X-Debug: X-Cache' http://ats/cache/60 -o /dev/null" 130 ) 131 assert "X-Cache: miss" in out 132 133 out = client.succeed( 134 "curl -vv -D - -H 'Host: httpbin.test' -H 'X-Debug: X-Cache' http://ats/cache/60 -o /dev/null" 135 ) 136 assert "X-Cache: hit-fresh" in out 137 138 with subtest("pushing to cache works"): 139 url = "http://ats/tspush" 140 141 ats.succeed(f"echo {url} > /tmp/urls.txt") 142 out = ats.succeed( 143 f"tspush -f '${sampleFile}' -u {url}" 144 ) 145 assert "HTTP/1.0 201 Created" in out, "cache push failed" 146 147 out = ats.succeed( 148 "traffic_cache_tool --spans /etc/trafficserver/storage.config find --input /tmp/urls.txt" 149 ) 150 assert "Span: /dev/vdb" in out, "cache not stored on disk" 151 152 out = client.succeed(f"curl {url}").strip() 153 expected = ( 154 open("${sampleFile}").read().strip() 155 ) 156 assert out == expected, "cache content mismatch" 157 158 with subtest("healthcheck plugin works"): 159 out = client.succeed("curl -vv http://ats/status -o /dev/null -w '%{http_code}'") 160 assert out.strip() == "500" 161 162 ats.succeed("touch /tmp/ats.status") 163 164 out = client.succeed("curl -vv http://ats/status -o /dev/null -w '%{http_code}'") 165 assert out.strip() == "200" 166 167 with subtest("logging works"): 168 access_log_path = "/var/log/trafficserver/squid.blog" 169 ats.wait_for_file(access_log_path) 170 171 out = ats.succeed(f"traffic_logcat {access_log_path}").split("\n")[0] 172 expected = "^\S+ \S+ \S+ TCP_MISS/200 \S+ GET http://httpbin/headers - DIRECT/httpbin application/json$" 173 assert re.fullmatch(expected, out) is not None, "no matching logs" 174 175 out = json.loads(ats.succeed(f"traffic_logstats -jf {access_log_path}")) 176 assert isinstance(out, dict) 177 assert out["total"]["error.total"]["req"] == "0", "unexpected log stat" 178 ''; 179})