From 782104a0f8794853152d5444c0a7c13bf2982b85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Erik=20Hedenstro=CC=88m?= <erik@hedenstroem.com>
Date: Wed, 27 Jan 2016 11:27:11 +0100
Subject: [PATCH] Skeleton in place

---
 .gitignore                                  |  4 +-
 .gitlab-ci.yml                              | 67 +++++++++++++++++++++
 LICENSE                                     | 42 ++++++-------
 Makefile                                    | 38 ++++++++++++
 apps/consul-proxy/include/consul-proxy.hrl  |  1 +
 apps/consul-proxy/priv/Dockerfile           | 20 ++++++
 apps/consul-proxy/priv/consul-proxy-wrapper | 28 +++++++++
 apps/consul-proxy/src/consul-proxy.app.src  | 36 ++++++-----
 apps/consul-proxy/src/consul-proxy_app.erl  |  5 +-
 apps/consul-proxy/src/consul-proxy_sup.erl  | 17 ++++--
 apps/consul-proxy/test/features_test.erl    | 16 +++++
 config/sys.config                           | 30 ++++++++-
 config/test-sys.config                      | 29 +++++++++
 config/test-vm.args                         | 19 ++++++
 config/vm.args                              | 19 +++++-
 rebar.config                                | 49 ++++++++++-----
 16 files changed, 352 insertions(+), 68 deletions(-)
 create mode 100644 .gitlab-ci.yml
 create mode 100644 Makefile
 create mode 100644 apps/consul-proxy/include/consul-proxy.hrl
 create mode 100644 apps/consul-proxy/priv/Dockerfile
 create mode 100755 apps/consul-proxy/priv/consul-proxy-wrapper
 create mode 100644 apps/consul-proxy/test/features_test.erl
 create mode 100644 config/test-sys.config
 create mode 100644 config/test-vm.args

diff --git a/.gitignore b/.gitignore
index a939dce..d1be8c7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,4 +16,6 @@ _deps
 _plugins
 _tdeps
 logs
-_build
\ No newline at end of file
+_build
+rebar3
+rebar.lock
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..9488840
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,67 @@
+before_script:
+  - rebar3 update
+
+stages:
+  - compile
+  - test
+  - publish
+  - docker
+
+compile:
+  stage: compile
+  script:
+    - rebar3 as production do compile
+
+test:
+  stage: test
+  script:
+    - ERL_AFLAGS="-args_file config/test-vm.args -config config/test-sys.config" rebar3 as test do eunit --cover --application=consul-proxy --dir=apps/consul-proxy/test, cover --verbose
+    - coverage.escript _build/test/cover/eunit.coverdata
+
+publish_hex:
+  stage: publish
+  only:
+    - /^\d+[.]\d+[.]\d+$/ # Only publish HEAD tagged with semantic version
+  script:
+    - mkdir -p ~/.hex && printf "{key,<<\"$HEX_KEY\">>}.\n{username,<<\"$HEX_USERNAME\">>}.\n" > ~/.hex/hex.config
+    - mkdir -p ~/.config/rebar3 && printf "{plugins, [rebar3_hex]}.\n" > ~/.config/rebar3/rebar.config
+    - echo "Y" | rebar3 hex publish
+
+publish_aws:
+  stage: publish
+  only:
+    - /^\d+[.]\d+[.]\d+$/ # Only publish HEAD tagged with semantic version
+  script:
+    - rebar3 edoc
+    - aws s3 cp doc s3://s3.erlang.ninja/consul-proxy/$CI_BUILD_REF_NAME/ --recursive
+    - rebar3 as production do tar
+    - aws s3 cp _build/production/rel/consul-proxy/consul-proxy-$CI_BUILD_REF_NAME.tar.gz s3://s3.erlang.ninja/consul-proxy/
+    - aws s3 cp s3://s3.erlang.ninja/consul-proxy/consul-proxy-$CI_BUILD_REF_NAME.tar.gz s3://s3.erlang.ninja/consul-proxy/consul-proxy-latest.tar.gz
+
+docker_x86:
+  stage: docker
+  only:
+    - master # Only master branch
+  script:
+    - rebar3 as production do release
+    - PLATFORM=x86 envsubst '$PLATFORM' < apps/consul-proxy/priv/Dockerfile > _build/production/Dockerfile
+    - docker build --no-cache=true -t ehedenst/consul-proxy:x86 -f _build/production/Dockerfile _build/production
+    - if [ ! -f ~/.docker/config.json ]; then docker login --username=$DOCKER_HUB_USERNAME --password=$DOCKER_HUB_PASSWORD --email=$DOCKER_HUB_EMAIL; fi
+    - docker push ehedenst/consul-proxy:x86
+  tags:
+    - docker
+    - x86_64
+
+docker_arm:
+  stage: docker
+  only:
+    - master # Only master branch
+  script:
+    - rebar3 as production do release
+    - PLATFORM=arm envsubst '$PLATFORM' < apps/consul-proxy/priv/Dockerfile > _build/production/Dockerfile
+    - docker build --no-cache=true -t ehedenst/consul-proxy:arm -f _build/production/Dockerfile _build/production
+    - if [ ! -f ~/.docker/config.json ]; then docker login --username=$DOCKER_HUB_USERNAME --password=$DOCKER_HUB_PASSWORD --email=$DOCKER_HUB_EMAIL; fi
+    - docker push ehedenst/consul-proxy:arm
+  tags:
+    - docker
+    - armv7l
diff --git a/LICENSE b/LICENSE
index 4f8d9dc..2bf1f48 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,29 +1,21 @@
-Copyright (c) 2016, Erik Hedenström <erik@hedenstroem.com>.
-All rights reserved.
+The MIT License (MIT)
 
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
+Copyright (c) 2016 Erik Hedenström <erik@democra.se>
 
-* Redistributions of source code must retain the above copyright
-  notice, this list of conditions and the following disclaimer.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
 
-* Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
 
-* The names of its contributors may not be used to endorse or promote
-  products derived from this software without specific prior written
-  permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6670b44
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,38 @@
+REBAR_VERSION := $(shell rebar3 --version 2>/dev/null)
+ifdef REBAR_VERSION
+REBAR := rebar3
+else
+REBAR := $(CURDIR)/rebar3
+$(shell if ! [ -e "$(REBAR)" ]; then curl -jksSL -o $(REBAR) https://s3.amazonaws.com/rebar3/rebar3; chmod +x $(REBAR); fi)
+endif
+
+all: eunit
+
+compile:
+	@$(REBAR) compile
+
+eunit:
+	@ERL_AFLAGS="-args_file config/test-vm.args -config config/test-sys.config" $(REBAR) as test do eunit --cover --application=consul-proxy --dir=apps/consul-proxy/test, cover --verbose
+
+dialyzer:
+	@$(REBAR) dialyzer
+
+release:
+	@$(REBAR) release
+
+image:
+	@$(REBAR) release -d false
+	PLATFORM=x86 envsubst '$$PLATFORM' < apps/consul-proxy/priv/Dockerfile > _build/default/Dockerfile
+	docker build --no-cache=true -t ehedenst/consul-proxy:x86 -f _build/default/Dockerfile _build/default
+
+edoc:
+	@$(REBAR) edoc
+
+clean:
+	@$(REBAR) clean
+
+distclean:
+	@rm -rf _build rebar.lock log $(REBAR)
+
+shell:
+	@$(REBAR) shell --config=config/test-sys.config
diff --git a/apps/consul-proxy/include/consul-proxy.hrl b/apps/consul-proxy/include/consul-proxy.hrl
new file mode 100644
index 0000000..7a96c87
--- /dev/null
+++ b/apps/consul-proxy/include/consul-proxy.hrl
@@ -0,0 +1 @@
+-define(APPLICATION, 'consul-proxy').
diff --git a/apps/consul-proxy/priv/Dockerfile b/apps/consul-proxy/priv/Dockerfile
new file mode 100644
index 0000000..3692242
--- /dev/null
+++ b/apps/consul-proxy/priv/Dockerfile
@@ -0,0 +1,20 @@
+FROM        ehedenst/erlang:${PLATFORM}
+MAINTAINER  Erik Hedenström <erik@hedenstroem.com>
+
+ENV NAME_PREFIX consul-proxy
+ENV COOKIE Nax7jEj7bay6ril
+
+RUN apk --update add \
+    erlang-inets=$ERLANG_VERSION \
+    erlang-ssl=$ERLANG_VERSION \
+    erlang-asn1=$ERLANG_VERSION \
+    erlang-observer=$ERLANG_VERSION \
+    erlang-public-key=$ERLANG_VERSION && \
+    rm -rf /var/cache/apk/*
+
+COPY rel/consul-proxy /opt/consul-proxy
+
+EXPOSE 80 443
+
+ENTRYPOINT [ "/opt/consul-proxy/bin/consul-proxy-wrapper" ]
+CMD [ "foreground" ]
diff --git a/apps/consul-proxy/priv/consul-proxy-wrapper b/apps/consul-proxy/priv/consul-proxy-wrapper
new file mode 100755
index 0000000..4173351
--- /dev/null
+++ b/apps/consul-proxy/priv/consul-proxy-wrapper
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+set -e
+
+SCRIPT=$(readlink $0 || true)
+if [ -z $SCRIPT ]; then
+    SCRIPT=$0
+fi;
+SCRIPT_DIR="$(cd `dirname "$SCRIPT"` && pwd -P)"
+
+if [ -z "$NAME_PREFIX" ]; then
+    NAME_PREFIX="consul-proxy-$(openssl rand -hex 4)"
+fi
+
+if [ -z "$COOKIE" ]; then
+    export COOKIE=$(openssl rand -hex 16)
+fi
+
+if [ -z "$HOST_IP" ]; then
+    HOST_IP=$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p' | head -n 1)
+fi
+
+export RELX_REPLACE_OS_VARS=true
+export NODE_NAME=${NAME_PREFIX}@${HOST_IP}
+
+echo "Starting ${NODE_NAME} with cookie ${COOKIE}"
+
+${SCRIPT_DIR}/consul-proxy $@
diff --git a/apps/consul-proxy/src/consul-proxy.app.src b/apps/consul-proxy/src/consul-proxy.app.src
index 928a047..865972d 100644
--- a/apps/consul-proxy/src/consul-proxy.app.src
+++ b/apps/consul-proxy/src/consul-proxy.app.src
@@ -1,16 +1,20 @@
-{application, 'consul-proxy',
- [{description, "An OTP application"},
-  {vsn, "0.1.0"},
-  {registered, []},
-  {mod, {'consul-proxy_app', []}},
-  {applications,
-   [kernel,
-    stdlib
-   ]},
-  {env,[]},
-  {modules, []},
-
-  {contributors, []},
-  {licenses, []},
-  {links, []}
- ]}.
+{application, 'consul-proxy', [
+    {description, "Proxy for docker swarm using consul and vegur"},
+    {vsn, "0.1.0"},
+    {registered, []},
+    {mod, {'consul-proxy_app', []}},
+    {applications, [
+        kernel,
+        stdlib,
+        sasl,
+        inets,
+        lager,
+        tsuru
+    ]},
+    {env, []},
+    {modules, []},
+    {maintainers, ["Erik Hedenstrom"]},
+    {contributors, []},
+    {licenses, ["MIT"]},
+    {links, [{"GitLab", "https://gitlab.hedenstroem.com/erlang-ninja/consul-proxy"}]}
+]}.
diff --git a/apps/consul-proxy/src/consul-proxy_app.erl b/apps/consul-proxy/src/consul-proxy_app.erl
index af8717e..c4d65d5 100644
--- a/apps/consul-proxy/src/consul-proxy_app.erl
+++ b/apps/consul-proxy/src/consul-proxy_app.erl
@@ -15,8 +15,9 @@
 %% API
 %%====================================================================
 
-start(_StartType, _StartArgs) ->
-    'consul-proxy_sup':start_link().
+start(_StartType, StartArgs) ->
+    tsuru_application:set_env('consul-proxy'),
+    'consul-proxy_sup':start_link(StartArgs).
 
 %%--------------------------------------------------------------------
 stop(_State) ->
diff --git a/apps/consul-proxy/src/consul-proxy_sup.erl b/apps/consul-proxy/src/consul-proxy_sup.erl
index 5310530..afdf97b 100644
--- a/apps/consul-proxy/src/consul-proxy_sup.erl
+++ b/apps/consul-proxy/src/consul-proxy_sup.erl
@@ -8,7 +8,7 @@
 -behaviour(supervisor).
 
 %% API
--export([start_link/0]).
+-export([start_link/1]).
 
 %% Supervisor callbacks
 -export([init/1]).
@@ -19,16 +19,23 @@
 %% API functions
 %%====================================================================
 
-start_link() ->
-    supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+start_link(Args) ->
+    supervisor:start_link({local, ?SERVER}, ?MODULE, Args).
 
 %%====================================================================
 %% Supervisor callbacks
 %%====================================================================
 
 %% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
-init([]) ->
-    {ok, { {one_for_all, 0, 1}, []} }.
+init(_Args) ->
+
+    SupFlags = #{
+        strategy => one_for_one,
+        intensity => 10,
+        period => 10
+    },
+
+    {ok, {SupFlags, []}}.
 
 %%====================================================================
 %% Internal functions
diff --git a/apps/consul-proxy/test/features_test.erl b/apps/consul-proxy/test/features_test.erl
new file mode 100644
index 0000000..457c303
--- /dev/null
+++ b/apps/consul-proxy/test/features_test.erl
@@ -0,0 +1,16 @@
+-module(features_test).
+
+-include_lib("eunit/include/eunit.hrl").
+
+features_test_() ->
+    setup(),
+    Features = fun() ->
+        filelib:fold_files("features", ".*[.]feature", true, fun(File, Files) -> [File | Files] end, [])
+               end,
+    gurka_eunit:setup(Features, fun teardown/1).
+
+setup() ->
+    lager:start().
+
+teardown(_) ->
+    ok.
diff --git a/config/sys.config b/config/sys.config
index 266026b..b590738 100644
--- a/config/sys.config
+++ b/config/sys.config
@@ -1,3 +1,31 @@
 [
-  {'consul-proxy', []}
+    {kernel, [
+        {start_timer, true},
+        {inet_default_listen_options, [{nodelay, true}, {sndbuf, 32768}, {recbuf, 32768}]},
+        {inet_default_connect_options, [{delay_send, true}]}
+    ]},
+    {sasl, [
+        {sasl_error_logger, {file, "log/sasl-error.log"}},
+        {errlog_type, error},
+        {error_logger_mf_dir, "log/sasl"},
+        {error_logger_mf_maxbytes, 10485760},
+        {error_logger_mf_maxfiles, 5},
+        {utc_log, true}
+    ]},
+    {lager, [
+        {colored, true},
+        {handlers, [
+            {lager_console_backend, [info, {lager_default_formatter, [color, time, " {", {module, "?"}, ":", {line, "?"}, "} ", pid, " [", severity, "] ", message, "\n"]}]},
+            {lager_file_backend, [{file, "log/error.log"}, {level, error}, {size, 10485760}, {date, "$D0"}, {count, 5}]},
+            {lager_file_backend, [{file, "log/console.log"}, {level, info}, {size, 10485760}, {date, "$D0"}, {count, 5}]}
+        ]},
+        {crash_log, "log/crash.log"},
+        {crash_log_msg_size, 65536},
+        {crash_log_size, 10485760},
+        {crash_log_date, "$D0"},
+        {crash_log_count, 5},
+        {error_logger_redirect, true}
+    ]},
+    {'consul-proxy', [
+    ]}
 ].
diff --git a/config/test-sys.config b/config/test-sys.config
new file mode 100644
index 0000000..ab62773
--- /dev/null
+++ b/config/test-sys.config
@@ -0,0 +1,29 @@
+[
+    {kernel, [
+        {start_timer, true},
+        {inet_default_listen_options, [{nodelay, true}, {sndbuf, 32768}, {recbuf, 32768}]},
+        {inet_default_connect_options, [{delay_send, true}]}
+    ]},
+    {sasl, [
+        {sasl_error_logger, {file, "log/sasl-error.log"}},
+        {errlog_type, error},
+        {error_logger_mf_dir, "log/sasl"},
+        {error_logger_mf_maxbytes, 10485760},
+        {error_logger_mf_maxfiles, 5},
+        {utc_log, true}
+    ]},
+    {lager, [
+        {colored, true},
+        {handlers, [
+            {lager_console_backend, [debug, {lager_default_formatter, [color, time, " {", {module, "?"}, ":", {line, "?"}, "} ", pid, " [", severity, "] ", message, "\n"]}]}
+        ]},
+        {crash_log, "log/crash.log"},
+        {crash_log_msg_size, 65536},
+        {crash_log_size, 10485760},
+        {crash_log_date, "$D0"},
+        {crash_log_count, 5},
+        {error_logger_redirect, true}
+    ]},
+    {'consul-proxy', [
+    ]}
+].
diff --git a/config/test-vm.args b/config/test-vm.args
new file mode 100644
index 0000000..dbfc87f
--- /dev/null
+++ b/config/test-vm.args
@@ -0,0 +1,19 @@
+## Name of the node
+-name consul-proxy@127.0.01
+
+## Cookie for distributed erlang
+-setcookie Nax7jEj7bay6ril
+
+## Enable kernel poll and a few async threads
++K true
++A 64
++P 262144
+
+## enable smp support
+-smp auto
+
+## Increase number of concurrent ports/sockets
+-env ERL_MAX_PORTS 16384
+
+## Tweak GC to run more often
+-env ERL_FULLSWEEP_AFTER 10
diff --git a/config/vm.args b/config/vm.args
index 7f923d1..3394a1a 100644
--- a/config/vm.args
+++ b/config/vm.args
@@ -1,6 +1,19 @@
--sname consul-proxy
+## Name of the node
+-name ${NODE_NAME}
 
--setcookie consul-proxy_cookie
+## Cookie for distributed erlang
+-setcookie ${COOKIE}
 
+## Enable kernel poll and a few async threads
 +K true
-+A30
++A 64
++P 262144
+
+## enable smp support
+-smp auto
+
+## Increase number of concurrent ports/sockets
+-env ERL_MAX_PORTS 16384
+
+## Tweak GC to run more often
+-env ERL_FULLSWEEP_AFTER 10
diff --git a/rebar.config b/rebar.config
index dee631f..506cd39 100644
--- a/rebar.config
+++ b/rebar.config
@@ -1,20 +1,39 @@
-{erl_opts, [debug_info]}.
-{deps, []}.
+{erl_opts, [{parse_transform, lager_transform}]}.
 
-{relx, [{release, {'consul-proxy', "0.1.0"},
-         ['consul-proxy',
-          sasl]},
+{eunit_opts, [{report, {eunit_surefire, [{dir, "_build/test"}]}}]}.
 
-        {sys_config, "./config/sys.config"},
-        {vm_args, "./config/vm.args"},
+{edoc_opts, []}.
 
-        {dev_mode, true},
-        {include_erts, false},
+{deps, [
+    {lager, "3.0.2"},
+    {tsuru, "1.0.2"},
+    {vegur, {git, "https://github.com/heroku/vegur.git", {branch, "master"}}}
+]}.
 
-        {extended_start_script, true}]
-}.
+{relx, [
+    {release, {'consul-proxy', "0.1.0"}, ['consul-proxy']},
+    {sys_config, "./config/sys.config"},
+    {vm_args, "./config/vm.args"},
+    {dev_mode, true},
+    {include_erts, false},
+    {extended_start_script, true},
+    {overlay, [
+        {copy, "apps/consul-proxy/priv/consul-proxy-wrapper", "bin/consul-proxy-wrapper"}
+    ]}
+]}.
 
-{profiles, [{prod, [{relx, [{dev_mode, false},
-                            {include_erts, true}]}]
-            }]
-}.
+{profiles, [
+    {test, [
+        {deps, [
+            {gurka, "0.1.3"}
+        ]},
+        {erl_opts, [debug_info, nowarn_unused_vars]}
+    ]},
+    {prod, [
+        {relx, [
+            {dev_mode, false},
+            {include_erts, false}
+        ]},
+        {erl_opts, [no_debug_info, warnings_as_errors]}
+    ]}
+]}.
-- 
GitLab