1 of 22

Lua Configlets in Traffic Ops

Dave Neuman & Matt Mills

2 of 22

What’s Lua?

  • Lua is a powerful, efficient, lightweight, embeddable scripting language
  • It supports procedural programming, object-oriented programming, functional programming, data-driven programming, and data description
  • Lua is dynamically typed, runs by interpreting bytecode with a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal for configuration, scripting, and rapid prototyping
  • https://www.lua.org/about.html

3 of 22

Why lua?

  • Customers often want odd, one off functionality in our CDN.
  • C++ plugins require C++ developers (good ones)
  • C++ plugins can easily crash ATS, leak memory, do other bad things
  • Compiled vs Interpreted
  • Lua is fast

4 of 22

What can we do with lua in ATS?

More reading: https://docs.trafficserver.apache.org/en/latest/admin-guide/plugins/ts_lua.en.html

5 of 22

Manipulate the Cache key

function do_remap()

local to_host = ts.remap.get_to_url_host()

local to_uri = ts.remap.get_to_uri()

if to_host == 'http://somewhere.com/'ts.remap.set_cache_url('http://somewhere-else.com/' .. to_uri)

return TS_LUA_REMAP_NO_REMAPend

6 of 22

Debug in production?

function do_remap()

local query_params = ts.client_request.get_uri_args()

if(string.find(query_params, 'turn_debug_on=secret') ~= nil) then� ts.http.set_debug(1)

end

return TS_LUA_REMAP_NO_REMAPend

7 of 22

Manipulate headers before forwarding to Origin

function send_request()� ts.server_request.header['X-Super-Secret-Authorization'] = 'Because I said so.'end��function do_remap()� ts.hook(TS_LUA_HOOK_SEND_REQUEST_HDR, send_request)� return TS_LUA_REMAP_NO_REMAPend

8 of 22

Manipulate ATS’ response

function do_remap()� ts.http.set_error_resp(418, "I’m a teapot\n")� return TS_LUA_REMAP_NO_REMAPend

function send_response()� ts.client_response.header['Rhost'] = ts.ctx['rhost']� return 0end��function do_remap()� local req_host = ts.client_request.header.Hostts.ctx['rhost'] = string.reverse(req_host)� ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response)� return TS_LUA_REMAP_NO_REMAPend

9 of 22

Dynamically manipulate remap

function do_remap()� local to_host = ts.remap.get_to_url_host()

local client_method = ts.client_request.get_method()

if(to_host == 'somewhere.com' and client_method == 'POST') then

ts.client_request.set_url_host = 'somewhere-else.com'

end

ts.client_request.header['X-Original-Host'] = to_host� return TS_LUA_REMAP_DID_REMAP_STOPend

10 of 22

Decide if an object in cache is acceptable

function cache_lookup()� local status = ts.http.get_cache_lookup_status()� if status == TS_LUA_CACHE_LOOKUP_HIT_FRESH then

if ts.cached_response.header['Content-Type'] == 'text/plain'

ts.http.set_cache_lookup_status(TS_LUA_CACHE_LOOKUP_MISS)

end � endend��function do_remap()� ts.hook(TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE, cache_lookup)� return TS_LUA_REMAP_NO_REMAPend

11 of 22

AWS S3 v4 Url Signing

function do_remap()

ts.hook(TS_LUA_HOOK_SEND_REQUEST_HDR, do_s3_signing)

return 0

end

function do_s3_signing()

…(lots snipped)...

local request_scope = os.date('!%Y%m%d') .. '/' .. region .. '/' .. service .. '/aws4_request'

local canonical_request = http_method .. "\n" .. canonical_uri .. "\n" .. canonicalized_query_string .. "\n" .. canonicalized_headers .. "\n" .. signed_headers .. "\n" .. body_sha256

canonical_request_sha256 = crypto_evp.digest('sha256', canonical_request)

local string_to_sign = 'AWS4-HMAC-SHA256' .. "\n" .. timestamp_iso8601 .. "\n" .. request_scope .. "\n" .. canonical_request_sha256

date_key = crypto_hmac.digest('sha256', os.date('!%Y%m%d'), 'AWS4' .. secret_key, true)

date_region_key = crypto_hmac.digest('sha256', region, date_key, true)

date_region_service_key = crypto_hmac.digest('sha256', service, date_region_key, true)

signing_key = crypto_hmac.digest('sha256', 'aws4_request', date_region_service_key, true)

signature = crypto_hmac.digest('sha256', string_to_sign, signing_key, false)

ts.server_request.header['Authorization'] = 'AWS4-HMAC-SHA256 Credential='.. access_key .. "/" .. request_scope .. ',SignedHeaders=' .. signed_headers .. ',Signature='.. signature

return TS_LUA_REMAP_NO_REMAP

end

12 of 22

Limitations

  • The `traffic_line -x` option doesn’t pick up script changes
  • A syntax error breaks the remap rule
  • Plugin is somewhat experimental (in experimental repo)
  • Original developer no longer with ATS (could cause support issues)

13 of 22

How?

  • Take and Bake
    • Create a param containing text of the config file
    • Enter raw remap text
    • Delicate
  • Manually
    • Copying files to caches (puppet/ansible?)
    • Update remap.config (ORT will overwrite)
  • Traffic Ops

14 of 22

Traffic Ops Support

    • Repository of Lua Scripts with defined inputs
    • Assign Lua Script to DS and populate variable values
    • Validation of variable inputs
    • A few database changes

UID�name�url

custom_script

UID�custom_script_id�name

type

validation (regex)

custom_script_vars

deliveryservice_id

var_id�var_value

cs_var_input

15 of 22

Demo

16 of 22

Questions?

17 of 22

:( Demo didn’t work...screenshots...

18 of 22

Tools -> Manage Lua Configs

19 of 22

Add Lua Config

20 of 22

Edit Lua Config

21 of 22

If Lua Configs enabled, button to manage config

22 of 22

Configure Lua Config for a DS