From cf7fdc8d5945b788eca362d11db645d0b4200ae8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Erik=20Hedenstro=CC=88m?= <erik@hedenstroem.com>
Date: Thu, 7 Apr 2016 00:33:13 +0200
Subject: [PATCH] Initial working luerl resolver

---
 apps/consul_proxy/src/consul_proxy_router.erl | 30 +++++++++++---
 apps/consul_proxy/src/consul_proxy_utils.erl  | 41 +++++++++++++++----
 test/defaults.consul                          |  6 ++-
 3 files changed, 60 insertions(+), 17 deletions(-)

diff --git a/apps/consul_proxy/src/consul_proxy_router.erl b/apps/consul_proxy/src/consul_proxy_router.erl
index fc373a6..30e07e8 100644
--- a/apps/consul_proxy/src/consul_proxy_router.erl
+++ b/apps/consul_proxy/src/consul_proxy_router.erl
@@ -153,14 +153,14 @@ lookup_nodes(Domain, _Upstream, _Properties, Nodes, CacheFlag) ->
 lookup_resolver(_Domain, _Upstream, _Properties, undefined, _CacheFlag) ->
     {error, route_lookup_failed};
 lookup_resolver(Domain, Upstream, Properties, ServiceResolver, _CacheFlag) ->
-    case consul_proxy_utils:eval_script(ServiceResolver, [{'Req', Upstream}]) of
+    case consul_proxy_utils:eval_script(ServiceResolver, build_script_vars(Upstream)) of
         {ok, ServiceName} when is_binary(ServiceName) ->
-            lookup_services(Domain, Upstream, Properties, {ServiceName, undefined, []}, false);
+            lookup_services(Domain, Upstream, Properties, {ServiceName, <<".*">>, <<".*">>}, false);
+        {ok, [ServiceName]} when is_binary(ServiceName) ->
+            lookup_services(Domain, Upstream, Properties, {ServiceName, <<".*">>, <<".*">>}, false);
         {ok, {ServiceName, ServiceID}} when is_binary(ServiceName), is_binary(ServiceID) ->
-            lookup_services(Domain, Upstream, Properties, {ServiceName, ServiceID, []}, false);
-        {ok, {ServiceName, ServiceTags}} when is_binary(ServiceName), is_list(ServiceTags) ->
-            lookup_services(Domain, Upstream, Properties, {ServiceName, undefined, ServiceTags}, false);
-        {ok, {ServiceName, ServiceID, ServiceTags}} when is_binary(ServiceName), is_binary(ServiceID), is_list(ServiceTags) ->
+            lookup_services(Domain, Upstream, Properties, {ServiceName, ServiceID, <<".*">>}, false);
+        {ok, {ServiceName, ServiceID, ServiceTags}} when is_binary(ServiceName), is_binary(ServiceID), is_binary(ServiceTags) ->
             lookup_services(Domain, Upstream, Properties, {ServiceName, ServiceID, ServiceTags}, false);
         {ok, {Host, Port}} when is_binary(Host), is_integer(Port) ->
             lookup_nodes(Domain, Upstream, Properties, [[{<<"ServiceHost">>, Host}, {<<"ServicePort">>, Port}]], false);
@@ -216,3 +216,21 @@ matches(Subject, RE) ->
             lager:warning("Regexp failed: ~p", [Reason]),
             false
     end.
+
+build_script_vars(Req) ->
+    [
+        {request, [
+            {method, element(1, cowboyku_req:method(Req))},
+            {domain, element(1, cowboyku_req:host(Req))},
+            {port, element(1, cowboyku_req:port(Req))},
+            {path, element(1, cowboyku_req:path(Req))},
+            {query, element(1, cowboyku_req:qs_vals(Req))},
+            {headers, element(1, cowboyku_req:headers(Req))},
+            {cookies, element(1, cowboyku_req:cookies(Req))},
+            {meta, [
+                {request_id, element(1, cowboyku_req:meta(request_id, Req, nil))},
+                {initial_host, element(1, cowboyku_req:meta(initial_host, Req, nil))},
+                {host_capture, element(1, cowboyku_req:meta(host_capture, Req, []))}
+            ]}
+        ]}
+    ].
\ No newline at end of file
diff --git a/apps/consul_proxy/src/consul_proxy_utils.erl b/apps/consul_proxy/src/consul_proxy_utils.erl
index 6e80655..2faae06 100644
--- a/apps/consul_proxy/src/consul_proxy_utils.erl
+++ b/apps/consul_proxy/src/consul_proxy_utils.erl
@@ -158,8 +158,14 @@ detect_protocol(Req) ->
     end.
 
 -spec eval_script(Name :: binary(), Vars :: list()) -> {error, term()} | {ok, term()}.
-eval_script(Name, Vars) ->
-    Key = <<"script:", Name/binary>>,
+eval_script(Name, Vars) when byte_size(Name) > 4 ->
+    eval_script(Name, Vars, binary:part(Name, {byte_size(Name), -4}));
+eval_script(Name, _Vars) ->
+    {error, {bad_script_name, Name}}.
+
+-spec eval_script(Name :: binary(), Vars :: list(), Type :: erl | lua) -> {error, term()} | {ok, term()}.
+eval_script(Name, Vars, <<".erl">>) ->
+    Key = <<"erl_script:", Name/binary>>,
     Parsed = case cache_get(Key) of
                  undefined ->
                      case consul_client:get(<<"consul_proxy/scripts/", Name/binary>>) of
@@ -187,12 +193,7 @@ eval_script(Name, Vars) ->
         {error, Reason1} ->
             {error, Reason1};
         {ok, ExprList1} ->
-            Bindings = lists:foldl(
-                fun({K, V}, AccIn) ->
-                    erl_eval:add_binding(K, V, AccIn);
-                    (_, AccIn) ->
-                        AccIn
-                end, erl_eval:new_bindings(), Vars),
+            Bindings = erl_eval:add_binding('Props', Vars, erl_eval:new_bindings()),
             try
                 {value, Value, _} = erl_eval:exprs(ExprList1, Bindings),
                 {ok, Value}
@@ -202,7 +203,29 @@ eval_script(Name, Vars) ->
                     lager:error("Eval of script '~s' failed~nStacktrace:~s", [Name, Stacktrace]),
                     {error, {Class, ExceptionReason}}
             end
-    end.
+    end;
+eval_script(Name, Vars, <<".lua">>) ->
+    case consul_client:get(<<"consul_proxy/scripts/", Name/binary>>) of
+        {error, Reason} ->
+            {error, Reason};
+        {ok, Binary} ->
+            State = lists:foldl(
+                fun({Path, Value}, AccIn) ->
+                    luerl:set_table(Path, Value, AccIn)
+                end, luerl:init(), vars_to_table([props], Vars)),
+            luerl:eval(Binary, State)
+    end;
+eval_script(Name, _Vars, _Suffix) ->
+    {error, {unknown_language, Name}}.
+
+vars_to_table([], []) ->
+    [];
+vars_to_table(Path, [{Key, Value} | Vars]) ->
+    vars_to_table(Path, Vars) ++ vars_to_table([Key | Path], Value);
+vars_to_table(Path, Value) ->
+    [{lists:reverse(Path), Value}].
+
+
 -spec normalize(jsx:json_term()) -> jsx:json_term().
 normalize([{Key, Value} | Tuples]) ->
     [{normalize_key(Key), normalize(Value)} | normalize(Tuples)];
diff --git a/test/defaults.consul b/test/defaults.consul
index b1c5dd1..e1eb12a 100644
--- a/test/defaults.consul
+++ b/test/defaults.consul
@@ -1,9 +1,11 @@
 consul_proxy/domains/test.service.docker:ewogICJTZXJ2aWNlTmFtZSIgOiAidGVzdCIKfQ==
 consul_proxy/domains/consul.service.docker:ewogICJTZXJ2aWNlTmFtZSIgOiAiY29uc3VsIgp9
 consul_proxy/domains/rewrite-example:ewogICJTZXJ2aWNlTmFtZSIgOiAiJDxzZXJ2aWNlPiIsCiAgIkFsaWFzZXMiIDogWwogICAgIig/PHNlcnZpY2U+LiopLXJld3JpdGVbLl1zZXJ2aWNlWy5dZG9ja2VyIgogIF0sCiAgIlJld3JpdGUiIDogWwogICAgWyJeL2FwaS8oLiopJCIsIi9pbmZvLnBocD9hcGk9JDEiXQogIF0KfQ==
-consul_proxy/domains/resolver-example:ewogICJTZXJ2aWNlUmVzb2x2ZXIiIDogInJlc29sdmVyLWV4YW1wbGUuZXJsIiwKICAiQWxpYXNlcyIgOiBbCiAgICAiKD88c2VydmljZT4uKiktcmVzb2x2ZXJbLl1zZXJ2aWNlWy5dZG9ja2VyIgogIF0KfQ==
-consul_proxy/scripts/resolver-example.erl:e0NhcHR1cmUsX30gPSBjb3dib3lrdV9yZXE6bWV0YShob3N0X2NhcHR1cmUsIFJlcSksCnByb3BsaXN0czpnZXRfdmFsdWUoPDwic2VydmljZSI+PiwgQ2FwdHVyZSku
+consul_proxy/scripts/resolver-example.erl:UmVxdWVzdCA9IHByb3BsaXN0czpnZXRfdmFsdWUocmVxdWVzdCwgUHJvcHMsIFtdKSwKTWV0YSA9IHByb3BsaXN0czpnZXRfdmFsdWUobWV0YSwgUmVxdWVzdCwgW10pLApDYXB0dXJlID0gcHJvcGxpc3RzOmdldF92YWx1ZShob3N0X2NhcHR1cmUsIE1ldGEsIFtdKSwKcHJvcGxpc3RzOmdldF92YWx1ZSg8PCJzZXJ2aWNlIj4+LCBDYXB0dXJlKS4=
 consul_proxy/watchers/nodes:WwogICAgImh0dHBzOi8vdGVzdC5zZXJ2aWNlLmRvY2tlci9pbmZvLnBocCIKXQ==
 consul_proxy/watchers/services:WwogICAgImh0dHBzOi8vdGVzdC5zZXJ2aWNlLmRvY2tlci9pbmZvLnBocCIKXQ==
 consul_proxy/watchers/kv:WwogICAgImh0dHBzOi8vdGVzdC5zZXJ2aWNlLmRvY2tlci9pbmZvLnBocCIKXQ==
 consul_proxy/hijackers:WwogIHsKICAgICJ1c2VybmFtZSIgOiAiaGlqYWNrZXIiLAogICAgInBhc3N3b3JkIiA6ICIwdEhWdFNhOThrSGkyZStkVHVWdHo3S3lYWTgzVys3cGZ6eEZYd2VKWUtualcxOXRSeHBVbFFSV1lYbGI4V21YIiwKICAgICJkb21haW5zIiA6IFsKICAgICAgIi4qIgogICAgXQogIH0KXQ==
+consul_proxy/domains/resolver-example-erl:ewogICJTZXJ2aWNlUmVzb2x2ZXIiIDogInJlc29sdmVyLWV4YW1wbGUuZXJsIiwKICAiQWxpYXNlcyIgOiBbCiAgICAiKD88c2VydmljZT4uKiktcmVzb2x2ZXItZXJsWy5dc2VydmljZVsuXWRvY2tlciIKICBdCn0=
+consul_proxy/domains/resolver-example-lua:ewogICJTZXJ2aWNlUmVzb2x2ZXIiIDogInJlc29sdmVyLWV4YW1wbGUubHVhIiwKICAiQWxpYXNlcyIgOiBbCiAgICAiKD88c2VydmljZT4uKiktcmVzb2x2ZXItbHVhWy5dc2VydmljZVsuXWRvY2tlciIKICBdCn0=
+consul_proxy/scripts/resolver-example.lua:cmV0dXJuIHByb3BzLnJlcXVlc3QubWV0YS5ob3N0X2NhcHR1cmUuc2VydmljZTs=
-- 
GitLab