From 1bfd38131e5cce61128a00ff610c8adfe342503b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Erik=20Hedenstro=CC=88m?= <erik@hedenstroem.com>
Date: Wed, 6 Apr 2016 20:29:02 +0200
Subject: [PATCH] Implemented regexp matching for service id and tags (fixes
 #10 and #11).

---
 README.md                                     | 10 +++++
 apps/consul_proxy/src/consul_proxy.app.src    |  2 +-
 apps/consul_proxy/src/consul_proxy_router.erl | 40 +++++++++++++++----
 rebar.config                                  |  2 +-
 4 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/README.md b/README.md
index 614b8e5..45e58e1 100644
--- a/README.md
+++ b/README.md
@@ -30,3 +30,13 @@ Todo
 ----
 
 - Allow explicit setting of upstream/downstream headers
+
+
+Domain descriptor
+-----------------
+
+{
+  "ServiceName" : "test", (String)
+  "ServiceID" : "fast", (Regexp)
+  "ServiceTags" : "fast" (Regexp)
+}
\ No newline at end of file
diff --git a/apps/consul_proxy/src/consul_proxy.app.src b/apps/consul_proxy/src/consul_proxy.app.src
index 7513d3a..418155c 100644
--- a/apps/consul_proxy/src/consul_proxy.app.src
+++ b/apps/consul_proxy/src/consul_proxy.app.src
@@ -1,6 +1,6 @@
 {application, consul_proxy, [
     {description, "Proxy for docker swarm using consul and vegur"},
-    {vsn, "0.4.2"},
+    {vsn, "0.4.3"},
     {registered, []},
     {mod, {consul_proxy_app, []}},
     {applications, [
diff --git a/apps/consul_proxy/src/consul_proxy_router.erl b/apps/consul_proxy/src/consul_proxy_router.erl
index ec3c8ca..fc373a6 100644
--- a/apps/consul_proxy/src/consul_proxy_router.erl
+++ b/apps/consul_proxy/src/consul_proxy_router.erl
@@ -94,9 +94,9 @@ lookup_services(Domain, Upstream, State) ->
                     {Capture, Upstream1} = cowboyku_req:meta(host_capture, Upstream, []),
                     InterpolatedProperties = consul_proxy_utils:string_interpolate(Properties, Capture, [<<"Rewrite">>]),
                     ServiceName = proplists:get_value(<<"ServiceName">>, InterpolatedProperties),
-                    ServiceID = proplists:get_value(<<"ServiceID">>, InterpolatedProperties),
-                    ServiceTags = proplists:get_value(<<"ServiceTags">>, InterpolatedProperties, []),
-                    case lookup_services(Domain, Upstream1, InterpolatedProperties, {ServiceName, ServiceID, ServiceTags}, true) of
+                    ServiceIDRE = proplists:get_value(<<"ServiceID">>, InterpolatedProperties, <<".*">>),
+                    ServiceTagsRE = proplists:get_value(<<"ServiceTags">>, InterpolatedProperties, <<".*">>),
+                    case lookup_services(Domain, Upstream1, InterpolatedProperties, {ServiceName, ServiceIDRE, ServiceTagsRE}, true) of
                         {ok, Services, true} ->
                             consul_proxy_utils:cache_add(<<"services:", Domain/binary>>, {ok, Services}),
                             {ok, Services, Upstream1, State};
@@ -112,17 +112,19 @@ lookup_services(Domain, Upstream, State) ->
             {ok, Services, Upstream, State}
     end.
 
-lookup_services(Domain, Upstream, Properties, {undefined, _ServiceID, _ServiceTags}, CacheFlag) ->
+lookup_services(Domain, Upstream, Properties, {undefined, _ServiceIDRE, _ServiceTagsRE}, CacheFlag) ->
     lookup_nodes(Domain, Upstream, Properties, proplists:get_value(<<"ServiceNodes">>, Properties), CacheFlag);
-lookup_services(_Domain, _Upstream, _Properties, {ServiceName, _, _}, CacheFlag) ->
+lookup_services(_Domain, _Upstream, _Properties, {ServiceName, ServiceIDRE, ServiceTagsRE}, CacheFlag) ->
     case consul_client:service(ServiceName) of
         {ok, Nodes} ->
             {ok, lists:foldr(
                 fun(Node, Acc) ->
                     ServiceID = proplists:get_value(<<"ServiceID">>, Node),
-                    ServicePort = proplists:get_value(<<"ServicePort">>, Node, 80),
+                    ServiceTags = proplists:get_value(<<"ServiceTags">>, Node),
+                    ServiceMatches = matches(ServiceID, ServiceIDRE) and matches(ServiceTags, ServiceTagsRE),
                     case get_ip_addresses(proplists:get_value(<<"ServiceAddress">>, Node)) of
-                        [ServiceAddress] ->
+                        [ServiceAddress] when ServiceMatches ->
+                            ServicePort = proplists:get_value(<<"ServicePort">>, Node, 80),
                             [{{service, ServiceName, ServiceID}, ServiceAddress, ServicePort} | Acc];
                         _ ->
                             Acc
@@ -190,3 +192,27 @@ get_ip_addresses(Host) ->
             lager:warning("Unable to lookup addresses for '~s': ~p", [Host, Reason]),
             []
     end.
+
+matches(_Subject, <<".*">>) ->
+    true;
+matches([], _RE) ->
+    false;
+matches(undefined, _RE) ->
+    false;
+matches([Subject | Subjects], RE) ->
+    case matches(Subject, RE) of
+        true ->
+            true;
+        false ->
+            matches(Subjects, RE)
+    end;
+matches(Subject, RE) ->
+    case catch re:run(Subject, RE) of
+        {match, _} ->
+            true;
+        nomatch ->
+            false;
+        {'EXIT', Reason} ->
+            lager:warning("Regexp failed: ~p", [Reason]),
+            false
+    end.
diff --git a/rebar.config b/rebar.config
index 1ffb5ee..8a68d21 100644
--- a/rebar.config
+++ b/rebar.config
@@ -18,7 +18,7 @@
 ]}.
 
 {relx, [
-    {release, {consul_proxy, "0.4.2"}, [consul_proxy]}, {sys_config, "./config/sys.config"},
+    {release, {consul_proxy, "0.4.3"}, [consul_proxy]}, {sys_config, "./config/sys.config"},
     {vm_args, "./config/vm.args"},
     {dev_mode, true},
     {include_erts, false},
-- 
GitLab