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).
This commit is contained in:
Joshua Boniface 2024-09-09 10:52:44 -04:00
parent 73c0834f85
commit a2e5df9f6d
3 changed files with 75 additions and 27 deletions

View File

@ -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 import pvcapid.Daemon # noqa: F401
pvcapid.Daemon.entrypoint() pvcapid.Daemon.entrypoint()

View File

@ -19,15 +19,15 @@
# #
############################################################################### ###############################################################################
import sys
import os
import subprocess
from ssl import SSLContext, TLSVersion from ssl import SSLContext, TLSVersion
from distutils.util import strtobool as dustrtobool from distutils.util import strtobool as dustrtobool
import daemon_lib.config as cfg import daemon_lib.config as cfg
# Daemon version # Daemon version
version = "0.9.100" version = "0.9.100~git-73c0834f"
# API version # API version
API_VERSION = 1.0 API_VERSION = 1.0
@ -37,7 +37,6 @@ API_VERSION = 1.0
# Helper Functions # Helper Functions
########################################################## ##########################################################
def strtobool(stringv): def strtobool(stringv):
if stringv is None: if stringv is None:
return False return False
@ -53,7 +52,6 @@ def strtobool(stringv):
# Configuration Parsing # Configuration Parsing
########################################################## ##########################################################
# Get our configuration # Get our configuration
config = cfg.get_configuration() config = cfg.get_configuration()
config["daemon_name"] = "pvcapid" config["daemon_name"] = "pvcapid"
@ -61,22 +59,15 @@ config["daemon_version"] = version
########################################################## ##########################################################
# Entrypoint # Flask App Creation for Gunicorn
########################################################## ##########################################################
def create_app():
def entrypoint(): """
import pvcapid.flaskapi as pvc_api # noqa: E402 Create and return the Flask app and SSL context if necessary.
"""
if config["api_ssl_enabled"]: # Import the Flask app from pvcapid.flaskapi after adjusting the path
context = SSLContext() import pvcapid.flaskapi as pvc_api
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
# Print our startup messages # Print our startup messages
print("") print("")
@ -102,9 +93,59 @@ def entrypoint():
print("") print("")
pvc_api.celery_startup() pvc_api.celery_startup()
pvc_api.app.run(
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_address"],
config["api_listen_port"], config["api_listen_port"],
threaded=True, threaded=True,
ssl_context=context, 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)

2
debian/control vendored
View File

@ -32,7 +32,7 @@ Description: Parallel Virtual Cluster worker daemon
Package: pvc-daemon-api Package: pvc-daemon-api
Architecture: all 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 Description: Parallel Virtual Cluster API daemon
A KVM/Zookeeper/Ceph-based VM and private cloud manager A KVM/Zookeeper/Ceph-based VM and private cloud manager
. .