1
0
mirror of https://github.com/quay/quay.git synced 2026-01-26 06:21:37 +03:00

build: move quay to python 3.12 (PROJQUAY-8800) (#3780)

Move Quay to python version 3.12 and switch out rehash with the resumable hash library.
This commit is contained in:
Syed Ahmed
2025-05-29 09:35:48 -04:00
committed by GitHub
parent 5d27fd009d
commit 723102e641
13 changed files with 121 additions and 197 deletions

View File

@@ -18,10 +18,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Python 3.9
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: 3.9
python-version: 3.12
- name: Install dependencies
run: |
@@ -57,10 +57,10 @@ jobs:
with:
fetch-depth: 0 # fetch all commits and branches for pre-commit
- name: Set up Python 3.9
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: 3.9
python-version: 3.12
- name: Set up Node 18
uses: actions/setup-node@v3
@@ -85,31 +85,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Install deps and OpenSSL 1.1
run: |
sudo apt-get -y update
sudo apt-get install -y wget build-essential
wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz
tar -xzf openssl-1.1.1w.tar.gz
cd openssl-1.1.1w
./config --prefix=/opt/openssl-1.1 --openssldir=/opt/openssl-1.1
sudo make install
- name: Download Python and configure python with OpenSSL 1.1
run: |
cd /usr/local/src
sudo wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz
sudo tar -xzf Python-3.9.0.tgz
cd Python-3.9.0
sudo ./configure --prefix=/opt/python3.9-openssl1.1 \
--with-openssl=/opt/openssl-1.1 \
--enable-optimizations
sudo make -j$(nproc)
sudo make altinstall
- name: Test OpenSSL version
run: |
/opt/python3.9-openssl1.1/bin/python3.9 -c "import ssl; print(ssl.OPENSSL_VERSION)"
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: 3.12
- name: Install dependencies
run: |
@@ -119,10 +98,7 @@ jobs:
- name: tox
run: |
/opt/python3.9-openssl1.1/bin/python3.9 -c "import ssl; print(ssl.OPENSSL_VERSION)"
/opt/python3.9-openssl1.1/bin/python3.9 -m venv .venv
source .venv/bin/activate
tox -e py39-unit -- --cov=./ --cov-report=xml
tox -e py312-unit -- --cov=./ --cov-report=xml
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
@@ -138,10 +114,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Python 3.9
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: 3.9
python-version: 3.12
cache: 'pip'
cache-dependency-path: |
requirements.txt
@@ -172,31 +148,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Install deps and OpenSSL 1.1
run: |
sudo apt-get -y update
sudo apt-get install -y wget build-essential
wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz
tar -xzf openssl-1.1.1w.tar.gz
cd openssl-1.1.1w
./config --prefix=/opt/openssl-1.1 --openssldir=/opt/openssl-1.1
sudo make install
- name: Download Python and configure python with OpenSSL 1.1
run: |
cd /usr/local/src
sudo wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz
sudo tar -xzf Python-3.9.0.tgz
cd Python-3.9.0
sudo ./configure --prefix=/opt/python3.9-openssl1.1 \
--with-openssl=/opt/openssl-1.1 \
--enable-optimizations
sudo make -j$(nproc)
sudo make altinstall
- name: Test OpenSSL version
run: |
/opt/python3.9-openssl1.1/bin/python3.9 -c "import ssl; print(ssl.OPENSSL_VERSION)"
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: 3.12
- name: Install dependencies
run: |
@@ -207,10 +162,7 @@ jobs:
- name: tox
run: |
/opt/python3.9-openssl1.1/bin/python3.9 -c "import ssl; print(ssl.OPENSSL_VERSION)"
/opt/python3.9-openssl1.1/bin/python3.9 -m venv .venv
source .venv/bin/activate
tox -e py39-e2e
tox -e py312-e2e
registry:
name: E2E Registry Tests
@@ -220,31 +172,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Install deps and OpenSSL 1.1
run: |
sudo apt-get -y update
sudo apt-get install -y wget build-essential
wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz
tar -xzf openssl-1.1.1w.tar.gz
cd openssl-1.1.1w
./config --prefix=/opt/openssl-1.1 --openssldir=/opt/openssl-1.1
sudo make install
- name: Download Python and configure python with OpenSSL 1.1
run: |
cd /usr/local/src
sudo wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz
sudo tar -xzf Python-3.9.0.tgz
cd Python-3.9.0
sudo ./configure --prefix=/opt/python3.9-openssl1.1 \
--with-openssl=/opt/openssl-1.1 \
--enable-optimizations
sudo make -j$(nproc)
sudo make altinstall
- name: Test OpenSSL version
run: |
/opt/python3.9-openssl1.1/bin/python3.9 -c "import ssl; print(ssl.OPENSSL_VERSION)"
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: 3.12
- name: Install dependencies
run: |
@@ -255,10 +186,7 @@ jobs:
- name: tox
run: |
/opt/python3.9-openssl1.1/bin/python3.9 -c "import ssl; print(ssl.OPENSSL_VERSION)"
/opt/python3.9-openssl1.1/bin/python3.9 -m venv .venv
source .venv/bin/activate
tox -e py39-registry
tox -e py312-registry
cypress:
name: Cypress Tests
@@ -288,10 +216,10 @@ jobs:
- name: Seed Database
run: cd web && npm run quay:seed
- name: Set up Python 3.9
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: 3.9
python-version: 3.12
- name: Install dependencies
run: |
@@ -355,31 +283,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Install deps and OpenSSL 1.1
run: |
sudo apt-get -y update
sudo apt-get install -y wget build-essential
wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz
tar -xzf openssl-1.1.1w.tar.gz
cd openssl-1.1.1w
./config --prefix=/opt/openssl-1.1 --openssldir=/opt/openssl-1.1
sudo make install
- name: Download Python and configure python with OpenSSL 1.1
run: |
cd /usr/local/src
sudo wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz
sudo tar -xzf Python-3.9.0.tgz
cd Python-3.9.0
sudo ./configure --prefix=/opt/python3.9-openssl1.1 \
--with-openssl=/opt/openssl-1.1 \
--enable-optimizations
sudo make -j$(nproc)
sudo make altinstall
- name: Test OpenSSL version
run: |
/opt/python3.9-openssl1.1/bin/python3.9 -c "import ssl; print(ssl.OPENSSL_VERSION)"
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: 3.12
- name: Install dependencies
run: |
@@ -393,10 +300,7 @@ jobs:
- name: tox
run: |
/opt/python3.9-openssl1.1/bin/python3.9 -c "import ssl; print(ssl.OPENSSL_VERSION)"
/opt/python3.9-openssl1.1/bin/python3.9 -m venv .venv
source .venv/bin/activate
tox -e py39-mysql
tox -e py312-mysql
psql:
name: E2E Postgres Test
@@ -406,31 +310,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Install deps and OpenSSL 1.1
run: |
sudo apt-get -y update
sudo apt-get install -y wget build-essential
wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz
tar -xzf openssl-1.1.1w.tar.gz
cd openssl-1.1.1w
./config --prefix=/opt/openssl-1.1 --openssldir=/opt/openssl-1.1
sudo make install
- name: Download Python and configure python with OpenSSL 1.1
run: |
cd /usr/local/src
sudo wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz
sudo tar -xzf Python-3.9.0.tgz
cd Python-3.9.0
sudo ./configure --prefix=/opt/python3.9-openssl1.1 \
--with-openssl=/opt/openssl-1.1 \
--enable-optimizations
sudo make -j$(nproc)
sudo make altinstall
- name: Test OpenSSL version
run: |
/opt/python3.9-openssl1.1/bin/python3.9 -c "import ssl; print(ssl.OPENSSL_VERSION)"
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: 3.12
- name: Install dependencies
run: |
@@ -444,7 +327,4 @@ jobs:
- name: tox
run: |
/opt/python3.9-openssl1.1/bin/python3.9 -c "import ssl; print(ssl.OPENSSL_VERSION)"
/opt/python3.9-openssl1.1/bin/python3.9 -m venv .venv
source .venv/bin/activate
tox -e py39-psql
tox -e py312-psql

View File

@@ -1,18 +1,26 @@
FROM registry.access.redhat.com/ubi8/ubi-minimal:latest AS base
FROM registry.access.redhat.com/ubi9/python-312:latest as base
# Only set variables or install packages that need to end up in the
# final container here.
USER root
ENV PATH=/app/bin/:$PATH \
PYTHONUNBUFFERED=1 \
PYTHONIOENCODING=UTF-8 \
LC_ALL=C.UTF-8 \
LANG=C.UTF-8
PYTHON_VERSION=3.12 \
PATH=$HOME/.local/bin/:$PATH \
PYTHONUNBUFFERED=1 \
PYTHONIOENCODING=UTF-8 \
LC_ALL=en_US.UTF-8 \
LANG=en_US.UTF-8 \
CNB_STACK_ID=com.redhat.stacks.ubi9-python-312 \
CNB_USER_ID=1001 \
CNB_GROUP_ID=0 \
PIP_NO_CACHE_DIR=off
ENV PYTHONUSERBASE /app
ENV TZ UTC
RUN set -ex\
; microdnf -y module enable nginx:1.22 \
; microdnf -y module enable python39:3.9 \
; microdnf update -y \
; microdnf -y --setopt=tsflags=nodocs install \
; dnf -y module enable nginx:1.22 \
; dnf update -y \
; dnf -y --setopt=tsflags=nodocs install \
dnsmasq \
memcached \
nginx \
@@ -20,13 +28,12 @@ RUN set -ex\
libjpeg-turbo \
openldap \
openssl \
python39 \
python3-gpg \
python3-six \
skopeo \
findutils \
; microdnf -y reinstall tzdata \
; microdnf remove platform-python-pip python39-pip \
; microdnf -y clean all && rm -rf /var/cache/yum
; dnf -y reinstall tzdata \
; dnf -y clean all && rm -rf /var/cache/yum
# Config-editor builds the javascript for the configtool.
FROM registry.access.redhat.com/ubi8/nodejs-16 AS config-editor
@@ -42,11 +49,11 @@ RUN set -ex\
FROM base AS build-python
ENV PYTHONDONTWRITEBYTECODE 1
RUN set -ex\
; microdnf -y --setopt=tsflags=nodocs install \
; dnf -y --setopt=tsflags=nodocs install \
gcc-c++ \
git \
openldap-devel \
python39-devel \
python3.12-devel \
libffi-devel \
openssl-devel \
diffutils \
@@ -59,7 +66,7 @@ RUN set -ex\
libxml2-devel \
libxslt-devel \
freetype-devel \
; microdnf -y clean all
; dnf -y clean all
WORKDIR /build
RUN python3 -m ensurepip --upgrade
COPY requirements.txt .
@@ -77,25 +84,27 @@ ENV CARGO_NET_GIT_FETCH_WITH_CLI=true
# In Future if wget is to be removed , then uncomment below line for grpc installation on IBMZ i.e. s390x
ENV GRPC_PYTHON_BUILD_SYSTEM_OPENSSL 1
USER 1001
RUN ARCH=$(uname -m) ; echo $ARCH; \
if [ "$ARCH" == "ppc64le" ] ; then \
GE_LATEST=$(grep "gevent" requirements.txt |cut -d "=" -f 3); \
wget https://github.com/IBM/oss-ecosystem-gevent/releases/download/${GE_LATEST}/manylinux_ppc64le_wheels_${GE_LATEST}.tar.gz; \
tar xvf manylinux_ppc64le_wheels_${GE_LATEST}.tar.gz; \
python3 -m pip install --no-cache-dir --user wheelhouse/gevent-${GE_LATEST}-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl; \
python3 -m pip install --no-cache-dir wheelhouse/gevent-${GE_LATEST}-cp39-cp3.12-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl; \
GRPC_LATEST=$(grep "grpcio" requirements.txt |cut -d "=" -f 3); \
wget https://github.com/IBM/oss-ecosystem-grpc/releases/download/${GRPC_LATEST}/grpcio-${GRPC_LATEST}-cp39-cp39-linux_ppc64le.whl; \
python3 -m pip install --no-cache-dir --user grpcio-${GRPC_LATEST}-cp39-cp39-linux_ppc64le.whl; \
python3 -m pip install --no-cache-dir grpcio-${GRPC_LATEST}-cp39-cp39-linux_ppc64le.whl; \
fi
RUN set -ex\
; python3 -m pip install --no-cache-dir --progress-bar off --user $(grep -e '^pip=' -e '^wheel=' -e '^setuptools=' ./requirements.txt) \
; python3 -m pip install --no-cache-dir --progress-bar off --user --requirement requirements.txt \
; python3 -m pip install --no-cache-dir --progress-bar off $(grep -e '^pip=' -e '^wheel=' -e '^setuptools=' ./requirements.txt) \
; python3 -m pip install --no-cache-dir --progress-bar off --requirement requirements.txt \
;
RUN set -ex\
# Doing this is explicitly against the purpose and use of certifi.
; for dir in\
$(find "$(python3 -m site --user-base)" -type d -name certifi)\
$(find "/opt/app-root/lib/python3.12/site-packages" -type d -name certifi)\
; do chgrp -R 0 "$dir" && chmod -R g=u "$dir" ; done\
;
@@ -169,7 +178,6 @@ ENV PYTHONPATH $QUAYPATH
# Openshift runs a container as a random UID and GID 0, so anything
# that's in the base image and needs to be modified at runtime needs
# to make sure it's group-writable.
RUN alternatives --set python /usr/bin/python3
RUN set -ex\
; setperms() { for d in "$@"; do chgrp -R 0 "$d" && chmod -R g=u "$d" && ls -ld "$d"; done; }\
; newdir() { for d in "$@"; do mkdir -m 775 "$d" && ls -ld "$d"; done; }\
@@ -185,15 +193,26 @@ RUN set -ex\
; ln -s $QUAYCONF /conf\
# Make a grip of runtime directories.
; newdir /certificates "$QUAYDIR" "$QUAYDIR/conf" "$QUAYDIR/conf/stack" /datastorage\
# Another Openshift-ism: it doesn't bother picking a uid that means
# anything to the OS inside the container, so the process needs
# permissions to modify the user database.
# Harden /etc/passwd no group write.
; chown root:root /etc/passwd \
; chmod 0644 /etc/passwd \
;
; chown -R 1001:0 /etc/pki/ \
; chown -R 1001:0 /etc/ssl/ \
; chown -R 1001:0 /quay-registry \
; chmod ug+wx -R /etc/pki/ \
; chmod ug+wx -R /etc/ssl/
RUN python3 -m pip install --no-cache-dir --progress-bar off dumb-init
WORKDIR $QUAYDIR
# Ordered from least changing to most changing.
COPY --from=pushgateway /usr/local/bin/pushgateway /usr/local/bin/pushgateway
COPY --from=build-python /app /app
COPY --from=build-python /opt/app-root/lib/python3.12/site-packages /opt/app-root/lib/python3.12/site-packages
COPY --from=build-python /opt/app-root/bin /opt/app-root/bin
COPY --from=config-tool /opt/app-root/src/go/bin/config-tool /bin
COPY --from=build-quaydir /quaydir $QUAYDIR

View File

@@ -156,7 +156,7 @@ generate-proto-py:
black:
black --line-length=100 --target-version=py39 --exclude "/(\.eggs|\.git|\.hg|\.mypy_cache|\.nox|\.tox|\.venv|_build|buck-out|build|dist)/" .
black --line-length=100 --target-version=py312 --exclude "/(\.eggs|\.git|\.hg|\.mypy_cache|\.nox|\.tox|\.venv|_build|buck-out|build|dist)/" .
#################################
# Local Development Environment #

View File

@@ -5,7 +5,7 @@ QUAYCONF=${QUAYCONF:-"$QUAYPATH/conf"}
QUAYCONFIG=${QUAYCONFIG:-"$QUAYCONF/stack"}
CERTDIR=${CERTDIR:-"$QUAYCONFIG/extra_ca_certs"}
SYSTEM_CERTDIR=${SYSTEM_CERTDIR:-"/etc/pki/ca-trust/source/anchors"}
PYTHONUSERBASE_SITE_PACKAGE=${PYTHONUSERBASE_SITE_PACKAGE:-"$(python -m site --user-site)"}
PYTHONUSERBASE_SITE_PACKAGE=/opt/app-root/lib/python3.12/site-packages
cd ${QUAYDIR:-"/quay-registry"}
@@ -64,4 +64,11 @@ do
done
# Update all CA certificates.
update-ca-trust extract
# hack for UBI9, extract it a temp location and move
# to /etc/pki after because of permission issues
mkdir -p /tmp/extracted
rm -rf /etc/pki/ca-trust/extracted
update-ca-trust extract -o /tmp/extracted
chmod ug+w -R /tmp/extracted
mv /tmp/extracted /etc/pki/ca-trust

View File

@@ -14,7 +14,7 @@ from datetime import datetime
from enum import Enum, IntEnum, unique
from random import SystemRandom
import rehash
import resumablesha256 as rehash
import toposort
from cachetools.func import lru_cache
from peewee import *

View File

@@ -5,8 +5,6 @@ import pytest
from dateutil.parser import parse
from mock import Mock, patch
from data.logs_model import configure
from .mock_elasticsearch import *
from .test_elasticsearch import (
app_config,
@@ -15,6 +13,7 @@ from .test_elasticsearch import (
mock_db_model,
mock_elasticsearch,
)
from data.logs_model import configure
logger = logging.getLogger(__name__)
@@ -64,7 +63,7 @@ def test_kafka_logs_producers(
producer_config = kafka_logs_producer_config
with patch("kafka.client_async.KafkaClient.check_version"), patch(
"kafka.KafkaProducer.send"
) as mock_send, patch("kafka.KafkaProducer._max_usable_produce_magic"):
) as mock_send, patch("kafka.KafkaProducer.max_usable_produce_magic"):
configure(producer_config)
logs_model.log_action(
"pull_repo",

View File

@@ -1,6 +1,6 @@
from abc import ABCMeta, abstractmethod, abstractproperty
from deprecated import deprecated
from deprecation import deprecated
from six import add_metaclass
@@ -58,7 +58,7 @@ class SecurityScannerInterface(object):
"""
@abstractproperty
@deprecated(reason="Only exposed for the legacy notification worker")
@deprecated(details="Only exposed for the legacy notification worker")
def legacy_api_handler(self):
"""
Exposes the legacy security scan API for legacy workers that need it or None if none.

View File

@@ -191,3 +191,9 @@ ignore_missing_imports = True
[mypy-xhtml2pdf]
ignore_missing_imports = True
[mypy-resumablesha256]
ignore_missing_imports = True
[mypy-deprecation]
ignore_missing_imports = True

View File

@@ -49,7 +49,7 @@ jmespath==1.0.1
jsonpath-rw==1.4.0
jsonpointer==2.4
jsonschema==3.2.0
kafka-python==1.4.7
kafka-python==2.2.10
keystoneauth1==3.18.0
Mako==1.2.4
MarkupSafe==2.1.3
@@ -78,7 +78,7 @@ os-service-types==1.7.0
peewee==3.13.1
pillow==10.3.0
ply==3.11
prometheus-client==0.7.1
prometheus_client==0.7.1
protobuf==5.28.2
psutil==5.9.0
psycopg2==2.9.9
@@ -114,9 +114,9 @@ requests-oauthlib==1.3.1
rfc3986==1.3.2
s3transfer==0.7.0
semantic-version==2.10.0
six==1.14.0
six==1.17.0
soupsieve==1.9.5
splunk-sdk==1.7.4
splunk-sdk==2.1.0
SQLAlchemy==1.4.49
stevedore==5.1.0
stringscore==0.1.0
@@ -135,6 +135,8 @@ WebOb==1.8.8
websocket-client==1.7.0
Werkzeug==3.0.6
xhtml2pdf==0.2.6
resumablesha256==1.0
deprecation==2.1.0
# Leverage wheels for faster builds
setuptools==71.1.0
@@ -164,7 +166,7 @@ tinycss2==1.2.1
tqdm==4.66.4
typing_extensions==4.8.0
tzdata==2023.3
wrapt==1.13.3
wrapt==1.17.2
zipp==3.19.2
zope.event==5.0
zope.interface==5.4.0

View File

@@ -4,8 +4,6 @@ import hashlib
import tarfile
from io import BytesIO
import bencode
import rehash
from werkzeug.datastructures import Accept
from app import app as original_app

View File

@@ -222,6 +222,12 @@ def _create_app(requires_email=True):
"interface": "admin",
"id": "29beb2f1567642eb810b042b6719ea88",
},
{
"url": server_url + "/v3/identity",
"region": "RegionOne",
"interface": "public",
"id": "29beb2f1567642eb810b042b6719ea89",
},
],
"type": "identity",
"id": "bd73972c0e14fb69bae8ff76e112a90",

View File

@@ -1,5 +1,5 @@
[tox]
envlist = py39-{unit,registry,e2e,mysql,psql}
envlist = py312-{unit,registry,e2e,mysql,psql}
skipsdist = True
[pytest]
@@ -39,7 +39,7 @@ environment =
MYSQL_ALLOW_EMPTY_PASSWORD=1
MYSQL_USER=quay
[testenv:py39-unit]
[testenv:py312-unit]
setenv =
PYTHONDONTWRITEBYTECODE = 1
PYTHONPATH={toxinidir}{:}{toxinidir}
@@ -52,7 +52,7 @@ commands =
alembic upgrade head
pytest --timeout=3600 -m {env:MARKERS} --exitfirst --ignore=buildman/test/test_buildman.py -vv {env:FILE:} {posargs}
[testenv:py39-mysql]
[testenv:py312-mysql]
setenv =
PYTHONDONTWRITEBYTECODE = 1
PYTHONPATH={toxinidir}{:}{toxinidir}
@@ -80,7 +80,7 @@ environment =
POSTGRES_PASSWORD=quay
POSTGRES_USER=quay
[testenv:py39-psql]
[testenv:py312-psql]
# TODO(kleesc): Re-enable buildman tests after buildman rewrite
setenv =
PYTHONDONTWRITEBYTECODE = 1

View File

@@ -54,6 +54,13 @@ class GeneratorFile(object):
def flush(self):
_complain_ifclosed(self._closed)
@property
def closed(self):
"""
Return whether the file is closed.
"""
return self._closed
def read(self, size=-1):
"""
Read at most size bytes from the file (less if the read hits EOF before obtaining size