Merge "nova: Fix comments for _config_nova_apache_wsgi"
diff --git a/files/rpms/nova b/files/rpms/nova
index 45f1c94..a368c55 100644
--- a/files/rpms/nova
+++ b/files/rpms/nova
@@ -9,10 +9,6 @@
 iputils
 kernel-modules # dist:f23,f24,f25
 kpartx
-kvm # NOPRIME
-libvirt-bin # NOPRIME
-libvirt-devel # NOPRIME
-libvirt-python # NOPRIME
 libxml2-python
 m2crypto
 mysql-devel
@@ -21,7 +17,6 @@
 numpy # needed by websockify for spice console
 parted
 polkit
-qemu-kvm # NOPRIME
 rabbitmq-server # NOPRIME
 sqlite
 sudo
diff --git a/inc/python b/inc/python
index 5afc07f..2bdc097 100644
--- a/inc/python
+++ b/inc/python
@@ -111,6 +111,111 @@
     echo $classifier
 }
 
+# python3_enabled_for() checks if the service(s) specified as arguments are
+# enabled by the user in ``ENABLED_PYTHON3_PACKAGES``.
+#
+# Multiple services specified as arguments are ``OR``'ed together; the test
+# is a short-circuit boolean, i.e it returns on the first match.
+#
+# Uses global ``ENABLED_PYTHON3_PACKAGES``
+# python3_enabled_for dir [dir ...]
+function python3_enabled_for {
+    local xtrace
+    xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+
+    local enabled=1
+    local dirs=$@
+    local dir
+    for dir in ${dirs}; do
+        [[ ,${ENABLED_PYTHON3_PACKAGES}, =~ ,${dir}, ]] && enabled=0
+    done
+
+    $xtrace
+    return $enabled
+}
+
+# python3_disabled_for() checks if the service(s) specified as arguments are
+# disabled by the user in ``DISABLED_PYTHON3_PACKAGES``.
+#
+# Multiple services specified as arguments are ``OR``'ed together; the test
+# is a short-circuit boolean, i.e it returns on the first match.
+#
+# Uses global ``DISABLED_PYTHON3_PACKAGES``
+# python3_disabled_for dir [dir ...]
+function python3_disabled_for {
+    local xtrace
+    xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+
+    local enabled=1
+    local dirs=$@
+    local dir
+    for dir in ${dirs}; do
+        [[ ,${DISABLED_PYTHON3_PACKAGES}, =~ ,${dir}, ]] && enabled=0
+    done
+
+    $xtrace
+    return $enabled
+}
+
+# enable_python3_package() adds the repositories passed as argument to the
+# ``ENABLED_PYTHON3_PACKAGES`` list, if they are not already present.
+#
+# For example:
+#   enable_python3_package nova
+#
+# Uses global ``ENABLED_PYTHON3_PACKAGES``
+# enable_python3_package dir [dir ...]
+function enable_python3_package {
+    local xtrace
+    xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+
+    local tmpsvcs="${ENABLED_PYTHON3_PACKAGES}"
+    local python3
+    for dir in $@; do
+        if [[ ,${DISABLED_PYTHON3_PACKAGES}, =~ ,${dir}, ]]; then
+            warn $LINENO "Attempt to enable_python3_package ${dir} when it has been disabled"
+            continue
+        fi
+        if ! python3_enabled_for $dir; then
+            tmpsvcs+=",$dir"
+        fi
+    done
+    ENABLED_PYTHON3_PACKAGES=$(_cleanup_service_list "$tmpsvcs")
+
+    $xtrace
+}
+
+# disable_python3_package() prepares the services passed as argument to be
+# removed from the ``ENABLED_PYTHON3_PACKAGES`` list, if they are present.
+#
+# For example:
+#   disable_python3_package swift
+#
+# Uses globals ``ENABLED_PYTHON3_PACKAGES`` and ``DISABLED_PYTHON3_PACKAGES``
+# disable_python3_package dir [dir ...]
+function disable_python3_package {
+    local xtrace
+    xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+
+    local disabled_svcs="${DISABLED_PYTHON3_PACKAGES}"
+    local enabled_svcs=",${ENABLED_PYTHON3_PACKAGES},"
+    local dir
+    for dir in $@; do
+        disabled_svcs+=",$dir"
+        if python3_enabled_for $dir; then
+            enabled_svcs=${enabled_svcs//,$dir,/,}
+        fi
+    done
+    DISABLED_PYTHON3_PACKAGES=$(_cleanup_service_list "$disabled_svcs")
+    ENABLED_PYTHON3_PACKAGES=$(_cleanup_service_list "$enabled_svcs")
+
+    $xtrace
+}
+
 # Wrapper for ``pip install`` to set cache and proxy environment variables
 # Uses globals ``OFFLINE``, ``PIP_VIRTUAL_ENV``,
 # ``PIP_UPGRADE``, ``TRACK_DEPENDS``, ``*_proxy``,
@@ -163,16 +268,16 @@
                 # support for python3 in progress, but don't claim support
                 # in their classifier
                 echo "Check python version for : $package_dir"
-                if [[ ${package_dir##*/} == "nova" || ${package_dir##*/} == "glance" || \
-                        ${package_dir##*/} == "cinder" || ${package_dir##*/} == "swift" || \
-                        ${package_dir##*/} == "uwsgi" ]]; then
-                    echo "Using $PYTHON3_VERSION version to install $package_dir"
+                if python3_disabled_for ${package_dir##*/}; then
+                    echo "Explicitly using $PYTHON2_VERSION version to install $package_dir based on DISABLED_PYTHON3_PACKAGES"
+                elif python3_enabled_for ${package_dir##*/}; then
+                    echo "Explicitly using $PYTHON3_VERSION version to install $package_dir based on ENABLED_PYTHON3_PACKAGES"
                     sudo_pip="$sudo_pip LC_ALL=en_US.UTF-8"
                     cmd_pip=$(get_pip_command $PYTHON3_VERSION)
                 elif [[ -d "$package_dir" ]]; then
                     python_versions=$(get_python_versions_for_package $package_dir)
                     if [[ $python_versions =~ $PYTHON3_VERSION ]]; then
-                        echo "Using $PYTHON3_VERSION version to install $package_dir"
+                        echo "Automatically using $PYTHON3_VERSION version to install $package_dir based on classifiers"
                         sudo_pip="$sudo_pip LC_ALL=en_US.UTF-8"
                         cmd_pip=$(get_pip_command $PYTHON3_VERSION)
                     else
@@ -181,7 +286,7 @@
                         # a warning.
                         python3_classifier=$(check_python3_support_for_package_local $package_dir)
                         if [[ ! -z "$python3_classifier" ]]; then
-                            echo "Using $PYTHON3_VERSION version to install $package_dir"
+                            echo "Automatically using $PYTHON3_VERSION version to install $package_dir based on local package settings"
                             sudo_pip="$sudo_pip LC_ALL=en_US.UTF-8"
                             cmd_pip=$(get_pip_command $PYTHON3_VERSION)
                         fi
@@ -191,7 +296,7 @@
                     package=$(echo $package_dir | grep -o '^[.a-zA-Z0-9_-]*')
                     python3_classifier=$(check_python3_support_for_package_remote $package)
                     if [[ ! -z "$python3_classifier" ]]; then
-                        echo "Using $PYTHON3_VERSION version to install $package"
+                        echo "Automatically using $PYTHON3_VERSION version to install $package based on remote package settings"
                         sudo_pip="$sudo_pip LC_ALL=en_US.UTF-8"
                         cmd_pip=$(get_pip_command $PYTHON3_VERSION)
                     fi
@@ -308,6 +413,16 @@
 function setup_dev_lib {
     local name=$1
     local dir=${GITDIR[$name]}
+    if python3_enabled; then
+        # Turn off Python 3 mode and install the package again,
+        # forcing a Python 2 installation. This ensures that all libs
+        # being used for development are installed under both versions
+        # of Python.
+        echo "Installing $name again without Python 3 enabled"
+        USE_PYTHON3=False
+        setup_develop $dir
+        USE_PYTHON3=True
+    fi
     setup_develop $dir
 }
 
diff --git a/lib/cinder_backends/fake b/lib/cinder_backends/fake
new file mode 100644
index 0000000..4749ace
--- /dev/null
+++ b/lib/cinder_backends/fake
@@ -0,0 +1,47 @@
+#!/bin/bash
+#
+# lib/cinder_backends/fake
+# Configure the Fake backend
+
+# Enable with:
+#
+#   CINDER_ENABLED_BACKENDS+=,fake:fake
+
+# Dependencies:
+#
+# - ``functions`` file
+# - ``cinder`` configurations
+
+# CINDER_CONF
+
+# clean_cinder_backend_fake - called from clean_cinder()
+# configure_cinder_backend_fake - called from configure_cinder()
+# init_cinder_backend_fake - called from init_cinder()
+
+
+# Save trace setting
+_XTRACE_CINDER_FAKE=$(set +o | grep xtrace)
+set +o xtrace
+
+
+function cleanup_cinder_backend_fake {
+    local be_name=$1
+}
+
+function configure_cinder_backend_fake {
+    local be_name=$1
+
+    iniset $CINDER_CONF $be_name volume_backend_name $be_name
+    iniset $CINDER_CONF $be_name volume_driver "cinder.tests.fake_driver.FakeLoggingVolumeDriver"
+
+}
+
+function init_cinder_backend_fake {
+    local be_name=$1
+}
+
+# Restore xtrace
+$_XTRACE_CINDER_FAKE
+
+# mode: shell-script
+# End:
diff --git a/lib/cinder_backends/fake_gate b/lib/cinder_backends/fake_gate
new file mode 100644
index 0000000..6b1f848
--- /dev/null
+++ b/lib/cinder_backends/fake_gate
@@ -0,0 +1,74 @@
+#!/bin/bash
+#
+# lib/cinder_backends/lvm
+# Configure the LVM backend
+
+# Enable with:
+#
+#   CINDER_ENABLED_BACKENDS+=,fake_gate:lvmname
+
+# Dependencies:
+#
+# - ``functions`` file
+# - ``cinder`` configurations
+
+# CINDER_CONF
+# DATA_DIR
+# VOLUME_GROUP_NAME
+
+# clean_cinder_backend_lvm - called from clean_cinder()
+# configure_cinder_backend_lvm - called from configure_cinder()
+# init_cinder_backend_lvm - called from init_cinder()
+
+
+# Save trace setting
+_XTRACE_CINDER_LVM=$(set +o | grep xtrace)
+set +o xtrace
+
+
+# TODO: resurrect backing device...need to know how to set values
+#VOLUME_BACKING_DEVICE=${VOLUME_BACKING_DEVICE:-}
+
+# Entry Points
+# ------------
+
+# cleanup_cinder_backend_lvm - Delete volume group and remove backing file
+# cleanup_cinder_backend_lvm $be_name
+function cleanup_cinder_backend_lvm {
+    local be_name=$1
+
+    # Campsite rule: leave behind a volume group at least as clean as we found it
+    clean_lvm_volume_group $VOLUME_GROUP_NAME-$be_name
+    clean_lvm_filter
+}
+
+# configure_cinder_backend_lvm - Set config files, create data dirs, etc
+# configure_cinder_backend_lvm $be_name
+function configure_cinder_backend_lvm {
+    local be_name=$1
+
+    iniset $CINDER_CONF $be_name volume_backend_name $be_name
+    iniset $CINDER_CONF $be_name volume_driver "cinder.tests.fake_driver.FakeGateDriver"
+    iniset $CINDER_CONF $be_name volume_group $VOLUME_GROUP_NAME-$be_name
+    iniset $CINDER_CONF $be_name iscsi_helper "$CINDER_ISCSI_HELPER"
+    iniset $CINDER_CONF $be_name lvm_type "$CINDER_LVM_TYPE"
+
+    if [[ "$CINDER_VOLUME_CLEAR" == "non" ]]; then
+        iniset $CINDER_CONF $be_name volume_clear none
+    fi
+}
+
+# init_cinder_backend_lvm - Initialize volume group
+# init_cinder_backend_lvm $be_name
+function init_cinder_backend_lvm {
+    local be_name=$1
+
+    # Start with a clean volume group
+    init_lvm_volume_group $VOLUME_GROUP_NAME-$be_name $VOLUME_BACKING_FILE_SIZE
+}
+
+# Restore xtrace
+$_XTRACE_CINDER_LVM
+
+# mode: shell-script
+# End:
diff --git a/lib/neutron b/lib/neutron
index 19568ea..f277062 100644
--- a/lib/neutron
+++ b/lib/neutron
@@ -395,9 +395,9 @@
         service_protocol="http"
     fi
 
-    local opts = ""
-    opts+="--config-file $NEUTRON_CONF"
-    opts+="--config-file $NEUTRON_CORE_PLUGIN_CONF"
+    local opts=""
+    opts+=" --config-file $NEUTRON_CONF"
+    opts+=" --config-file $NEUTRON_CORE_PLUGIN_CONF"
     local cfg_file
     for cfg_file in ${_NEUTRON_SERVER_EXTRA_CONF_FILES_ABS[@]}; do
         opts+=" --config-file $cfg_file"
@@ -405,7 +405,7 @@
 
     # Start the Neutron service
     # TODO(sc68cal) Stop hard coding this
-    run_process neutron-api "$NEUTRON_BIN_DIR/neutron-server $ops"
+    run_process neutron-api "$NEUTRON_BIN_DIR/neutron-server $opts"
 
     if is_ssl_enabled_service "neutron"; then
         ssl_ca="--ca-certificate=${SSL_BUNDLE_FILE}"
@@ -510,7 +510,10 @@
     local plugins=""
 
     plugins=$(iniget $NEUTRON_CONF DEFAULT service_plugins)
-    plugins+=",${service_plugin_class}"
+    if [ $plugins ]; then
+        plugins+=","
+    fi
+    plugins+="${service_plugin_class}"
     iniset $NEUTRON_CONF DEFAULT service_plugins $plugins
 }
 
diff --git a/lib/nova_plugins/functions-libvirt b/lib/nova_plugins/functions-libvirt
index 47b054b..d225ef8 100644
--- a/lib/nova_plugins/functions-libvirt
+++ b/lib/nova_plugins/functions-libvirt
@@ -34,18 +34,23 @@
         #pip_install_gr <there-si-no-guestfs-in-pypi>
     elif is_fedora || is_suse; then
         # On "KVM for IBM z Systems", kvm does not have its own package
-        if [[ ! ${DISTRO} =~ "kvmibm1" ]]; then
+        if [[ ! ${DISTRO} =~ "kvmibm1" && ! ${DISTRO} =~ "rhel7" ]]; then
             install_package kvm
         fi
-        # there is a dependency issue with kvm (which is really just a
-        # wrapper to qemu-system-x86) that leaves some bios files out,
-        # so install qemu-kvm (which shouldn't strictly be needed, as
-        # everything has been merged into qemu-system-x86) to bring in
-        # the right packages. see
-        # https://bugzilla.redhat.com/show_bug.cgi?id=1235890
-        install_package qemu-kvm
+
+        if [[ ${DISTRO} =~ "rhel7" ]]; then
+            # On centos7 install the qemu-kvm-ev package, which is a
+            # later version of qemu-kvm rebuilt from the qemu-kvm-rhev
+            # package by the virt SIG (as required by nova).  This
+            # package is only provided for RHOS (openstack) or RHV
+            # (ovirt) in RHEL.  We have already insalled the RDO
+            # repositories which provide this.
+            install_package qemu-kvm-ev
+        fi
+
         install_package libvirt libvirt-devel
         pip_install_gr libvirt-python
+
     fi
 }
 
diff --git a/stackrc b/stackrc
index afe385c..95f017b 100644
--- a/stackrc
+++ b/stackrc
@@ -102,9 +102,19 @@
     source $RC_DIR/.localrc.password
 fi
 
-# Control whether Python 3 should be used.
+# Control whether Python 3 should be used at all.
 export USE_PYTHON3=$(trueorfalse False USE_PYTHON3)
 
+# Control whether Python 3 is enabled for specific services by the
+# base name of the directory from which they are installed. See
+# enable_python3_package to edit this variable and use_python3_for to
+# test membership.
+export ENABLED_PYTHON3_PACKAGES="nova,glance,cinder,uwsgi"
+
+# Explicitly list services not to run under Python 3. See
+# disable_python3_package to edit this variable.
+export DISABLED_PYTHON3_PACKAGES=""
+
 # When Python 3 is supported by an application, adding the specific
 # version of Python 3 to this variable will install the app using that
 # version of the interpreter instead of 2.7.
diff --git a/tests/test_python.sh b/tests/test_python.sh
new file mode 100755
index 0000000..8652798
--- /dev/null
+++ b/tests/test_python.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Tests for DevStack INI functions
+
+TOP=$(cd $(dirname "$0")/.. && pwd)
+
+source $TOP/functions-common
+source $TOP/inc/python
+
+source $TOP/tests/unittest.sh
+
+echo "Testing Python 3 functions"
+
+# Initialize variables manipulated by functions under test.
+export ENABLED_PYTHON3_PACKAGES=""
+export DISABLED_PYTHON3_PACKAGES=""
+
+assert_false "should not be enabled yet" python3_enabled_for testpackage1
+
+enable_python3_package testpackage1
+assert_equal "$ENABLED_PYTHON3_PACKAGES" "testpackage1"  "unexpected result"
+assert_true "should be enabled" python3_enabled_for testpackage1
+
+assert_false "should not be disabled yet" python3_disabled_for testpackage2
+
+disable_python3_package testpackage2
+assert_equal "$DISABLED_PYTHON3_PACKAGES" "testpackage2"  "unexpected result"
+assert_true "should be disabled" python3_disabled_for testpackage2
+
+report_results