Merge "enable -o errexit"
diff --git a/files/apts/n-cpu b/files/apts/n-cpu
index b287107..a82304d 100644
--- a/files/apts/n-cpu
+++ b/files/apts/n-cpu
@@ -5,4 +5,4 @@
 genisoimage
 sysfsutils
 sg3-utils
-python-guestfs
+python-guestfs # NOPRIME
diff --git a/files/rpms/n-cpu b/files/rpms/n-cpu
index e4fdaf4..32b1546 100644
--- a/files/rpms/n-cpu
+++ b/files/rpms/n-cpu
@@ -4,4 +4,4 @@
 genisoimage
 sysfsutils
 sg3_utils
-python-libguestfs
+python-libguestfs # NOPRIME
diff --git a/functions b/functions
index 6979c6c..3101111 100644
--- a/functions
+++ b/functions
@@ -44,60 +44,6 @@
 }
 
 
-# ``pip install -e`` the package, which processes the dependencies
-# using pip before running `setup.py develop`
-#
-# Updates the dependencies in project_dir from the
-# openstack/requirements global list before installing anything.
-#
-# Uses globals ``TRACK_DEPENDS``, ``REQUIREMENTS_DIR``, ``UNDO_REQUIREMENTS``
-# setup_develop directory
-function setup_develop() {
-    local project_dir=$1
-
-    echo "cd $REQUIREMENTS_DIR; $SUDO_CMD python update.py $project_dir"
-
-    # Don't update repo if local changes exist
-    # Don't use buggy "git diff --quiet"
-    (cd $project_dir && git diff --exit-code >/dev/null)
-    local update_requirements=$?
-
-    if [ $update_requirements -eq 0 ]; then
-        (cd $REQUIREMENTS_DIR; \
-            $SUDO_CMD python update.py $project_dir)
-    fi
-
-    setup_develop_no_requirements_update $project_dir
-
-    # We've just gone and possibly modified the user's source tree in an
-    # automated way, which is considered bad form if it's a development
-    # tree because we've screwed up their next git checkin. So undo it.
-    #
-    # However... there are some circumstances, like running in the gate
-    # where we really really want the overridden version to stick. So provide
-    # a variable that tells us whether or not we should UNDO the requirements
-    # changes (this will be set to False in the OpenStack ci gate)
-    if [ $UNDO_REQUIREMENTS = "True" ]; then
-        if [ $update_requirements -eq 0 ]; then
-            (cd $project_dir && git reset --hard)
-        fi
-    fi
-}
-
-
-# ``pip install -e`` the package, which processes the dependencies
-# using pip before running `setup.py develop`
-# Uses globals ``STACK_USER``
-# setup_develop_no_requirements_update directory
-function setup_develop_no_requirements_update() {
-    local project_dir=$1
-
-    pip_install -e $project_dir
-    # ensure that further actions can do things like setup.py sdist
-    safe_chown -R $STACK_USER $1/*.egg-info
-}
-
-
 # Retrieve an image from a URL and upload into Glance.
 # Uses the following variables:
 #
diff --git a/functions-common b/functions-common
index 3e29e8c..2248fbb 100644
--- a/functions-common
+++ b/functions-common
@@ -527,16 +527,16 @@
         if [[ ! -d $GIT_DEST ]]; then
             [[ "$ERROR_ON_CLONE" = "True" ]] && \
                 die $LINENO "Cloning not allowed in this configuration"
-            git clone $GIT_REMOTE $GIT_DEST
+            git_timed clone $GIT_REMOTE $GIT_DEST
         fi
         cd $GIT_DEST
-        git fetch $GIT_REMOTE $GIT_REF && git checkout FETCH_HEAD
+        git_timed fetch $GIT_REMOTE $GIT_REF && git checkout FETCH_HEAD
     else
         # do a full clone only if the directory doesn't exist
         if [[ ! -d $GIT_DEST ]]; then
             [[ "$ERROR_ON_CLONE" = "True" ]] && \
                 die $LINENO "Cloning not allowed in this configuration"
-            git clone $GIT_REMOTE $GIT_DEST
+            git_timed clone $GIT_REMOTE $GIT_DEST
             cd $GIT_DEST
             # This checkout syntax works for both branches and tags
             git checkout $GIT_REF
@@ -545,7 +545,7 @@
             cd $GIT_DEST
             # set the url to pull from and fetch
             git remote set-url origin $GIT_REMOTE
-            git fetch origin
+            git_timed fetch origin
             # remove the existing ignored files (like pyc) as they cause breakage
             # (due to the py files having older timestamps than our pyc, so python
             # thinks the pyc files are correct using them)
@@ -570,6 +570,37 @@
     git show --oneline | head -1
 }
 
+# git can sometimes get itself infinitely stuck with transient network
+# errors or other issues with the remote end.  This wraps git in a
+# timeout/retry loop and is intended to watch over non-local git
+# processes that might hang.  GIT_TIMEOUT, if set, is passed directly
+# to timeout(1); otherwise the default value of 0 maintains the status
+# quo of waiting forever.
+# usage: git_timed <git-command>
+function git_timed() {
+    local count=0
+    local timeout=0
+
+    if [[ -n "${GIT_TIMEOUT}" ]]; then
+        timeout=${GIT_TIMEOUT}
+    fi
+
+    until timeout -s SIGINT ${timeout} git "$@"; do
+        # 124 is timeout(1)'s special return code when it reached the
+        # timeout; otherwise assume fatal failure
+        if [[ $? -ne 124 ]]; then
+            die $LINENO "git call failed: [git $@]"
+        fi
+
+        count=$(($count + 1))
+        warn "timeout ${count} for git call: [git $@]"
+        if [ $count -eq 3 ]; then
+            die $LINENO "Maximum of 3 git retries reached"
+        fi
+        sleep 5
+    done
+}
+
 # git update using reference as a branch.
 # git_update_branch ref
 function git_update_branch() {
@@ -600,7 +631,7 @@
 
     git tag -d $GIT_TAG
     # fetching given tag only
-    git fetch origin tag $GIT_TAG
+    git_timed fetch origin tag $GIT_TAG
     git checkout -f $GIT_TAG
 }
 
@@ -1182,6 +1213,58 @@
         && $SUDO_PIP rm -rf ${pip_build_tmp}
 }
 
+# ``pip install -e`` the package, which processes the dependencies
+# using pip before running `setup.py develop`
+#
+# Updates the dependencies in project_dir from the
+# openstack/requirements global list before installing anything.
+#
+# Uses globals ``TRACK_DEPENDS``, ``REQUIREMENTS_DIR``, ``UNDO_REQUIREMENTS``
+# setup_develop directory
+function setup_develop() {
+    local project_dir=$1
+
+    echo "cd $REQUIREMENTS_DIR; $SUDO_CMD python update.py $project_dir"
+
+    # Don't update repo if local changes exist
+    # Don't use buggy "git diff --quiet"
+    (cd $project_dir && git diff --exit-code >/dev/null)
+    local update_requirements=$?
+
+    if [ $update_requirements -eq 0 ]; then
+        (cd $REQUIREMENTS_DIR; \
+            $SUDO_CMD python update.py $project_dir)
+    fi
+
+    setup_develop_no_requirements_update $project_dir
+
+    # We've just gone and possibly modified the user's source tree in an
+    # automated way, which is considered bad form if it's a development
+    # tree because we've screwed up their next git checkin. So undo it.
+    #
+    # However... there are some circumstances, like running in the gate
+    # where we really really want the overridden version to stick. So provide
+    # a variable that tells us whether or not we should UNDO the requirements
+    # changes (this will be set to False in the OpenStack ci gate)
+    if [ $UNDO_REQUIREMENTS = "True" ]; then
+        if [ $update_requirements -eq 0 ]; then
+            (cd $project_dir && git reset --hard)
+        fi
+    fi
+}
+
+# ``pip install -e`` the package, which processes the dependencies
+# using pip before running `setup.py develop`
+# Uses globals ``STACK_USER``
+# setup_develop_no_requirements_update directory
+function setup_develop_no_requirements_update() {
+    local project_dir=$1
+
+    pip_install -e $project_dir
+    # ensure that further actions can do things like setup.py sdist
+    safe_chown -R $STACK_USER $1/*.egg-info
+}
+
 
 # Service Functions
 # =================
diff --git a/lib/cinder b/lib/cinder
index c8c90c0..e8f30b6 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -496,8 +496,12 @@
             sudo stop tgt || true
             sudo start tgt
         elif is_fedora; then
-            # bypass redirection to systemctl during restart
-            sudo /sbin/service --skip-redirect tgtd restart
+            if [[ $DISTRO =~ (rhel6) ]]; then
+                sudo /sbin/service tgtd restart
+            else
+                # bypass redirection to systemctl during restart
+                sudo /sbin/service --skip-redirect tgtd restart
+            fi
         elif is_suse; then
             restart_service tgtd
         else
diff --git a/lib/heat b/lib/heat
index 1b6dc86..972c35c 100644
--- a/lib/heat
+++ b/lib/heat
@@ -214,7 +214,7 @@
         --description "Manages users and projects created by heat"
     openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
         --os-identity-api-version=3 role add \
-        --user ${U_ID} --domain ${D_ID} admin
+        --user heat_domain_admin --domain ${D_ID} admin
     iniset $HEAT_CONF DEFAULT stack_domain_admin heat_domain_admin
     iniset $HEAT_CONF DEFAULT stack_domain_admin_password $SERVICE_PASSWORD
 }
diff --git a/lib/keystone b/lib/keystone
index cebb4d3..73af1d3 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -424,7 +424,7 @@
     fi
 
     echo "Waiting for keystone to start..."
-    if ! timeout $SERVICE_TIMEOUT sh -c "while ! curl --noproxy '*' -s $KEYSTONE_AUTH_PROTOCOL://$SERVICE_HOST:$service_port/v$IDENTITY_API_VERSION/ >/dev/null; do sleep 1; done"; then
+    if ! timeout $SERVICE_TIMEOUT sh -c "while ! curl --noproxy '*' -k -s $KEYSTONE_AUTH_PROTOCOL://$SERVICE_HOST:$service_port/v$IDENTITY_API_VERSION/ >/dev/null; do sleep 1; done"; then
         die $LINENO "keystone did not start"
     fi
 
diff --git a/lib/neutron_plugins/embrane b/lib/neutron_plugins/embrane
index 4206a20..325e939 100644
--- a/lib/neutron_plugins/embrane
+++ b/lib/neutron_plugins/embrane
@@ -37,4 +37,4 @@
 }
 
 # Restore xtrace
-$MY_XTRACE
\ No newline at end of file
+$MY_XTRACE
diff --git a/lib/nova_plugins/hypervisor-libvirt b/lib/nova_plugins/hypervisor-libvirt
index 415244f..a550600 100644
--- a/lib/nova_plugins/hypervisor-libvirt
+++ b/lib/nova_plugins/hypervisor-libvirt
@@ -58,40 +58,40 @@
 
     if is_fedora || is_suse; then
         if is_fedora && [[ $DISTRO =~ (rhel6) || "$os_RELEASE" -le "17" ]]; then
-            sudo bash -c "cat <<EOF >/etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla
+            cat <<EOF | sudo tee /etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla
 [libvirt Management Access]
 Identity=unix-group:$LIBVIRT_GROUP
 Action=org.libvirt.unix.manage
 ResultAny=yes
 ResultInactive=yes
 ResultActive=yes
-EOF"
+EOF
         elif is_suse && [[ $os_RELEASE = 12.2 || "$os_VENDOR" = "SUSE LINUX" ]]; then
             # openSUSE < 12.3 or SLE
             # Work around the fact that polkit-default-privs overrules pklas
             # with 'unix-group:$group'.
-            sudo bash -c "cat <<EOF >/etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla
+            cat <<EOF | sudo tee /etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla
 [libvirt Management Access]
 Identity=unix-user:$STACK_USER
 Action=org.libvirt.unix.manage
 ResultAny=yes
 ResultInactive=yes
 ResultActive=yes
-EOF"
+EOF
         else
             # Starting with fedora 18 and opensuse-12.3 enable stack-user to
             # virsh -c qemu:///system by creating a policy-kit rule for
             # stack-user using the new Javascript syntax
             rules_dir=/etc/polkit-1/rules.d
             sudo mkdir -p $rules_dir
-            sudo bash -c "cat <<EOF > $rules_dir/50-libvirt-$STACK_USER.rules
+            cat <<EOF | sudo tee $rules_dir/50-libvirt-$STACK_USER.rules
 polkit.addRule(function(action, subject) {
     if (action.id == 'org.libvirt.unix.manage' &&
         subject.user == '"$STACK_USER"') {
         return polkit.Result.YES;
     }
 });
-EOF"
+EOF
             unset rules_dir
         fi
     fi
@@ -140,10 +140,12 @@
         install_package kvm
         install_package libvirt-bin
         install_package python-libvirt
+        install_package python-guestfs
     elif is_fedora || is_suse; then
         install_package kvm
         install_package libvirt
         install_package libvirt-python
+        install_package python-libguestfs
     fi
 
     # Install and configure **LXC** if specified.  LXC is another approach to
diff --git a/lib/oslo b/lib/oslo
index b089842..516ce1c 100644
--- a/lib/oslo
+++ b/lib/oslo
@@ -24,6 +24,7 @@
 OSLOCFG_DIR=$DEST/oslo.config
 OSLOMSG_DIR=$DEST/oslo.messaging
 OSLORWRAP_DIR=$DEST/oslo.rootwrap
+OSLOVMWARE_DIR=$DEST/oslo.vmware
 PYCADF_DIR=$DEST/pycadf
 STEVEDORE_DIR=$DEST/stevedore
 TASKFLOW_DIR=$DEST/taskflow
@@ -49,6 +50,9 @@
     git_clone $OSLORWRAP_REPO $OSLORWRAP_DIR $OSLORWRAP_BRANCH
     setup_develop $OSLORWRAP_DIR
 
+    git_clone $OSLOVMWARE_REPO $OSLOVMWARE_DIR $OSLOVMWARE_BRANCH
+    setup_develop $OSLOVMWARE_DIR
+
     git_clone $PYCADF_REPO $PYCADF_DIR $PYCADF_BRANCH
     setup_develop $PYCADF_DIR
 
diff --git a/lib/tempest b/lib/tempest
index 83ce5d2..410c80c 100644
--- a/lib/tempest
+++ b/lib/tempest
@@ -63,6 +63,9 @@
 TEMPEST_VOLUME_VENDOR=${TEMPEST_VOLUME_VENDOR:-"Open Source"}
 TEMPEST_STORAGE_PROTOCOL=${TEMPEST_STORAGE_PROTOCOL:-iSCSI}
 
+# Neutron/Network variables
+IPV6_ENABLED=$(trueorfalse True $IPV6_ENABLED)
+
 # Functions
 # ---------
 
@@ -284,11 +287,13 @@
     # Compute admin
     iniset $TEMPEST_CONFIG "compute-admin" password "$password" # DEPRECATED
 
+    # Network
     iniset $TEMPEST_CONFIG network api_version 2.0
     iniset $TEMPEST_CONFIG network tenant_networks_reachable "$tenant_networks_reachable"
     iniset $TEMPEST_CONFIG network public_network_id "$public_network_id"
     iniset $TEMPEST_CONFIG network public_router_id "$public_router_id"
     iniset $TEMPEST_CONFIG network default_network "$FIXED_RANGE"
+    iniset $TEMPEST_CONFIG network ipv6_enabled "$IPV6_ENABLED"
 
     # boto
     iniset $TEMPEST_CONFIG boto ec2_url "http://$SERVICE_HOST:8773/services/Cloud"
diff --git a/stack.sh b/stack.sh
index d43a73a..ac89e52 100755
--- a/stack.sh
+++ b/stack.sh
@@ -181,7 +181,7 @@
     # Installing Open vSwitch on RHEL6 requires enabling the RDO repo.
     RHEL6_RDO_REPO_RPM=${RHEL6_RDO_REPO_RPM:-"http://rdo.fedorapeople.org/openstack-havana/rdo-release-havana.rpm"}
     RHEL6_RDO_REPO_ID=${RHEL6_RDO_REPO_ID:-"openstack-havana"}
-    if ! yum repolist enabled $RHEL6_RDO_REPO_ID | grep -q $RHEL6_RDO_REPO_ID; then
+    if ! sudo yum repolist enabled $RHEL6_RDO_REPO_ID | grep -q $RHEL6_RDO_REPO_ID; then
         echo "RDO repo not detected; installing"
         yum_install $RHEL6_RDO_REPO_RPM || \
             die $LINENO "Error installing RDO repo, cannot continue"
@@ -189,11 +189,15 @@
 
     # RHEL6 requires EPEL for many Open Stack dependencies
     RHEL6_EPEL_RPM=${RHEL6_EPEL_RPM:-"http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm"}
-    if ! yum repolist enabled epel | grep -q 'epel'; then
+    if ! sudo yum repolist enabled epel | grep -q 'epel'; then
         echo "EPEL not detected; installing"
         yum_install ${RHEL6_EPEL_RPM} || \
             die $LINENO "Error installing EPEL repo, cannot continue"
     fi
+
+    # ... and also optional to be enabled
+    sudo yum-config-manager --enable rhel-6-server-optional-rpms
+
 fi
 
 
diff --git a/stackrc b/stackrc
index 0b081c4..f235ccc 100644
--- a/stackrc
+++ b/stackrc
@@ -80,6 +80,17 @@
 # (currently only implemented for MySQL backend)
 DATABASE_QUERY_LOGGING=$(trueorfalse True $DATABASE_QUERY_LOGGING)
 
+# Set a timeout for git operations.  If git is still running when the
+# timeout expires, the command will be retried up to 3 times.  This is
+# in the format for timeout(1);
+#
+#  DURATION is a floating point number with an optional suffix: 's'
+#  for seconds (the default), 'm' for minutes, 'h' for hours or 'd'
+#  for days.
+#
+# Zero disables timeouts
+GIT_TIMEOUT=${GIT_TIMEOUT:-0}
+
 # Repositories
 # ------------
 
@@ -167,6 +178,10 @@
 OSLORWRAP_REPO=${OSLORWRAP_REPO:-${GIT_BASE}/openstack/oslo.rootwrap.git}
 OSLORWRAP_BRANCH=${OSLORWRAP_BRANCH:-master}
 
+# oslo.vmware
+OSLOVMWARE_REPO=${OSLOVMWARE_REPO:-${GIT_BASE}/openstack/oslo.vmware.git}
+OSLOVMWARE_BRANCH=${OSLOVMWARE_BRANCH:-master}
+
 # pycadf auditing library
 PYCADF_REPO=${PYCADF_REPO:-${GIT_BASE}/openstack/pycadf.git}
 PYCADF_BRANCH=${PYCADF_BRANCH:-master}
diff --git a/tools/bash8.py b/tools/bash8.py
index ca0abd9..f89b241 100755
--- a/tools/bash8.py
+++ b/tools/bash8.py
@@ -25,6 +25,7 @@
 # - E001: check that lines do not end with trailing whitespace
 # - E002: ensure that indents are only spaces, and not hard tabs
 # - E003: ensure all indents are a multiple of 4 spaces
+# - E004: file did not end with a newline
 #
 # Structure errors
 #
@@ -34,6 +35,7 @@
 #
 # - E010: *do* not on the same line as *for*
 # - E011: *then* not on the same line as *if*
+# - E012: heredoc didn't end before EOF
 
 import argparse
 import fileinput
@@ -54,11 +56,16 @@
     return IGNORE and re.search(IGNORE, error)
 
 
-def print_error(error, line):
+def print_error(error, line,
+                filename=None, filelineno=None):
+    if not filename:
+        filename = fileinput.filename()
+    if not filelineno:
+        filelineno = fileinput.filelineno()
     global ERRORS
     ERRORS = ERRORS + 1
     print("%s: '%s'" % (error, line.rstrip('\n')))
-    print(" - %s: L%s" % (fileinput.filename(), fileinput.filelineno()))
+    print(" - %s: L%s" % (filename, filelineno))
 
 
 def not_continuation(line):
@@ -112,17 +119,44 @@
 
 def check_files(files, verbose):
     in_multiline = False
+    multiline_start = 0
+    multiline_line = ""
     logical_line = ""
     token = False
+    prev_file = None
+    prev_line = ""
+    prev_lineno = 0
+
     for line in fileinput.input(files):
-        if verbose and fileinput.isfirstline():
-            print "Running bash8 on %s" % fileinput.filename()
+        if fileinput.isfirstline():
+            # if in_multiline when the new file starts then we didn't
+            # find the end of a heredoc in the last file.
+            if in_multiline:
+                print_error('E012: heredoc did not end before EOF',
+                            multiline_line,
+                            filename=prev_file, filelineno=multiline_start)
+                in_multiline = False
+
+            # last line of a previous file should always end with a
+            # newline
+            if prev_file and not prev_line.endswith('\n'):
+                print_error('E004: file did not end with a newline',
+                            prev_line,
+                            filename=prev_file, filelineno=prev_lineno)
+
+            prev_file = fileinput.filename()
+
+            if verbose:
+                print "Running bash8 on %s" % fileinput.filename()
+
         # NOTE(sdague): multiline processing of heredocs is interesting
         if not in_multiline:
             logical_line = line
             token = starts_multiline(line)
             if token:
                 in_multiline = True
+                multiline_start = fileinput.filelineno()
+                multiline_line = line
                 continue
         else:
             logical_line = logical_line + line
@@ -136,6 +170,8 @@
         check_for_do(logical_line)
         check_if_then(logical_line)
 
+        prev_line = logical_line
+        prev_lineno = fileinput.filelineno()
 
 def get_options():
     parser = argparse.ArgumentParser(
diff --git a/tools/fixup_stuff.sh b/tools/fixup_stuff.sh
index 048024a..47b0cd1 100755
--- a/tools/fixup_stuff.sh
+++ b/tools/fixup_stuff.sh
@@ -98,10 +98,6 @@
         sudo setenforce 0
     fi
 
-    # make sure we have the "optional" repo enabled; it provides some
-    # packages like libffi-devel for example
-    sudo yum-config-manager --enable rhel-6-server-optional-rpms
-
     # If the ``dbus`` package was installed by DevStack dependencies the
     # uuid may not be generated because the service was never started (PR#598200),
     # causing Nova to stop later on complaining that ``/var/lib/dbus/machine-id``