Merge "Switch devstack nodeset to Ubuntu 24.04 (Noble)"
diff --git a/.zuul.yaml b/.zuul.yaml
index 6a6b686..2fbfa04 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -432,6 +432,8 @@
       - ^releasenotes/.*$
       # Translations
       - ^.*/locale/.*po$
+      # pre-commit config
+      - ^.pre-commit-config.yaml$
 
 - job:
     name: devstack-minimal
@@ -954,15 +956,6 @@
     #    things, this job is not experimental but often is used to test
     #    things that are not yet production ready or to test what will be
     #    the new default after a deprecation period has ended.
-    # * neutron-fullstack-with-uwsgi: maintained by neutron for fullstack test
-    #    when neutron-api is served by uwsgi, it's in exprimental for testing.
-    #    the next cycle we can remove this  job if things turn out to be
-    #    stable enough.
-    # * neutron-functional-with-uwsgi: maintained by neutron for functional
-    #    test. Next cycle we can remove this one if things turn out to be
-    #    stable engouh with uwsgi.
-    # * neutron-ovn-tempest-with-uwsgi: maintained by neutron for tempest test.
-    #    Next cycle we can remove this if everything run out stable enough.
     # * nova-multi-cell: maintained by nova and now is voting in the
     #    check queue for nova changes but relies on devstack configuration
 
@@ -970,9 +963,6 @@
       jobs:
         - nova-multi-cell
         - nova-next
-        - neutron-fullstack-with-uwsgi
-        - neutron-functional-with-uwsgi
-        - neutron-ovn-tempest-with-uwsgi
         - devstack-plugin-ceph-tempest-py3:
             irrelevant-files:
               - ^.*\.rst$
diff --git a/clean.sh b/clean.sh
index 6a31cc6..092f557 100755
--- a/clean.sh
+++ b/clean.sh
@@ -40,7 +40,7 @@
 
 source $TOP_DIR/lib/tls
 
-source $TOP_DIR/lib/oslo
+source $TOP_DIR/lib/libraries
 source $TOP_DIR/lib/lvm
 source $TOP_DIR/lib/horizon
 source $TOP_DIR/lib/keystone
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index a83b2de..3cfba71 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -323,7 +323,7 @@
 
    [[local|localrc]]
    DEST=/opt/stack/
-   LOGFILE=$LOGDIR/stack.sh.log
+   LOGFILE=$DEST/stack.sh.log
    LOG_COLOR=False
 
 Database Backend
@@ -351,30 +351,21 @@
 
   disable_service rabbit
 
-
 Apache Frontend
 ---------------
 
-The Apache web server can be enabled for wsgi services that support
-being deployed under HTTPD + mod_wsgi. By default, services that
-recommend running under HTTPD + mod_wsgi are deployed under Apache. To
-use an alternative deployment strategy (e.g. eventlet) for services
-that support an alternative to HTTPD + mod_wsgi set
-``ENABLE_HTTPD_MOD_WSGI_SERVICES`` to ``False`` in your
-``local.conf``.
+The Apache web server is enabled for services that support via WSGI. Today this
+means HTTPD and uWSGI but historically this meant HTTPD + mod_wsgi. This
+historical legacy is captured by the naming of many variables, which include
+``MOD_WSGI`` rather than ``UWSGI``.
 
-Each service that can be run under HTTPD + mod_wsgi also has an
-override toggle available that can be set in your ``local.conf``.
-
-Keystone is run under Apache with ``mod_wsgi`` by default.
-
-Example (Keystone)::
-
-    KEYSTONE_USE_MOD_WSGI="True"
-
-Example (Nova)::
-
-    NOVA_USE_MOD_WSGI="True"
+Some services support alternative deployment strategies (e.g. eventlet). You
+can enable these ``ENABLE_HTTPD_MOD_WSGI_SERVICES`` to ``False`` in your
+``local.conf``.  In addition, each service that can be run under HTTPD +
+mod_wsgi also has an override toggle available that can be set in your
+``local.conf``. These are, however, slowly being removed as services have
+adopted standardized deployment mechanisms and more generally moved away from
+eventlet.
 
 Example (Swift)::
 
@@ -384,11 +375,6 @@
 
     HEAT_USE_MOD_WSGI="True"
 
-Example (Cinder)::
-
-    CINDER_USE_MOD_WSGI="True"
-
-
 Libraries from Git
 ------------------
 
diff --git a/doc/source/guides/nova.rst b/doc/source/guides/nova.rst
index 705d427..6b8aabf 100644
--- a/doc/source/guides/nova.rst
+++ b/doc/source/guides/nova.rst
@@ -122,7 +122,7 @@
 .. code-block:: shell
 
   $ openstack --os-compute-api-version 2.37 server create --flavor cirros256 \
-      --image cirros-0.6.2-x86_64-disk --nic none --wait test-server
+      --image cirros-0.6.3-x86_64-disk --nic none --wait test-server
 
 .. note:: ``--os-compute-api-version`` greater than or equal to 2.37 is
           required to use ``--nic=none``.
diff --git a/doc/source/plugin-registry.rst b/doc/source/plugin-registry.rst
index 21cf52c..2984a5c 100644
--- a/doc/source/plugin-registry.rst
+++ b/doc/source/plugin-registry.rst
@@ -31,6 +31,7 @@
 openstack/cloudkitty                     `https://opendev.org/openstack/cloudkitty <https://opendev.org/openstack/cloudkitty>`__
 openstack/cyborg                         `https://opendev.org/openstack/cyborg <https://opendev.org/openstack/cyborg>`__
 openstack/designate                      `https://opendev.org/openstack/designate <https://opendev.org/openstack/designate>`__
+openstack/designate-tempest-plugin       `https://opendev.org/openstack/designate-tempest-plugin <https://opendev.org/openstack/designate-tempest-plugin>`__
 openstack/devstack-plugin-amqp1          `https://opendev.org/openstack/devstack-plugin-amqp1 <https://opendev.org/openstack/devstack-plugin-amqp1>`__
 openstack/devstack-plugin-ceph           `https://opendev.org/openstack/devstack-plugin-ceph <https://opendev.org/openstack/devstack-plugin-ceph>`__
 openstack/devstack-plugin-container      `https://opendev.org/openstack/devstack-plugin-container <https://opendev.org/openstack/devstack-plugin-container>`__
@@ -48,9 +49,7 @@
 openstack/ironic-prometheus-exporter     `https://opendev.org/openstack/ironic-prometheus-exporter <https://opendev.org/openstack/ironic-prometheus-exporter>`__
 openstack/ironic-ui                      `https://opendev.org/openstack/ironic-ui <https://opendev.org/openstack/ironic-ui>`__
 openstack/keystone                       `https://opendev.org/openstack/keystone <https://opendev.org/openstack/keystone>`__
-openstack/kuryr-kubernetes               `https://opendev.org/openstack/kuryr-kubernetes <https://opendev.org/openstack/kuryr-kubernetes>`__
 openstack/kuryr-libnetwork               `https://opendev.org/openstack/kuryr-libnetwork <https://opendev.org/openstack/kuryr-libnetwork>`__
-openstack/kuryr-tempest-plugin           `https://opendev.org/openstack/kuryr-tempest-plugin <https://opendev.org/openstack/kuryr-tempest-plugin>`__
 openstack/magnum                         `https://opendev.org/openstack/magnum <https://opendev.org/openstack/magnum>`__
 openstack/magnum-ui                      `https://opendev.org/openstack/magnum-ui <https://opendev.org/openstack/magnum-ui>`__
 openstack/manila                         `https://opendev.org/openstack/manila <https://opendev.org/openstack/manila>`__
diff --git a/files/apache-placement-api.template b/files/apache-placement-api.template
deleted file mode 100644
index 011abb9..0000000
--- a/files/apache-placement-api.template
+++ /dev/null
@@ -1,27 +0,0 @@
-# NOTE(sbauza): This virtualhost is only here because some directives can
-# only be set by a virtualhost or server context, so that's why the port is not bound.
-# TODO(sbauza): Find a better way to identify a free port that is not corresponding to an existing
-# vhost.
-<VirtualHost *:8780>
-    WSGIDaemonProcess placement-api processes=%APIWORKERS% threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV%
-    WSGIProcessGroup placement-api
-    WSGIScriptAlias / %PUBLICWSGI%
-    WSGIApplicationGroup %{GLOBAL}
-    WSGIPassAuthorization On
-    <IfVersion >= 2.4>
-      ErrorLogFormat "%M"
-    </IfVersion>
-    ErrorLog /var/log/%APACHE_NAME%/placement-api.log
-    %SSLENGINE%
-    %SSLCERTFILE%
-    %SSLKEYFILE%
-</VirtualHost>
-
-Alias /placement %PUBLICWSGI%
-<Location /placement>
-    SetHandler wsgi-script
-    Options +ExecCGI
-    WSGIProcessGroup placement-api
-    WSGIApplicationGroup %{GLOBAL}
-    WSGIPassAuthorization On
-</Location>
diff --git a/inc/python b/inc/python
index 2083b74..c94e5a4 100644
--- a/inc/python
+++ b/inc/python
@@ -199,13 +199,7 @@
         echo "Using python $PYTHON3_VERSION to install $package_dir"
     else
         local cmd_pip="python$PYTHON3_VERSION -m pip"
-        # See
-        #  https://github.com/pypa/setuptools/issues/2232
-        #  http://lists.openstack.org/pipermail/openstack-discuss/2020-August/016905.html
-        # this makes setuptools >=50 use the platform distutils.
-        # We only want to do this on global pip installs, not if
-        # installing in a virtualenv
-        local sudo_pip="sudo -H LC_ALL=en_US.UTF-8 SETUPTOOLS_USE_DISTUTILS=stdlib "
+        local sudo_pip="sudo -H LC_ALL=en_US.UTF-8"
         echo "Using python $PYTHON3_VERSION to install $package_dir"
     fi
 
diff --git a/lib/cinder b/lib/cinder
index 0adca4f..259018e 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -160,10 +160,6 @@
 # Supported backup drivers are in lib/cinder_backups
 CINDER_BACKUP_DRIVER=${CINDER_BACKUP_DRIVER:-swift}
 
-# Toggle for deploying Cinder under a wsgi server. Legacy mod_wsgi
-# reference should be cleaned up to more accurately refer to uwsgi.
-CINDER_USE_MOD_WSGI=${CINDER_USE_MOD_WSGI:-True}
-
 # Source the enabled backends
 if is_service_enabled c-vol && [[ -n "$CINDER_ENABLED_BACKENDS" ]]; then
     for be in ${CINDER_ENABLED_BACKENDS//,/ }; do
@@ -393,14 +389,8 @@
     if is_service_enabled tls-proxy; then
         if [[ "$ENABLED_SERVICES" =~ "c-api" ]]; then
             # Set the service port for a proxy to take the original
-            if [ "$CINDER_USE_MOD_WSGI" == "True" ]; then
-                iniset $CINDER_CONF DEFAULT osapi_volume_listen_port $CINDER_SERVICE_PORT_INT
-                iniset $CINDER_CONF oslo_middleware enable_proxy_headers_parsing True
-            else
-                iniset $CINDER_CONF DEFAULT osapi_volume_listen_port $CINDER_SERVICE_PORT_INT
-                iniset $CINDER_CONF DEFAULT public_endpoint $CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT
-                iniset $CINDER_CONF DEFAULT osapi_volume_base_URL $CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT
-            fi
+            iniset $CINDER_CONF DEFAULT osapi_volume_listen_port $CINDER_SERVICE_PORT_INT
+            iniset $CINDER_CONF oslo_middleware enable_proxy_headers_parsing True
         fi
     fi
 
@@ -411,7 +401,7 @@
     iniset_rpc_backend cinder $CINDER_CONF
 
     # Format logging
-    setup_logging $CINDER_CONF $CINDER_USE_MOD_WSGI
+    setup_logging $CINDER_CONF
 
     if is_service_enabled c-api; then
         write_uwsgi_config "$CINDER_UWSGI_CONF" "$CINDER_UWSGI" "/volume"
@@ -476,32 +466,15 @@
 
         create_service_user "cinder" $extra_role
 
+        local cinder_api_url
+        cinder_api_url="$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST/volume"
+
         # block-storage is the official service type
         get_or_create_service "cinder" "block-storage" "Cinder Volume Service"
-        if [ "$CINDER_USE_MOD_WSGI" == "False" ]; then
-            get_or_create_endpoint \
-                "block-storage" \
-                "$REGION_NAME" \
-                "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v3/\$(project_id)s"
-
-            get_or_create_service "cinderv3" "volumev3" "Cinder Volume Service V3"
-            get_or_create_endpoint \
-                "volumev3" \
-                "$REGION_NAME" \
-                "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v3/\$(project_id)s"
-        else
-            get_or_create_endpoint \
-                "block-storage" \
-                "$REGION_NAME" \
-                "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST/volume/v3/\$(project_id)s"
-
-            get_or_create_service "cinderv3" "volumev3" "Cinder Volume Service V3"
-            get_or_create_endpoint \
-                "volumev3" \
-                "$REGION_NAME" \
-                "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST/volume/v3/\$(project_id)s"
-        fi
-
+        get_or_create_endpoint \
+            "block-storage" \
+            "$REGION_NAME" \
+            "$cinder_api_url/v3"
         configure_cinder_internal_tenant
     fi
 }
@@ -622,10 +595,6 @@
     local service_port=$CINDER_SERVICE_PORT
     local service_protocol=$CINDER_SERVICE_PROTOCOL
     local cinder_url
-    if is_service_enabled tls-proxy && [ "$CINDER_USE_MOD_WSGI" == "False" ]; then
-        service_port=$CINDER_SERVICE_PORT_INT
-        service_protocol="http"
-    fi
     if [ "$CINDER_TARGET_HELPER" = "tgtadm" ]; then
         if is_service_enabled c-vol; then
             # Delete any old stack.conf
@@ -642,17 +611,8 @@
     fi
 
     if [[ "$ENABLED_SERVICES" =~ "c-api" ]]; then
-        if [ "$CINDER_USE_MOD_WSGI" == "False" ]; then
-            run_process c-api "$CINDER_BIN_DIR/cinder-api --config-file $CINDER_CONF"
-            cinder_url=$service_protocol://$SERVICE_HOST:$service_port
-            # Start proxy if tls enabled
-            if is_service_enabled tls-proxy; then
-                start_tls_proxy cinder '*' $CINDER_SERVICE_PORT $CINDER_SERVICE_HOST $CINDER_SERVICE_PORT_INT
-            fi
-        else
-            run_process "c-api" "$(which uwsgi) --procname-prefix cinder-api --ini $CINDER_UWSGI_CONF"
-            cinder_url=$service_protocol://$SERVICE_HOST/volume/v3
-        fi
+        run_process "c-api" "$(which uwsgi) --procname-prefix cinder-api --ini $CINDER_UWSGI_CONF"
+        cinder_url=$service_protocol://$SERVICE_HOST/volume/v3
     fi
 
     echo "Waiting for Cinder API to start..."
diff --git a/lib/databases/postgresql b/lib/databases/postgresql
index b21418b..2aa38cc 100644
--- a/lib/databases/postgresql
+++ b/lib/databases/postgresql
@@ -46,6 +46,10 @@
     createdb -h $DATABASE_HOST -U$DATABASE_USER -l C -T template0 -E utf8 $db
 }
 
+function _exit_pg_init {
+    sudo cat /var/lib/pgsql/initdb_postgresql.log
+}
+
 function configure_database_postgresql {
     local pg_conf pg_dir pg_hba check_role version
     echo_summary "Configuring and starting PostgreSQL"
@@ -53,7 +57,9 @@
         pg_hba=/var/lib/pgsql/data/pg_hba.conf
         pg_conf=/var/lib/pgsql/data/postgresql.conf
         if ! sudo [ -e $pg_hba ]; then
+            trap _exit_pg_init EXIT
             sudo postgresql-setup initdb
+            trap - EXIT
         fi
     elif is_ubuntu; then
         version=`psql --version | cut -d ' ' -f3 | cut -d. -f1-2`
diff --git a/lib/glance b/lib/glance
index 2746871..5c3643d 100644
--- a/lib/glance
+++ b/lib/glance
@@ -41,6 +41,12 @@
     GLANCE_BIN_DIR=$(get_python_exec_prefix)
 fi
 
+#S3 for Glance
+GLANCE_USE_S3=$(trueorfalse False GLANCE_USE_S3)
+GLANCE_S3_DEFAULT_BACKEND=${GLANCE_S3_DEFAULT_BACKEND:-s3_fast}
+GLANCE_S3_BUCKET_ON_PUT=$(trueorfalse True GLANCE_S3_BUCKET_ON_PUT)
+GLANCE_S3_BUCKET_NAME=${GLANCE_S3_BUCKET_NAME:-images}
+
 # Cinder for Glance
 USE_CINDER_FOR_GLANCE=$(trueorfalse False USE_CINDER_FOR_GLANCE)
 # GLANCE_CINDER_DEFAULT_BACKEND should be one of the values
@@ -104,6 +110,9 @@
 # For more detail: https://docs.openstack.org/oslo.policy/latest/configuration/index.html#oslo_policy.enforce_scope
 GLANCE_ENFORCE_SCOPE=$(trueorfalse True GLANCE_ENFORCE_SCOPE)
 
+# Flag to disable image format inspection on upload
+GLANCE_ENFORCE_IMAGE_FORMAT=$(trueorfalse True GLANCE_ENFORCE_IMAGE_FORMAT)
+
 GLANCE_CONF_DIR=${GLANCE_CONF_DIR:-/etc/glance}
 GLANCE_METADEF_DIR=$GLANCE_CONF_DIR/metadefs
 GLANCE_API_CONF=$GLANCE_CONF_DIR/glance-api.conf
@@ -171,6 +180,34 @@
     remove_uwsgi_config "$GLANCE_UWSGI_CONF" "glance-wsgi-api"
 }
 
+# Set multiple s3 store related config options
+#
+function configure_multiple_s3_stores {
+    enabled_backends="${GLANCE_S3_DEFAULT_BACKEND}:s3"
+
+    iniset $GLANCE_API_CONF DEFAULT enabled_backends ${enabled_backends}
+    iniset $GLANCE_API_CONF glance_store default_backend $GLANCE_S3_DEFAULT_BACKEND
+}
+
+# Set common S3 store options to given config section
+#
+# Arguments:
+# config_section
+#
+function set_common_s3_store_params {
+    local config_section="$1"
+    openstack ec2 credential create
+    iniset $GLANCE_API_CONF $config_section s3_store_host "$SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:$S3_SERVICE_PORT"
+    iniset $GLANCE_API_CONF $config_section s3_store_access_key "$(openstack ec2 credential list -c Access -f value)"
+    iniset $GLANCE_API_CONF $config_section s3_store_secret_key "$(openstack ec2 credential list -c Secret -f value)"
+    iniset $GLANCE_API_CONF $config_section s3_store_create_bucket_on_put $GLANCE_S3_BUCKET_ON_PUT
+    iniset $GLANCE_API_CONF $config_section s3_store_bucket $GLANCE_S3_BUCKET_NAME
+    iniset $GLANCE_API_CONF $config_section s3_store_bucket_url_format "path"
+    if is_service_enabled tls-proxy; then
+        iniset $GLANCE_API_CONF $config_section s3_store_cacert $SSL_BUNDLE_FILE
+    fi
+}
+
 # Set multiple cinder store related config options for each of the cinder store
 #
 function configure_multiple_cinder_stores {
@@ -255,7 +292,6 @@
     local be
 
     if [[ "$glance_enable_multiple_stores" == "False" ]]; then
-        # Configure traditional glance_store
         if [[ "$use_cinder_for_glance" == "True" ]]; then
             # set common glance_store parameters
             iniset $GLANCE_API_CONF glance_store stores "cinder,file,http"
@@ -278,7 +314,7 @@
         if [[ "$use_cinder_for_glance" == "True" ]]; then
             # Configure multiple cinder stores for glance
             configure_multiple_cinder_stores
-        else
+        elif ! is_service_enabled s-proxy && [[ "$GLANCE_USE_S3" == "False" ]]; then
             # Configure multiple file stores for glance
             configure_multiple_file_stores
         fi
@@ -343,6 +379,7 @@
     # Only use these if you know what you are doing!  See OSSN-0065
     iniset $GLANCE_API_CONF DEFAULT show_image_direct_url $GLANCE_SHOW_DIRECT_URL
     iniset $GLANCE_API_CONF DEFAULT show_multiple_locations $GLANCE_SHOW_MULTIPLE_LOCATIONS
+    iniset $GLANCE_API_CONF image_format require_image_format_match $GLANCE_ENFORCE_IMAGE_FORMAT
 
     # Configure glance_store
     configure_glance_store $USE_CINDER_FOR_GLANCE $GLANCE_ENABLE_MULTIPLE_STORES
@@ -356,8 +393,15 @@
 
     # No multiple stores for swift yet
     if [[ "$GLANCE_ENABLE_MULTIPLE_STORES" == "False" ]]; then
-        # Store the images in swift if enabled.
-        if is_service_enabled s-proxy; then
+        # Return if s3api is enabled for glance
+        if [[ "$GLANCE_USE_S3" == "True" ]]; then
+            if is_service_enabled s3api; then
+                # set common glance_store parameters
+                iniset $GLANCE_API_CONF glance_store stores "s3,file,http"
+                iniset $GLANCE_API_CONF glance_store default_store s3
+            fi
+        elif is_service_enabled s-proxy; then
+            # Store the images in swift if enabled.
             iniset $GLANCE_API_CONF glance_store default_store swift
             iniset $GLANCE_API_CONF glance_store swift_store_create_container_on_put True
 
@@ -375,6 +419,12 @@
             iniset $GLANCE_SWIFT_STORE_CONF ref1 auth_address $KEYSTONE_SERVICE_URI/v3
             iniset $GLANCE_SWIFT_STORE_CONF ref1 auth_version 3
         fi
+    else
+        if [[ "$GLANCE_USE_S3" == "True" ]]; then
+            if is_service_enabled s3api; then
+                configure_multiple_s3_stores
+            fi
+        fi
     fi
 
     # We need to tell glance what it's public endpoint is so that the version
@@ -480,6 +530,13 @@
             configure_glance_quotas
         fi
 
+        if is_service_enabled s3api && [[ "$GLANCE_USE_S3" == "True" ]]; then
+            if [[ "$GLANCE_ENABLE_MULTIPLE_STORES" == "False" ]]; then
+                set_common_s3_store_params glance_store
+            else
+                set_common_s3_store_params $GLANCE_S3_DEFAULT_BACKEND
+            fi
+        fi
     fi
 }
 
diff --git a/lib/keystone b/lib/keystone
index 7d6b05f..76e2598 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -49,16 +49,7 @@
 KEYSTONE_CONF_DIR=${KEYSTONE_CONF_DIR:-/etc/keystone}
 KEYSTONE_CONF=$KEYSTONE_CONF_DIR/keystone.conf
 KEYSTONE_PUBLIC_UWSGI_CONF=$KEYSTONE_CONF_DIR/keystone-uwsgi-public.ini
-KEYSTONE_PUBLIC_UWSGI=$KEYSTONE_BIN_DIR/keystone-wsgi-public
-
-# KEYSTONE_DEPLOY defines how keystone is deployed, allowed values:
-# - mod_wsgi : Run keystone under Apache HTTPd mod_wsgi
-# - uwsgi : Run keystone under uwsgi
-if [[ "$WSGI_MODE" == "uwsgi" ]]; then
-    KEYSTONE_DEPLOY=uwsgi
-else
-    KEYSTONE_DEPLOY=mod_wsgi
-fi
+KEYSTONE_PUBLIC_UWSGI=keystone.wsgi.api:application
 
 # Select the Identity backend driver
 KEYSTONE_IDENTITY_BACKEND=${KEYSTONE_IDENTITY_BACKEND:-sql}
@@ -144,15 +135,9 @@
 # cleanup_keystone() - Remove residual data files, anything left over from previous
 # runs that a clean run would need to clean up
 function cleanup_keystone {
-    if [ "$KEYSTONE_DEPLOY" == "mod_wsgi" ]; then
-        # These files will be created if we are running WSGI_MODE="mod_wsgi"
-        disable_apache_site keystone
-        sudo rm -f $(apache_site_config_for keystone)
-    else
-        stop_process "keystone"
-        remove_uwsgi_config "$KEYSTONE_PUBLIC_UWSGI_CONF" "keystone-wsgi-public"
-        sudo rm -f $(apache_site_config_for keystone-wsgi-public)
-    fi
+    stop_process "keystone"
+    remove_uwsgi_config "$KEYSTONE_PUBLIC_UWSGI_CONF" "keystone-wsgi-public"
+    sudo rm -f $(apache_site_config_for keystone-wsgi-public)
 }
 
 # _config_keystone_apache_wsgi() - Set WSGI config files of Keystone
@@ -241,12 +226,7 @@
 
     iniset $KEYSTONE_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL
 
-    if [ "$KEYSTONE_DEPLOY" == "mod_wsgi" ]; then
-        iniset $KEYSTONE_CONF DEFAULT logging_exception_prefix "%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s"
-        _config_keystone_apache_wsgi
-    else # uwsgi
-        write_uwsgi_config "$KEYSTONE_PUBLIC_UWSGI_CONF" "$KEYSTONE_PUBLIC_UWSGI" "/identity"
-    fi
+    write_uwsgi_config "$KEYSTONE_PUBLIC_UWSGI_CONF" "$KEYSTONE_PUBLIC_UWSGI" "/identity" "" "keystone-api"
 
     iniset $KEYSTONE_CONF DEFAULT max_token_size 16384
 
@@ -543,10 +523,6 @@
     if is_service_enabled ldap; then
         setup_develop $KEYSTONE_DIR ldap
     fi
-
-    if [ "$KEYSTONE_DEPLOY" == "mod_wsgi" ]; then
-        install_apache_wsgi
-    fi
 }
 
 # start_keystone() - Start running processes
@@ -559,12 +535,7 @@
         auth_protocol="http"
     fi
 
-    if [ "$KEYSTONE_DEPLOY" == "mod_wsgi" ]; then
-        enable_apache_site keystone
-        restart_apache_server
-    else # uwsgi
-        run_process keystone "$(which uwsgi) --procname-prefix keystone --ini $KEYSTONE_PUBLIC_UWSGI_CONF" ""
-    fi
+    run_process keystone "$(which uwsgi) --procname-prefix keystone --ini $KEYSTONE_PUBLIC_UWSGI_CONF" ""
 
     echo "Waiting for keystone to start..."
     # Check that the keystone service is running. Even if the tls tunnel
@@ -589,12 +560,7 @@
 
 # stop_keystone() - Stop running processes
 function stop_keystone {
-    if [ "$KEYSTONE_DEPLOY" == "mod_wsgi" ]; then
-        disable_apache_site keystone
-        restart_apache_server
-    else
-        stop_process keystone
-    fi
+    stop_process keystone
 }
 
 # bootstrap_keystone() - Initialize user, role and project
diff --git a/lib/libraries b/lib/libraries
index 9ea3230..9d5d655 100755
--- a/lib/libraries
+++ b/lib/libraries
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# lib/oslo
+# lib/libraries
 #
 # Functions to install libraries from git
 #
diff --git a/lib/nova b/lib/nova
index 35c6893..20e19da 100644
--- a/lib/nova
+++ b/lib/nova
@@ -75,14 +75,6 @@
 
 NOVA_API_PASTE_INI=${NOVA_API_PASTE_INI:-$NOVA_CONF_DIR/api-paste.ini}
 
-# Toggle for deploying Nova-API under a wsgi server. We default to
-# true to use UWSGI, but allow False so that fall back to the
-# eventlet server can happen for grenade runs.
-# NOTE(cdent): We can adjust to remove the eventlet-base api service
-# after pike, at which time we can stop using NOVA_USE_MOD_WSGI to
-# mean "use uwsgi" because we'll be always using uwsgi.
-NOVA_USE_MOD_WSGI=${NOVA_USE_MOD_WSGI:-True}
-
 # We do not need to report service status every 10s for devstack-like
 # deployments. In the gate this generates extra work for the services and the
 # database which are already taxed.
@@ -393,11 +385,7 @@
         create_service_user "nova" "admin"
 
         local nova_api_url
-        if [[ "$NOVA_USE_MOD_WSGI" == "False" ]]; then
-            nova_api_url="$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT"
-        else
-            nova_api_url="$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST/compute"
-        fi
+        nova_api_url="$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST/compute"
 
         get_or_create_service "nova_legacy" "compute_legacy" "Nova Compute Service (Legacy 2.0)"
         get_or_create_endpoint \
@@ -513,11 +501,6 @@
             iniset $NOVA_CONF oslo_policy enforce_new_defaults False
             iniset $NOVA_CONF oslo_policy enforce_scope False
         fi
-        if is_service_enabled tls-proxy && [ "$NOVA_USE_MOD_WSGI" == "False" ]; then
-            # Set the service port for a proxy to take the original
-            iniset $NOVA_CONF DEFAULT osapi_compute_listen_port "$NOVA_SERVICE_PORT_INT"
-            iniset $NOVA_CONF DEFAULT osapi_compute_link_prefix $NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT
-        fi
 
         configure_keystone_authtoken_middleware $NOVA_CONF nova
     fi
@@ -998,17 +981,8 @@
     local old_path=$PATH
     export PATH=$NOVA_BIN_DIR:$PATH
 
-    if [ "$NOVA_USE_MOD_WSGI" == "False" ]; then
-        run_process n-api "$NOVA_BIN_DIR/nova-api"
-        nova_url=$service_protocol://$SERVICE_HOST:$service_port
-        # Start proxy if tsl enabled
-        if is_service_enabled tls-proxy; then
-            start_tls_proxy nova '*' $NOVA_SERVICE_PORT $NOVA_SERVICE_HOST $NOVA_SERVICE_PORT_INT
-        fi
-    else
-        run_process "n-api" "$(which uwsgi) --procname-prefix nova-api --ini $NOVA_UWSGI_CONF"
-        nova_url=$service_protocol://$SERVICE_HOST/compute/v2.1/
-    fi
+    run_process "n-api" "$(which uwsgi) --procname-prefix nova-api --ini $NOVA_UWSGI_CONF"
+    nova_url=$service_protocol://$SERVICE_HOST/compute/v2.1/
 
     echo "Waiting for nova-api to start..."
     if ! wait_for_service $SERVICE_TIMEOUT $nova_url; then
@@ -1114,11 +1088,7 @@
     local compute_cell_conf=$NOVA_CONF
 
     run_process n-sch "$NOVA_BIN_DIR/nova-scheduler --config-file $compute_cell_conf"
-    if [ "$NOVA_USE_MOD_WSGI" == "False" ]; then
-        run_process n-api-meta "$NOVA_BIN_DIR/nova-api-metadata --config-file $compute_cell_conf"
-    else
-        run_process n-api-meta "$(which uwsgi) --procname-prefix nova-api-meta --ini $NOVA_METADATA_UWSGI_CONF"
-    fi
+    run_process n-api-meta "$(which uwsgi) --procname-prefix nova-api-meta --ini $NOVA_METADATA_UWSGI_CONF"
 
     export PATH=$old_path
 }
diff --git a/lib/oslo b/lib/oslo
deleted file mode 100644
index 3ae64c8..0000000
--- a/lib/oslo
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-#
-# lib/oslo
-#
-# Functions to install **Oslo** libraries from git
-#
-# We need this to handle the fact that projects would like to use
-# pre-released versions of oslo libraries.
-#
-# Included for compatibility with grenade, remove in Queens
-source $TOP_DIR/lib/libraries
diff --git a/lib/placement b/lib/placement
index 63fdfb6..6297ab2 100644
--- a/lib/placement
+++ b/lib/placement
@@ -71,32 +71,6 @@
     remove_uwsgi_config "$PLACEMENT_UWSGI_CONF" "placement-api"
 }
 
-# _config_placement_apache_wsgi() - Set WSGI config files
-function _config_placement_apache_wsgi {
-    local placement_api_apache_conf
-    local venv_path=""
-    local placement_bin_dir=""
-    placement_bin_dir=$(get_python_exec_prefix)
-    placement_api_apache_conf=$(apache_site_config_for placement-api)
-
-    if [[ ${USE_VENV} = True ]]; then
-        venv_path="python-path=${PROJECT_VENV["placement"]}/lib/$(python_version)/site-packages"
-        placement_bin_dir=${PROJECT_VENV["placement"]}/bin
-    fi
-
-    sudo cp $FILES/apache-placement-api.template $placement_api_apache_conf
-    sudo sed -e "
-        s|%APACHE_NAME%|$APACHE_NAME|g;
-        s|%PUBLICWSGI%|$placement_bin_dir/placement-api|g;
-        s|%SSLENGINE%|$placement_ssl|g;
-        s|%SSLCERTFILE%|$placement_certfile|g;
-        s|%SSLKEYFILE%|$placement_keyfile|g;
-        s|%USER%|$STACK_USER|g;
-        s|%VIRTUALENV%|$venv_path|g
-        s|%APIWORKERS%|$API_WORKERS|g
-    " -i $placement_api_apache_conf
-}
-
 # create_placement_conf() - Write config
 function create_placement_conf {
     rm -f $PLACEMENT_CONF
@@ -112,11 +86,7 @@
     sudo install -d -o $STACK_USER $PLACEMENT_CONF_DIR
     create_placement_conf
 
-    if [[ "$WSGI_MODE" == "uwsgi" ]]; then
-        write_uwsgi_config "$PLACEMENT_UWSGI_CONF" "$PLACEMENT_UWSGI" "/placement"
-    else
-        _config_placement_apache_wsgi
-    fi
+    write_uwsgi_config "$PLACEMENT_UWSGI_CONF" "$PLACEMENT_UWSGI" "/placement"
     if [[ "$PLACEMENT_ENFORCE_SCOPE" == "True" || "$ENFORCE_SCOPE" == "True" ]]; then
         iniset $PLACEMENT_CONF oslo_policy enforce_new_defaults True
         iniset $PLACEMENT_CONF oslo_policy enforce_scope True
@@ -147,7 +117,6 @@
 
 # install_placement() - Collect source and prepare
 function install_placement {
-    install_apache_wsgi
     # Install the openstackclient placement client plugin for CLI
     pip_install_gr osc-placement
     git_clone $PLACEMENT_REPO $PLACEMENT_DIR $PLACEMENT_BRANCH
@@ -156,12 +125,7 @@
 
 # start_placement_api() - Start the API processes ahead of other things
 function start_placement_api {
-    if [[ "$WSGI_MODE" == "uwsgi" ]]; then
-        run_process "placement-api" "$(which uwsgi) --procname-prefix placement --ini $PLACEMENT_UWSGI_CONF"
-    else
-        enable_apache_site placement-api
-        restart_apache_server
-    fi
+    run_process "placement-api" "$(which uwsgi) --procname-prefix placement --ini $PLACEMENT_UWSGI_CONF"
 
     echo "Waiting for placement-api to start..."
     if ! wait_for_service $SERVICE_TIMEOUT $PLACEMENT_SERVICE_PROTOCOL://$PLACEMENT_SERVICE_HOST/placement; then
@@ -175,12 +139,7 @@
 
 # stop_placement() - Disable the api service and stop it.
 function stop_placement {
-    if [[ "$WSGI_MODE" == "uwsgi" ]]; then
-        stop_process "placement-api"
-    else
-        disable_apache_site placement-api
-        restart_apache_server
-    fi
+    stop_process "placement-api"
 }
 
 # Restore xtrace
diff --git a/lib/swift b/lib/swift
index 1ebf073..3659624 100644
--- a/lib/swift
+++ b/lib/swift
@@ -844,14 +844,14 @@
 
 function swift_configure_tempurls {
     # note we are using swift credentials!
-    openstack --os-cloud "" \
-        --os-region-name $REGION_NAME \
-        --os-auth-url $KEYSTONE_SERVICE_URI \
-        --os-username=swift \
-        --os-password=$SERVICE_PASSWORD \
-        --os-user-domain-name=$SERVICE_DOMAIN_NAME \
-        --os-project-name=$SERVICE_PROJECT_NAME \
-        --os-project-domain-name=$SERVICE_DOMAIN_NAME \
+    openstack --os-cloud="" \
+        --os-region-name="$REGION_NAME" \
+        --os-auth-url="$KEYSTONE_SERVICE_URI" \
+        --os-username="swift" \
+        --os-password="$SERVICE_PASSWORD" \
+        --os-user-domain-name="$SERVICE_DOMAIN_NAME" \
+        --os-project-name="$SERVICE_PROJECT_NAME" \
+        --os-project-domain-name="$SERVICE_DOMAIN_NAME" \
         object store account \
         set --property "Temp-URL-Key=$SWIFT_TEMPURL_KEY"
 }
diff --git a/lib/tempest b/lib/tempest
index 310db2d..eeeef67 100644
--- a/lib/tempest
+++ b/lib/tempest
@@ -368,6 +368,7 @@
         if [[ -n "$image_conversion" ]]; then
             iniset $TEMPEST_CONFIG image-feature-enabled image_conversion True
         fi
+        iniset $TEMPEST_CONFIG image-feature-enabled image_format_enforcement $GLANCE_ENFORCE_IMAGE_FORMAT
     fi
 
     iniset $TEMPEST_CONFIG network project_network_cidr $FIXED_RANGE
diff --git a/stack.sh b/stack.sh
index dcfd398..bfa0573 100755
--- a/stack.sh
+++ b/stack.sh
@@ -308,8 +308,11 @@
             # adding delorean-deps repo to provide current master rpms
             sudo wget https://trunk.rdoproject.org/centos9-master/delorean-deps.repo -O /etc/yum.repos.d/delorean-deps.repo
         else
-            # For stable/unmaintained branches use corresponding release rpm
-            sudo dnf -y install centos-release-openstack-${rdo_release}
+            if sudo dnf provides centos-release-openstack-${rdo_release} >/dev/null 2>&1; then
+                sudo dnf -y install centos-release-openstack-${rdo_release}
+            else
+                sudo wget https://trunk.rdoproject.org/centos9-${rdo_release}/delorean-deps.repo -O /etc/yum.repos.d/delorean-deps.repo
+            fi
         fi
     fi
     sudo dnf -y update
diff --git a/stackrc b/stackrc
index ab1f8a6..c05d4e2 100644
--- a/stackrc
+++ b/stackrc
@@ -85,7 +85,7 @@
 # Global toggle for enabling services under mod_wsgi. If this is set to
 # ``True`` all services that use HTTPD + mod_wsgi as the preferred method of
 # deployment, will be deployed under Apache. If this is set to ``False`` all
-# services will rely on the local toggle variable (e.g. ``KEYSTONE_USE_MOD_WSGI``)
+# services will rely on the local toggle variable.
 ENABLE_HTTPD_MOD_WSGI_SERVICES=True
 
 # Set the default Nova APIs to enable
@@ -223,6 +223,9 @@
 # proxy uwsgi in front of it, or "mod_wsgi", which runs in
 # apache. mod_wsgi is deprecated, don't use it.
 WSGI_MODE=${WSGI_MODE:-"uwsgi"}
+if [[ "$WSGI_MODE" != "uwsgi" ]]; then
+    die $LINENO "$WSGI_MODE is no longer a supported WSGI mode. Only uwsgi is valid."
+fi
 
 # Repositories
 # ------------
@@ -656,7 +659,7 @@
 
 #IMAGE_URLS="https://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-disk.img" # cirros full disk image
 
-CIRROS_VERSION=${CIRROS_VERSION:-"0.6.2"}
+CIRROS_VERSION=${CIRROS_VERSION:-"0.6.3"}
 CIRROS_ARCH=${CIRROS_ARCH:-$(uname -m)}
 
 # Set default image based on ``VIRT_DRIVER`` and ``LIBVIRT_TYPE``, either of
@@ -673,11 +676,11 @@
                 lxc) # the cirros root disk in the uec tarball is empty, so it will not work for lxc
                     DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-rootfs}
                     DEFAULT_IMAGE_FILE_NAME=${DEFAULT_IMAGE_FILE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-rootfs.img.gz}
-                    IMAGE_URLS+="https://download.cirros-cloud.net/${CIRROS_VERSION}/${DEFAULT_IMAGE_FILE_NAME}";;
+                    IMAGE_URLS+="https://github.com/cirros-dev/cirros/releases/download/${CIRROS_VERSION}/${DEFAULT_IMAGE_FILE_NAME}";;
                 *) # otherwise, use the qcow image
                     DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-disk}
                     DEFAULT_IMAGE_FILE_NAME=${DEFAULT_IMAGE_FILE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-disk.img}
-                    IMAGE_URLS+="https://download.cirros-cloud.net/${CIRROS_VERSION}/${DEFAULT_IMAGE_FILE_NAME}";;
+                    IMAGE_URLS+="https://github.com/cirros-dev/cirros/releases/download/${CIRROS_VERSION}/${DEFAULT_IMAGE_FILE_NAME}";;
                 esac
             ;;
         vsphere)
@@ -688,7 +691,7 @@
             # Use the same as the default for libvirt
             DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-disk}
             DEFAULT_IMAGE_FILE_NAME=${DEFAULT_IMAGE_FILE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-disk.img}
-            IMAGE_URLS+="http://download.cirros-cloud.net/${CIRROS_VERSION}/${DEFAULT_IMAGE_FILE_NAME}";;
+            IMAGE_URLS+="https://github.com/cirros-dev/cirros/releases/download/${CIRROS_VERSION}/${DEFAULT_IMAGE_FILE_NAME}";;
     esac
     DOWNLOAD_DEFAULT_IMAGES=False
 fi
diff --git a/tools/outfilter.py b/tools/outfilter.py
index e910f79..55f9ee1 100644
--- a/tools/outfilter.py
+++ b/tools/outfilter.py
@@ -76,7 +76,8 @@
         # with zuulv3 native jobs and ansible capture it may become
         # clearer what to do
         if HAS_DATE.search(line) is None:
-            now = datetime.datetime.utcnow()
+            now = datetime.datetime.now(datetime.timezone.utc).replace(
+                    tzinfo=None)
             ts_line = ("%s | %s" % (
                 now.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3],
                 line))