diff --git a/.gitignore b/.gitignore index a939dce30324c1f8dc1b16110f678177057a4637..d1be8c7e288e1154a8d1eafd9306c892832f547a 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 0000000000000000000000000000000000000000..94888404a044597a76d1a749e2c9bce9e64573c6 --- /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 4f8d9dc730b913b6c12b6dafec7ad745971f1bea..2bf1f48e24b43b6f402f1b1e5a8b7753ef827585 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 0000000000000000000000000000000000000000..6670b4488752aacd34e50718ad0f27cf1479e790 --- /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 0000000000000000000000000000000000000000..7a96c87001a1a2b5332a62b5b18b3f45f405a4a7 --- /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 0000000000000000000000000000000000000000..3692242fa7733fd8a7b4c35f0bc532e297255b86 --- /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 0000000000000000000000000000000000000000..41733518d2e9a0b449c68da0004f7a962a7f336f --- /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 928a0473bee2228a1096ec1d1f9386048917e6cb..865972d765cc3d5f1315f8f123d122a5b85604df 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 af8717e63d7e262716e4d4dc833f2b873df16baf..c4d65d5202da3be2898155f30b1a45c7b6ab2446 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 5310530fc4b11203b361dd1ac8117358b4691d9e..afdf97b55bdd3800ed77cfad2688bc164e55b378 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 0000000000000000000000000000000000000000..457c303c3b4c07f7790e0a968e74b8abae97ef96 --- /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 266026b2d3e465bf9e3f29b10a2715d93f16c381..b590738204facf8cb7c8126e6f01a8eadd79b1aa 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 0000000000000000000000000000000000000000..ab6277330b299b69ca9793606bc2ee50f543e7ee --- /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 0000000000000000000000000000000000000000..dbfc87f76dcdccd0f0a4b4eef49fa89730494eb4 --- /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 7f923d12449eeff68be47cdbf396b46643896836..3394a1a741197be045d0245e96af91904da9eff3 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 dee631fe2118b7ab8a04f1ed50ea57eece022a68..506cd390c4628d578675fbe4a63a883b3ee05cee 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]} + ]} +]}.