Merge "Allow others to override NOVA_SERVICE_REPORT_INTERVAL"
diff --git a/.zuul.yaml b/.zuul.yaml
index e65dc5b..356acec 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -430,6 +430,7 @@
         /var/log/mysql: logs
         /var/log/libvirt: logs
         /etc/libvirt: logs
+        /etc/lvm: logs
         /etc/sudoers: logs
         /etc/sudoers.d: logs
         '{{ stage_dir }}/iptables.txt': logs
@@ -708,9 +709,6 @@
     nodeset: devstack-single-node-centos-9-stream
     timeout: 9000
     voting: false
-    vars:
-      devstack_localrc:
-        GLOBAL_VENV: false
 
 - job:
     name: devstack-platform-debian-bookworm
@@ -745,15 +743,6 @@
     timeout: 9000
     vars:
       configure_swap_size: 4096
-      devstack_localrc:
-        GLOBAL_VENV: false
-
-- job:
-    name: devstack-platform-ubuntu-focal
-    parent: tempest-full-py3
-    description: Ubuntu 20.04 LTS (focal) platform test
-    nodeset: openstack-single-node-focal
-    timeout: 9000
 
 - job:
     name: devstack-platform-ubuntu-jammy-ovn-source
@@ -950,7 +939,6 @@
         - devstack-platform-debian-bookworm
         - devstack-platform-debian-bullseye
         - devstack-platform-rocky-blue-onyx
-        - devstack-platform-ubuntu-focal
         - devstack-platform-ubuntu-jammy-ovn-source
         - devstack-platform-ubuntu-jammy-ovs
         - devstack-platform-openEuler-22.03-ovn-source
@@ -999,7 +987,6 @@
         - devstack
         - devstack-ipv6
         - devstack-platform-debian-bullseye
-        - devstack-platform-ubuntu-focal
         - devstack-platform-rocky-blue-onyx
         - devstack-enforce-scope
         - devstack-multinode
diff --git a/functions-common b/functions-common
index f752271..c57c4cc 100644
--- a/functions-common
+++ b/functions-common
@@ -1114,6 +1114,12 @@
     return 1
 }
 
+function is_ironic_sharded {
+    # todo(JayF): Support >1 shard with multiple n-cpu instances for each
+    is_service_enabled ironic && [[ "$IRONIC_SHARDS" == "1" ]] && return 0
+    return 1
+}
+
 
 # Package Functions
 # =================
diff --git a/lib/cinder b/lib/cinder
index 768a069..f7824eb 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -414,7 +414,9 @@
     if [[ ! -z "$CINDER_COORDINATION_URL" ]]; then
         iniset $CINDER_CONF coordination backend_url "$CINDER_COORDINATION_URL"
     elif is_service_enabled etcd3; then
-        iniset $CINDER_CONF coordination backend_url "etcd3+http://${SERVICE_HOST}:$ETCD_PORT"
+        # NOTE(jan.gutter): api_version can revert to default once tooz is
+        # updated with the etcd v3.4 defaults
+        iniset $CINDER_CONF coordination backend_url "etcd3+http://${SERVICE_HOST}:$ETCD_PORT?api_version=v3"
     fi
 
     if [[ "$CINDER_ENFORCE_SCOPE" == True || "$ENFORCE_SCOPE" == True ]] ; then
diff --git a/lib/glance b/lib/glance
index e64f000..3cf8230 100644
--- a/lib/glance
+++ b/lib/glance
@@ -584,9 +584,10 @@
     write_uwsgi_user_unit_file devstack@g-api-r.service "$(which uwsgi) \
                                --procname-prefix \
                                glance-api-remote \
-                               --ini $glance_remote_uwsgi" \
+                               --ini $glance_remote_uwsgi \
+                               --venv $DEVSTACK_VENV" \
                                "" "$STACK_USER"
-    iniset -sudo ${SYSTEMD_DIR}/devstack@g-api-r.service \
+    iniadd -sudo ${SYSTEMD_DIR}/devstack@g-api-r.service \
            "Service" "Environment" \
            "OS_GLANCE_CONFIG_DIR=$glance_remote_conf_dir"
 
diff --git a/lib/lvm b/lib/lvm
index 162c491..b7e84d9 100644
--- a/lib/lvm
+++ b/lib/lvm
@@ -200,7 +200,7 @@
     filter_string=$filter_string$filter_suffix
 
     clean_lvm_filter
-    sudo sed -i "/# global_filter = \[*\]/a\    $global_filter$filter_string" /etc/lvm/lvm.conf
+    sudo sed -i "/# global_filter = \[.*\]/a\        $filter_string" /etc/lvm/lvm.conf
     echo_summary "set lvm.conf device global_filter to: $filter_string"
 }
 
diff --git a/lib/neutron b/lib/neutron
index a6de722..808043c 100644
--- a/lib/neutron
+++ b/lib/neutron
@@ -303,6 +303,11 @@
     Q_USE_SECGROUP=False
 fi
 
+# OVN_BRIDGE_MAPPINGS - ovn-bridge-mappings
+# NOTE(hjensas): Initialize after sourcing neutron_plugins/services/l3
+# which initialize PUBLIC_BRIDGE.
+OVN_BRIDGE_MAPPINGS=${OVN_BRIDGE_MAPPINGS:-$PHYSICAL_NETWORK:$PUBLIC_BRIDGE}
+
 # Save trace setting
 _XTRACE_NEUTRON=$(set +o | grep xtrace)
 set +o xtrace
@@ -570,8 +575,15 @@
 # Start running OVN processes
 function start_ovn_services {
     if [[ $Q_AGENT == "ovn" ]]; then
-        init_ovn
-        start_ovn
+        if [ "$VIRT_DRIVER" != 'ironic' ]; then
+            # NOTE(TheJulia): Ironic's devstack plugin needs to perform
+            # additional networking configuration to setup a working test
+            # environment with test virtual machines to emulate baremetal,
+            # which requires OVN to be up and running earlier to complete
+            # that base configuration.
+            init_ovn
+            start_ovn
+        fi
         if [[ "$OVN_L3_CREATE_PUBLIC_NETWORK" == "True" ]]; then
             if [[ "$NEUTRON_CREATE_INITIAL_NETWORKS" != "True" ]]; then
                 echo "OVN_L3_CREATE_PUBLIC_NETWORK=True is being ignored "
@@ -1075,7 +1087,10 @@
         sudo install -o root -g root -m 644 $NEUTRON_DIR/etc/rootwrap.conf $Q_RR_CONF_FILE
     fi
     sudo sed -e "s:^filters_path=.*$:filters_path=$Q_CONF_ROOTWRAP_D:" -i $Q_RR_CONF_FILE
-    sudo sed -e 's:^exec_dirs=\(.*\)$:exec_dirs=\1,/usr/local/bin:' -i $Q_RR_CONF_FILE
+    # Rely on $PATH set by devstack to determine what is safe to execute
+    # by rootwrap rather than use explicit whitelist of paths in
+    # rootwrap.conf
+    sudo sed -e 's/^exec_dirs=.*/#&/' -i $Q_RR_CONF_FILE
 
     # Specify ``rootwrap.conf`` as first parameter to neutron-rootwrap
     ROOTWRAP_SUDOER_CMD="$NEUTRON_ROOTWRAP $Q_RR_CONF_FILE *"
diff --git a/lib/neutron_plugins/ovn_agent b/lib/neutron_plugins/ovn_agent
index 3526ccd..c51b708 100644
--- a/lib/neutron_plugins/ovn_agent
+++ b/lib/neutron_plugins/ovn_agent
@@ -288,7 +288,7 @@
 function create_public_bridge {
     # Create the public bridge that OVN will use
     sudo ovs-vsctl --may-exist add-br $PUBLIC_BRIDGE -- set bridge $PUBLIC_BRIDGE protocols=OpenFlow13,OpenFlow15
-    sudo ovs-vsctl set open . external-ids:ovn-bridge-mappings=$PHYSICAL_NETWORK:$PUBLIC_BRIDGE
+    sudo ovs-vsctl set open . external-ids:ovn-bridge-mappings=${OVN_BRIDGE_MAPPINGS}
     _configure_public_network_connectivity
 }
 
diff --git a/lib/neutron_plugins/services/l3 b/lib/neutron_plugins/services/l3
index 2bf884a..c6d4663 100644
--- a/lib/neutron_plugins/services/l3
+++ b/lib/neutron_plugins/services/l3
@@ -47,7 +47,8 @@
 # used for the network.  In case of ofagent, you should add the
 # corresponding entry to your OFAGENT_PHYSICAL_INTERFACE_MAPPINGS.
 # For openvswitch agent, you should add the corresponding entry to
-# your OVS_BRIDGE_MAPPINGS.
+# your OVS_BRIDGE_MAPPINGS and for OVN add the corresponding entry
+# to your OVN_BRIDGE_MAPPINGS.
 #
 # eg.  (ofagent)
 #    Q_USE_PROVIDERNET_FOR_PUBLIC=True
@@ -60,6 +61,11 @@
 #    PUBLIC_PHYSICAL_NETWORK=public
 #    OVS_BRIDGE_MAPPINGS=public:br-ex
 #
+# eg.  (ovn agent)
+#    Q_USER_PROVIDERNET_FOR_PUBLIC=True
+#    PUBLIC_PHYSICAL_NETWORK=public
+#    OVN_BRIDGE_MAPPINGS=public:br-ex
+#
 # The provider-network-type defaults to flat, however, the values
 # PUBLIC_PROVIDERNET_TYPE and PUBLIC_PROVIDERNET_SEGMENTATION_ID could
 # be set to specify the parameters for an alternate network type.
diff --git a/lib/nova_plugins/hypervisor-ironic b/lib/nova_plugins/hypervisor-ironic
index f058e9b..9a39c79 100644
--- a/lib/nova_plugins/hypervisor-ironic
+++ b/lib/nova_plugins/hypervisor-ironic
@@ -53,6 +53,10 @@
         iniset $NOVA_CONF ironic project_domain_id default
         iniset $NOVA_CONF ironic project_name demo
     fi
+    if is_ironic_sharded; then
+        iniset $NOVA_CONF ironic shard $IRONIC_SHARD_1_NAME
+    fi
+
     iniset $NOVA_CONF ironic user_domain_id default
     iniset $NOVA_CONF ironic region_name $REGION_NAME
 
diff --git a/stack.sh b/stack.sh
index d8b70a2..530fda4 100755
--- a/stack.sh
+++ b/stack.sh
@@ -230,7 +230,7 @@
 
 # Warn users who aren't on an explicitly supported distro, but allow them to
 # override check and attempt installation with ``FORCE=yes ./stack``
-SUPPORTED_DISTROS="bookworm|bullseye|focal|jammy|rhel8|rhel9|openEuler-22.03"
+SUPPORTED_DISTROS="bookworm|bullseye|jammy|rhel8|rhel9|openEuler-22.03"
 
 if [[ ! ${DISTRO} =~ $SUPPORTED_DISTROS ]]; then
     echo "WARNING: this script has not been tested on $DISTRO"
@@ -312,22 +312,14 @@
             sudo dnf -y install https://rdoproject.org/repos/openstack-${rdo_release}/rdo-release-${rdo_release}.el8.rpm
         fi
     elif [[ $DISTRO == "rhel9" ]]; then
-        install_package wget
-        # We need to download rdo-release package using wget as installing with dnf from repo.fedoraproject.org fails in
-        # FIPS enabled systems after https://bugzilla.redhat.com/show_bug.cgi?id=2157951
-        # Until we can pull rdo-release from a server which supports EMS, this workaround is doing wget, which does
-        # not relies on openssl but on gnutls, and then install it locally using rpm
-        TEMPRDODIR=$(mktemp -d)
         if [[ "$TARGET_BRANCH" == "master" ]]; then
             # rdo-release.el9.rpm points to latest RDO release, use that for master
-            wget -P $TEMPRDODIR  https://rdoproject.org/repos/rdo-release.el9.rpm
+            sudo dnf -y install https://rdoproject.org/repos/rdo-release.el9.rpm
         else
             # For stable branches use corresponding release rpm
             rdo_release=$(echo $TARGET_BRANCH | sed "s|stable/||g")
-            wget -P $TEMPRDODIR https://rdoproject.org/repos/openstack-${rdo_release}/rdo-release-${rdo_release}.el9.rpm
+            sudo dnf -y install https://rdoproject.org/repos/openstack-${rdo_release}/rdo-release-${rdo_release}.el9.rpm
         fi
-        sudo rpm -ivh $TEMPRDODIR/rdo-release*rpm
-        rm -rf $TEMPRDODIR
     fi
     sudo dnf -y update
 }
@@ -350,7 +342,9 @@
 
 # Destination path for devstack logs
 if [[ -n ${LOGDIR:-} ]]; then
-    mkdir -p $LOGDIR
+    sudo mkdir -p $LOGDIR
+    safe_chown -R $STACK_USER $LOGDIR
+    safe_chmod 0755 $LOGDIR
 fi
 
 # Destination path for service data
@@ -829,7 +823,6 @@
     # TODO(frickler): find a better solution for this
     sudo ln -sf /opt/stack/data/venv/bin/cinder-rtstool /usr/local/bin
     sudo ln -sf /opt/stack/data/venv/bin/glance /usr/local/bin
-    sudo ln -sf /opt/stack/data/venv/bin/nova /usr/local/bin
     sudo ln -sf /opt/stack/data/venv/bin/nova-manage /usr/local/bin
     sudo ln -sf /opt/stack/data/venv/bin/openstack /usr/local/bin
     sudo ln -sf /opt/stack/data/venv/bin/privsep-helper /usr/local/bin
diff --git a/stackrc b/stackrc
index 0d1880c..ff30d37 100644
--- a/stackrc
+++ b/stackrc
@@ -188,9 +188,18 @@
 # Note that the DATA_DIR is selected because grenade testing uses a shared
 # DATA_DIR but different DEST dirs and we don't want two sets of venvs,
 # instead we want one global set.
-GLOBAL_VENV=$(trueorfalse True GLOBAL_VENV)
 DEVSTACK_VENV=${DEVSTACK_VENV:-$DATA_DIR/venv}
 
+# NOTE(kopecmartin): remove this once this is fixed
+# https://bugs.launchpad.net/devstack/+bug/2031639
+# This couldn't go to fixup_stuff as that's called after projects
+# (e.g. certain paths) are set taking GLOBAL_VENV into account
+if [[ "$os_VENDOR" =~ (CentOSStream|Rocky) ]]; then
+    GLOBAL_VENV=$(trueorfalse False GLOBAL_VENV)
+else
+    GLOBAL_VENV=$(trueorfalse True GLOBAL_VENV)
+fi
+
 # Enable use of Python virtual environments.  Individual project use of
 # venvs are controlled by the PROJECT_VENV array; every project with
 # an entry in the array will be installed into the named venv.
@@ -728,11 +737,11 @@
 EXTRA_CACHE_URLS=""
 
 # etcd3 defaults
-ETCD_VERSION=${ETCD_VERSION:-v3.3.12}
-ETCD_SHA256_AMD64=${ETCD_SHA256_AMD64:-"dc5d82df095dae0a2970e4d870b6929590689dd707ae3d33e7b86da0f7f211b6"}
-ETCD_SHA256_ARM64=${ETCD_SHA256_ARM64:-"170b848ac1a071fe7d495d404a868a2c0090750b2944f8a260ef1c6125b2b4f4"}
-ETCD_SHA256_PPC64=${ETCD_SHA256_PPC64:-"77f807b1b51abbf51e020bb05bdb8ce088cb58260fcd22749ea32eee710463d3"}
-# etcd v3.2.x doesn't have anything for s390x
+ETCD_VERSION=${ETCD_VERSION:-v3.4.27}
+ETCD_SHA256_AMD64=${ETCD_SHA256_AMD64:-"a32d21e006252dbc3405b0645ba8468021ed41376974b573285927bf39b39eb9"}
+ETCD_SHA256_ARM64=${ETCD_SHA256_ARM64:-"ed7e257c225b9b9545fac22246b97f4074a4b5109676e92dbaebfb9315b69cc0"}
+ETCD_SHA256_PPC64=${ETCD_SHA256_PPC64:-"eb8825e0bc2cbaf9e55947f5ee373ebc9ca43b6a2ea5ced3b992c81855fff37e"}
+# etcd v3.2.x and later doesn't have anything for s390x
 ETCD_SHA256_S390X=${ETCD_SHA256_S390X:-""}
 # Make sure etcd3 downloads the correct architecture
 if is_arch "x86_64"; then
diff --git a/tools/fixup_stuff.sh b/tools/fixup_stuff.sh
index 80a83bb..faea44f 100755
--- a/tools/fixup_stuff.sh
+++ b/tools/fixup_stuff.sh
@@ -94,11 +94,6 @@
     if [[ $os_VENDOR == "CentOSStream" && $os_RELEASE -eq 8 ]]; then
         sudo sysctl -w net.ipv4.ping_group_range='0 2147483647'
     fi
-    # TODO(ykarel): Workaround for systemd issue, remove once fix is
-    # included in systemd rpm https://bugs.launchpad.net/devstack/+bug/2029335
-    if [[ $os_VENDOR == "CentOSStream" && $os_RELEASE -eq 9 ]]; then
-        echo 'LIBVIRTD_ARGS=""' | sudo tee /etc/sysconfig/libvirtd
-    fi
 }
 
 function fixup_ovn_centos {