From 1292ebb1bf2f5660ceb574c966a69ec1a6a9c54c Mon Sep 17 00:00:00 2001 From: Takashi Kajinami Date: Thu, 7 Dec 2023 17:16:30 +0900 Subject: [PATCH] Add wsgi module The wsgi_script feature is being removed because of some changes in underlying python packaging tooling. This makes heat to vendor the wsgi module which can be used instead of the wsgi script, according to the proposed community goal[1]. The existing wsgi scripts are kept now for smooth transition. [1] https://review.opendev.org/c/openstack/governance/+/902807 Depends-On: https://review.opendev.org/c/openstack/devstack/+/902758 Change-Id: I4dc92f06610753171215913180ce7cdab15ba047 --- devstack/lib/heat | 18 +++++++------- doc/source/conf.py | 2 +- .../heat/httpd}/heat-api-cfn.conf | 2 +- .../files => etc/heat/httpd}/heat-api.conf | 2 +- .../heat/uwsgi}/heat-api-cfn-uwsgi.ini | 2 +- .../heat/uwsgi}/heat-api-uwsgi.ini | 2 +- .../heat_api_cfn.py => api/cfn/wsgi.py} | 0 .../heat_api.py => api/openstack/wsgi.py} | 0 heat/httpd/files/uwsgi-heat-api-cfn.conf | 2 -- heat/httpd/files/uwsgi-heat-api.conf | 2 -- heat/{httpd => wsgi}/__init__.py | 0 heat/wsgi/api.py | 24 +++++++++++++++++++ heat/wsgi/cfn.py | 24 +++++++++++++++++++ ...add-heat-wsgi-module-bd75e71b4fc47568.yaml | 22 +++++++++++++++++ setup.cfg | 4 ++-- 15 files changed, 86 insertions(+), 20 deletions(-) rename {heat/httpd/files => etc/heat/httpd}/heat-api-cfn.conf (93%) rename {heat/httpd/files => etc/heat/httpd}/heat-api.conf (93%) rename {heat/httpd/files => etc/heat/uwsgi}/heat-api-cfn-uwsgi.ini (84%) rename {heat/httpd/files => etc/heat/uwsgi}/heat-api-uwsgi.ini (85%) rename heat/{httpd/heat_api_cfn.py => api/cfn/wsgi.py} (100%) rename heat/{httpd/heat_api.py => api/openstack/wsgi.py} (100%) delete mode 100644 heat/httpd/files/uwsgi-heat-api-cfn.conf delete mode 100644 heat/httpd/files/uwsgi-heat-api.conf rename heat/{httpd => wsgi}/__init__.py (100%) create mode 100644 heat/wsgi/api.py create mode 100644 heat/wsgi/cfn.py create mode 100644 releasenotes/notes/add-heat-wsgi-module-bd75e71b4fc47568.yaml diff --git a/devstack/lib/heat b/devstack/lib/heat index 0bd5a7f18e..248e2a670a 100644 --- a/devstack/lib/heat +++ b/devstack/lib/heat @@ -39,7 +39,7 @@ GITBRANCH["python-heatclient"]=${HEATCLIENT_BRANCH:-master} HEAT_USE_APACHE=${HEAT_USE_APACHE:-${HEAT_USE_MOD_WSGI:-True}} HEAT_DIR=$DEST/heat -HEAT_FILES_DIR=$HEAT_DIR/heat/httpd/files +HEAT_HTTPD_VHOST_FILES_DIR=$HEAT_DIR/etc/heat/httpd HEAT_STANDALONE=$(trueorfalse False HEAT_STANDALONE) HEAT_ENABLE_ADOPT_ABANDON=$(trueorfalse False HEAT_ENABLE_ADOPT_ABANDON) @@ -58,8 +58,8 @@ HEAT_TRUSTEE_DOMAIN=${HEAT_TRUSTEE_DOMAIN:-default} HEAT_BIN_DIR=$(get_python_exec_prefix) HEAT_API_UWSGI_CONF=$HEAT_CONF_DIR/heat-api-uwsgi.ini HEAT_CFN_API_UWSGI_CONF=$HEAT_CONF_DIR/heat-api-cfn-uwsgi.ini -HEAT_API_UWSGI=$HEAT_BIN_DIR/heat-wsgi-api -HEAT_CFN_API_UWSGI=$HEAT_BIN_DIR/heat-wsgi-api-cfn +HEAT_API_UWSGI=heat.wsgi.api:application +HEAT_CFN_API_UWSGI=heat.wsgi.cfn:application # Flag to set the oslo_policy.enforce_scope and oslo_policy.enforce_new_defaults. # This is used to disable the compute API policies scope and new defaults. @@ -159,12 +159,12 @@ function configure_heat { if [[ "$HEAT_USE_APACHE" == "True" ]]; then if [[ $WSGI_MODE == "uwsgi" ]]; then - write_uwsgi_config "$HEAT_API_UWSGI_CONF" "$HEAT_API_UWSGI" "/heat-api" + write_uwsgi_config "$HEAT_API_UWSGI_CONF" "$HEAT_API_UWSGI" "/heat-api" "" "heat-api" # configure threads for h-api to avoid IO wait and messaging timeout. We use # 'nproc/4' to calculate API workers, hence, 4 would be probably correct # approximation. iniset "$HEAT_API_UWSGI_CONF" uwsgi threads 4 - write_uwsgi_config "$HEAT_CFN_API_UWSGI_CONF" "$HEAT_CFN_API_UWSGI" "/heat-api-cfn" + write_uwsgi_config "$HEAT_CFN_API_UWSGI_CONF" "$HEAT_CFN_API_UWSGI" "/heat-api-cfn" "" "heat-api-cfn" else _config_heat_apache_wsgi fi @@ -368,11 +368,11 @@ function _config_heat_apache_wsgi { local heat_cfn_api_port=$HEAT_API_CFN_PORT local venv_path="" - sudo cp $HEAT_FILES_DIR/heat-api.conf $heat_apache_conf + sudo cp $HEAT_HTTPD_VHOST_FILES_DIR/heat-api.conf $heat_apache_conf sudo sed -e " s|%PUBLICPORT%|$heat_api_port|g; s|%APACHE_NAME%|$APACHE_NAME|g; - s|%HEAT_BIN_DIR%|$HEAT_BIN_DIR|g; + s|%HEAT_DIR%|$HEAT_DIR|g; s|%API_WORKERS%|$API_WORKERS|g; s|%SSLENGINE%|$heat_ssl|g; s|%SSLCERTFILE%|$heat_certfile|g; @@ -381,11 +381,11 @@ function _config_heat_apache_wsgi { s|%VIRTUALENV%|$venv_path|g " -i $heat_apache_conf - sudo cp $HEAT_FILES_DIR/heat-api-cfn.conf $heat_cfn_apache_conf + sudo cp $HEAT_HTTPD_VHOST_FILES_DIR/heat-api-cfn.conf $heat_cfn_apache_conf sudo sed -e " s|%PUBLICPORT%|$heat_cfn_api_port|g; s|%APACHE_NAME%|$APACHE_NAME|g; - s|%HEAT_BIN_DIR%|$HEAT_BIN_DIR|g; + s|%HEAT_DIR%|$HEAT_DIR|g; s|%API_WORKERS%|$API_WORKERS|g; s|%SSLENGINE%|$heat_ssl|g; s|%SSLCERTFILE%|$heat_certfile|g; diff --git a/doc/source/conf.py b/doc/source/conf.py index 933b0f3cbc..24dc6228a2 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -180,10 +180,10 @@ apidoc_excluded_paths = [ 'engine/resources/aws', 'engine/resources/openstack', 'hacking', - 'httpd', 'locale', 'tests', 'version.py', + 'wsgi', ] diff --git a/heat/httpd/files/heat-api-cfn.conf b/etc/heat/httpd/heat-api-cfn.conf similarity index 93% rename from heat/httpd/files/heat-api-cfn.conf rename to etc/heat/httpd/heat-api-cfn.conf index 7cbca4a05f..0359c80c10 100644 --- a/heat/httpd/files/heat-api-cfn.conf +++ b/etc/heat/httpd/heat-api-cfn.conf @@ -3,7 +3,7 @@ Listen %PUBLICPORT% WSGIDaemonProcess heat-api-cfn processes=%API_WORKERS% threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV% WSGIProcessGroup heat-api-cfn - WSGIScriptAlias / %HEAT_BIN_DIR%/heat-wsgi-api-cfn + WSGIScriptAlias / %HEAT_DIR%/cfn/wsgi.py WSGIApplicationGroup %{GLOBAL} WSGIPassAuthorization On AllowEncodedSlashes On diff --git a/heat/httpd/files/heat-api.conf b/etc/heat/httpd/heat-api.conf similarity index 93% rename from heat/httpd/files/heat-api.conf rename to etc/heat/httpd/heat-api.conf index 01411be667..877ad5918b 100644 --- a/heat/httpd/files/heat-api.conf +++ b/etc/heat/httpd/heat-api.conf @@ -3,7 +3,7 @@ Listen %PUBLICPORT% WSGIDaemonProcess heat-api processes=%API_WORKERS% threads=10 user=%USER% display-name=%{GROUP} %VIRTUALENV% WSGIProcessGroup heat-api - WSGIScriptAlias / %HEAT_BIN_DIR%/heat-wsgi-api + WSGIScriptAlias / %HEAT_DIR%/api/wsgi.py WSGIApplicationGroup %{GLOBAL} WSGIPassAuthorization On AllowEncodedSlashes On diff --git a/heat/httpd/files/heat-api-cfn-uwsgi.ini b/etc/heat/uwsgi/heat-api-cfn-uwsgi.ini similarity index 84% rename from heat/httpd/files/heat-api-cfn-uwsgi.ini rename to etc/heat/uwsgi/heat-api-cfn-uwsgi.ini index cd08bd7198..cb88c5e953 100644 --- a/heat/httpd/files/heat-api-cfn-uwsgi.ini +++ b/etc/heat/uwsgi/heat-api-cfn-uwsgi.ini @@ -11,4 +11,4 @@ die-on-term = true master = true processes = 4 http = 127.0.0.1:80998 -wsgi-file = /usr/local/bin/heat-wsgi-api-cfn +module = heat.wsgi.cfn:application diff --git a/heat/httpd/files/heat-api-uwsgi.ini b/etc/heat/uwsgi/heat-api-uwsgi.ini similarity index 85% rename from heat/httpd/files/heat-api-uwsgi.ini rename to etc/heat/uwsgi/heat-api-uwsgi.ini index f5b11f94e2..9b7151c83d 100644 --- a/heat/httpd/files/heat-api-uwsgi.ini +++ b/etc/heat/uwsgi/heat-api-uwsgi.ini @@ -11,4 +11,4 @@ die-on-term = true master = true processes = 4 http = 127.0.0.1:80999 -wsgi-file = /usr/local/bin/heat-wsgi-api +module = heat.wsgi.api:application diff --git a/heat/httpd/heat_api_cfn.py b/heat/api/cfn/wsgi.py similarity index 100% rename from heat/httpd/heat_api_cfn.py rename to heat/api/cfn/wsgi.py diff --git a/heat/httpd/heat_api.py b/heat/api/openstack/wsgi.py similarity index 100% rename from heat/httpd/heat_api.py rename to heat/api/openstack/wsgi.py diff --git a/heat/httpd/files/uwsgi-heat-api-cfn.conf b/heat/httpd/files/uwsgi-heat-api-cfn.conf deleted file mode 100644 index 5b9879d9ad..0000000000 --- a/heat/httpd/files/uwsgi-heat-api-cfn.conf +++ /dev/null @@ -1,2 +0,0 @@ -KeepAlive Off -ProxyPass "/heat-api-cfn" "http://127.0.0.1:80998" retry=0 diff --git a/heat/httpd/files/uwsgi-heat-api.conf b/heat/httpd/files/uwsgi-heat-api.conf deleted file mode 100644 index 3ac14e03cd..0000000000 --- a/heat/httpd/files/uwsgi-heat-api.conf +++ /dev/null @@ -1,2 +0,0 @@ -KeepAlive Off -ProxyPass "/heat-api" "http://127.0.0.1:80999" retry=0 diff --git a/heat/httpd/__init__.py b/heat/wsgi/__init__.py similarity index 100% rename from heat/httpd/__init__.py rename to heat/wsgi/__init__.py diff --git a/heat/wsgi/api.py b/heat/wsgi/api.py new file mode 100644 index 0000000000..59624c1cd5 --- /dev/null +++ b/heat/wsgi/api.py @@ -0,0 +1,24 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""WSGI application entry-point for the Heat API.""" + +import threading + +from heat.api.openstack import wsgi + +application = None + +lock = threading.Lock() +with lock: + if application is None: + application = wsgi.init_application() diff --git a/heat/wsgi/cfn.py b/heat/wsgi/cfn.py new file mode 100644 index 0000000000..a81bf9455d --- /dev/null +++ b/heat/wsgi/cfn.py @@ -0,0 +1,24 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""WSGI application entry-point for the Heat API.""" + +import threading + +from heat.api.cfn import wsgi + +application = None + +lock = threading.Lock() +with lock: + if application is None: + application = wsgi.init_application() diff --git a/releasenotes/notes/add-heat-wsgi-module-bd75e71b4fc47568.yaml b/releasenotes/notes/add-heat-wsgi-module-bd75e71b4fc47568.yaml new file mode 100644 index 0000000000..fb3c89d6c3 --- /dev/null +++ b/releasenotes/notes/add-heat-wsgi-module-bd75e71b4fc47568.yaml @@ -0,0 +1,22 @@ +--- +features: + - | + A new module, ``heat.wsgi``, has been added as a place to gather WSGI + ``application`` objects. This is intended to ease deployment by providing + a consistent location for these objects. For example, if using uWSGI then + instead of: + + .. code-block:: ini + + [uwsgi] + wsgi-file = /bin/heat-api + + You can now use: + + .. code-block:: ini + + [uwsgi] + module = heat.wsgi.api:application + + This also simplifies deployment with other WSGI servers that expect module + paths such as gunicorn. diff --git a/setup.cfg b/setup.cfg index 54587e9bbf..d44a44180f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -43,8 +43,8 @@ console_scripts = heat-status = heat.cmd.status:main wsgi_scripts = - heat-wsgi-api = heat.httpd.heat_api:init_application - heat-wsgi-api-cfn = heat.httpd.heat_api_cfn:init_application + heat-wsgi-api = heat.api.openstack.wsgi:init_application + heat-wsgi-api-cfn = heat.api.cfn.wsgi:init_application oslo.config.opts = heat.common.cache = heat.common.cache:list_opts