From a2e5df9f6d2c67ec7dd474c1ee9159ab82a5b8cc Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Mon, 9 Sep 2024 10:52:44 -0400 Subject: [PATCH] Add support for Gunicorn execution Modifies pvcapid to run under Gunicorn when in non-debug mode, instead of the Flask development server. This is proper practice for one, and also helps increase performance slightly in some workloads (file uploads mainly). --- api-daemon/pvcapid.py | 7 +++ api-daemon/pvcapid/Daemon.py | 93 ++++++++++++++++++++++++++---------- debian/control | 2 +- 3 files changed, 75 insertions(+), 27 deletions(-) diff --git a/api-daemon/pvcapid.py b/api-daemon/pvcapid.py index 80c5caa4..b39336d6 100755 --- a/api-daemon/pvcapid.py +++ b/api-daemon/pvcapid.py @@ -19,6 +19,13 @@ # ############################################################################### +import sys +from os import path + +# Ensure current directory (/usr/share/pvc) is in the system path for Gunicorn +current_dir = path.dirname(path.abspath(__file__)) +sys.path.append(current_dir) + import pvcapid.Daemon # noqa: F401 pvcapid.Daemon.entrypoint() diff --git a/api-daemon/pvcapid/Daemon.py b/api-daemon/pvcapid/Daemon.py index d42f2001..09edde5a 100755 --- a/api-daemon/pvcapid/Daemon.py +++ b/api-daemon/pvcapid/Daemon.py @@ -19,15 +19,15 @@ # ############################################################################### - +import sys +import os +import subprocess from ssl import SSLContext, TLSVersion - from distutils.util import strtobool as dustrtobool - import daemon_lib.config as cfg # Daemon version -version = "0.9.100" +version = "0.9.100~git-73c0834f" # API version API_VERSION = 1.0 @@ -37,7 +37,6 @@ API_VERSION = 1.0 # Helper Functions ########################################################## - def strtobool(stringv): if stringv is None: return False @@ -53,7 +52,6 @@ def strtobool(stringv): # Configuration Parsing ########################################################## - # Get our configuration config = cfg.get_configuration() config["daemon_name"] = "pvcapid" @@ -61,22 +59,15 @@ config["daemon_version"] = version ########################################################## -# Entrypoint +# Flask App Creation for Gunicorn ########################################################## - -def entrypoint(): - import pvcapid.flaskapi as pvc_api # noqa: E402 - - if config["api_ssl_enabled"]: - context = SSLContext() - context.minimum_version = TLSVersion.TLSv1 - context.get_ca_certs() - context.load_cert_chain( - config["api_ssl_cert_file"], keyfile=config["api_ssl_key_file"] - ) - else: - context = None +def create_app(): + """ + Create and return the Flask app and SSL context if necessary. + """ + # Import the Flask app from pvcapid.flaskapi after adjusting the path + import pvcapid.flaskapi as pvc_api # Print our startup messages print("") @@ -102,9 +93,59 @@ def entrypoint(): print("") pvc_api.celery_startup() - pvc_api.app.run( - config["api_listen_address"], - config["api_listen_port"], - threaded=True, - ssl_context=context, - ) + + return pvc_api.app + + +########################################################## +# Entrypoint +########################################################## + +def entrypoint(): + if config['debug']: + app = create_app() + + if config["api_ssl_enabled"]: + ssl_context = SSLContext() + ssl_context.minimum_version = TLSVersion.TLSv1 + ssl_context.get_ca_certs() + ssl_context.load_cert_chain( + config["api_ssl_cert_file"], keyfile=config["api_ssl_key_file"] + ) + else: + ssl_context = None + + app.run( + config["api_listen_address"], + config["api_listen_port"], + threaded=True, + ssl_context=ssl_context, + ) + else: + # Build the command to run Gunicorn + gunicorn_cmd = [ + 'gunicorn', + '--workers', '1', + '--threads', '8', + '--timeout', '86400', + '--bind', '{}:{}'.format(config["api_listen_address"], config["api_listen_port"]), + 'pvcapid.Daemon:create_app()', + '--log-level', 'info', + '--access-logfile', '-', + '--error-logfile', '-', + ] + + if config["api_ssl_enabled"]: + gunicorn_cmd += [ + '--certfile', config["api_ssl_cert_file"], + '--keyfile', config["api_ssl_key_file"] + ] + + # Run Gunicorn + try: + subprocess.run(gunicorn_cmd) + except KeyboardInterrupt: + exit(0) + except Exception as e: + print(e) + exit(1) diff --git a/debian/control b/debian/control index 9bd771b3..36e90319 100644 --- a/debian/control +++ b/debian/control @@ -32,7 +32,7 @@ Description: Parallel Virtual Cluster worker daemon Package: pvc-daemon-api Architecture: all -Depends: systemd, pvc-daemon-common, python3-yaml, python3-flask, python3-flask-restful, python3-celery, python3-distutils, python3-redis, python3-lxml, python3-flask-migrate +Depends: systemd, pvc-daemon-common, gunicorn, python3-gunicorn, python3-yaml, python3-flask, python3-flask-restful, python3-celery, python3-distutils, python3-redis, python3-lxml, python3-flask-migrate Description: Parallel Virtual Cluster API daemon A KVM/Zookeeper/Ceph-based VM and private cloud manager .