Skip to content

gsjurseth/envoy-filter-experiments

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

envoy-filter-experiments

Have you ever thought that it would be great if there were a couple of envoy examples that used LUA to do something real and began to at least approach what might be considered a realistic use case?

This repo aims to show:

  • Inline lua examples that execute on every request
  • Lua examples that use the LuaPerRoute setup to execute on specific routes
  • Included lua addons to extend the base functaionlity
  • A simple translation that converts xml->json and then json->xml if the appropriate headers are set
  • A library that's referenced from the code so that everything isn't embedded as a monster inside the envoy.yaml file.
  • A simple docker-compose setup to make it all work

Run it

So checkout this repo and then run:

docker-compose build && docker-compose up

That's it. If you'd like to turn on debug logging then edit the docker composition and change: LOGLEVEL to debug

  proxy:
    build:
      context: .
      dockerfile: ./Dockerfile-envoy
    environment:
      LOGLEVEL: "debug"

Once it's up you can test it

Testing it

Running the following will send a get request to httpbin.org and then add a new header called X-Apigee-Bar which is just a dynamic copy of the user-agent.

Run it like so:

 docker exec -it envoy-filter-experiments_proxy_1 curl http://localhost:10000/get

which should yield something like:

{
 "args": {},
 "headers": {
   "Accept": "*/*",
   "Host": "httpbin.org",
   "User-Agent": "curl/7.58.0",
   "X-Amzn-Trace-Id": "Root=1-606de78c-1e4a4e15124016f82293e01f",
   "X-Apigee-Bar": "curl/7.58.0",
   "X-Envoy-Expected-Rq-Timeout-Ms": "15000"
 },
 "origin": "1.2.3.4",
 "url": "http://httpbin.org/get"
}

If you'd like to test a post and a dynamic conversion of xml -> json then then back again run something like this:

docker exec -it envoy-filter-experiments_proxy_1 curl -i http://localhost:10000/post -X POST -d '<xml><foo>bar</foo></xml>' -H "content-type: application/xml" -H "Accept: application/xml"

Which yields:

<body>
  <args>

  </args>
  <origin>1.2.3.4</origin>
  <url>http://httpbin.org/post</url>
  <headers>
        <X-Envoy-Expected-Rq-Timeout-Ms>15000</X-Envoy-Expected-Rq-Timeout-Ms>
        <User-Agent>curl/7.58.0</User-Agent>
        <X-Amzn-Trace-Id>Root=1-606de87f-49b9391d5ad7c47928347487</X-Amzn-Trace-Id>
        <Content-Length>21</Content-Length>
        <Content-Type>application/json</Content-Type>
        <Accept>application/xml</Accept>
        <Host>httpbin.org</Host>
  </headers>
  <data>{"xml":{"foo":"bar"}}</data>
  <json>
          <xml>
              <foo>bar</foo>
          </xml>
  </json>
  <files>

  </files>
  <form>

  </form>
</body>

Running it with an accept header of appliation/json will keep it all in json as expected.

docker exec -it envoy-filter-experiments_proxy_1 curl -i http://localhost:10000/post -X POST -d '<xml><foo>bar</foo></xml>' -H "content-type: application/xml" -H "Accept: application/json"

And yields:

{
  "args": {},
  "data": "{\"xml\":{\"foo\":\"bar\"}}",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "application/json",
    "Content-Length": "21",
    "Content-Type": "application/json",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.58.0",
    "X-Amzn-Trace-Id": "Root=1-606de89e-5805b64047517ba04082bd9a",
    "X-Envoy-Expected-Rq-Timeout-Ms": "15000"
  },
  "json": {
    "xml": {
      "foo": "bar"
    }
  },
  "origin": "1.2.3.4",
  "url": "http://httpbin.org/post"
}

Another example: A SOAP -> REST use case

And what if you wanted to setup a GET request that transforms the request to a SOAP/POST? This example does just that. The backend is not a real SOAP service, but it does send a real SOAP request to the mocked backend. I simply copied the currencies example available online. In the future I may redeploy a real SOAP service i've used in the past and connect this to that backend. It changes nothing about the capabilities illustrated in this example.

Maybe you don't want any code in envoy.yaml at all. That's easily accomplished by specifying the source like so:

source_codes:
  xform.lua:
    filename: ./xform.lua

The xform.lua script still uses the same envoy_on_request and envoy_on_response stream handlers to do its work. However, in this final case we're also taking an inbound GET request, transforming it to a POST and then sending a SOAP payload.

Then, if the Accept header is set to application/json the response is converted to json before sending back.

That example is executed like so:

docker exec -it envoy-filter-experiments_proxy_1 curl -i http://localhost:10000/xform -H "accept: application/json"

And yields:

{"ArrayOfString":{"_attr":{"xmlns":"http://tempuri.org/","xmlns:xsd":"http://www.w3.org/2001/XMLSchema","xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance"},"string":["AED","AFN","ALL","AMD","ANG","AOA","ARS","AUD","AWG","AZN","BAM","BBD","BDT","BGN","BHD","BIF","BND","BOB","BRL","BSD","BWP","BYN","BZD","CAD","CDF","CHF","CLP","CNY","COP","CRC","CUP","CVE","CYP","CZK","DJF","DKK","DOP","DZD","EEK","EGP","ERN","ETB","EUR","FJD","GBP","GEL","GHS","GIP","GMD","GNF","GTQ","GYD","HKD","HNL","HRK","HTG","HUF","IDR","ILS","INR","IQD","IRR","ISK","JMD","JOD","JPY","KES","KGS","KHR","KMF","KRW","KWD","KZT","LAK","LBP","LKR","LRD","LSL","LTL","LVL","LYD","MAD","MDL","MGA","MKD","MMK","MNT","MOP","MRO","MRU","MTL","MUR","MVR","MWK","MXN","MYR","MZN","NAD","NGN","NIO","NOK","NPR","NZD","OMR","PAB","PEN","PGK","PHP","PKR","PLN","PYG","QAR","RON","RSD","RUB","RWF","SAR","SBD","SCR","SDG","SEK","SGD","SIT","SKK","SLL","SOS","SRD","SSP","STN","SVC"]}}

An example with a callout

What if you need to grab an incoming request, make another request in flight, use some part of that response and add it to the next requst. Like say for a login. Well this login example shows that.

The login.lua script uses the same apigee proxy from the previous example to make a call (a POST), grab that output and then add it to a header. This obviously could be an actual login, but in this case it's just showing the basic flow.

The key is this piece in the envoy_on_request method:

  local h,b = rh:httpCall(
  "apigee",
  {
    [":method"] = "POST",
    [":path"] = "/foobar/snarf",
    [":authority"] = "emea-poc15-test.apigee.net",
    ["accept"] = "application/json",
    ["Content-Type"] = "application/json"
  },
  "{\"msg\": \"I am a little teapot\" }",
  0)

That makes an additional callout to another envoy defined cluster: apigee

Execute like so:

docker exec -it envoy-filter-experiments_proxy_1 curl -i http://localhost:10000/callout

And that yields the following:

{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.58.0",
    "X-Amzn-Trace-Id": "Root=1-6076d847-120b2e2c3036e57a3fdf4ccd",
    "X-Apigee-Message": "I am a little teapot",
    "X-Envoy-Expected-Rq-Timeout-Ms": "15000",
    "X-Envoy-Original-Path": "/callout"
  },
  "origin": "1.2.3.4",
  "url": "http://httpbin.org/get"
}

What's next

We could obviously do a lot more, but I think this repo shows it's possible to build real, body-touching examles with envoy that shoudld be able to accomplish at least simple mediation.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages