From 719f33545771ee4f0d370e79adb9bedbbdfe44c7 Mon Sep 17 00:00:00 2001 From: vixns Date: Fri, 29 Dec 2017 18:15:23 +0100 Subject: [PATCH] Upgrade to haproxy 1.8.2 (#527) * Upgrade to haproxy 1.8.1 * Use haproxy's new master worker, remove old iptables / sleep / lock hacks. * :bangbang: BREAKING CHANGE: you _must_ remove "daemon" form your custom HAPROXY_HEAD templates. * upgrade libssl to version 1.1 * bump to haproxy 1.8.2 * use the default gpg keyserver --- Dockerfile | 15 +++-- Longhelp.md | 5 +- config.py | 3 +- haproxy_wrapper.py | 70 ---------------------- run | 1 + service/haproxy/run | 73 +---------------------- tests/test_marathon_lb.py | 3 +- tests/test_marathon_lb_haproxy_options.py | 3 +- 8 files changed, 15 insertions(+), 158 deletions(-) delete mode 100755 haproxy_wrapper.py diff --git a/Dockerfile b/Dockerfile index 16869e90..d6ebaa0c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,19 +4,18 @@ FROM debian:buster RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ inetutils-syslogd \ - iptables \ libcurl3 \ liblua5.3-0 \ - libssl1.0.2 \ + libssl1.1 \ openssl \ procps \ python3 \ runit \ gnupg-agent \ - socat \ + socat \ && rm -rf /var/lib/apt/lists/* -ENV TINI_VERSION=v0.13.2 \ +ENV TINI_VERSION=v0.16.1 \ TINI_GPG_KEY=595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7 RUN set -x \ && apt-get update && apt-get install -y --no-install-recommends dirmngr gpg wget \ @@ -24,7 +23,7 @@ RUN set -x \ && wget -O tini "https://github.com/krallin/tini/releases/download/$TINI_VERSION/tini-amd64" \ && wget -O tini.asc "https://github.com/krallin/tini/releases/download/$TINI_VERSION/tini-amd64.asc" \ && export GNUPGHOME="$(mktemp -d)" \ - && gpg --keyserver hkps://hkps.pool.sks-keyservers.net --recv-keys "$TINI_GPG_KEY" \ + && gpg --recv-keys "$TINI_GPG_KEY" \ && gpg --batch --verify tini.asc tini \ && rm -rf "$GNUPGHOME" tini.asc \ && mv tini /usr/bin/tini \ @@ -33,9 +32,9 @@ RUN set -x \ && apt-get purge -y --auto-remove dirmngr gpg wget -ENV HAPROXY_MAJOR=1.7 \ - HAPROXY_VERSION=1.7.6 \ - HAPROXY_MD5=8f4328cf66137f0dbf6901e065f603cc +ENV HAPROXY_MAJOR=1.8 \ + HAPROXY_VERSION=1.8.2 \ + HAPROXY_MD5=5e72829793e163bea93da1df6b4aaa1e COPY requirements.txt /marathon-lb/ diff --git a/Longhelp.md b/Longhelp.md index 1ccc9a95..1dd1cbc8 100644 --- a/Longhelp.md +++ b/Longhelp.md @@ -58,7 +58,7 @@ optional arguments: every --reload-interval seconds. Set to 0 to disable or -1 for infinite retries. (default: 10) --reload-interval RELOAD_INTERVAL - Wait this number of seconds betwee nreload retries. + Wait this number of seconds between reload retries. (default: 10) --strict-mode If set, backends are only advertised if HAPROXY_{n}_ENABLED=true. Strict mode will be enabled @@ -367,7 +367,6 @@ and defaults. **Default template for `HAPROXY_HEAD`:** ``` global - daemon log /dev/log local0 log /dev/log local1 notice spread-checks 5 @@ -378,7 +377,7 @@ global ssl-default-bind-options no-sslv3 no-tlsv10 no-tls-tickets ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:!aNULL:!MD5:!DSS ssl-default-server-options no-sslv3 no-tlsv10 no-tls-tickets - stats socket /var/run/haproxy/socket + stats socket /var/run/haproxy/socket expose-fd listeners server-state-file global server-state-base /var/state/haproxy/ lua-load /marathon-lb/getpids.lua diff --git a/config.py b/config.py index 5f291128..9a64221e 100644 --- a/config.py +++ b/config.py @@ -33,7 +33,6 @@ def load(self): ConfigTemplate(name='HEAD', value='''\ global - daemon log /dev/log local0 log /dev/log local1 notice spread-checks 5 @@ -56,7 +55,7 @@ def load(self): DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:\ AES256-SHA256:!aNULL:!MD5:!DSS ssl-default-server-options no-sslv3 no-tlsv10 no-tls-tickets - stats socket /var/run/haproxy/socket + stats socket /var/run/haproxy/socket expose-fd listeners server-state-file global server-state-base /var/state/haproxy/ lua-load /marathon-lb/getpids.lua diff --git a/haproxy_wrapper.py b/haproxy_wrapper.py deleted file mode 100755 index e8698df1..00000000 --- a/haproxy_wrapper.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python3 -import os -import sys -import time -import errno -import logging - -logger = logging.getLogger('haproxy_wrapper') -logger.setLevel(getattr(logging, 'DEBUG')) -formatter = logging.Formatter("%(asctime)-15s %(name)s: %(message)s") -consoleHandler = logging.StreamHandler() -consoleHandler.setFormatter(formatter) -logger.addHandler(consoleHandler) - - -def create_haproxy_pipe(): - logger.debug("create_haproxy_pipe called") - pipefd = os.pipe() - os.set_inheritable(pipefd[0], True) - os.set_inheritable(pipefd[1], True) - logger.debug("create_haproxy_pipe done") - return pipefd - - -def close_and_swallow(fd): - logger.debug("close_and_swallow called") - try: - os.close(fd) - logger.debug("close_and_swallow successful") - except OSError as e: - # swallow - logger.debug("close_and_swallow swallow OSError: %s", e) - pass - - -def wait_on_haproxy_pipe(pipefd): - logger.debug("wait_on_haproxy_pipe called") - try: - ret = os.read(pipefd[0], 1) - if len(ret) == 0: - close_and_swallow(pipefd[0]) - close_and_swallow(pipefd[1]) - logger.debug("wait_on_haproxy_pipe done (False)") - return False - except OSError as e: - logger.debug("wait_on_haproxy_pipe OSError: %s", e) - if e.args[0] != errno.EINTR: - close_and_swallow(pipefd[0]) - close_and_swallow(pipefd[1]) - logger.debug("wait_on_haproxy_pipe done (False)") - return False - logger.debug("wait_on_haproxy_pipe done (True)") - return True - - -pipefd = create_haproxy_pipe() - -pid = os.fork() - -if not pid: - os.environ["HAPROXY_WRAPPER_FD"] = str(pipefd[1]) - # Close the read side - os.close(pipefd[0]) - os.execv(sys.argv[1], sys.argv[1:]) - -# Close the write side -os.close(pipefd[1]) -while wait_on_haproxy_pipe(pipefd): - time.sleep(0.005) -sys.exit(0) diff --git a/run b/run index eaf0f52a..cef5117e 100755 --- a/run +++ b/run @@ -121,6 +121,7 @@ done cat > $LB_SERVICE/run << EOF #!/bin/sh exec 2>&1 +sv status /marathon-lb/service/haproxy || exit 1 cd /marathon-lb exec /marathon-lb/marathon_lb.py \ --syslog-socket $SYSLOG_SOCKET \ diff --git a/service/haproxy/run b/service/haproxy/run index b902f24d..0a5487fa 100755 --- a/service/haproxy/run +++ b/service/haproxy/run @@ -1,78 +1,9 @@ #!/bin/bash exec 2>&1 export PIDFILE="/tmp/haproxy.pid" - -LOG_PREFIX="$(pwd) $0" -log() { - logline="[$LOG_PREFIX] $1\n" - printf "$logline" >&1 -} -log_error() { - logline="[$LOG_PREFIX] $1\n" - printf "$logline" >&1 - printf "$logline" >&2 -} - -addFirewallRules() { - IFS=',' read -ra ADDR <<< "$PORTS" - for i in "${ADDR[@]}"; do - iptables -w -I INPUT -p tcp --dport $i --syn -j DROP - done -} - -removeFirewallRules() { - IFS=',' read -ra ADDR <<< "$PORTS" - for i in "${ADDR[@]}"; do - while iptables -w -D INPUT -p tcp --dport $i --syn -j DROP 2>/dev/null; do :; done - done -} - -reload() { - log "Reloading haproxy" - - ( - flock 200 - - log "Dropping SYN packets with addFirewallRules" - addFirewallRules - - # Wait to settle - sleep 0.1 - log "addFirewallRules done" - - log "Saving the current HAProxy state" - socat /var/run/haproxy/socket - <<< "show servers state" > /var/state/haproxy/global - log "Done saving the current HAProxy state" - - # Trigger reload - LATEST_HAPROXY_PID=$(cat $PIDFILE) - log "LATEST_HAPROXY_PID: [$LATEST_HAPROXY_PID]" - - WHICH_HAPROXY=$(which haproxy) - - log "/marathon-lb/haproxy_wrapper.py $WHICH_HAPROXY -D -p $PIDFILE -f /marathon-lb/haproxy.cfg -sf $LATEST_HAPROXY_PID 200>&-" - /marathon-lb/haproxy_wrapper.py $WHICH_HAPROXY -D -p $PIDFILE -f /marathon-lb/haproxy.cfg -sf $LATEST_HAPROXY_PID 200>&- - local exit_code=$? - log "exit code: $exit_code" - if [ $exit_code -ne 0 ]; then - log_error "HAProxy reload failed" - fi - - log "Removing firewall rules with removeFirewallRules" - removeFirewallRules - log "removeFirewallRules done" - - # Need to wait 1s to prevent TCP SYN exponential backoff - sleep 1 - - log "Reload finished" - ) 200>/var/run/haproxy/lock -} +WHICH_HAPROXY=$(which haproxy) mkdir -p /var/state/haproxy mkdir -p /var/run/haproxy -reload - -trap reload SIGHUP -while true; do sleep 0.5; done +exec $WHICH_HAPROXY -W -p $PIDFILE -f /marathon-lb/haproxy.cfg -x /var/run/haproxy/socket -sf \ No newline at end of file diff --git a/tests/test_marathon_lb.py b/tests/test_marathon_lb.py index fc02c41e..e96984ab 100644 --- a/tests/test_marathon_lb.py +++ b/tests/test_marathon_lb.py @@ -12,7 +12,6 @@ def setUp(self): if 'HAPROXY_GLOBAL_DEFAULT_OPTIONS' in os.environ: del os.environ['HAPROXY_GLOBAL_DEFAULT_OPTIONS'] self.base_config = '''global - daemon log /dev/log local0 log /dev/log local1 notice spread-checks 5 @@ -35,7 +34,7 @@ def setUp(self): DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:\ AES256-SHA256:!aNULL:!MD5:!DSS ssl-default-server-options no-sslv3 no-tlsv10 no-tls-tickets - stats socket /var/run/haproxy/socket + stats socket /var/run/haproxy/socket expose-fd listeners server-state-file global server-state-base /var/state/haproxy/ lua-load /marathon-lb/getpids.lua diff --git a/tests/test_marathon_lb_haproxy_options.py b/tests/test_marathon_lb_haproxy_options.py index f23be4fb..5e7b474b 100644 --- a/tests/test_marathon_lb_haproxy_options.py +++ b/tests/test_marathon_lb_haproxy_options.py @@ -8,7 +8,6 @@ def template_option(opt): base_config_prefix = '''global - daemon log /dev/log local0 log /dev/log local1 notice spread-checks 5 @@ -31,7 +30,7 @@ def template_option(opt): DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:\ AES256-SHA256:!aNULL:!MD5:!DSS ssl-default-server-options no-sslv3 no-tlsv10 no-tls-tickets - stats socket /var/run/haproxy/socket + stats socket /var/run/haproxy/socket expose-fd listeners server-state-file global server-state-base /var/state/haproxy/ lua-load /marathon-lb/getpids.lua