From fd7b211d26dcab44cb46dcbaa40fd93069ab2a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Mon, 3 Jun 2024 15:38:21 +0200 Subject: [PATCH] Allow the usage of gunicorn.conf.py config file in gunicorn applications Fixes: #599 --- .../.gitignore | 57 +++++++++++++++++++ .../gunicorn-using-configfile-test-app/app.py | 4 ++ .../gunicorn.conf.py | 6 ++ .../requirements.txt | 1 + manifest-minimal.yml | 3 + manifest.yml | 3 + src/s2i/bin/run | 16 ++++++ test/run | 2 +- 8 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 examples/gunicorn-using-configfile-test-app/.gitignore create mode 100644 examples/gunicorn-using-configfile-test-app/app.py create mode 100644 examples/gunicorn-using-configfile-test-app/gunicorn.conf.py create mode 100644 examples/gunicorn-using-configfile-test-app/requirements.txt diff --git a/examples/gunicorn-using-configfile-test-app/.gitignore b/examples/gunicorn-using-configfile-test-app/.gitignore new file mode 100644 index 00000000..ba746605 --- /dev/null +++ b/examples/gunicorn-using-configfile-test-app/.gitignore @@ -0,0 +1,57 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ diff --git a/examples/gunicorn-using-configfile-test-app/app.py b/examples/gunicorn-using-configfile-test-app/app.py new file mode 100644 index 00000000..09fee1b7 --- /dev/null +++ b/examples/gunicorn-using-configfile-test-app/app.py @@ -0,0 +1,4 @@ + +def application(environ, start_response): + start_response('200 OK', [('Content-Type','text/plain')]) + return [b"Hello from gunicorn WSGI application!"] diff --git a/examples/gunicorn-using-configfile-test-app/gunicorn.conf.py b/examples/gunicorn-using-configfile-test-app/gunicorn.conf.py new file mode 100644 index 00000000..bcb267f6 --- /dev/null +++ b/examples/gunicorn-using-configfile-test-app/gunicorn.conf.py @@ -0,0 +1,6 @@ +import multiprocessing + +bind = "0.0.0.0:8085" +workers = multiprocessing.cpu_count() * 2 + 1 + +wsgi_app = "app:application" diff --git a/examples/gunicorn-using-configfile-test-app/requirements.txt b/examples/gunicorn-using-configfile-test-app/requirements.txt new file mode 100644 index 00000000..b0d8963f --- /dev/null +++ b/examples/gunicorn-using-configfile-test-app/requirements.txt @@ -0,0 +1 @@ +gunicorn>=20.1.0; python_version >= '3.5' diff --git a/manifest-minimal.yml b/manifest-minimal.yml index 91c2e9fa..4ea981c5 100644 --- a/manifest-minimal.yml +++ b/manifest-minimal.yml @@ -142,6 +142,9 @@ SYMLINK_RULES: - src: ../../examples/gunicorn-config-different-port-test-app dest: test/gunicorn-config-different-port-test-app + - src: ../../examples/gunicorn-using-configfile-test-app + dest: test/gunicorn-using-configfile-test-app + - src: ../../examples/locale-test-app dest: test/locale-test-app diff --git a/manifest.yml b/manifest.yml index 9e71f094..45c1dbc8 100644 --- a/manifest.yml +++ b/manifest.yml @@ -141,6 +141,9 @@ SYMLINK_RULES: - src: ../../examples/gunicorn-config-different-port-test-app dest: test/gunicorn-config-different-port-test-app + - src: ../../examples/gunicorn-using-configfile-test-app + dest: test/gunicorn-using-configfile-test-app + - src: ../../examples/locale-test-app dest: test/locale-test-app diff --git a/src/s2i/bin/run b/src/s2i/bin/run index 2a982cd1..56e03a1e 100755 --- a/src/s2i/bin/run +++ b/src/s2i/bin/run @@ -49,6 +49,22 @@ function maybe_run_in_init_wrapper() { fi } +# Look for gunicorn>=20.1.0 to utilize gunicorn.conf.py +if is_gunicorn_installed && [[ -f "gunicorn.conf.py" ]]; then + python -c 'import gunicorn +ver = gunicorn.version_info +if (ver[0] >= 20 and ver[1] >= 1) or ver[0] > 20: + exit(0)' + ret=$? + grep -q "wsgi_app" gunicorn.conf.py + grep_result=$? + if [[ $ret -eq 0 ]] && [[ -f "gunicorn.conf.py" ]] && [[ $grep_result -eq 0 ]]; then + echo "--> Using gunicorn.conf.py" + echo "---> Serving application with gunicorn ..." + exec gunicorn + fi +fi + APP_HOME=$(readlink -f "${APP_HOME:-.}") # Change the working directory to APP_HOME PYTHONPATH="$(pwd)${PYTHONPATH:+:$PYTHONPATH}" diff --git a/test/run b/test/run index f0d50c67..563b717e 100755 --- a/test/run +++ b/test/run @@ -6,7 +6,7 @@ # IMAGE_NAME specifies a name of the candidate image used for testing. # The image has to be available before this script is executed. # -declare -a COMMON_WEB_APPS=({gunicorn-config-different-port,gunicorn-different-port,django-different-port,standalone,setup,setup-requirements,django,numpy,app-home,locale,pipenv,pipenv-and-micropipenv-should-fail,app-module,pyuwsgi-pipenv{% if spec.version.startswith("3.") %},micropipenv,standalone-custom-pypi-index{% endif %}}-test-app) +declare -a COMMON_WEB_APPS=({gunicorn-config-different-port,gunicorn-different-port,gunicorn-using-configfile,django-different-port,standalone,setup,setup-requirements,django,numpy,app-home,locale,pipenv,pipenv-and-micropipenv-should-fail,app-module,pyuwsgi-pipenv{% if spec.version.startswith("3.") %},micropipenv,standalone-custom-pypi-index{% endif %}}-test-app) declare -a FULL_WEB_APPS=({setup-cfg,npm-virtualenv-uwsgi,mod-wsgi,pin-pipenv-version{% if spec.version.startswith("3.") %},micropipenv-requirements,poetry-src-layout{% endif %}}-test-app) declare -a MINIMAL_WEB_APPS=() {% if spec.minimal %}