Merge "doc: Use dnf instead of yum"
diff --git a/.zuul.yaml b/.zuul.yaml
index 2fbfa04..7d72ab1 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -311,6 +311,36 @@
           - compute1
           - compute2
 
+- nodeset:
+    name: devstack-two-node-debian-bookworm
+    nodes:
+      - name: controller
+        label: debian-bookworm
+      - name: compute1
+        label: debian-bookworm
+    groups:
+      # Node where tests are executed and test results collected
+      - name: tempest
+        nodes:
+          - controller
+      # Nodes running the compute service
+      - name: compute
+        nodes:
+          - controller
+          - compute1
+      # Nodes that are not the controller
+      - name: subnode
+        nodes:
+          - compute1
+      # Switch node for multinode networking setup
+      - name: switch
+        nodes:
+          - controller
+      # Peer nodes for multinode networking setup
+      - name: peers
+        nodes:
+          - compute1
+
 - job:
     name: devstack-base
     parent: openstack-multinode-fips
@@ -357,6 +387,7 @@
         '{{ devstack_conf_dir }}/.localrc.auto': logs
         '{{ devstack_conf_dir }}/.stackenv': logs
         '{{ devstack_log_dir }}/dstat-csv.log': logs
+        '{{ devstack_log_dir }}/atop': logs
         '{{ devstack_log_dir }}/devstacklog.txt': logs
         '{{ devstack_log_dir }}/devstacklog.txt.summary': logs
         '{{ devstack_log_dir }}/tcpdump.pcap': logs
@@ -745,8 +776,8 @@
     vars:
       devstack_localrc:
         OVN_BUILD_FROM_SOURCE: True
-        OVN_BRANCH: "v21.06.0"
-        OVS_BRANCH: "a4b04276ab5934d087669ff2d191a23931335c87"
+        OVN_BRANCH: "branch-24.03"
+        OVS_BRANCH: "branch-3.3"
         OVS_SYSCONFDIR: "/usr/local/etc/openvswitch"
 
 - job:
diff --git a/doc/source/guides/multinode-lab.rst b/doc/source/guides/multinode-lab.rst
index 4b50b2c..ef339f1 100644
--- a/doc/source/guides/multinode-lab.rst
+++ b/doc/source/guides/multinode-lab.rst
@@ -210,6 +210,48 @@
 
 .. _Cells v2: https://docs.openstack.org/nova/latest/user/cells.html
 
+Configure Tempest Node to run the Tempest tests
+-----------------------------------------------
+
+If there is a need to execute Tempest tests against different Cluster
+Controller node then it can be done by re-using the ``local.conf`` file from
+the Cluster Controller node but with not enabled Controller services in
+``ENABLED_SERVICES`` variable. This variable needs to contain only ``tempest``
+as a configured service. Then variable ``SERVICES_FOR_TEMPEST`` must be
+configured to contain those services that were enabled on the Cluster
+Controller node in the ``ENABLED_SERVICES`` variable. For example the
+``local.conf`` file could look as follows:
+
+::
+
+    [[local|localrc]]
+    HOST_IP=192.168.42.12 # change this per compute node
+    FIXED_RANGE=10.4.128.0/20
+    FLOATING_RANGE=192.168.42.128/25
+    LOGFILE=/opt/stack/logs/stack.sh.log
+    ADMIN_PASSWORD=labstack
+    DATABASE_PASSWORD=supersecret
+    RABBIT_PASSWORD=supersecret
+    SERVICE_PASSWORD=supersecret
+    DATABASE_TYPE=mysql
+    SERVICE_HOST=192.168.42.11
+    MYSQL_HOST=$SERVICE_HOST
+    RABBIT_HOST=$SERVICE_HOST
+    GLANCE_HOSTPORT=$SERVICE_HOST:9292
+    NOVA_VNC_ENABLED=True
+    NOVNCPROXY_URL="http://$SERVICE_HOST:6080/vnc_lite.html"
+    VNCSERVER_LISTEN=$HOST_IP
+    VNCSERVER_PROXYCLIENT_ADDRESS=$VNCSERVER_LISTEN
+    ENABLED_SERVICES=tempest
+    SERVICES_FOR_TEMPEST=keystone,nova,neutron,glance
+
+Then just execute the devstack:
+
+::
+
+    ./stack.sh
+
+
 Cleaning Up After DevStack
 --------------------------
 
diff --git a/doc/source/plugin-registry.rst b/doc/source/plugin-registry.rst
index 2984a5c..f7873c9 100644
--- a/doc/source/plugin-registry.rst
+++ b/doc/source/plugin-registry.rst
@@ -38,6 +38,7 @@
 openstack/devstack-plugin-kafka          `https://opendev.org/openstack/devstack-plugin-kafka <https://opendev.org/openstack/devstack-plugin-kafka>`__
 openstack/devstack-plugin-nfs            `https://opendev.org/openstack/devstack-plugin-nfs <https://opendev.org/openstack/devstack-plugin-nfs>`__
 openstack/devstack-plugin-open-cas       `https://opendev.org/openstack/devstack-plugin-open-cas <https://opendev.org/openstack/devstack-plugin-open-cas>`__
+openstack/devstack-plugin-prometheus     `https://opendev.org/openstack/devstack-plugin-prometheus <https://opendev.org/openstack/devstack-plugin-prometheus>`__
 openstack/freezer                        `https://opendev.org/openstack/freezer <https://opendev.org/openstack/freezer>`__
 openstack/freezer-api                    `https://opendev.org/openstack/freezer-api <https://opendev.org/openstack/freezer-api>`__
 openstack/freezer-tempest-plugin         `https://opendev.org/openstack/freezer-tempest-plugin <https://opendev.org/openstack/freezer-tempest-plugin>`__
@@ -169,7 +170,6 @@
 x/scalpels                               `https://opendev.org/x/scalpels <https://opendev.org/x/scalpels>`__
 x/slogging                               `https://opendev.org/x/slogging <https://opendev.org/x/slogging>`__
 x/stackube                               `https://opendev.org/x/stackube <https://opendev.org/x/stackube>`__
-x/tap-as-a-service-dashboard             `https://opendev.org/x/tap-as-a-service-dashboard <https://opendev.org/x/tap-as-a-service-dashboard>`__
 x/tatu                                   `https://opendev.org/x/tatu <https://opendev.org/x/tatu>`__
 x/trio2o                                 `https://opendev.org/x/trio2o <https://opendev.org/x/trio2o>`__
 x/valet                                  `https://opendev.org/x/valet <https://opendev.org/x/valet>`__
diff --git a/inc/meta-config b/inc/meta-config
index be73b60..b9d9649 100644
--- a/inc/meta-config
+++ b/inc/meta-config
@@ -90,6 +90,7 @@
     local real_configfile
     real_configfile=$(eval echo $configfile)
     if [ ! -f $real_configfile ]; then
+        mkdir -p $(dirname $real_configfile) || die $LINENO "could not create the directory of $real_configfile ($configfile)"
         touch $real_configfile || die $LINENO "could not create config file $real_configfile ($configfile)"
     fi
 
diff --git a/lib/apache b/lib/apache
index 1c034d3..fc174f3 100644
--- a/lib/apache
+++ b/lib/apache
@@ -313,9 +313,7 @@
 # For services using chunked encoding, the only services known to use this
 # currently are Glance and Swift, we need to use an http proxy instead of
 # mod_proxy_uwsgi because the chunked encoding gets dropped. See:
-# https://github.com/unbit/uwsgi/issues/1540 You can workaround this on python2
-# but that involves having apache buffer the request before sending it to
-# uwsgi.
+# https://github.com/unbit/uwsgi/issues/1540.
 function write_local_uwsgi_http_config {
     local conf=$1
     local wsgi=$2
diff --git a/lib/atop b/lib/atop
new file mode 100644
index 0000000..e0b14cb
--- /dev/null
+++ b/lib/atop
@@ -0,0 +1,48 @@
+#!/bin/bash
+#
+# lib/atop
+# Functions to start and stop atop
+
+# Dependencies:
+#
+# - ``functions`` file
+
+# ``stack.sh`` calls the entry points in this order:
+#
+# - configure_atop
+# - install_atop
+# - start_atop
+# - stop_atop
+
+# Save trace setting
+_XTRACE_ATOP=$(set +o | grep xtrace)
+set +o xtrace
+
+function configure_atop {
+        cat <<EOF | sudo tee /etc/default/atop >/dev/null
+# /etc/default/atop
+# see man atoprc for more possibilities to configure atop execution
+
+LOGOPTS="-R"
+LOGINTERVAL=${ATOP_LOGINTERVAL:-"30"}
+LOGGENERATIONS=${ATOP_LOGGENERATIONS:-"1"}
+LOGPATH=$LOGDIR/atop
+EOF
+}
+
+function install_atop {
+    install_package atop
+}
+
+# start_() - Start running processes
+function start_atop {
+    start_service atop
+}
+
+# stop_atop() stop atop process
+function stop_atop {
+    stop_service atop
+}
+
+# Restore xtrace
+$_XTRACE_ATOP
diff --git a/lib/cinder b/lib/cinder
index 259018e..b557d4b 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -62,7 +62,7 @@
 
 CINDER_CONF_DIR=/etc/cinder
 CINDER_CONF=$CINDER_CONF_DIR/cinder.conf
-CINDER_UWSGI=$CINDER_BIN_DIR/cinder-wsgi
+CINDER_UWSGI=cinder.wsgi.api:application
 CINDER_UWSGI_CONF=$CINDER_CONF_DIR/cinder-api-uwsgi.ini
 CINDER_API_PASTE_INI=$CINDER_CONF_DIR/api-paste.ini
 
@@ -404,7 +404,7 @@
     setup_logging $CINDER_CONF
 
     if is_service_enabled c-api; then
-        write_uwsgi_config "$CINDER_UWSGI_CONF" "$CINDER_UWSGI" "/volume"
+        write_uwsgi_config "$CINDER_UWSGI_CONF" "$CINDER_UWSGI" "/volume" "" "cinder-api"
     fi
 
     if [[ -r $CINDER_PLUGINS/$CINDER_DRIVER ]]; then
diff --git a/lib/glance b/lib/glance
index 5c3643d..4e51910 100644
--- a/lib/glance
+++ b/lib/glance
@@ -133,11 +133,11 @@
 GLANCE_SERVICE_PORT_INT=${GLANCE_SERVICE_PORT_INT:-19292}
 GLANCE_HOSTPORT=${GLANCE_HOSTPORT:-$GLANCE_SERVICE_HOST:$GLANCE_SERVICE_PORT}
 GLANCE_SERVICE_PROTOCOL=${GLANCE_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL}
-GLANCE_UWSGI=$GLANCE_BIN_DIR/glance-wsgi-api
+GLANCE_UWSGI=glance.wsgi.api:application
 GLANCE_UWSGI_CONF=$GLANCE_CONF_DIR/glance-uwsgi.ini
 
 # Glance default limit for Devstack
-GLANCE_LIMIT_IMAGE_SIZE_TOTAL=${GLANCE_LIMIT_IMAGE_SIZE_TOTAL:-1000}
+GLANCE_LIMIT_IMAGE_SIZE_TOTAL=${GLANCE_LIMIT_IMAGE_SIZE_TOTAL:-2000}
 
 # If wsgi mode is uwsgi run glance under uwsgi, else default to eventlet
 # TODO(mtreinish): Remove the eventlet path here and in all the similar
@@ -472,12 +472,11 @@
     fi
 
     if [[ "$GLANCE_STANDALONE" == False ]]; then
-        write_local_uwsgi_http_config "$GLANCE_UWSGI_CONF" "$GLANCE_UWSGI" "/image"
+        write_local_uwsgi_http_config "$GLANCE_UWSGI_CONF" "$GLANCE_UWSGI" "/image" "glance-api"
         # Grab our uwsgi listen address and use that to fill out our
         # worker_self_reference_url config
         iniset $GLANCE_API_CONF DEFAULT worker_self_reference_url \
-               $(awk '-F= ' '/^http-socket/ { print "http://"$2}' \
-                    $GLANCE_UWSGI_CONF)
+               $(awk '-F= ' '/^http-socket/ { print "http://"$2}' $GLANCE_UWSGI_CONF)
     else
         write_local_proxy_http_config glance "http://$GLANCE_SERVICE_HOST:$GLANCE_SERVICE_PORT_INT" "/image"
         iniset $GLANCE_API_CONF DEFAULT bind_host $GLANCE_SERVICE_LISTEN_ADDRESS
diff --git a/lib/neutron_plugins/ovn_agent b/lib/neutron_plugins/ovn_agent
index be3a9e7..71b5e33 100644
--- a/lib/neutron_plugins/ovn_agent
+++ b/lib/neutron_plugins/ovn_agent
@@ -28,7 +28,7 @@
 OVN_REPO=${OVN_REPO:-https://github.com/ovn-org/ovn.git}
 OVN_REPO_NAME=$(basename ${OVN_REPO} | cut -f1 -d'.')
 OVN_REPO_NAME=${OVN_REPO_NAME:-ovn}
-OVN_BRANCH=${OVN_BRANCH:-v20.06.1}
+OVN_BRANCH=${OVN_BRANCH:-branch-24.03}
 # The commit removing OVN bits from the OVS tree, it is the commit that is not
 # present in OVN tree and is used to distinguish if OVN is part of OVS or not.
 # https://github.com/openvswitch/ovs/commit/05bf1dbb98b0635a51f75e268ef8aed27601401d
@@ -161,8 +161,10 @@
 
 # Defaults Overwrite
 # ------------------
-
-Q_ML2_PLUGIN_MECHANISM_DRIVERS=${Q_ML2_PLUGIN_MECHANISM_DRIVERS:-ovn,logger}
+# NOTE(ralonsoh): during the eventlet removal, the "logger" mech
+# driver has been removed from this list. Re-add it once the removal
+# is finished or the mech driver does not call monkey_patch().
+Q_ML2_PLUGIN_MECHANISM_DRIVERS=${Q_ML2_PLUGIN_MECHANISM_DRIVERS:-ovn}
 Q_ML2_PLUGIN_TYPE_DRIVERS=${Q_ML2_PLUGIN_TYPE_DRIVERS:-local,flat,vlan,geneve}
 Q_ML2_TENANT_NETWORK_TYPE=${Q_ML2_TENANT_NETWORK_TYPE:-"geneve"}
 Q_ML2_PLUGIN_GENEVE_TYPE_OPTIONS=${Q_ML2_PLUGIN_GENEVE_TYPE_OPTIONS:-"vni_ranges=1:65536"}
@@ -704,28 +706,23 @@
     fi
 }
 
-function _start_ovn_services {
-    _start_process "$OVSDB_SERVER_SERVICE"
-    _start_process "$OVS_VSWITCHD_SERVICE"
+function _wait_for_ovn_and_set_custom_config {
+    # Wait for the service to be ready
+    # Check for socket and db files for both OVN NB and SB
+    wait_for_sock_file $OVN_RUNDIR/ovnnb_db.sock
+    wait_for_sock_file $OVN_RUNDIR/ovnsb_db.sock
+    wait_for_db_file $OVN_DATADIR/ovnnb_db.db
+    wait_for_db_file $OVN_DATADIR/ovnsb_db.db
 
-    if is_service_enabled ovn-northd ; then
-        _start_process "$OVN_NORTHD_SERVICE"
+    if is_service_enabled tls-proxy; then
+        sudo ovn-nbctl --db=unix:$OVN_RUNDIR/ovnnb_db.sock set-ssl $INT_CA_DIR/private/$DEVSTACK_CERT_NAME.key $INT_CA_DIR/$DEVSTACK_CERT_NAME.crt $INT_CA_DIR/ca-chain.pem
+        sudo ovn-sbctl --db=unix:$OVN_RUNDIR/ovnsb_db.sock set-ssl $INT_CA_DIR/private/$DEVSTACK_CERT_NAME.key $INT_CA_DIR/$DEVSTACK_CERT_NAME.crt $INT_CA_DIR/ca-chain.pem
     fi
-    if is_service_enabled ovn-controller ; then
-        _start_process "$OVN_CONTROLLER_SERVICE"
-    fi
-    if is_service_enabled ovn-controller-vtep ; then
-        _start_process "$OVN_CONTROLLER_VTEP_SERVICE"
-    fi
-    if is_service_enabled ovs-vtep ; then
-        _start_process "devstack@ovs-vtep.service"
-    fi
-    if is_service_enabled q-ovn-metadata-agent neutron-ovn-metadata-agent ; then
-        _start_process "devstack@q-ovn-metadata-agent.service"
-    fi
-    if is_service_enabled q-ovn-agent neutron-ovn-agent ; then
-        _start_process "devstack@q-ovn-agent.service"
-    fi
+
+    sudo ovn-nbctl --db=unix:$OVN_RUNDIR/ovnnb_db.sock set-connection p${OVN_PROTO}:6641:$SERVICE_LISTEN_ADDRESS -- set connection . inactivity_probe=60000
+    sudo ovn-sbctl --db=unix:$OVN_RUNDIR/ovnsb_db.sock set-connection p${OVN_PROTO}:6642:$SERVICE_LISTEN_ADDRESS -- set connection . inactivity_probe=60000
+    sudo ovs-appctl -t $OVN_RUNDIR/ovnnb_db.ctl vlog/set console:off syslog:$OVN_DBS_LOG_LEVEL file:$OVN_DBS_LOG_LEVEL
+    sudo ovs-appctl -t $OVN_RUNDIR/ovnsb_db.ctl vlog/set console:off syslog:$OVN_DBS_LOG_LEVEL file:$OVN_DBS_LOG_LEVEL
 }
 
 # start_ovn() - Start running processes, including screen
@@ -749,21 +746,8 @@
             _start_process "$OVN_NORTHD_SERVICE"
         fi
 
-        # Wait for the service to be ready
-        # Check for socket and db files for both OVN NB and SB
-        wait_for_sock_file $OVN_RUNDIR/ovnnb_db.sock
-        wait_for_sock_file $OVN_RUNDIR/ovnsb_db.sock
-        wait_for_db_file $OVN_DATADIR/ovnnb_db.db
-        wait_for_db_file $OVN_DATADIR/ovnsb_db.db
+        _wait_for_ovn_and_set_custom_config
 
-        if is_service_enabled tls-proxy; then
-            sudo ovn-nbctl --db=unix:$OVN_RUNDIR/ovnnb_db.sock set-ssl $INT_CA_DIR/private/$DEVSTACK_CERT_NAME.key $INT_CA_DIR/$DEVSTACK_CERT_NAME.crt $INT_CA_DIR/ca-chain.pem
-            sudo ovn-sbctl --db=unix:$OVN_RUNDIR/ovnsb_db.sock set-ssl $INT_CA_DIR/private/$DEVSTACK_CERT_NAME.key $INT_CA_DIR/$DEVSTACK_CERT_NAME.crt $INT_CA_DIR/ca-chain.pem
-        fi
-        sudo ovn-nbctl --db=unix:$OVN_RUNDIR/ovnnb_db.sock set-connection p${OVN_PROTO}:6641:$SERVICE_LISTEN_ADDRESS -- set connection . inactivity_probe=60000
-        sudo ovn-sbctl --db=unix:$OVN_RUNDIR/ovnsb_db.sock set-connection p${OVN_PROTO}:6642:$SERVICE_LISTEN_ADDRESS -- set connection . inactivity_probe=60000
-        sudo ovs-appctl -t $OVN_RUNDIR/ovnnb_db.ctl vlog/set console:off syslog:$OVN_DBS_LOG_LEVEL file:$OVN_DBS_LOG_LEVEL
-        sudo ovs-appctl -t $OVN_RUNDIR/ovnsb_db.ctl vlog/set console:off syslog:$OVN_DBS_LOG_LEVEL file:$OVN_DBS_LOG_LEVEL
     fi
 
     if is_service_enabled ovn-controller ; then
@@ -797,8 +781,6 @@
         # Format logging
         setup_logging $OVN_AGENT_CONF
     fi
-
-    _start_ovn_services
 }
 
 function _stop_ovs_dp {
diff --git a/lib/neutron_plugins/ovs_source b/lib/neutron_plugins/ovs_source
index 75e7d7c..6b6f531 100644
--- a/lib/neutron_plugins/ovs_source
+++ b/lib/neutron_plugins/ovs_source
@@ -20,7 +20,7 @@
 OVS_REPO=${OVS_REPO:-https://github.com/openvswitch/ovs.git}
 OVS_REPO_NAME=$(basename ${OVS_REPO} | cut -f1 -d'.')
 OVS_REPO_NAME=${OVS_REPO_NAME:-ovs}
-OVS_BRANCH=${OVS_BRANCH:-0047ca3a0290f1ef954f2c76b31477cf4b9755f5}
+OVS_BRANCH=${OVS_BRANCH:-branch-3.3}
 
 # Functions
 
diff --git a/lib/nova b/lib/nova
index 20e19da..810a3d9 100644
--- a/lib/nova
+++ b/lib/nova
@@ -127,6 +127,9 @@
 # ``NOVA_VNC_ENABLED`` can be used to forcibly enable VNC configuration.
 # In multi-node setups allows compute hosts to not run ``n-novnc``.
 NOVA_VNC_ENABLED=$(trueorfalse False NOVA_VNC_ENABLED)
+# same as ``NOVA_VNC_ENABLED`` but for Spice and serial console respectively.
+NOVA_SPICE_ENABLED=$(trueorfalse False NOVA_SPICE_ENABLED)
+NOVA_SERIAL_ENABLED=$(trueorfalse False NOVA_SERIAL_ENABLED)
 
 # Get hypervisor configuration
 # ----------------------------
@@ -464,7 +467,7 @@
     # only setup database connections and cache backend if there are services
     # that require them running on the host. The ensures that n-cpu doesn't
     # leak a need to use the db in a multinode scenario.
-    if is_service_enabled n-api n-cond n-sched; then
+    if is_service_enabled n-api n-cond n-sched n-spice n-novnc n-sproxy; then
         # If we're in multi-tier cells mode, we want our control services pointing
         # at cell0 instead of cell1 to ensure isolation. If not, we point everything
         # at the main database like normal.
@@ -509,6 +512,10 @@
         configure_cinder_access
     fi
 
+    if is_service_enabled manila; then
+        configure_manila_access
+    fi
+
     if [ -n "$NOVA_STATE_PATH" ]; then
         iniset $NOVA_CONF DEFAULT state_path "$NOVA_STATE_PATH"
         iniset $NOVA_CONF oslo_concurrency lock_path "$NOVA_STATE_PATH"
@@ -654,6 +661,18 @@
     fi
 }
 
+# Configure access to manila.
+function configure_manila_access {
+    iniset $NOVA_CONF manila os_region_name "$REGION_NAME"
+    iniset $NOVA_CONF manila auth_type "password"
+    iniset $NOVA_CONF manila auth_url "$KEYSTONE_SERVICE_URI"
+    iniset $NOVA_CONF manila username nova
+    iniset $NOVA_CONF manila password "$SERVICE_PASSWORD"
+    iniset $NOVA_CONF manila user_domain_name "$SERVICE_DOMAIN_NAME"
+    iniset $NOVA_CONF manila project_name "$SERVICE_TENANT_NAME"
+    iniset $NOVA_CONF manila project_domain_name "$SERVICE_DOMAIN_NAME"
+}
+
 function configure_console_compute {
     # If we are running multiple cells (and thus multiple console proxies) on a
     # single host, we offset the ports to avoid collisions.  We need to
@@ -700,7 +719,7 @@
         iniset $NOVA_CPU_CONF vnc enabled false
     fi
 
-    if is_service_enabled n-spice; then
+    if is_service_enabled n-spice || [ "$NOVA_SPICE_ENABLED" != False ]; then
         # Address on which instance spiceservers will listen on compute hosts.
         # For multi-host, this should be the management ip of the compute host.
         SPICESERVER_PROXYCLIENT_ADDRESS=${SPICESERVER_PROXYCLIENT_ADDRESS:-$default_proxyclient_addr}
@@ -710,7 +729,7 @@
         iniset $NOVA_CPU_CONF spice server_proxyclient_address "$SPICESERVER_PROXYCLIENT_ADDRESS"
     fi
 
-    if is_service_enabled n-sproxy; then
+    if is_service_enabled n-sproxy || [ "$NOVA_SERIAL_ENABLED" != False ]; then
         iniset $NOVA_CPU_CONF serial_console enabled True
         iniset $NOVA_CPU_CONF serial_console base_url "ws://$SERVICE_HOST:$((6082 + offset))/"
     fi
diff --git a/lib/placement b/lib/placement
index 6297ab2..03aaa03 100644
--- a/lib/placement
+++ b/lib/placement
@@ -37,7 +37,7 @@
 else
     PLACEMENT_BIN_DIR=$(get_python_exec_prefix)
 fi
-PLACEMENT_UWSGI=$PLACEMENT_BIN_DIR/placement-api
+PLACEMENT_UWSGI=placement.wsgi.api:application
 PLACEMENT_UWSGI_CONF=$PLACEMENT_CONF_DIR/placement-uwsgi.ini
 
 if is_service_enabled tls-proxy; then
@@ -86,7 +86,7 @@
     sudo install -d -o $STACK_USER $PLACEMENT_CONF_DIR
     create_placement_conf
 
-    write_uwsgi_config "$PLACEMENT_UWSGI_CONF" "$PLACEMENT_UWSGI" "/placement"
+    write_uwsgi_config "$PLACEMENT_UWSGI_CONF" "$PLACEMENT_UWSGI" "/placement" "" "placement-api"
     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
diff --git a/lib/tempest b/lib/tempest
index eeeef67..29b01f1 100644
--- a/lib/tempest
+++ b/lib/tempest
@@ -197,6 +197,8 @@
         pip_install_gr testrepository
     fi
 
+    local ENABLED_SERVICES=${SERVICES_FOR_TEMPEST:=$ENABLED_SERVICES}
+
     local image_lines
     local images
     local num_images
@@ -512,9 +514,15 @@
         iniset $TEMPEST_CONFIG compute-feature-enabled volume_multiattach True
     fi
 
-    if is_service_enabled n-novnc; then
+    if is_service_enabled n-novnc || [ "$NOVA_VNC_ENABLED" != False ]; then
         iniset $TEMPEST_CONFIG compute-feature-enabled vnc_console True
     fi
+    if is_service_enabled n-spice || [ "$NOVA_SPICE_ENABLED" != False ]; then
+        iniset $TEMPEST_CONFIG compute-feature-enabled spice_console True
+    fi
+    if is_service_enabled n-sproxy || [ "$NOVA_SERIAL_ENABLED" != False ]; then
+        iniset $TEMPEST_CONFIG compute-feature-enabled serial_console True
+    fi
 
     # Network
     iniset $TEMPEST_CONFIG network project_networks_reachable false
diff --git a/stack.sh b/stack.sh
index bfa0573..04b5f4c 100755
--- a/stack.sh
+++ b/stack.sh
@@ -641,6 +641,7 @@
 source $TOP_DIR/lib/neutron
 source $TOP_DIR/lib/ldap
 source $TOP_DIR/lib/dstat
+source $TOP_DIR/lib/atop
 source $TOP_DIR/lib/tcpdump
 source $TOP_DIR/lib/etcd3
 source $TOP_DIR/lib/os-vif
@@ -1093,6 +1094,12 @@
 # A better kind of sysstat, with the top process per time slice
 start_dstat
 
+if is_service_enabled atop; then
+    configure_atop
+    install_atop
+    start_atop
+fi
+
 # Run a background tcpdump for debugging
 # Note: must set TCPDUMP_ARGS with the enabled service
 if is_service_enabled tcpdump; then
@@ -1307,10 +1314,7 @@
     start_ovn_services
 fi
 
-if is_service_enabled neutron-api; then
-    echo_summary "Starting Neutron"
-    start_neutron_api
-elif is_service_enabled q-svc; then
+if is_service_enabled q-svc neutron-api; then
     echo_summary "Starting Neutron"
     configure_neutron_after_post_config
     start_neutron_service_and_check
@@ -1327,7 +1331,7 @@
     start_neutron
 fi
 # Once neutron agents are started setup initial network elements
-if is_service_enabled q-svc && [[ "$NEUTRON_CREATE_INITIAL_NETWORKS" == "True" ]]; then
+if is_service_enabled q-svc neutron-api && [[ "$NEUTRON_CREATE_INITIAL_NETWORKS" == "True" ]]; then
     echo_summary "Creating initial neutron network elements"
     # Here's where plugins can wire up their own networks instead
     # of the code in lib/neutron_plugins/services/l3
diff --git a/tools/build_venv.sh b/tools/build_venv.sh
index cfa39a8..a439163 100755
--- a/tools/build_venv.sh
+++ b/tools/build_venv.sh
@@ -38,7 +38,7 @@
 fi
 
 # Build new venv
-virtualenv $VENV_DEST
+python$PYTHON3_VERSION -m venv --system-site-packages $VENV_DEST
 
 # Install modern pip
 PIP_VIRTUAL_ENV=$VENV_DEST pip_install -U pip
diff --git a/unstack.sh b/unstack.sh
index 1b2d8dd..29c8071 100755
--- a/unstack.sh
+++ b/unstack.sh
@@ -73,6 +73,7 @@
 source $TOP_DIR/lib/neutron
 source $TOP_DIR/lib/ldap
 source $TOP_DIR/lib/dstat
+source $TOP_DIR/lib/atop
 source $TOP_DIR/lib/etcd3
 
 # Extras Source
@@ -174,6 +175,10 @@
 
 stop_dstat
 
+if is_service_enabled atop; then
+    stop_atop
+fi
+
 # NOTE: Cinder automatically installs the lvm2 package, independently of the
 # enabled backends. So if Cinder is enabled, and installed successfully we are
 # sure lvm2 (lvremove, /etc/lvm/lvm.conf, etc.) is here.