From b0910418b673dc19272e724649426f2c0cebc23d Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Tue, 2 Jun 2020 09:21:09 +0200 Subject: [PATCH] Update from upstream github repo - pipenv is locked to older stable version - ENV for micropipenv - no python-virtualenv package - updated documentation --- Dockerfile | 6 +- README.md | 12 +- s2i/bin/assemble | 27 +++- .../.s2i/environment | 2 + test/micropipenv-requirements-test-app/app.py | 14 ++ .../requirements.txt | 2 + .../micropipenv-requirements-test-app/wsgi.py | 9 ++ test/micropipenv-test-app/.gitignore | 57 ++++++++ test/micropipenv-test-app/.s2i/environment | 2 + test/micropipenv-test-app/Pipfile | 14 ++ test/micropipenv-test-app/Pipfile.lock | 133 ++++++++++++++++++ test/micropipenv-test-app/setup.py | 10 ++ test/micropipenv-test-app/testapp.py | 7 + .../.s2i/environment | 2 + test/run | 28 +++- 15 files changed, 308 insertions(+), 17 deletions(-) create mode 100644 test/micropipenv-requirements-test-app/.s2i/environment create mode 100644 test/micropipenv-requirements-test-app/app.py create mode 100644 test/micropipenv-requirements-test-app/requirements.txt create mode 100644 test/micropipenv-requirements-test-app/wsgi.py create mode 100644 test/micropipenv-test-app/.gitignore create mode 100644 test/micropipenv-test-app/.s2i/environment create mode 100644 test/micropipenv-test-app/Pipfile create mode 100644 test/micropipenv-test-app/Pipfile.lock create mode 100644 test/micropipenv-test-app/setup.py create mode 100644 test/micropipenv-test-app/testapp.py create mode 100644 test/pipenv-and-micropipenv-should-fail-test-app/.s2i/environment diff --git a/Dockerfile b/Dockerfile index 7b55cb6..8832721 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,9 +38,9 @@ LABEL summary="$SUMMARY" \ usage="s2i build https://github.com/sclorg/s2i-python-container.git --context-dir=3.8/test/setup-test-app/ $FGC/$NAME python-sample-app" \ maintainer="SoftwareCollections.org " -RUN INSTALL_PKGS="python3 python3-devel python3-setuptools python3-pip python3-virtualenv \ - nss_wrapper httpd httpd-devel atlas-devel gcc-gfortran \ - libffi-devel libtool-ltdl enchant redhat-rpm-config" && \ +RUN INSTALL_PKGS="python3 python3-devel python3-setuptools python3-pip nss_wrapper \ + httpd httpd-devel atlas-devel gcc-gfortran libffi-devel \ + libtool-ltdl enchant redhat-rpm-config" && \ dnf -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \ rpm -V $INSTALL_PKGS && \ dnf -y clean all --enablerepo='*' diff --git a/README.md b/README.md index 8b8cc26..f24f41e 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ the nodejs itself is included just to make the npm work. Usage --------------------- -For this, we will assume that you are using the `rhscl/python-38-rhel7 image`, available via `python:3.8` imagestream tag in Openshift. +For this, we will assume that you are using the supported image, available via `python:3.8` imagestream tag in Openshift. Building a simple [python-sample-app](https://github.com/sclorg/s2i-python-container/tree/master/3.8/test/setup-test-app) application in Openshift can be achieved with the following step: @@ -43,9 +43,11 @@ in Openshift can be achieved with the following step: The same application can also be built using the standalone [S2I](https://github.com/openshift/source-to-image) application on systems that have it available: ``` - $ s2i build https://github.com/sclorg/s2i-python-container.git --context-dir=3.8/test/setup-test-app/ rhscl/python-38-rhel7 python-sample-app + $ s2i build https://github.com/sclorg/s2i-python-container.git --context-dir=3.8/test/setup-test-app/ python-sample-app ``` +Where `` is the s2i-python image you [downloaded from RHEL, Centos or Fedora registry](../README.md#Download) or [built](../README.md#Build) from these sources. For example ubi8/python-36, centos/python-36-centos7 or f31/python3. + **Accessing the application:** ``` $ curl 127.0.0.1:8080 @@ -125,6 +127,12 @@ file inside your source code repository. the higher-level Python packaging tool, to manage dependencies of the application. This should be used only if your project contains properly formated Pipfile and Pipfile.lock. +* **ENABLE_MICROPIPENV** + + Set this variable to use [micropipenv](https://github.com/thoth-station/micropipenv), + a lightweight wrapper for pip to support requirements.txt, Pipenv and Poetry lock + files or converting them to pip-tools compatible output. Designed for containerized Python applications. + Available only for Python 3 images. * **ENABLE_INIT_WRAPPER** diff --git a/s2i/bin/assemble b/s2i/bin/assemble index 6f24d63..e1d72ac 100755 --- a/s2i/bin/assemble +++ b/s2i/bin/assemble @@ -14,22 +14,30 @@ function virtualenv_bin() { python3.8 -m venv $1 } -# Install pipenv to the separate virtualenv to isolate it +# Install pipenv or micropipenv to the separate virtualenv to isolate it # from system Python packages and packages in the main # virtualenv. Executable is simlinked into ~/.local/bin # to be accessible. This approach is inspired by pipsi # (pip script installer). -function install_pipenv() { - echo "---> Installing pipenv packaging tool ..." - VENV_DIR=$HOME/.local/venvs/pipenv +function install_tool() { + echo "---> Installing $1 packaging tool ..." + VENV_DIR=$HOME/.local/venvs/$1 virtualenv_bin "$VENV_DIR" - $VENV_DIR/bin/pip --isolated install -U pipenv + $VENV_DIR/bin/pip --isolated install -U $1$2 # Combines package name with [extras] if [extras] is defined as $2 mkdir -p $HOME/.local/bin - ln -s $VENV_DIR/bin/pipenv $HOME/.local/bin/pipenv + ln -s $VENV_DIR/bin/$1 $HOME/.local/bin/$1 } set -e +# First of all, check that we don't have disallowed combination of ENVs +if [[ ! -z "$ENABLE_PIPENV" && ! -z "$ENABLE_MICROPIPENV" ]]; then + echo "ERROR: Pipenv and micropipenv cannot be enabled at the same time!" + # podman/buildah does not relay this exit code but it will be fixed hopefuly + # https://github.com/containers/buildah/issues/2305 + exit 3 +fi + shopt -s dotglob echo "---> Installing application source ..." mv /tmp/src/* "$HOME" @@ -50,7 +58,7 @@ if [[ ! -z "$UPGRADE_PIP_TO_LATEST" ]]; then fi if [[ ! -z "$ENABLE_PIPENV" ]]; then - install_pipenv + install_tool "pipenv" "==2018.11.26" echo "---> Installing dependencies via pipenv ..." if [[ -f Pipfile ]]; then pipenv install --deploy @@ -58,6 +66,11 @@ if [[ ! -z "$ENABLE_PIPENV" ]]; then pipenv install -r requirements.txt fi # pipenv check +elif [[ ! -z "$ENABLE_MICROPIPENV" ]]; then + install_tool "micropipenv" "[toml]" + echo "---> Installing dependencies via micropipenv ..." + # micropipenv detects Pipfile.lock and requirements.txt in this order + micropipenv install --deploy elif [[ -f requirements.txt ]]; then echo "---> Installing dependencies ..." pip install -r requirements.txt diff --git a/test/micropipenv-requirements-test-app/.s2i/environment b/test/micropipenv-requirements-test-app/.s2i/environment new file mode 100644 index 0000000..2d40b15 --- /dev/null +++ b/test/micropipenv-requirements-test-app/.s2i/environment @@ -0,0 +1,2 @@ +ENABLE_MICROPIPENV=true +DISABLE_SETUP_PY_PROCESSING=true diff --git a/test/micropipenv-requirements-test-app/app.py b/test/micropipenv-requirements-test-app/app.py new file mode 100644 index 0000000..bbac264 --- /dev/null +++ b/test/micropipenv-requirements-test-app/app.py @@ -0,0 +1,14 @@ +import os +import mod_wsgi.server + +mod_wsgi.server.start( + '--log-to-terminal', + '--port', '8080', + '--trust-proxy-header', 'X-Forwarded-For', + '--trust-proxy-header', 'X-Forwarded-Port', + '--trust-proxy-header', 'X-Forwarded-Proto', + '--processes', os.environ.get('MOD_WSGI_PROCESSES', '1'), + '--threads', os.environ.get('MOD_WSGI_THREADS', '5'), + '--application-type', 'module', + '--entry-point', 'wsgi' +) diff --git a/test/micropipenv-requirements-test-app/requirements.txt b/test/micropipenv-requirements-test-app/requirements.txt new file mode 100644 index 0000000..a74adef --- /dev/null +++ b/test/micropipenv-requirements-test-app/requirements.txt @@ -0,0 +1,2 @@ +mod_wsgi +Flask diff --git a/test/micropipenv-requirements-test-app/wsgi.py b/test/micropipenv-requirements-test-app/wsgi.py new file mode 100644 index 0000000..9e72469 --- /dev/null +++ b/test/micropipenv-requirements-test-app/wsgi.py @@ -0,0 +1,9 @@ +from flask import Flask +application = Flask(__name__) + +@application.route('/') +def hello(): + return b'Hello World from mod_wsgi hosted WSGI application!' + +if __name__ == '__main__': + application.run() diff --git a/test/micropipenv-test-app/.gitignore b/test/micropipenv-test-app/.gitignore new file mode 100644 index 0000000..ba74660 --- /dev/null +++ b/test/micropipenv-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/test/micropipenv-test-app/.s2i/environment b/test/micropipenv-test-app/.s2i/environment new file mode 100644 index 0000000..2d40b15 --- /dev/null +++ b/test/micropipenv-test-app/.s2i/environment @@ -0,0 +1,2 @@ +ENABLE_MICROPIPENV=true +DISABLE_SETUP_PY_PROCESSING=true diff --git a/test/micropipenv-test-app/Pipfile b/test/micropipenv-test-app/Pipfile new file mode 100644 index 0000000..e489272 --- /dev/null +++ b/test/micropipenv-test-app/Pipfile @@ -0,0 +1,14 @@ +[[source]] +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +"e1839a8" = {path = ".", editable = true} +requests = "==2.20.0" + +[dev-packages] +pytest = ">=2.8.0" + +[requires] +python_version = "3.8" diff --git a/test/micropipenv-test-app/Pipfile.lock b/test/micropipenv-test-app/Pipfile.lock new file mode 100644 index 0000000..e0bbf2e --- /dev/null +++ b/test/micropipenv-test-app/Pipfile.lock @@ -0,0 +1,133 @@ +{ + "_meta": { + "hash": { + "sha256": "f1d3ff05e8c9143e751780c871a656ef8794c15cf6e8ef08cfa211ad25a24320" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.8" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.python.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "certifi": { + "hashes": [ + "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", + "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" + ], + "version": "==2019.11.28" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "e1839a8": { + "editable": true, + "path": "." + }, + "gunicorn": { + "hashes": [ + "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626", + "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c" + ], + "version": "==20.0.4" + }, + "idna": { + "hashes": [ + "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", + "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" + ], + "version": "==2.7" + }, + "requests": { + "hashes": [ + "sha256:99dcfdaaeb17caf6e526f32b6a7b780461512ab3f1d992187801694cba42770c", + "sha256:a84b8c9ab6239b578f22d1c21d51b696dcfe004032bb80ea832398d6909d7279" + ], + "index": "pypi", + "version": "==2.20.0" + }, + "urllib3": { + "hashes": [ + "sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4", + "sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb" + ], + "version": "==1.24.3" + } + }, + "develop": { + "attrs": { + "hashes": [ + "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", + "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" + ], + "version": "==19.3.0" + }, + "more-itertools": { + "hashes": [ + "sha256:b84b238cce0d9adad5ed87e745778d20a3f8487d0f0cb8b8a586816c7496458d", + "sha256:c833ef592a0324bcc6a60e48440da07645063c453880c9477ceb22490aec1564" + ], + "version": "==8.0.2" + }, + "packaging": { + "hashes": [ + "sha256:28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47", + "sha256:d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108" + ], + "version": "==19.2" + }, + "pluggy": { + "hashes": [ + "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", + "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + ], + "version": "==0.13.1" + }, + "py": { + "hashes": [ + "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", + "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53" + ], + "version": "==1.8.0" + }, + "pyparsing": { + "hashes": [ + "sha256:20f995ecd72f2a1f4bf6b072b63b22e2eb457836601e76d6e5dfcd75436acc1f", + "sha256:4ca62001be367f01bd3e92ecbb79070272a9d4964dce6a48a82ff0b8bc7e683a" + ], + "version": "==2.4.5" + }, + "pytest": { + "hashes": [ + "sha256:63344a2e3bce2e4d522fd62b4fdebb647c019f1f9e4ca075debbd13219db4418", + "sha256:f67403f33b2b1d25a6756184077394167fe5e2f9d8bdaab30707d19ccec35427" + ], + "index": "pypi", + "version": "==5.3.1" + }, + "six": { + "hashes": [ + "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", + "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66" + ], + "version": "==1.13.0" + }, + "wcwidth": { + "hashes": [ + "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", + "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" + ], + "version": "==0.1.7" + } + } +} diff --git a/test/micropipenv-test-app/setup.py b/test/micropipenv-test-app/setup.py new file mode 100644 index 0000000..e313409 --- /dev/null +++ b/test/micropipenv-test-app/setup.py @@ -0,0 +1,10 @@ +from setuptools import setup, find_packages + + +setup ( + name = "testapp", + version = "0.1", + description = "Example application to be deployed.", + packages = find_packages(), + install_requires = ["gunicorn"], +) diff --git a/test/micropipenv-test-app/testapp.py b/test/micropipenv-test-app/testapp.py new file mode 100644 index 0000000..a9193ee --- /dev/null +++ b/test/micropipenv-test-app/testapp.py @@ -0,0 +1,7 @@ +import requests + + +def application(environ, start_response): + start_response('200 OK', [('Content-Type', 'text/plain')]) + assert requests.__version__ == '2.20.0' + return [b"Hello from gunicorn WSGI application!"] diff --git a/test/pipenv-and-micropipenv-should-fail-test-app/.s2i/environment b/test/pipenv-and-micropipenv-should-fail-test-app/.s2i/environment new file mode 100644 index 0000000..e3932ee --- /dev/null +++ b/test/pipenv-and-micropipenv-should-fail-test-app/.s2i/environment @@ -0,0 +1,2 @@ +ENABLE_PIPENV=true +ENABLE_MICROPIPENV=true diff --git a/test/run b/test/run index 78bd2d3..5b0efcb 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 WEB_APPS=({standalone,setup,setup-requirements,django,numpy,app-home,npm-virtualenv-uwsgi,locale,mod-wsgi,pipenv}-test-app) +declare -a WEB_APPS=({standalone,setup,setup-requirements,django,numpy,app-home,npm-virtualenv-uwsgi,locale,mod-wsgi,pipenv,pipenv-and-micropipenv-should-fail,micropipenv,micropipenv-requirements}-test-app) # TODO: Make command compatible for Mac users test_dir="$(readlink -zf $(dirname "${BASH_SOURCE[0]}"))" @@ -36,6 +36,7 @@ container_exists() { image_exists $(cat $cid_file) } + container_ip() { docker inspect --format="{{ .NetworkSettings.IPAddress }}" $(cat $cid_file) } @@ -82,11 +83,18 @@ cleanup() { } check_result() { + # positive test & non-zero exit status = ERROR + # negative test & zero exit status = ERROR local result="$1" - if [[ "$result" != "0" ]]; then - info "TEST FAILED (${result})" + local test=${2:-positive} # if not defined, we expect possitive test type (zero exit code) + if [[ "$type" == "positive" && "$result" != "0" ]]; then + info "TEST FAILED (${type}), EXPECTED:0 GOT:${result}" cleanup exit $result + elif [[ "$type" == "negative" && "$result" == "0" ]]; then + info "TEST FAILED (${type}), EXPECTED: non-zero GOT:${result}" + cleanup + exit 1 fi } @@ -189,10 +197,20 @@ check_result $? test_docker_run_usage check_result $? -for app in ${WEB_APPS[@]}; do +# For debugging purposes, this script can be run with one or more arguments +# those arguments list is a sub-set of values in the WEB_APPS array defined above +# Example: ./run app-home-test-app pipenv-test-app +for app in ${@:-${WEB_APPS[@]}}; do prepare ${app} run_s2i_build ${app} - check_result $? + RESULT=$? + if [[ "$app" == *"-should-fail-"* ]]; then + # Tests with '-should-fail-' in their name should fail during a build, expecting non-zero exit status + check_result $RESULT "negative" + continue + else + check_result $RESULT + fi # test application with default user test_application