auto-sync: master commit 897c8e39fe1df6c7bb6418d2892ccbd118d723f8

\n\nUpstreamCommitID: 546dfadbf110928dd357a55674ae7beabff8bcee\nUpstreamCommitLink: 546dfadbf1\nUpstreamRepository: https://github.com/sclorg/s2i-python-container
This commit is contained in:
phracek 2020-05-20 09:17:29 +00:00
commit 3300dd8839
17 changed files with 330 additions and 14 deletions

1
3.7 Symbolic link
View file

@ -0,0 +1 @@
.

1
Dockerfile.fedora Symbolic link
View file

@ -0,0 +1 @@
Dockerfile

View file

@ -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-37-rhel7 image`, available via `python:3.7` imagestream tag in Openshift.
For this, we will assume that you are using the supported image, available via `python:3.7` imagestream tag in Openshift.
Building a simple [python-sample-app](https://github.com/sclorg/s2i-python-container/tree/master/3.7/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.7/test/setup-test-app/ rhscl/python-37-rhel7 python-sample-app
$ s2i build https://github.com/sclorg/s2i-python-container.git --context-dir=3.7/test/setup-test-app/ <image_name> python-sample-app
```
Where `<image_name>` 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**

1
help.md Symbolic link
View file

@ -0,0 +1 @@
README.md

View file

@ -14,22 +14,30 @@ function virtualenv_bin() {
python3.7 -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"
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

View file

@ -0,0 +1,2 @@
ENABLE_MICROPIPENV=true
DISABLE_SETUP_PY_PROCESSING=true

View file

@ -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'
)

View file

@ -0,0 +1,2 @@
mod_wsgi
Flask

View file

@ -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()

57
test/micropipenv-test-app/.gitignore vendored Normal file
View file

@ -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/

View file

@ -0,0 +1,2 @@
ENABLE_MICROPIPENV=true
DISABLE_SETUP_PY_PROCESSING=true

View file

@ -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.7"

155
test/micropipenv-test-app/Pipfile.lock generated Normal file
View file

@ -0,0 +1,155 @@
{
"_meta": {
"hash": {
"sha256": "dbe9d3f790514385bed543a5fc1e85759ad0d0e39028c102d82c8d4afc1a5fc3"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.7"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"certifi": {
"hashes": [
"sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50",
"sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef"
],
"version": "==2019.9.11"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"e1839a8": {
"editable": true,
"path": "."
},
"gunicorn": {
"hashes": [
"sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471",
"sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3"
],
"version": "==19.9.0"
},
"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": {
"atomicwrites": {
"hashes": [
"sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4",
"sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"
],
"version": "==1.3.0"
},
"attrs": {
"hashes": [
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
"sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
],
"version": "==19.3.0"
},
"importlib-metadata": {
"hashes": [
"sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26",
"sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"
],
"markers": "python_version < '3.8'",
"version": "==0.23"
},
"more-itertools": {
"hashes": [
"sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832",
"sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"
],
"version": "==7.2.0"
},
"packaging": {
"hashes": [
"sha256:28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47",
"sha256:d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108"
],
"version": "==19.2"
},
"pluggy": {
"hashes": [
"sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6",
"sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34"
],
"version": "==0.13.0"
},
"py": {
"hashes": [
"sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa",
"sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"
],
"version": "==1.8.0"
},
"pyparsing": {
"hashes": [
"sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80",
"sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4"
],
"version": "==2.4.2"
},
"pytest": {
"hashes": [
"sha256:27abc3fef618a01bebb1f0d6d303d2816a99aa87a5968ebc32fe971be91eb1e6",
"sha256:58cee9e09242937e136dbb3dab466116ba20d6b7828c7620f23947f37eb4dae4"
],
"index": "pypi",
"version": "==5.2.2"
},
"six": {
"hashes": [
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
],
"version": "==1.12.0"
},
"wcwidth": {
"hashes": [
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e",
"sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"
],
"version": "==0.1.7"
},
"zipp": {
"hashes": [
"sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e",
"sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"
],
"version": "==0.6.0"
}
}
}

View file

@ -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"],
)

View file

@ -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!"]

View file

@ -0,0 +1,2 @@
ENABLE_PIPENV=true
ENABLE_MICROPIPENV=true

View file

@ -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