From 9e2a157e7c11c6864394d736d416be3f051e811b Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 10 Dec 2021 11:04:56 +0100 Subject: [PATCH] Update from upstream - F35 + Py3.10 --- Dockerfile | 20 +-- README.md | 20 +-- root/opt/app-root/etc/scl_enable | 2 +- s2i/bin/assemble | 2 +- s2i/bin/usage | 6 +- test/check_imagestreams.py | 30 ++-- test/micropipenv-test-app/Pipfile | 2 +- test/micropipenv-test-app/Pipfile.lock | 85 +++++----- test/pipenv-test-app/Pipfile | 2 +- test/pipenv-test-app/Pipfile.lock | 85 +++++----- test/setup-cfg-test-app/pyproject.toml | 6 + test/setup-cfg-test-app/setup.cfg | 14 ++ test/setup-cfg-test-app/wsgi.py | 4 + test/test-lib-openshift.sh | 77 +++++---- test/test-lib-remote-openshift.sh | 4 + test/test-lib.sh | 214 +++++++++++++++++++++---- 16 files changed, 385 insertions(+), 188 deletions(-) create mode 100644 test/setup-cfg-test-app/pyproject.toml create mode 100644 test/setup-cfg-test-app/setup.cfg create mode 100644 test/setup-cfg-test-app/wsgi.py diff --git a/Dockerfile b/Dockerfile index 9b7dcd9..f1b510b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ -# This image provides a Python 3.9 environment you can use to run your Python +# This image provides a Python 3.10 environment you can use to run your Python # applications. -FROM registry.fedoraproject.org/f34/s2i-base:latest +FROM registry.fedoraproject.org/f35/s2i-base:latest EXPOSE 8080 -ENV PYTHON_VERSION=3.9 \ +ENV PYTHON_VERSION=3.10 \ PATH=$HOME/.local/bin/:$PATH \ PYTHONUNBUFFERED=1 \ PYTHONIOENCODING=UTF-8 \ @@ -29,13 +29,13 @@ on most platforms." LABEL summary="$SUMMARY" \ description="$DESCRIPTION" \ io.k8s.description="$DESCRIPTION" \ - io.k8s.display-name="Python 3.9" \ + io.k8s.display-name="Python 3.10" \ io.openshift.expose-services="8080:http" \ - io.openshift.tags="builder,python,python39,python-39,rh-python39" \ + io.openshift.tags="builder,python,python310,python-310,rh-python310" \ com.redhat.component="$NAME" \ name="$FGC/$NAME" \ version="$VERSION" \ - usage="s2i build https://github.com/sclorg/s2i-python-container.git --context-dir=3.9/test/setup-test-app/ $FGC/$NAME python-sample-app" \ + usage="s2i build https://github.com/sclorg/s2i-python-container.git --context-dir=3.10/test/setup-test-app/ $FGC/$NAME python-sample-app" \ maintainer="SoftwareCollections.org " RUN INSTALL_PKGS="python3 python3-devel python3-setuptools python3-pip nss_wrapper \ @@ -46,24 +46,24 @@ RUN INSTALL_PKGS="python3 python3-devel python3-setuptools python3-pip nss_wrapp dnf -y clean all --enablerepo='*' # Copy the S2I scripts from the specific language image to $STI_SCRIPTS_PATH. -COPY 3.9/s2i/bin/ $STI_SCRIPTS_PATH +COPY 3.10/s2i/bin/ $STI_SCRIPTS_PATH # Copy extra files to the image. -COPY 3.9/root/ / +COPY 3.10/root/ / # Python 3 only # Yes, the directory below is already copied by the previous command. # The problem here is that the wheels directory is copied as a symlink. # Only if you specify symlink directly as a source, COPY copies all the # files from the symlink destination. -COPY 3.9/root/opt/wheels /opt/wheels +COPY 3.10/root/opt/wheels /opt/wheels # - Create a Python virtual environment for use by any application to avoid # potential conflicts with Python packages preinstalled in the main Python # installation. # - In order to drop the root user, we have to make some directories world # writable as OpenShift default security model is to run the container # under random UID. -RUN python3.9 -m venv ${APP_ROOT} && \ +RUN python3.10 -m venv ${APP_ROOT} && \ # Python 3 only code, Python 2 installs pip from PyPI in the assemble script. \ # We have to upgrade pip to a newer verison because: \ # * pip < 9 does not support different packages' versions for Python 2/3 \ diff --git a/README.md b/README.md index 31c9cc5..633b589 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -Python 3.9 container image +Python 3.10 container image ========================= -This container image includes Python 3.9 as a [S2I](https://github.com/openshift/source-to-image) base image for your Python 3.9 applications. +This container image includes Python 3.10 as a [S2I](https://github.com/openshift/source-to-image) base image for your Python 3.10 applications. Users can choose between RHEL and CentOS based builder images. The RHEL images are available in the [Red Hat Container Catalog](https://catalog.redhat.com/software/containers/explore), the CentOS images are available on [Quay.io](https://quay.io/organization/centos7), @@ -14,8 +14,8 @@ Note: while the examples in this README are calling `podman`, you can replace an Description ----------- -Python 3.9 available as container is a base platform for -building and running various Python 3.9 applications and frameworks. +Python 3.10 available as container is a base platform for +building and running various Python 3.10 applications and frameworks. Python is an easy to learn, powerful programming language. It has efficient high-level data structures and a simple but effective approach to object-oriented programming. Python's elegant syntax and dynamic typing, together with its interpreted nature, @@ -32,12 +32,12 @@ the nodejs itself is included just to make the npm work. Usage in Openshift ------------------ -For this, we will assume that you are using the supported image, available via `python:3.9` imagestream tag in Openshift. +For this, we will assume that you are using the supported image, available via `python:3.10` imagestream tag in Openshift. Building a simple [python-sample-app](https://github.com/sclorg/django-ex.git) application in Openshift can be achieved with the following step: ``` - oc new-app python:3.9~https://github.com/sclorg/django-ex.git + oc new-app python:3.10~https://github.com/sclorg/django-ex.git ``` **Accessing the application:** @@ -74,7 +74,7 @@ To use the Python image in a Dockerfile, follow these steps: #### 1. Pull a base builder image to build on ``` -podman pull registry.access.redhat.com/ubi8/python-39 +podman pull registry.fedoraproject.org/f35/python3 ``` #### 2. Pull and application code @@ -105,7 +105,7 @@ prepared for a future flawless switch to a newer or different platform. To use the Source-to-Image scripts and build an image using a Dockerfile, create a Dockerfile with this content: ``` -FROM registry.access.redhat.com/ubi8/python-39 +FROM registry.fedoraproject.org/f35/python3 # Add application sources to a directory that the assemble script expects them # and set permissions so that the container runs without root access @@ -125,7 +125,7 @@ If you decide not to use the Source-to-Image scripts, you will need to manually Example Dockerfile for a simple Django application: ``` -FROM registry.access.redhat.com/ubi8/python-39 +FROM registry.fedoraproject.org/f35/python3 # Add application sources with correct permissions for OpenShift USER 0 @@ -188,7 +188,7 @@ file inside your source code repository. If using `setup.py` for installing the application, the `MODULE_NAME` part can be read from there. For an example, see - [setup-test-app](https://github.com/sclorg/s2i-python-container/tree/master/3.9/test/setup-test-app). + [setup-test-app](https://github.com/sclorg/s2i-python-container/tree/master/3.10/test/setup-test-app). * **APP_HOME** diff --git a/root/opt/app-root/etc/scl_enable b/root/opt/app-root/etc/scl_enable index 766e4de..710920b 100644 --- a/root/opt/app-root/etc/scl_enable +++ b/root/opt/app-root/etc/scl_enable @@ -4,6 +4,6 @@ unset BASH_ENV PROMPT_COMMAND ENV if head "/etc/redhat-release" | grep -q "^CentOS Linux release 7" || \ head "/etc/redhat-release" | grep -q "^Red Hat Enterprise Linux\( Server\)\? release 7"; then - source scl_source enable httpd24 $NODEJS_SCL rh-python39 + source scl_source enable httpd24 $NODEJS_SCL rh-python310 fi source /opt/app-root/bin/activate diff --git a/s2i/bin/assemble b/s2i/bin/assemble index 18c8373..e772594 100755 --- a/s2i/bin/assemble +++ b/s2i/bin/assemble @@ -11,7 +11,7 @@ function should_collectstatic() { function virtualenv_bin() { # New versions of Python (>3.6) should use venv module # from stdlib instead of virtualenv package - python3.9 -m venv $1 + python3.10 -m venv $1 } # Install pipenv or micropipenv to the separate virtualenv to isolate it diff --git a/s2i/bin/usage b/s2i/bin/usage index a45027f..4fe16df 100755 --- a/s2i/bin/usage +++ b/s2i/bin/usage @@ -5,12 +5,12 @@ NAMESPACE=centos [[ $DISTRO =~ rhel* ]] && NAMESPACE=rhscl cat < Any: with open(str(filename)) as f: - return json.load(f) + data = json.load(f) + isinstance(data, Dict) + return data - def check_version(self, json_dict: Dict): + def check_version(self, json_dict: Dict[Any, Any]) -> List[str]: res = [] for tags in json_dict["spec"]["tags"]: # The name can be"" or "-elX" or "-ubiX" - if (tags["name"] == self.version or - tags["name"].startswith(self.version + '-')): + if tags["name"] == self.version or tags["name"].startswith( + self.version + "-" + ): res.append(tags) return res - def check_latest_tag(self, json_dict: Dict): + def check_latest_tag(self, json_dict: Dict[Any, Any]) -> bool: latest_tag_correct: bool = False for tags in json_dict["spec"]["tags"]: if tags["name"] != "latest": continue # The latest can link to either "" or "-elX" or "-ubiX" - if tags["from"]["name"] == self.version or tags["from"]["name"].startswith(self.version + '-'): + if tags["from"]["name"] == self.version or tags["from"]["name"].startswith( + self.version + "-" + ): latest_tag_correct = True return latest_tag_correct - def check_imagestreams(self): + def check_imagestreams(self) -> int: p = Path(".") json_files = p.glob(f"{IMAGESTREAMS_DIR}/*.json") if not json_files: @@ -76,7 +81,9 @@ class ImageStreamChecker(object): print(f"Checking file {str(f)}.") json_dict = self.load_json_file(f) if not (self.check_version(json_dict) and self.check_latest_tag(json_dict)): - print(f"The latest version is not present in {str(f)} or in latest tag.") + print( + f"The latest version is not present in {str(f)} or in latest tag." + ) self.results[f] = False if self.results: return 1 @@ -92,4 +99,3 @@ if __name__ == "__main__": print(f"Version to check is {sys.argv[1]}.") isc = ImageStreamChecker(version=sys.argv[1]) sys.exit(isc.check_imagestreams()) - diff --git a/test/micropipenv-test-app/Pipfile b/test/micropipenv-test-app/Pipfile index 117b223..dcd54e7 100644 --- a/test/micropipenv-test-app/Pipfile +++ b/test/micropipenv-test-app/Pipfile @@ -11,4 +11,4 @@ requests = "==2.20.0" pytest = ">=2.8.0" [requires] -python_version = "3.9" +python_version = "3.10" diff --git a/test/micropipenv-test-app/Pipfile.lock b/test/micropipenv-test-app/Pipfile.lock index 2574173..712b776 100644 --- a/test/micropipenv-test-app/Pipfile.lock +++ b/test/micropipenv-test-app/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "9d47e9d2d35583e081cf783e9421e75fafb102d07969ad6f74546f48db3a8101" + "sha256": "9a2e94684dd37b09b75b2cefccf407a9b8a22498cbd36cde8afb8ed2eb06fe14" }, "pipfile-spec": 6, "requires": { - "python_version": "3.9" + "python_version": "3.10" }, "sources": [ { @@ -18,10 +18,10 @@ "default": { "certifi": { "hashes": [ - "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", - "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41" + "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", + "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" ], - "version": "==2020.6.20" + "version": "==2021.10.8" }, "chardet": { "hashes": [ @@ -36,11 +36,11 @@ }, "gunicorn": { "hashes": [ - "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626", - "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c" + "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", + "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8" ], - "markers": "python_version >= '3.4'", - "version": "==20.0.4" + "markers": "python_version >= '3.5'", + "version": "==20.1.0" }, "idna": { "hashes": [ @@ -73,73 +73,66 @@ "develop": { "attrs": { "hashes": [ - "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594", - "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc" + "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", + "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.2.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==21.2.0" }, "iniconfig": { "hashes": [ - "sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437", - "sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69" + "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", + "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" ], - "version": "==1.0.1" + "version": "==1.1.1" }, "packaging": { "hashes": [ - "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8", - "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181" + "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", + "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.4" + "markers": "python_version >= '3.6'", + "version": "==21.3" }, "pluggy": { "hashes": [ - "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", - "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", + "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.13.1" + "markers": "python_version >= '3.6'", + "version": "==1.0.0" }, "py": { "hashes": [ - "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2", - "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342" + "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", + "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.9.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.11.0" }, "pyparsing": { "hashes": [ - "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", - "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" + "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4", + "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.4.7" + "markers": "python_version >= '3.6'", + "version": "==3.0.6" }, "pytest": { "hashes": [ - "sha256:7a8190790c17d79a11f847fba0b004ee9a8122582ebff4729a082c109e81a4c9", - "sha256:8f593023c1a0f916110285b6efd7f99db07d59546e3d8c36fc60e2ab05d3be92" + "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89", + "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134" ], "index": "pypi", - "version": "==6.1.1" - }, - "six": { - "hashes": [ - "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", - "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.15.0" + "version": "==6.2.5" }, "toml": { "hashes": [ - "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f", - "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88" + "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", + "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" ], - "version": "==0.10.1" + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'", + "version": "==0.10.2" } } } diff --git a/test/pipenv-test-app/Pipfile b/test/pipenv-test-app/Pipfile index 117b223..dcd54e7 100644 --- a/test/pipenv-test-app/Pipfile +++ b/test/pipenv-test-app/Pipfile @@ -11,4 +11,4 @@ requests = "==2.20.0" pytest = ">=2.8.0" [requires] -python_version = "3.9" +python_version = "3.10" diff --git a/test/pipenv-test-app/Pipfile.lock b/test/pipenv-test-app/Pipfile.lock index 2574173..712b776 100644 --- a/test/pipenv-test-app/Pipfile.lock +++ b/test/pipenv-test-app/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "9d47e9d2d35583e081cf783e9421e75fafb102d07969ad6f74546f48db3a8101" + "sha256": "9a2e94684dd37b09b75b2cefccf407a9b8a22498cbd36cde8afb8ed2eb06fe14" }, "pipfile-spec": 6, "requires": { - "python_version": "3.9" + "python_version": "3.10" }, "sources": [ { @@ -18,10 +18,10 @@ "default": { "certifi": { "hashes": [ - "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", - "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41" + "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", + "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" ], - "version": "==2020.6.20" + "version": "==2021.10.8" }, "chardet": { "hashes": [ @@ -36,11 +36,11 @@ }, "gunicorn": { "hashes": [ - "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626", - "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c" + "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", + "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8" ], - "markers": "python_version >= '3.4'", - "version": "==20.0.4" + "markers": "python_version >= '3.5'", + "version": "==20.1.0" }, "idna": { "hashes": [ @@ -73,73 +73,66 @@ "develop": { "attrs": { "hashes": [ - "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594", - "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc" + "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", + "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.2.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==21.2.0" }, "iniconfig": { "hashes": [ - "sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437", - "sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69" + "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", + "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" ], - "version": "==1.0.1" + "version": "==1.1.1" }, "packaging": { "hashes": [ - "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8", - "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181" + "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", + "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.4" + "markers": "python_version >= '3.6'", + "version": "==21.3" }, "pluggy": { "hashes": [ - "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", - "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", + "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.13.1" + "markers": "python_version >= '3.6'", + "version": "==1.0.0" }, "py": { "hashes": [ - "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2", - "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342" + "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", + "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.9.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.11.0" }, "pyparsing": { "hashes": [ - "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", - "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" + "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4", + "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.4.7" + "markers": "python_version >= '3.6'", + "version": "==3.0.6" }, "pytest": { "hashes": [ - "sha256:7a8190790c17d79a11f847fba0b004ee9a8122582ebff4729a082c109e81a4c9", - "sha256:8f593023c1a0f916110285b6efd7f99db07d59546e3d8c36fc60e2ab05d3be92" + "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89", + "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134" ], "index": "pypi", - "version": "==6.1.1" - }, - "six": { - "hashes": [ - "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", - "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.15.0" + "version": "==6.2.5" }, "toml": { "hashes": [ - "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f", - "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88" + "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", + "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" ], - "version": "==0.10.1" + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'", + "version": "==0.10.2" } } } diff --git a/test/setup-cfg-test-app/pyproject.toml b/test/setup-cfg-test-app/pyproject.toml new file mode 100644 index 0000000..374b58c --- /dev/null +++ b/test/setup-cfg-test-app/pyproject.toml @@ -0,0 +1,6 @@ +[build-system] +requires = [ + "setuptools>=42", + "wheel" +] +build-backend = "setuptools.build_meta" diff --git a/test/setup-cfg-test-app/setup.cfg b/test/setup-cfg-test-app/setup.cfg new file mode 100644 index 0000000..a8bedfd --- /dev/null +++ b/test/setup-cfg-test-app/setup.cfg @@ -0,0 +1,14 @@ +[metadata] +name = testapp +version = 0.1 + +[options] +install_requires = + gunicorn<20.0.0; python_version < '3.5' + gunicorn>=20.0.0; python_version >= '3.5' +package_dir = + = . +packages = find: + +[options.packages.find] +where = . diff --git a/test/setup-cfg-test-app/wsgi.py b/test/setup-cfg-test-app/wsgi.py new file mode 100644 index 0000000..09fee1b --- /dev/null +++ b/test/setup-cfg-test-app/wsgi.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/test/test-lib-openshift.sh b/test/test-lib-openshift.sh index fa15eae..b98e628 100644 --- a/test/test-lib-openshift.sh +++ b/test/test-lib-openshift.sh @@ -342,6 +342,10 @@ function _ct_os_get_uniq_project_name() { # to authenticate to image registries. # shellcheck disable=SC2120 function ct_os_new_project() { + if [ "${CVP:-0}" -eq "1" ]; then + echo "Testing in CVP environment. No need to create OpenShift project. This is done by CVP pipeline" + return + fi if [ "${CT_SKIP_NEW_PROJECT:-false}" == 'true' ] ; then echo "Creating project skipped." return @@ -364,7 +368,7 @@ function ct_os_new_project() { # Arguments: project - project name, uses the current project if omitted # shellcheck disable=SC2120 function ct_os_delete_project() { - if [ "${CT_SKIP_NEW_PROJECT:-false}" == 'true' ] ; then + if [ "${CT_SKIP_NEW_PROJECT:-false}" == 'true' ] || [ "${CVP:-0}" -eq "1" ]; then echo "Deleting project skipped, cleaning objects only." # when not having enough privileges (remote cluster), it might fail and # it is not a big problem, so ignore failure in this case @@ -526,6 +530,8 @@ function ct_os_cluster_up() { # Shuts down the local OpenShift cluster using 'oc cluster down' function ct_os_cluster_down() { if [ ${OS_CLUSTER_STARTED_BY_TEST:-0} -eq 1 ] ; then + echo "Switching user to system:admin before cluster is going down." + oc login -u system:admin echo "Cluster started by the test, shutting down." oc cluster down else @@ -665,20 +671,24 @@ function ct_os_test_s2i_app_func() { namespace=${CT_NAMESPACE:-"$(oc project -q)"} local image_tagged="${image_name_no_namespace%:*}:${VERSION}" - if [ "${CT_EXTERNAL_REGISTRY:-false}" == 'true' ] ; then - ct_os_import_image_ocp4 "${image_name}" "${image_tagged}" - else - # Create a specific imagestream tag for the image so that oc cannot use anything else - if [ "${CT_SKIP_UPLOAD_IMAGE:-false}" == 'true' ] ; then - echo "Importing image ${image_name} as ${namespace}/${image_tagged}" - # Use --reference-policy=local to pull remote image content to the cluster - # Works around the issue of builder pods not having access to registry.redhat.io - oc tag --source=docker "${image_name}" "${namespace}/${image_tagged}" --insecure=true --reference-policy=local - ct_os_wait_stream_ready "${image_tagged}" "${namespace}" + if [ "${CVP:-0}" -eq "0" ]; then + if [ "${CT_EXTERNAL_REGISTRY:-false}" == 'true' ] ; then + ct_os_import_image_ocp4 "${image_name}" "${image_tagged}" else - echo "Uploading image ${image_name} as ${image_tagged}" - ct_os_upload_image "${image_name}" "${image_tagged}" + # Create a specific imagestream tag for the image so that oc cannot use anything else + if [ "${CT_SKIP_UPLOAD_IMAGE:-false}" == 'true' ] ; then + echo "Importing image ${image_name} as ${namespace}/${image_tagged}" + # Use --reference-policy=local to pull remote image content to the cluster + # Works around the issue of builder pods not having access to registry.redhat.io + oc tag --source=docker "${image_name}" "${namespace}/${image_tagged}" --insecure=true --reference-policy=local + ct_os_wait_stream_ready "${image_tagged}" "${namespace}" + else + echo "Uploading image ${image_name} as ${image_tagged}" + ct_os_upload_image "${image_name}" "${image_tagged}" + fi fi + else + echo "Testing image ${image_name} in CVP pipeline." fi local app_param="${app}" @@ -803,21 +813,27 @@ function ct_os_test_template_app_func() { ct_os_new_project namespace=${CT_NAMESPACE:-"$(oc project -q)"} - # Create a specific imagestream tag for the image so that oc cannot use anything else - if [ "${CT_EXTERNAL_REGISTRY:-false}" == 'true' ] ; then - ct_os_import_image_ocp4 "${image_name}" "${image_tagged}" - else - if [ "${CT_SKIP_UPLOAD_IMAGE:-false}" == 'true' ] ; then - echo "Importing image ${image_name} as ${image_tagged}" - # Use --reference-policy=local to pull remote image content to the cluster - # Works around the issue of builder pods not having access to registry.redhat.io - oc tag --source=docker "${image_name}" "${namespace}/${image_tagged}" --insecure=true --reference-policy=local - ct_os_wait_stream_ready "${image_tagged}" "${namespace}" + # Upload main image is already done by CVP pipeline. No need to do it twice. + if [ "${CVP:-0}" -eq "0" ]; then + # Create a specific imagestream tag for the image so that oc cannot use anything else + if [ "${CT_EXTERNAL_REGISTRY:-false}" == 'true' ] ; then + ct_os_import_image_ocp4 "${image_name}" "${image_tagged}" else - echo "Uploading image ${image_name} as ${image_tagged}" - ct_os_upload_image "${image_name}" "${image_tagged}" + if [ "${CT_SKIP_UPLOAD_IMAGE:-false}" == 'true' ] ; then + echo "Importing image ${image_name} as ${image_tagged}" + # Use --reference-policy=local to pull remote image content to the cluster + # Works around the issue of builder pods not having access to registry.redhat.io + oc tag --source=docker "${image_name}" "${namespace}/${image_tagged}" --insecure=true --reference-policy=local + ct_os_wait_stream_ready "${image_tagged}" "${namespace}" + else + echo "Uploading image ${image_name} as ${image_tagged}" + ct_os_upload_image "${image_name}" "${image_tagged}" + fi fi + else + echo "Import is already done by CVP pipeline." fi + # Other images are not uploaded by CVP pipeline. We need to do it. if [ "${CT_SKIP_UPLOAD_IMAGE:-false}" == 'false' ] ; then # upload also other images, that template might need (list of pairs in the format | local image_tag_a @@ -825,7 +841,14 @@ function ct_os_test_template_app_func() { for i_t in ${other_images} ; do echo "${i_t}" IFS='|' read -ra image_tag_a <<< "${i_t}" - docker pull "${image_tag_a[0]}" + if [[ "$(docker images -q "$image_name" 2>/dev/null)" == "" ]]; then + echo "ERROR: Image $image_name is not pulled yet." + docker images + echo "Add to the beginning of scripts run-openshift-remote-cluster and run-openshift row" + echo "'ct_pull_image $image_name true'." + exit 1 + fi + if [ "${CT_EXTERNAL_REGISTRY:-false}" == 'true' ] ; then ct_os_import_image_ocp4 "${image_tag_a[0]}" "${image_tag_a[1]}" else @@ -1043,7 +1066,7 @@ ct_os_test_response_internal() { local status local response_code local response_file - local util_image_name='ubi7/ubi' + local util_image_name='registry.access.redhat.com/ubi7/ubi' response_file=$(mktemp /tmp/ct_test_response_XXXXXX) ct_os_deploy_cmd_image "${util_image_name}" diff --git a/test/test-lib-remote-openshift.sh b/test/test-lib-remote-openshift.sh index fd9a684..bda03f6 100644 --- a/test/test-lib-remote-openshift.sh +++ b/test/test-lib-remote-openshift.sh @@ -47,6 +47,10 @@ function ct_os_set_path_oc_4() { # # function ct_os_set_ocp4() { + if [ "${CVP:-0}" -eq "1" ]; then + echo "Testing in CVP environment. No need to login to OpenShift cluster. This is already done by CVP pipeline." + return + fi local login OS_OC_CLIENT_VERSION=${OS_OC_CLIENT_VERSION:-4.4} ct_os_set_path_oc_4 "${OS_OC_CLIENT_VERSION}" diff --git a/test/test-lib.sh b/test/test-lib.sh index b219ffd..42f22ba 100644 --- a/test/test-lib.sh +++ b/test/test-lib.sh @@ -2,11 +2,11 @@ # # Test a container image. # -# Always use sourced from a specific container testfile +# Always use sourced from a specific container testfile # # reguires definition of CID_FILE_DIR # CID_FILE_DIR=$(mktemp --suffix=_test_cidfiles -d) -# reguires definition of TEST_LIST +# reguires definition of TEST_LIST # TEST_LIST="\ # ctest_container_creation # ctest_doc_content" @@ -52,6 +52,50 @@ function ct_enable_cleanup() { trap ct_cleanup EXIT SIGINT } +# ct_pull_image +# ------------- +# Function pull an image before tests execution +# Argument: image_name - string containing the public name of the image to pull +# Argument: exit - in case "true" is defined and pull failed, then script has to exit with 1 and no tests are executed +# Argument: loops - how many times to pull image in case of failure +# Function returns either 0 in case of pull was successful +# Or the test suite exit with 1 in case of pull error +function ct_pull_image() { + local image_name="$1"; shift + local exit=${1:-"false"}; shift + local loops=${1:-10}; shift + local loop=0 + + # Let's try to pull image. + echo "-> Pulling image $image_name ..." + # Sometimes in Fedora case it fails with HTTP 50X + # Check if the image is available locally and try to pull it if it is not + if [[ "$(docker images -q "$image_name" 2>/dev/null)" != "" ]]; then + echo "The image $image_name is already pulled." + return 0 + fi + + # Try pulling the image to see if it is accessible + # WORKAROUND: Since Fedora registry sometimes fails randomly, let's try it more times + while ! docker pull "$image_name"; do + ((loop++)) || : + echo "Pulling image $image_name failed." + if [ "$loop" -gt "$loops" ]; then + echo "Pulling of image $image_name failed $loops times in a row. Giving up." + echo "!!! ERROR with pulling image $image_name !!!!" + # shellcheck disable=SC2268 + if [[ x"$exit" == x"false" ]]; then + return 1 + else + exit 1 + fi + fi + echo "Let's wait $((loop*5)) seconds and try again." + sleep "$((loop*5))" + done +} + + # ct_check_envs_set env_filter check_envs loop_envs [env_format] # -------------------- # Compares values from one list of environment variable definitions against such list, @@ -185,7 +229,7 @@ function ct_assert_container_creation_fails() { function ct_create_container() { local cid_file="$CID_FILE_DIR/$1" ; shift # create container with a cidfile in a directory for cleanup - # shellcheck disable=SC2086 + # shellcheck disable=SC2086,SC2153 docker run --cidfile="$cid_file" -d ${CONTAINER_ARGS:-} "$IMAGE_NAME" "$@" ct_wait_for_cid "$cid_file" || return 1 : "Created container $(cat "$cid_file")" @@ -310,6 +354,7 @@ function ct_npm_works() { if ! docker exec "$(cat "$cid_file")" /bin/bash -c "npm --verbose install jquery && test -f node_modules/jquery/src/jquery.js" >"${tmpdir}/jquery" 2>&1 ; then echo "ERROR: npm could not install jquery inside the image ${IMAGE_NAME}." >&2 + cat "${tmpdir}/jquery" return 1 fi @@ -582,13 +627,13 @@ ct_get_public_image_name() { local registry registry=$(ct_registry_from_os "$os") - if [ "x$os" == "xrhel7" ]; then + if [ "$os" == "rhel7" ]; then public_image_name=$registry/rhscl/$base_image_name-${version//./}-rhel7 - elif [ "x$os" == "xrhel8" ]; then + elif [ "$os" == "rhel8" ]; then public_image_name=$registry/rhel8/$base_image_name-${version//./} - elif [ "x$os" == "xcentos7" ]; then + elif [ "$os" == "centos7" ]; then public_image_name=$registry/centos7/$base_image_name-${version//./}-centos7 - elif [ "x$os" == "xcentos8" ]; then + elif [ "$os" == "centos8" ]; then public_image_name=$registry/centos8/$base_image_name-${version//./}-centos8 fi @@ -670,7 +715,7 @@ ct_s2i_build_as_df() local df_name= local tmpdir= local incremental=false - local mount_options="" + local mount_options=() # Run the entire thing inside a subshell so that we do not leak shell options outside of the function ( @@ -687,14 +732,11 @@ ct_s2i_build_as_df() # Default to root if no user is set by the image user=${user:-0} # run the user through the image in case it is non-numeric or does not exist - # NOTE: The '-eq' test is used to check if $user is numeric as it will fail if $user is not an integer - if ! [ "$user" -eq "$user" ] 2>/dev/null && ! user_id=$(docker run --rm "$src_image" bash -c "id -u $user 2>/dev/null"); then - echo "ERROR: id of user $user not found inside image $src_image." + if ! user_id=$(ct_get_uid_from_image "$user" "$src_image"); then echo "Terminating s2i build." return 1 - else - user_id=${user_id:-$user} fi + echo "$s2i_args" | grep -q "\-\-incremental" && incremental=true if $incremental; then inc_tmp=$(mktemp -d --tmpdir incremental.XXXX) @@ -757,14 +799,93 @@ EOF fi # Check if -v parameter is present in s2i_args and add it into docker build command - mount_options=$(echo "$s2i_args" | grep -o -e '\(-v\)[[:space:]]\.*\S*' || true) + read -ra mount_options <<< "$(echo "$s2i_args" | grep -o -e '\(-v\)[[:space:]]\.*\S*' || true)" # Run the build and tag the result - # shellcheck disable=SC2086 - docker build $mount_options -f "$df_name" --no-cache=true -t "$dst_image" . + docker build ${mount_options[@]+"${mount_options[@]}"} -f "$df_name" --no-cache=true -t "$dst_image" . ) } +# ct_s2i_multistage_build APP_PATH SRC_IMAGE DST_IMAGE SEC_IMAGE [S2I_ARGS] +# ---------------------------- +# Create a new s2i app image from local sources in a similar way as source-to-image would have used. +# Argument: APP_PATH - local path to the app sources to be used in the test +# Argument: SRC_IMAGE - image to be used as a base for the s2i build process +# Argument: SEC_IMAGE - image to be used as the base for the result of the build process +# Argument: DST_IMAGE - image name to be used during the tagging of the s2i build result +# Argument: S2I_ARGS - Additional list of source-to-image arguments. +# Only used to check for environment variable definitions. +ct_s2i_multistage_build() { + + local app_path=$1; shift + local src_image=$1; shift + local sec_image=$1; shift + local dst_image=$1; shift + local s2i_args=$*; + local local_app="app-src" + local user_id= + local mount_options=() + + + # Run the entire thing inside a subshell so that we do not leak shell options outside of the function + ( + # Error out if any part of the build fails + set -e + + user=$(docker inspect -f "{{.Config.User}}" "$src_image") + # Default to root if no user is set by the image + user=${user:-0} + # run the user through the image in case it is non-numeric or does not exist + if ! user_id=$(ct_get_uid_from_image "$user" "$src_image"); then + echo "Terminating s2i build." + return 1 + fi + + # Use /tmp to not pollute cwd + tmpdir=$(mktemp -d) + df_name=$(mktemp -p "$tmpdir" Dockerfile.XXXX) + cd "$tmpdir" + + # If the path exists on the local host, copy it into the directory for the build + # Otherwise handle it as a link to a git repository + if [ -e "${app_path/file:\/\//}/." ] ; then + mkdir -p "$local_app" + # Strip file:// from APP_PATH and copy its contents into current context + cp -r "${app_path/file:\/\//}/." "$local_app" + + else + ct_clone_git_repository "$app_path" "$local_app" + fi + + cat <"$df_name" +# First stage builds the application +FROM $src_image as builder +# Add application sources to a directory that the assemble script expects them +# and set permissions so that the container runs without root access +USER 0 +ADD app-src /tmp/src +RUN chown -R 1001:0 /tmp/src +$(echo "$s2i_args" | grep -o -e '\(-e\|--env\)[[:space:]=]\S*=\S*' | sed -e 's/-e /ENV /' -e 's/--env[ =]/ENV /') +# Check if CA autority is present on host and add it into Dockerfile +$([ -f "$(full_ca_file_path)" ] && echo "RUN cd /etc/pki/ca-trust/source/anchors && update-ca-trust extract") +USER $user_id +# Install the dependencies +RUN /usr/libexec/s2i/assemble +# Second stage copies the application to the minimal image +FROM $sec_image +# Copy the application source and build artifacts from the builder image to this one +COPY --from=builder \$HOME \$HOME +# Set the default command for the resulting image +CMD /usr/libexec/s2i/run +EOF + + # Check if -v parameter is present in s2i_args and add it into docker build command + read -ra mount_options <<< "$(echo "$s2i_args" | grep -o -e '\(-v\)[[:space:]]\.*\S*' || true)" + + docker build ${mount_options[@]+"${mount_options[@]}"} -f "$df_name" --no-cache=true -t "$dst_image" . + ) +} + # ct_check_image_availability PUBLIC_IMAGE_NAME # ---------------------------- # Pull an image from the public repositories to see if the image is already available. @@ -773,7 +894,7 @@ ct_check_image_availability() { local public_image_name=$1; # Try pulling the image to see if it is accessible - if ! docker pull "$public_image_name" &>/dev/null; then + if ! ct_pull_image "$public_image_name" &>/dev/null; then echo "$public_image_name could not be downloaded via 'docker'" return 1 fi @@ -823,6 +944,50 @@ ct_show_resources() lscpu } +# ct_clone_git_repository +# ----------------------------- +# Argument: app_url - git URI pointing to a repository, supports "@" to indicate a different branch +# Argument: app_dir (optional) - name of the directory to clone the repository into +ct_clone_git_repository() +{ + local app_url=$1; shift + local app_dir=$1 + + # If app_url contains @, the string after @ is considered + # as a name of a branch to clone instead of the main/master branch + IFS='@' read -ra git_url_parts <<< "${app_url}" + + if [ -n "${git_url_parts[1]}" ]; then + git_clone_cmd="git clone --branch ${git_url_parts[1]} ${git_url_parts[0]} ${app_dir}" + else + git_clone_cmd="git clone ${app_url} ${app_dir}" + fi + + if ! $git_clone_cmd ; then + echo "ERROR: Git repository ${app_url} cannot be cloned into ${app_dir}." + return 1 + fi +} + +# ct_get_uid_from_image +# ----------------------------- +# Argument: user - user to get uid for inside the image +# Argument: src_image - image to use for user information +ct_get_uid_from_image() +{ + local user=$1; shift + local src_image=$1 + local user_id= + + # NOTE: The '-eq' test is used to check if $user is numeric as it will fail if $user is not an integer + if ! [ "$user" -eq "$user" ] 2>/dev/null && ! user_id=$(docker run --rm "$src_image" bash -c "id -u $user 2>/dev/null"); then + echo "ERROR: id of user $user not found inside image $src_image." + return 1 + else + echo "${user_id:-$user}" + fi +} + # ct_test_app_dockerfile # ----------------------------- # Argument: dockerfile - path to a Dockerfile that will be used for building an image @@ -867,20 +1032,9 @@ ct_test_app_dockerfile() { if [ -d "$app_url" ] ; then echo "Copying local folder: $app_url -> $app_dir." - cp -Lr $app_url $app_dir + cp -Lr "$app_url" "$app_dir" else - # If app_url contains @, the string after @ is considered - # as a name of a branch to clone instead of the main/master branch - IFS='@' read -ra git_url_parts <<< "${app_url}" - - if [ -n "${git_url_parts[1]}" ]; then - git_clone_cmd="git clone --branch ${git_url_parts[1]} ${git_url_parts[0]} ${app_dir}" - else - git_clone_cmd="git clone ${app_url} ${app_dir}" - fi - - if ! $git_clone_cmd ; then - echo "ERROR: Git repository ${app_url} cannot be cloned into ${app_dir}." + if ! ct_clone_git_repository "$app_url" "$app_dir" ; then echo "Terminating the Dockerfile build." return 1 fi