Merge "tempest: Enable stable_rescue tests with Libvirt"
diff --git a/.zuul.yaml b/.zuul.yaml
index 26b57a2..48c2d0d 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -52,7 +52,7 @@
     name: devstack-single-node-fedora-latest
     nodes:
       - name: controller
-        label: fedora-30
+        label: fedora-31
     groups:
       - name: tempest
         nodes:
@@ -602,9 +602,12 @@
             voting: false
         - swift-dsvm-functional:
             voting: false
-            irrelevant-files:
+            irrelevant-files: &dsvm-irrelevant-files
               - ^.*\.rst$
               - ^doc/.*$
+        - swift-dsvm-functional-py3:
+            voting: false
+            irrelevant-files: *dsvm-irrelevant-files
         - grenade-py3:
             irrelevant-files:
               - ^.*\.rst$
@@ -617,7 +620,7 @@
             irrelevant-files:
               - ^.*\.rst$
               - ^doc/.*$
-        - tempest-multinode-full:
+        - tempest-multinode-full-py3:
             voting: false
             irrelevant-files:
               - ^.*\.rst$
diff --git a/doc/source/guides.rst b/doc/source/guides.rst
index 82e0dd6..e7ec629 100644
--- a/doc/source/guides.rst
+++ b/doc/source/guides.rst
@@ -10,6 +10,7 @@
 
 .. toctree::
    :glob:
+   :hidden:
    :maxdepth: 1
 
    guides/single-vm
@@ -68,6 +69,11 @@
 
 Guide to working with nova features :doc:`Nova and devstack <guides/nova>`.
 
+Configure Load-Balancer Version 2
+-----------------------------------
+
+Guide on :doc:`Configure Load-Balancer Version 2 <guides/devstack-with-lbaas-v2>`.
+
 Deploying DevStack with LDAP
 ----------------------------
 
diff --git a/doc/source/plugin-registry.rst b/doc/source/plugin-registry.rst
index 6f79102..70c18a8 100644
--- a/doc/source/plugin-registry.rst
+++ b/doc/source/plugin-registry.rst
@@ -38,6 +38,8 @@
 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>`__
 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-pika           `https://opendev.org/openstack/devstack-plugin-pika <https://opendev.org/openstack/devstack-plugin-pika>`__
 openstack/devstack-plugin-zmq            `https://opendev.org/openstack/devstack-plugin-zmq <https://opendev.org/openstack/devstack-plugin-zmq>`__
 openstack/dragonflow                     `https://opendev.org/openstack/dragonflow <https://opendev.org/openstack/dragonflow>`__
@@ -50,6 +52,7 @@
 openstack/heat-dashboard                 `https://opendev.org/openstack/heat-dashboard <https://opendev.org/openstack/heat-dashboard>`__
 openstack/ironic                         `https://opendev.org/openstack/ironic <https://opendev.org/openstack/ironic>`__
 openstack/ironic-inspector               `https://opendev.org/openstack/ironic-inspector <https://opendev.org/openstack/ironic-inspector>`__
+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/karbor                         `https://opendev.org/openstack/karbor <https://opendev.org/openstack/karbor>`__
 openstack/karbor-dashboard               `https://opendev.org/openstack/karbor-dashboard <https://opendev.org/openstack/karbor-dashboard>`__
@@ -94,10 +97,12 @@
 openstack/nova-powervm                   `https://opendev.org/openstack/nova-powervm <https://opendev.org/openstack/nova-powervm>`__
 openstack/octavia                        `https://opendev.org/openstack/octavia <https://opendev.org/openstack/octavia>`__
 openstack/octavia-dashboard              `https://opendev.org/openstack/octavia-dashboard <https://opendev.org/openstack/octavia-dashboard>`__
+openstack/octavia-tempest-plugin         `https://opendev.org/openstack/octavia-tempest-plugin <https://opendev.org/openstack/octavia-tempest-plugin>`__
 openstack/openstacksdk                   `https://opendev.org/openstack/openstacksdk <https://opendev.org/openstack/openstacksdk>`__
 openstack/os-loganalyze                  `https://opendev.org/openstack/os-loganalyze <https://opendev.org/openstack/os-loganalyze>`__
 openstack/osprofiler                     `https://opendev.org/openstack/osprofiler <https://opendev.org/openstack/osprofiler>`__
 openstack/oswin-tempest-plugin           `https://opendev.org/openstack/oswin-tempest-plugin <https://opendev.org/openstack/oswin-tempest-plugin>`__
+openstack/ovn-octavia-provider           `https://opendev.org/openstack/ovn-octavia-provider <https://opendev.org/openstack/ovn-octavia-provider>`__
 openstack/panko                          `https://opendev.org/openstack/panko <https://opendev.org/openstack/panko>`__
 openstack/patrole                        `https://opendev.org/openstack/patrole <https://opendev.org/openstack/patrole>`__
 openstack/qinling                        `https://opendev.org/openstack/qinling <https://opendev.org/openstack/qinling>`__
@@ -143,7 +148,6 @@
 x/devstack-plugin-hdfs                   `https://opendev.org/x/devstack-plugin-hdfs <https://opendev.org/x/devstack-plugin-hdfs>`__
 x/devstack-plugin-libvirt-qemu           `https://opendev.org/x/devstack-plugin-libvirt-qemu <https://opendev.org/x/devstack-plugin-libvirt-qemu>`__
 x/devstack-plugin-mariadb                `https://opendev.org/x/devstack-plugin-mariadb <https://opendev.org/x/devstack-plugin-mariadb>`__
-x/devstack-plugin-nfs                    `https://opendev.org/x/devstack-plugin-nfs <https://opendev.org/x/devstack-plugin-nfs>`__
 x/devstack-plugin-vmax                   `https://opendev.org/x/devstack-plugin-vmax <https://opendev.org/x/devstack-plugin-vmax>`__
 x/drbd-devstack                          `https://opendev.org/x/drbd-devstack <https://opendev.org/x/drbd-devstack>`__
 x/fenix                                  `https://opendev.org/x/fenix <https://opendev.org/x/fenix>`__
diff --git a/doc/source/systemd.rst b/doc/source/systemd.rst
index 15b3f75..4f83b36 100644
--- a/doc/source/systemd.rst
+++ b/doc/source/systemd.rst
@@ -208,7 +208,8 @@
   the one you want.
 - ``systemd`` - a python 3 only library, not what you want.
 - ``python-systemd`` - another library you don't want. Installing it
-  on a system will break ansible's ability to run.
+  on a system will break ansible's ability to run. The package has now
+  been renamed to ``cysystemd``, which avoids the namespace collision.
 
 
 If we were using user units, the ``[Service]`` - ``Group=`` parameter
diff --git a/doc/source/zuul_ci_jobs_migration.rst b/doc/source/zuul_ci_jobs_migration.rst
index 17e7e16..c43603e 100644
--- a/doc/source/zuul_ci_jobs_migration.rst
+++ b/doc/source/zuul_ci_jobs_migration.rst
@@ -195,12 +195,6 @@
      - A bridge called br-infra is set up for all jobs that inherit
        from multinode with a dedicated `bridge role
        <https://zuul-ci.org/docs/zuul-jobs/general-roles.html#role-multi-node-bridge>`_.
-   * - DEVSTACK_GATE_FEATURE_MATRIX
-     - devstack-gate
-     - ``test_matrix_features`` variable of the test-matrix role in
-       devstack-gate. This is a temporary solution, feature matrix
-       will go away. In the future services will be defined in jobs
-       only.
    * - DEVSTACK_CINDER_VOLUME_CLEAR
      - devstack
      - *CINDER_VOLUME_CLEAR: true/false* in devstack_localrc in the
diff --git a/files/debs/general b/files/debs/general
index df872a0..fe00613 100644
--- a/files/debs/general
+++ b/files/debs/general
@@ -27,9 +27,8 @@
 openssl
 pkg-config
 psmisc
-python2.7
-python-dev
-python-gdbm # needed for testr
+python3-dev
+python3-venv
 tar
 tcpdump
 unzip
diff --git a/files/debs/keystone b/files/debs/keystone
index fd0317b..1cfa6ff 100644
--- a/files/debs/keystone
+++ b/files/debs/keystone
@@ -2,5 +2,5 @@
 libldap2-dev
 libsasl2-dev
 memcached
-python-mysqldb
+python3-mysqldb
 sqlite3
diff --git a/files/debs/ldap b/files/debs/ldap
index aa3a934..54896bb 100644
--- a/files/debs/ldap
+++ b/files/debs/ldap
@@ -1,3 +1,3 @@
 ldap-utils
-python-ldap
+python3-ldap
 slapd
diff --git a/files/debs/n-cpu b/files/debs/n-cpu
index 636644f..54d6fa3 100644
--- a/files/debs/n-cpu
+++ b/files/debs/n-cpu
@@ -5,7 +5,7 @@
 lvm2 # NOPRIME
 netcat-openbsd
 open-iscsi
-python-guestfs # NOPRIME
+python3-guestfs # NOPRIME
 qemu-utils
 sg3-utils
 sysfsutils
diff --git a/files/debs/neutron-common b/files/debs/neutron-common
index b269f63..e548396 100644
--- a/files/debs/neutron-common
+++ b/files/debs/neutron-common
@@ -9,7 +9,7 @@
 libmysqlclient-dev
 mysql-server #NOPRIME
 postgresql-server-dev-all
-python-mysqldb
+python3-mysqldb
 rabbitmq-server # NOPRIME
 radvd # NOPRIME
 sqlite3
diff --git a/files/debs/nova b/files/debs/nova
index e5110e9..dce8f6a 100644
--- a/files/debs/nova
+++ b/files/debs/nova
@@ -16,7 +16,7 @@
 mysql-server # NOPRIME
 parted
 pm-utils
-python-mysqldb
+python3-mysqldb
 qemu # dist:wheezy,jessie NOPRIME
 qemu-kvm # NOPRIME
 rabbitmq-server # NOPRIME
diff --git a/files/rpms/cinder b/files/rpms/cinder
index e1e1f6c..a8201ea 100644
--- a/files/rpms/cinder
+++ b/files/rpms/cinder
@@ -1,5 +1,5 @@
 iscsi-initiator-utils
 lvm2
 qemu-img
-scsi-target-utils # not:rhel7,f30 NOPRIME
-targetcli # dist:rhel7,f30 NOPRIME
+scsi-target-utils # not:rhel7,f30,f31 NOPRIME
+targetcli # dist:rhel7,f30,f31 NOPRIME
diff --git a/files/rpms/dstat b/files/rpms/dstat
index e63af31..a091cce 100644
--- a/files/rpms/dstat
+++ b/files/rpms/dstat
@@ -1,2 +1,2 @@
-dstat # not:f30
-pcp-system-tools # dist:f30
+dstat # not:f30,f31
+pcp-system-tools # dist:f30,f31
diff --git a/files/rpms/general b/files/rpms/general
index e3d20b3..361416a 100644
--- a/files/rpms/general
+++ b/files/rpms/general
@@ -9,9 +9,9 @@
 graphviz # needed only for docs
 httpd
 httpd-devel
-iptables-services  # NOPRIME f30
+iptables-services  # NOPRIME f30,f31
 java-1.7.0-openjdk-headless  # NOPRIME rhel7
-java-1.8.0-openjdk-headless  # NOPRIME f30
+java-1.8.0-openjdk-headless  # NOPRIME f30,f31
 libffi-devel
 libjpeg-turbo-devel # Pillow 3.0.0
 libxml2-devel # lxml
@@ -27,7 +27,8 @@
 postgresql-devel  # psycopg2
 psmisc
 pyOpenSSL # version in pip uses too much memory
-python3-devel # f30
+python3-devel # dist:f30,f31
+python3-virtualenv # dist:f31
 python-devel
 redhat-rpm-config # missing dep for gcc hardening flags, see rhbz#1217376
 systemd-devel # for systemd-python
diff --git a/files/rpms/nova b/files/rpms/nova
index c590378..0f3d10f 100644
--- a/files/rpms/nova
+++ b/files/rpms/nova
@@ -7,7 +7,7 @@
 genisoimage # required for config_drive
 iptables
 iputils
-kernel-modules # dist:f30
+kernel-modules # dist:f30,f31
 kpartx
 libxml2-python
 m2crypto
diff --git a/files/rpms/swift b/files/rpms/swift
index eb94d14..745cc2e 100644
--- a/files/rpms/swift
+++ b/files/rpms/swift
@@ -2,7 +2,7 @@
 liberasurecode-devel
 memcached
 pyxattr
-rsync-daemon # dist:f30
+rsync-daemon # dist:f30,f31
 sqlite
 xfsprogs
 xinetd
diff --git a/inc/python b/inc/python
index 52ad565..dd77296 100644
--- a/inc/python
+++ b/inc/python
@@ -21,6 +21,14 @@
 # project.  A null value installs to the system Python directories.
 declare -A -g PROJECT_VENV
 
+# Utility Functions
+# =================
+
+# Joins bash array of extras with commas as expected by other functions
+function join_extras {
+    local IFS=","
+    echo "$*"
+}
 
 # Python Functions
 # ================
@@ -80,9 +88,9 @@
 function pip_install_gr_extras {
     local name=$1
     local extras=$2
-    local clean_name
-    clean_name=$(get_from_global_requirements $name)
-    pip_install $clean_name[$extras]
+    local version_constraints
+    version_constraints=$(get_version_constraints_from_global_requirements $name)
+    pip_install $name[$extras]$version_constraints
 }
 
 # enable_python3_package() -- no-op for backwards compatibility
@@ -179,13 +187,6 @@
 
     $xtrace
 
-    # Also install test requirements
-    local install_test_reqs=""
-    local test_req="${package_dir}/test-requirements.txt"
-    if [[ -e "$test_req" ]]; then
-        install_test_reqs="-r $test_req"
-    fi
-
     # adding SETUPTOOLS_SYS_PATH_TECHNIQUE is a workaround to keep
     # the same behaviour of setuptools before version 25.0.0.
     # related issue: https://github.com/pypa/pip/issues/3874
@@ -195,7 +196,7 @@
         no_proxy="${no_proxy:-}" \
         PIP_FIND_LINKS=$PIP_FIND_LINKS \
         SETUPTOOLS_SYS_PATH_TECHNIQUE=rewrite \
-        $cmd_pip $upgrade $install_test_reqs \
+        $cmd_pip $upgrade \
         $@
     result=$?
 
@@ -237,6 +238,19 @@
     echo $required_pkg
 }
 
+# get only version constraints of a package from global requirements file
+# get_version_constraints_from_global_requirements <package>
+function get_version_constraints_from_global_requirements {
+    local package=$1
+    local required_pkg_version_constraint
+    # drop the package name from output (\K)
+    required_pkg_version_constraint=$(grep -i -h -o -P "^${package}\K.*" $REQUIREMENTS_DIR/global-requirements.txt | cut -d\# -f1)
+    if [[ $required_pkg_version_constraint == ""  ]]; then
+        die $LINENO "Can't find package $package in requirements"
+    fi
+    echo $required_pkg_version_constraint
+}
+
 # should we use this library from their git repo, or should we let it
 # get pulled in via pip dependencies.
 function use_library_from_git {
@@ -285,7 +299,7 @@
 #
 # use this for non namespaced libraries
 #
-# setup_dev_lib [-bindep] <name>
+# setup_dev_lib [-bindep] <name> [<extras>]
 function setup_dev_lib {
     local bindep
     if [[ $1 == -bindep* ]]; then
@@ -294,7 +308,8 @@
     fi
     local name=$1
     local dir=${GITDIR[$name]}
-    setup_develop $bindep $dir
+    local extras=$2
+    setup_develop $bindep $dir $extras
 }
 
 # this should be used if you want to install globally, all libraries should
diff --git a/lib/databases/mysql b/lib/databases/mysql
index 420a86e..e5865f2 100644
--- a/lib/databases/mysql
+++ b/lib/databases/mysql
@@ -109,8 +109,10 @@
         sudo mysql $cmd_args -e "UPDATE mysql.user SET plugin='' WHERE user='$DATABASE_USER' AND host='localhost';"
         sudo mysql $cmd_args -e "FLUSH PRIVILEGES;"
     fi
+    # Create DB user if it does not already exist
+    sudo mysql $cmd_args -e "CREATE USER IF NOT EXISTS '$DATABASE_USER'@'%' identified by '$DATABASE_PASSWORD';"
     # Update the DB to give user '$DATABASE_USER'@'%' full control of the all databases:
-    sudo mysql $cmd_args -e "GRANT ALL PRIVILEGES ON *.* TO '$DATABASE_USER'@'%' identified by '$DATABASE_PASSWORD';"
+    sudo mysql $cmd_args -e "GRANT ALL PRIVILEGES ON *.* TO '$DATABASE_USER'@'%';"
 
     # Now update ``my.cnf`` for some local needs and restart the mysql service
 
@@ -120,8 +122,6 @@
     iniset -sudo $my_conf mysqld sql_mode TRADITIONAL
     iniset -sudo $my_conf mysqld default-storage-engine InnoDB
     iniset -sudo $my_conf mysqld max_connections 1024
-    iniset -sudo $my_conf mysqld query_cache_type OFF
-    iniset -sudo $my_conf mysqld query_cache_size 0
 
     if [[ "$DATABASE_QUERY_LOGGING" == "True" ]]; then
         echo_summary "Enabling MySQL query logging"
diff --git a/lib/glance b/lib/glance
index 740bcab..9398bd2 100644
--- a/lib/glance
+++ b/lib/glance
@@ -41,9 +41,29 @@
     GLANCE_BIN_DIR=$(get_python_exec_prefix)
 fi
 
+# Glance multi-store configuration
+# Boolean flag to enable multiple store configuration for glance
+GLANCE_ENABLE_MULTIPLE_STORES=$(trueorfalse False GLANCE_ENABLE_MULTIPLE_STORES)
+
+# Comma separated list for configuring multiple file stores of glance,
+# for example; GLANCE_MULTIPLE_FILE_STORES = fast,cheap,slow
+GLANCE_MULTIPLE_FILE_STORES=${GLANCE_MULTIPLE_FILE_STORES:-fast}
+
+# Default store/backend for glance, must be one of the store specified
+# in GLANCE_MULTIPLE_FILE_STORES option.
+GLANCE_DEFAULT_BACKEND=${GLANCE_DEFAULT_BACKEND:-fast}
+
 GLANCE_CACHE_DIR=${GLANCE_CACHE_DIR:=$DATA_DIR/glance/cache}
+
+# File path for each store specified in GLANCE_MULTIPLE_FILE_STORES, the store
+# identifier will be appended to this path at runtime. If GLANCE_MULTIPLE_FILE_STORES
+# has fast,cheap specified then filepath will be generated like $DATA_DIR/glance/fast
+# and $DATA_DIR/glance/cheap.
+GLANCE_MULTISTORE_FILE_IMAGE_DIR=${GLANCE_MULTISTORE_FILE_IMAGE_DIR:=$DATA_DIR/glance}
 GLANCE_IMAGE_DIR=${GLANCE_IMAGE_DIR:=$DATA_DIR/glance/images}
 GLANCE_LOCK_DIR=${GLANCE_LOCK_DIR:=$DATA_DIR/glance/locks}
+GLANCE_STAGING_DIR=${GLANCE_MULTISTORE_FILE_IMAGE_DIR:=$DATA_DIR/os_glance_staging_store}
+GLANCE_TASKS_DIR=${GLANCE_MULTISTORE_FILE_IMAGE_DIR:=$DATA_DIR/os_glance_tasks_store}
 
 GLANCE_CONF_DIR=${GLANCE_CONF_DIR:-/etc/glance}
 GLANCE_METADEF_DIR=$GLANCE_CONF_DIR/metadefs
@@ -97,6 +117,18 @@
 function cleanup_glance {
     # delete image files (glance)
     sudo rm -rf $GLANCE_CACHE_DIR $GLANCE_IMAGE_DIR
+
+    # Cleanup multiple stores directories
+    if [[ "$GLANCE_ENABLE_MULTIPLE_STORES" == "True" ]]; then
+        local store file_dir
+        for store in $(echo $GLANCE_MULTIPLE_FILE_STORES | tr "," "\n"); do
+            file_dir="${GLANCE_MULTISTORE_FILE_IMAGE_DIR}/${store}/"
+            sudo rm -rf $file_dir
+        done
+
+        # Cleanup reserved stores directories
+        sudo rm -rf $GLANCE_STAGING_DIR $GLANCE_TASKS_DIR
+    fi
 }
 
 # configure_glance() - Set config files, create data dirs, etc
@@ -117,6 +149,16 @@
     iniset_rpc_backend glance $GLANCE_REGISTRY_CONF
     iniset $GLANCE_REGISTRY_CONF DEFAULT graceful_shutdown_timeout "$SERVICE_GRACEFUL_SHUTDOWN_TIMEOUT"
 
+    # Configure multiple stores
+    if [[ "$GLANCE_ENABLE_MULTIPLE_STORES" == "True" ]]; then
+        local store enabled_backends
+        enabled_backends=""
+        for store in $(echo $GLANCE_MULTIPLE_FILE_STORES | tr "," "\n"); do
+            enabled_backends+="${store}:file,"
+        done
+        iniset $GLANCE_API_CONF DEFAULT enabled_backends ${enabled_backends::-1}
+    fi
+
     # Set non-default configuration options for the API server
     iniset $GLANCE_API_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL
     iniset $GLANCE_API_CONF database connection $dburl
@@ -141,8 +183,21 @@
         iniset $GLANCE_API_CONF DEFAULT enable_v1_api False
     fi
 
-    # Store specific configs
-    iniset $GLANCE_API_CONF glance_store filesystem_store_datadir $GLANCE_IMAGE_DIR/
+    # Glance multiple store Store specific configs
+    if [[ "$GLANCE_ENABLE_MULTIPLE_STORES" == "True" ]]; then
+        iniset $GLANCE_API_CONF glance_store default_backend $GLANCE_DEFAULT_BACKEND
+        local store
+        for store in $(echo $GLANCE_MULTIPLE_FILE_STORES | tr "," "\n"); do
+            iniset $GLANCE_API_CONF $store filesystem_store_datadir "${GLANCE_MULTISTORE_FILE_IMAGE_DIR}/${store}/"
+        done
+
+        # Glance configure reserved stores
+        iniset $GLANCE_API_CONF os_glance_staging_store filesystem_store_datadir "${GLANCE_MULTISTORE_FILE_IMAGE_DIR}/os_glance_staging_store/"
+        iniset $GLANCE_API_CONF os_glance_tasks_store filesystem_store_datadir "${GLANCE_MULTISTORE_FILE_IMAGE_DIR}/os_glance_tasks_store/"
+    else
+        # Store specific configs
+        iniset $GLANCE_API_CONF glance_store filesystem_store_datadir $GLANCE_IMAGE_DIR/
+    fi
     iniset $GLANCE_API_CONF DEFAULT registry_host $(ipv6_unquote $GLANCE_SERVICE_HOST)
 
     # CORS feature support - to allow calls from Horizon by default
@@ -152,6 +207,7 @@
         iniset $GLANCE_API_CONF cors allowed_origin "http://$SERVICE_HOST"
     fi
 
+    # No multiple stores for swift yet
     # Store the images in swift if enabled.
     if is_service_enabled s-proxy; then
         iniset $GLANCE_API_CONF glance_store default_store swift
@@ -299,11 +355,24 @@
 
 # install_glance() - Collect source and prepare
 function install_glance {
+    local glance_store_extras=()
+
+    if is_service_enabled cinder; then
+        glance_store_extras=("cinder" "${glance_store_extras[@]}")
+    fi
+
+    if is_service_enabled swift; then
+        glance_store_extras=("swift" "${glance_store_extras[@]}")
+    fi
+
     # Install glance_store from git so we make sure we're testing
     # the latest code.
     if use_library_from_git "glance_store"; then
         git_clone_by_name "glance_store"
-        setup_dev_lib "glance_store"
+        setup_dev_lib "glance_store" $(join_extras "${glance_store_extras[@]}")
+    else
+        # we still need to pass extras
+        pip_install_gr_extras glance-store $(join_extras "${glance_store_extras[@]}")
     fi
 
     git_clone $GLANCE_REPO $GLANCE_DIR $GLANCE_BRANCH
diff --git a/lib/keystone b/lib/keystone
index 9ceb829..366e6c7 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -421,7 +421,7 @@
     iniset $conf_file $section project_domain_name "$SERVICE_DOMAIN_NAME"
 
     iniset $conf_file $section cafile $SSL_BUNDLE_FILE
-    iniset $conf_file $section memcached_servers localhost:11211
+    iniset $conf_file $section memcached_servers $MEMCACHE_SERVERS
 }
 
 # configure_auth_token_middleware conf_file admin_user IGNORED [section]
diff --git a/lib/lvm b/lib/lvm
index d9e78a0..92265f2 100644
--- a/lib/lvm
+++ b/lib/lvm
@@ -124,13 +124,15 @@
     local vg=$1
     local size=$2
 
-    # Start the lvmetad and tgtd services
-    if is_fedora || is_suse; then
+    # Start the lvmetad on f30 (dropped from f31) or SUSE
+    if [[ $DISTRO =~ f30 ]] || is_suse; then
         # services is not started by default
         start_service lvm2-lvmetad
-        if [ "$CINDER_ISCSI_HELPER" = "tgtadm" ]; then
-            start_service tgtd
-        fi
+    fi
+
+    # Start the tgtd service on Fedora and SUSE if tgtadm is used
+    if  is_fedora || is_suse  && [[ "$CINDER_ISCSI_HELPER" = "tgtadm" ]]; then
+        start_service tgtd
     fi
 
     # Start with a clean volume group
diff --git a/lib/nova_plugins/hypervisor-libvirt b/lib/nova_plugins/hypervisor-libvirt
index d1b3d78..b0ae29e 100644
--- a/lib/nova_plugins/hypervisor-libvirt
+++ b/lib/nova_plugins/hypervisor-libvirt
@@ -117,7 +117,7 @@
             # Workaround for missing dependencies in python-libguestfs
             install_package python-libguestfs guestfs-data augeas augeas-lenses
         elif is_fedora; then
-            install_package python-libguestfs
+            install_package python3-libguestfs
         fi
     fi
 }
diff --git a/playbooks/pre.yaml b/playbooks/pre.yaml
index 60f365a..ff97a1f 100644
--- a/playbooks/pre.yaml
+++ b/playbooks/pre.yaml
@@ -26,7 +26,6 @@
       set_fact:
         external_bridge_mtu: "{{ local_mtu | int - 50 }}"
   roles:
-    - test-matrix
     - configure-swap
     - setup-stack-user
     - setup-tempest-user
diff --git a/stack.sh b/stack.sh
index 9879bd4..0f1ddb1 100755
--- a/stack.sh
+++ b/stack.sh
@@ -221,7 +221,7 @@
 
 # Warn users who aren't on an explicitly supported distro, but allow them to
 # override check and attempt installation with ``FORCE=yes ./stack``
-if [[ ! ${DISTRO} =~ (bionic|stretch|jessie|f30|opensuse-15.0|opensuse-15.1|opensuse-tumbleweed|rhel7) ]]; then
+if [[ ! ${DISTRO} =~ (bionic|stretch|jessie|f30|f31|opensuse-15.0|opensuse-15.1|opensuse-tumbleweed) ]]; then
     echo "WARNING: this script has not been tested on $DISTRO"
     if [[ "$FORCE" != "yes" ]]; then
         die $LINENO "If you wish to run this script anyway run with FORCE=yes"
diff --git a/stackrc b/stackrc
index 4e33b68..17641c3 100644
--- a/stackrc
+++ b/stackrc
@@ -150,7 +150,8 @@
 
 # Create a virtualenv with this
 if [[ ${USE_PYTHON3} == True ]]; then
-    export VIRTUALENV_CMD="virtualenv -p python3"
+    # Use the built-in venv to avoid more dependencies
+    export VIRTUALENV_CMD="python3 -m venv"
 else
     export VIRTUALENV_CMD="virtualenv "
 fi
diff --git a/tools/fixup_stuff.sh b/tools/fixup_stuff.sh
index 15b3ab7..e140929 100755
--- a/tools/fixup_stuff.sh
+++ b/tools/fixup_stuff.sh
@@ -200,35 +200,11 @@
     # have been dragged in by some other system dependency
     sudo rm -rf /usr/lib/python3.6/site-packages/ply-*.egg-info
     sudo rm -rf /usr/lib/python3.6/site-packages/six-*.egg-info
-}
 
-# The version of pip(1.5.4) supported by python-virtualenv(1.11.4) has
-# connection issues under proxy so re-install the latest version using
-# pip. To avoid having pip's virtualenv overwritten by the distro's
-# package (e.g. due to installing a distro package with a dependency
-# on python-virtualenv), first install the distro python-virtualenv
-# to satisfy any dependencies then use pip to overwrite it.
-
-# ... but, for infra builds, the pip-and-virtualenv [1] element has
-# already done this to ensure the latest pip, virtualenv and
-# setuptools on the base image for all platforms.  It has also added
-# the packages to the yum/dnf ignore list to prevent them being
-# overwritten with old versions.  F26 and dnf 2.0 has changed
-# behaviour that means re-installing python-virtualenv fails [2].
-# Thus we do a quick check if we're in the infra environment by
-# looking for the mirror config script before doing this, and just
-# skip it if so.
-
-# [1] https://opendev.org/openstack/diskimage-builder/src/branch/master/ \
-#        diskimage_builder/elements/pip-and-virtualenv/ \
-#            install.d/pip-and-virtualenv-source-install/04-install-pip
-# [2] https://bugzilla.redhat.com/show_bug.cgi?id=1477823
-
-function fixup_virtualenv {
-    if [[ ! -f /etc/ci/mirror_info.sh ]]; then
-        install_package python-virtualenv
-        pip_install -U --force-reinstall virtualenv
-    fi
+    # Ensure trusted CA certificates are up to date
+    # See https://bugzilla.suse.com/show_bug.cgi?id=1154871
+    # May be removed once a new opensuse-15 image is available in nodepool
+    sudo zypper up -y p11-kit ca-certificates-mozilla
 }
 
 function fixup_all {
@@ -236,5 +212,4 @@
     fixup_ubuntu
     fixup_fedora
     fixup_suse
-    fixup_virtualenv
 }