auto-sync: master commit 897c8e39fe1df6c7bb6418d2892ccbd118d723f8
\n\nUpstreamCommitID: 546dfadbf110928dd357a55674ae7beabff8bcee\nUpstreamCommitLink: 546dfadbf1\nUpstreamRepository: https://github.com/sclorg/s2i-python-container
This commit is contained in:
parent
854069d753
commit
3300dd8839
17 changed files with 330 additions and 14 deletions
1
3.7
Symbolic link
1
3.7
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
.
|
||||
1
Dockerfile.fedora
Symbolic link
1
Dockerfile.fedora
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
Dockerfile
|
||||
12
README.md
12
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-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
1
help.md
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
README.md
|
||||
|
|
@ -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
|
||||
|
|
|
|||
2
test/micropipenv-requirements-test-app/.s2i/environment
Normal file
2
test/micropipenv-requirements-test-app/.s2i/environment
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ENABLE_MICROPIPENV=true
|
||||
DISABLE_SETUP_PY_PROCESSING=true
|
||||
14
test/micropipenv-requirements-test-app/app.py
Normal file
14
test/micropipenv-requirements-test-app/app.py
Normal 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'
|
||||
)
|
||||
2
test/micropipenv-requirements-test-app/requirements.txt
Normal file
2
test/micropipenv-requirements-test-app/requirements.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
mod_wsgi
|
||||
Flask
|
||||
9
test/micropipenv-requirements-test-app/wsgi.py
Normal file
9
test/micropipenv-requirements-test-app/wsgi.py
Normal 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
57
test/micropipenv-test-app/.gitignore
vendored
Normal 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/
|
||||
2
test/micropipenv-test-app/.s2i/environment
Normal file
2
test/micropipenv-test-app/.s2i/environment
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ENABLE_MICROPIPENV=true
|
||||
DISABLE_SETUP_PY_PROCESSING=true
|
||||
14
test/micropipenv-test-app/Pipfile
Normal file
14
test/micropipenv-test-app/Pipfile
Normal 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
155
test/micropipenv-test-app/Pipfile.lock
generated
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
10
test/micropipenv-test-app/setup.py
Normal file
10
test/micropipenv-test-app/setup.py
Normal 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"],
|
||||
)
|
||||
7
test/micropipenv-test-app/testapp.py
Normal file
7
test/micropipenv-test-app/testapp.py
Normal 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!"]
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ENABLE_PIPENV=true
|
||||
ENABLE_MICROPIPENV=true
|
||||
28
test/run
28
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue