From 8d043ad40b3269825c2e3f37f52bbbeeefc2498c Mon Sep 17 00:00:00 2001 From: flopez Date: Tue, 7 May 2019 09:55:29 -0400 Subject: [PATCH] Use uwsgi instead of gunicorn This will allow us to add healthcheck to the netman container and not to log healthcheck calls. --- Dockerfile | 20 +++++++++++-------- constraints.txt | 1 + netman/main.py | 12 ++++++++++- requirements.txt | 1 + test-constraints.txt | 1 + test-requirements.txt | 1 + tests/system_tests/__init__.py | 2 +- ...lty_test.py => uwsgi_compatibilty_test.py} | 19 +++++++++--------- uwsgi.ini | 19 ++++++++++++++++++ 9 files changed, 56 insertions(+), 20 deletions(-) rename tests/system_tests/{gunicorn_compatibilty_test.py => uwsgi_compatibilty_test.py} (64%) create mode 100644 uwsgi.ini diff --git a/Dockerfile b/Dockerfile index 8e15a0d..15b5486 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,22 @@ FROM python:2.7-alpine -RUN apk update && apk add --no-cache python-dev gcc git g++ make libffi-dev openssl-dev libxml2 libxml2-dev libxslt libxslt-dev +ENV APP_EXPOSED_PORT 5000 -RUN mkdir -p /usr/src/app -WORKDIR /usr/src/app +RUN apk update && apk add --no-cache python-dev gcc git g++ make libffi-dev openssl-dev pcre-dev libxml2 libxml2-dev libxslt libxslt-dev curl -COPY requirements.txt /usr/src/app/ +ENV APP_ROOT /usr/src/app + +RUN mkdir -p $APP_ROOT +WORKDIR $APP_ROOT + +COPY requirements.txt $APP_ROOT RUN pip install --no-cache-dir -r requirements.txt -COPY . /usr/src/app +COPY . $APP_ROOT RUN PBR_VERSION=0.0.0 pip install . -EXPOSE 5000 -ENTRYPOINT [ "python" ] +EXPOSE $APP_EXPOSED_PORT -CMD [ "netman/main.py", "--host=0.0.0.0"] \ No newline at end of file +HEALTHCHECK --interval=5s --timeout=3s CMD curl --fail http://localhost:$APP_EXPOSED_PORT/healthcheck +ENTRYPOINT uwsgi --ini uwsgi.ini diff --git a/constraints.txt b/constraints.txt index d0ec9a3..529ec0f 100644 --- a/constraints.txt +++ b/constraints.txt @@ -31,4 +31,5 @@ requests==2.21.0 selectors2==2.0.1 # via ncclient six==1.12.0 # via bcrypt, cryptography, ncclient, pynacl urllib3==1.24.1 # via requests +uwsgi==2.0.18 werkzeug==0.14.1 # via flask diff --git a/netman/main.py b/netman/main.py index ca18f39..160cfad 100644 --- a/netman/main.py +++ b/netman/main.py @@ -13,9 +13,10 @@ # limitations under the License. import argparse +import json from logging import DEBUG, getLogger -from flask import request +from flask import make_response, request from flask.app import Flask from adapters.threading_lock_factory import ThreadingLockFactory @@ -40,6 +41,15 @@ def log_request(): logger.debug("Headers : " + ", ".join(["{0}={1}".format(h[0], h[1]) for h in request.headers])) +@app.route('/healthcheck') +def healthcheck(): + return make_response(( + json.dumps(dict(running=True)), + 200, + {'Content-Type': 'application/json'} + )) + + lock_factory = ThreadingLockFactory() switch_factory = FlowControlSwitchFactory(MemoryStorage(), lock_factory) real_switch_factory = RealSwitchFactory() diff --git a/requirements.txt b/requirements.txt index 63e5e26..68bc5dd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ netaddr>=0.7.13 ncclient>=0.5.0 requests>=2.6.2 pyeapi +uwsgi diff --git a/test-constraints.txt b/test-constraints.txt index 92beab2..c06c5f3 100644 --- a/test-constraints.txt +++ b/test-constraints.txt @@ -67,5 +67,6 @@ sphinxcontrib-httpdomain==1.7.0 tftpy==0.8.0 # via fake-switches twisted[conch]==16.6.0 # via fake-switches, mockssh urllib3==1.24.1 +uwsgi==2.0.18 werkzeug==0.14.1 zope.interface==4.6.0 # via twisted diff --git a/test-requirements.txt b/test-requirements.txt index c09cd1e..19f3f29 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -8,3 +8,4 @@ gunicorn>=19.4.5 flake8==3.4.1 futures; # Runtime dependency of gunicorn jabstract +uwsgi diff --git a/tests/system_tests/__init__.py b/tests/system_tests/__init__.py index 2586c0d..b700a79 100644 --- a/tests/system_tests/__init__.py +++ b/tests/system_tests/__init__.py @@ -43,7 +43,7 @@ def _start(self, path): params = self._popen_params(path) logging.info("starting netman : \"{}\"".format('" "'.join(params))) - self.proc = subprocess.Popen(params, stderr=subprocess.STDOUT, stdout=subprocess.PIPE) + self.proc = subprocess.Popen(params) self._wait_until_port_is_opened(self.port) def _stop(self): diff --git a/tests/system_tests/gunicorn_compatibilty_test.py b/tests/system_tests/uwsgi_compatibilty_test.py similarity index 64% rename from tests/system_tests/gunicorn_compatibilty_test.py rename to tests/system_tests/uwsgi_compatibilty_test.py index 363308f..c956463 100644 --- a/tests/system_tests/gunicorn_compatibilty_test.py +++ b/tests/system_tests/uwsgi_compatibilty_test.py @@ -4,14 +4,14 @@ import sys from hamcrest import assert_that, less_than from hamcrest import is_ -import os +from os.path import dirname, join from tests.system_tests import NetmanTestApp, create_session, get_available_switch -class GunicornCompatibilityTest(unittest.TestCase): - def test_run_netman_with_a_gunicorn_wrapper(self): - with GunicornNetmanTestApp() as partial_client: +class UwsgiCompatibilityTest(unittest.TestCase): + def test_run_netman_with_a_uwsgi_wrapper(self): + with UwsgiNetmanTestApp() as partial_client: client = partial_client(get_available_switch("cisco")) create_session(client, "my_session") @@ -20,7 +20,7 @@ def test_run_netman_with_a_gunicorn_wrapper(self): assert_that(result.status_code, is_(204), result.text) def test_parameters_can_be_passed_through_the_command_line(self): - with GunicornNetmanTestApp() as partial_client: + with UwsgiNetmanTestApp() as partial_client: client = partial_client(get_available_switch("brocade")) start_time = time.time() @@ -34,11 +34,10 @@ def test_parameters_can_be_passed_through_the_command_line(self): assert_that(time.time() - start_time, is_(less_than(3))) -class GunicornNetmanTestApp(NetmanTestApp): +class UwsgiNetmanTestApp(NetmanTestApp): def _popen_params(self, path): - gunicorn_executable = os.path.join(os.path.dirname(sys.executable), 'gunicorn') - params = [gunicorn_executable, - "netman.main:load_app(session_inactivity_timeout={})".format(self.session_inactivity_timeout), - "--bind", "{}:{}".format(self.ip, self.port), + uwsgi_executable = join(dirname(sys.executable), 'uwsgi') + params = [uwsgi_executable, "--module", "netman.main:app", + "--http", "{}:{}".format(self.ip, self.port), "--threads", "2"] return params diff --git a/uwsgi.ini b/uwsgi.ini new file mode 100644 index 0000000..cdf4a87 --- /dev/null +++ b/uwsgi.ini @@ -0,0 +1,19 @@ +[uwsgi] + +# Flask wsgi file +module = netman.main:app + +# process-related settings +master = true +processes = 1 +threads = 2 +lazy-apps = true +# clear environment on exit +vacuum = true + +http = 0.0.0.0:$(APP_EXPOSED_PORT) +http-timeout = 60 +no-orphans = true +die-on-term = true + +log-drain = GET /healthcheck