From b1b34aeccd2247c426a781337a7575e56b492ba4 Mon Sep 17 00:00:00 2001 From: František Zatloukal Date: Jan 27 2021 11:33:41 +0000 Subject: [PATCH 1/2] OpenShift --- diff --git a/.s2i/environment b/.s2i/environment new file mode 100644 index 0000000..4ef93c8 --- /dev/null +++ b/.s2i/environment @@ -0,0 +1,2 @@ +UPGRADE_PIP_TO_LATEST=1 +APP_CONFIG=/opt/app-root/src/gunicorn.cfg diff --git a/Dockerfile b/Dockerfile index ce8825b..d905190 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,57 @@ -FROM fedoraqa/flask-base:24 +# This will produce an image to be used in Openshift +# Build should be triggered from repo root like: +# docker build -f openshift/Dockerfile \ +# --tag -COPY . /usr/src/resultsdb -WORKDIR /usr/src/resultsdb -EXPOSE 5001 -ENV DEV true -RUN pip install -r requirements.txt &&\ - python run_cli.py init_db +FROM fedora:32 +LABEL \ + name="ResultsDB application" \ + vendor="ResultsDB developers" \ + license="GPLv2+" \ + description="ResultsDB is a results store engine for, but not limited to, Fedora QA tools." \ + usage="https://pagure.io/taskotron/resultsdb/blob/develop/f/openshift/README.md" \ + build-date="" + +USER root +COPY ./resultsdb.spec /opt/app-root/src/resultsdb/resultsdb.spec + +# install dependencies defined in RPM spec file +RUN dnf -y install findutils rpm-build python3-pip python3-mod_wsgi httpd python3-psycopg2 python3-stomppy \ + && rpm --query --requires --specfile /opt/app-root/src/resultsdb/resultsdb.spec | xargs -d '\n' dnf -y install + +COPY . /opt/app-root/src/resultsdb/ +# install using --no-deps option to ensure nothing comes from PyPi +RUN pip3 install --no-deps /opt/app-root/src/resultsdb + +# fix apache config for container use +RUN sed -i 's#^WSGISocketPrefix .*#WSGISocketPrefix /tmp/wsgi#' /opt/app-root/src/resultsdb/conf/resultsdb.conf -CMD ["python", "runapp.py"] +# config files +RUN install -d /usr/share/resultsdb/conf \ + && install -p -m 0644 /opt/app-root/src/resultsdb/conf/resultsdb.conf /usr/share/resultsdb/conf/ \ + && install -p -m 0644 /opt/app-root/src/resultsdb/conf/resultsdb.wsgi /usr/share/resultsdb/ \ + && install -d /etc/resultsdb \ + && install -p -m 0644 /opt/app-root/src/resultsdb/conf/resultsdb.conf /etc/httpd/conf.d/ + +# alembic +RUN install -p -m 0644 /opt/app-root/src/resultsdb/alembic.ini /usr/share/resultsdb/alembic.ini +RUN cp -a /opt/app-root/src/resultsdb/resultsdb/alembic /usr/share/resultsdb/alembic +RUN chmod -R 0755 /usr/share/resultsdb/alembic + +# clean up +RUN rm -rf /opt/app-root/src/resultsdb \ + && dnf -y autoremove findutils rpm-build \ + && dnf clean all + +# EXPOSE 5001/tcp +EXPOSE 5001 +CMD ["mod_wsgi-express-3", "start-server", "/usr/share/resultsdb/resultsdb.wsgi", \ + "--user", "apache", "--group", "apache", \ + "--port", "5001", "--threads", "5", \ + "--include-file", "/etc/httpd/conf.d/resultsdb.conf", \ + "--log-level", "info", \ + "--log-to-terminal", \ + "--access-log", \ + "--startup-log" \ +] +USER 1001:0 diff --git a/gunicorn.cfg b/gunicorn.cfg new file mode 100644 index 0000000..099d7e2 --- /dev/null +++ b/gunicorn.cfg @@ -0,0 +1,5 @@ +import logging +import sys + +gunicorn_logger = logging.getLogger('gunicorn.error') +gunicorn_logger.addHandler(logging.StreamHandler(sys.stdout)) diff --git a/requirements.txt b/requirements.txt index 3e80d51..64a0848 100644 --- a/requirements.txt +++ b/requirements.txt @@ -21,4 +21,7 @@ SQLAlchemy >= 0.9.8 # Test suite requirements pytest >= 2.4.2 pytest-cov >= 1.6 + +# s2i requirements psycopg2 +gunicorn diff --git a/resultsdb/__init__.py b/resultsdb/__init__.py index 7313e1f..f42e535 100644 --- a/resultsdb/__init__.py +++ b/resultsdb/__init__.py @@ -19,6 +19,7 @@ # Ralph Bean from resultsdb import proxy +from . import config import flask from flask import Flask @@ -67,11 +68,13 @@ def jsonify_with_jsonp(*args, **kwargs): flask.jsonify = jsonify_with_jsonp +openshift = os.getenv('OPENSHIFT_PROD') + # Load default config, then override that with a config file if os.getenv('DEV') == 'true': default_config_obj = 'resultsdb.config.DevelopmentConfig' default_config_file = os.getcwd() + '/conf/settings.py' -elif os.getenv('TEST') == 'true': +elif os.getenv('TEST') == 'true' or openshift == "0": default_config_obj = 'resultsdb.config.TestingConfig' default_config_file = os.getcwd() + '/conf/settings.py' else: @@ -80,6 +83,9 @@ else: app.config.from_object(default_config_obj) +if openshift: + config.openshift_config(app.config, openshift) + config_file = os.environ.get('RESULTSDB_CONFIG', default_config_file) if os.path.exists(config_file): diff --git a/resultsdb/config.py b/resultsdb/config.py index 768e5f1..b436624 100644 --- a/resultsdb/config.py +++ b/resultsdb/config.py @@ -17,8 +17,9 @@ # Authors: # Josef Skladanka # Ralph Bean -import os +import os +import sys class Config(object): DEBUG = True @@ -116,3 +117,32 @@ class TestingConfig(Config): ADDITIONAL_RESULT_OUTCOMES = ('AMAZING',) MESSAGE_BUS_PLUGIN = 'dummy' MESSAGE_BUS_KWARGS = {} + +def openshift_config(config_object, openshift_production): + # First, get db details from env + try: + config_object["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg2://%s:%s@%s:%s/%s" % ( + os.environ["POSTGRESQL_USER"], + os.environ["POSTGRESQL_PASSWORD"], + os.environ["POSTGRESQL_SERVICE_HOST"], + os.environ["POSTGRESQL_SERVICE_PORT"], + os.environ["POSTGRESQL_DATABASE"] + ) + config_object["SECRET_KEY"] = os.environ["SECRET_KEY"] + except(KeyError): + print("OpenShift mode enabled but required values couldn't be fetched. " + "Check, if you have these variables defined in you env: " + "(POSTGRESQL_[USER, PASSWORD, DATABASE, SERVICE_HOST, SERVICE_PORT], SECRET_KEY)", file=sys.stderr) + sys.exit(1) + + # Nuke out messaging, we don't support this in OpenShift mode + # Inject settings.py and disable OpenShift mode if you need this + config_object["MESSAGE_BUS_PLUGIN"] = 'dummy' + config_object["MESSAGE_BUS_KWARGS"] = {} + + if os.getenv("MESSAGE_BUS_PLUGIN") or os.getenv("MESSAGE_BUS_KWARGS"): + print("It appears you've tried to set up messaging in OpenShift mode.") + print("This is not supported, you need to inject setting.py and disable OpenShift mode if you need messaging.") + + # Danger zone, keep this False out in the wild, always + config_object["SHOW_DB_URI"] = False diff --git a/wsgi.py b/wsgi.py new file mode 100644 index 0000000..bc863f7 --- /dev/null +++ b/wsgi.py @@ -0,0 +1 @@ +from resultsdb import app as application From 85f3ee724177dffe2f7e8f0a970b449fea2d51cd Mon Sep 17 00:00:00 2001 From: František Zatloukal Date: Jan 27 2021 11:53:18 +0000 Subject: [PATCH 2/2] PR Review --- diff --git a/Dockerfile b/Dockerfile index d905190..8db44a3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # docker build -f openshift/Dockerfile \ # --tag -FROM fedora:32 +FROM registry.fedoraproject.org/fedora:33 LABEL \ name="ResultsDB application" \ vendor="ResultsDB developers" \ diff --git a/resultsdb/__init__.py b/resultsdb/__init__.py index f42e535..d3be913 100644 --- a/resultsdb/__init__.py +++ b/resultsdb/__init__.py @@ -68,6 +68,11 @@ def jsonify_with_jsonp(*args, **kwargs): flask.jsonify = jsonify_with_jsonp +# Checks for env variable OPENSHIFT_PROD to trigger OpenShift codepath on init +# The main difference is that settings will be queried from env (check config.openshift_config()) +# Possible values are: +# "1" - OpenShift production deployment +# "0" - OpenShift testing deployment openshift = os.getenv('OPENSHIFT_PROD') # Load default config, then override that with a config file diff --git a/resultsdb/config.py b/resultsdb/config.py index b436624..43d49cd 100644 --- a/resultsdb/config.py +++ b/resultsdb/config.py @@ -21,6 +21,7 @@ import os import sys + class Config(object): DEBUG = True PRODUCTION = False @@ -118,6 +119,7 @@ class TestingConfig(Config): MESSAGE_BUS_PLUGIN = 'dummy' MESSAGE_BUS_KWARGS = {} + def openshift_config(config_object, openshift_production): # First, get db details from env try: @@ -129,10 +131,11 @@ def openshift_config(config_object, openshift_production): os.environ["POSTGRESQL_DATABASE"] ) config_object["SECRET_KEY"] = os.environ["SECRET_KEY"] - except(KeyError): + except KeyError: print("OpenShift mode enabled but required values couldn't be fetched. " "Check, if you have these variables defined in you env: " - "(POSTGRESQL_[USER, PASSWORD, DATABASE, SERVICE_HOST, SERVICE_PORT], SECRET_KEY)", file=sys.stderr) + "(POSTGRESQL_[USER, PASSWORD, DATABASE, SERVICE_HOST, SERVICE_PORT], " + "SECRET_KEY)", file=sys.stderr) sys.exit(1) # Nuke out messaging, we don't support this in OpenShift mode @@ -142,7 +145,8 @@ def openshift_config(config_object, openshift_production): if os.getenv("MESSAGE_BUS_PLUGIN") or os.getenv("MESSAGE_BUS_KWARGS"): print("It appears you've tried to set up messaging in OpenShift mode.") - print("This is not supported, you need to inject setting.py and disable OpenShift mode if you need messaging.") + print("This is not supported, you need to inject setting.py and disable " + "OpenShift mode if you need messaging.") # Danger zone, keep this False out in the wild, always config_object["SHOW_DB_URI"] = False