Merge "Update v3 project tests to work w/ pre-prov"
diff --git a/.zuul.yaml b/.zuul.yaml
index 9546f1d..8ff151f 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -99,6 +99,7 @@
       tox_envlist: full
       devstack_localrc:
         ENABLE_FILE_INJECTION: true
+        ENABLE_VOLUME_MULTIATTACH: true
 
 - job:
     name: tempest-full-oslo-master
@@ -161,6 +162,7 @@
       devstack_localrc:
         USE_PYTHON3: true
         FORCE_CONFIG_DRIVE: true
+        ENABLE_VOLUME_MULTIATTACH: true
       devstack_services:
         s-account: false
         s-container: false
@@ -276,6 +278,7 @@
       tox_envlist: slow-serial
       devstack_localrc:
         CINDER_ENABLED_BACKENDS: lvm:lvmdriver-1,lvm:lvmdriver-2
+        ENABLE_VOLUME_MULTIATTACH: true
       tempest_concurrency: 2
 
 - job:
@@ -490,7 +493,7 @@
               - ^playbooks/
               - ^roles/
               - ^.zuul.yaml$
-        - nova-multiattach:
+        - tempest-full-parallel:
             # Define list of irrelevant files to use everywhere else
             irrelevant-files: &tempest-irrelevant-files
               - ^(test-|)requirements.txt$
@@ -502,8 +505,6 @@
               - ^tempest/hacking/.*$
               - ^tempest/tests/.*$
               - ^tools/.*$
-        - tempest-full-parallel:
-            irrelevant-files: *tempest-irrelevant-files
         - tempest-full-py3:
             irrelevant-files: *tempest-irrelevant-files
         - tempest-full-py3-ipv6:
@@ -578,8 +579,6 @@
             irrelevant-files: *tempest-irrelevant-files
     gate:
       jobs:
-        - nova-multiattach:
-            irrelevant-files: *tempest-irrelevant-files
         - tempest-slow-py3:
             irrelevant-files: *tempest-irrelevant-files
         - neutron-grenade-multinode:
diff --git a/releasenotes/notes/enable-volume-multiattach-fd5e9bf0e96b56ce.yaml b/releasenotes/notes/enable-volume-multiattach-fd5e9bf0e96b56ce.yaml
new file mode 100644
index 0000000..0959b22
--- /dev/null
+++ b/releasenotes/notes/enable-volume-multiattach-fd5e9bf0e96b56ce.yaml
@@ -0,0 +1,10 @@
+---
+upgrade:
+  - |
+    The ``tempest-full``, ``tempest-full-py3`` and ``tempest-slow`` zuul v3
+    job configurations now set ``ENABLE_VOLUME_MULTIATTACH: true`` in the
+    ``devstack_localrc`` variables section. If you have a plugin job
+    configuration that inherits from one of these jobs and the backend cinder
+    volume driver or nova compute driver do not support volume multiattach then
+    you should override and set this variable to
+    ``ENABLE_VOLUME_MULTIATTACH: false`` in your job configuration.
diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py
index 6b58939..cc83c04 100644
--- a/tempest/api/compute/admin/test_volume_swap.py
+++ b/tempest/api/compute/admin/test_volume_swap.py
@@ -148,6 +148,13 @@
     # so it's marked as such.
     @decorators.attr(type='slow')
     @decorators.idempotent_id('e8f8f9d1-d7b7-4cd2-8213-ab85ef697b6e')
+    # For some reason this test intermittently fails on teardown when there are
+    # multiple compute nodes and the servers are split across the computes.
+    # For now, just skip this test if there are multiple computes.
+    # Alternatively we could put the servers in an affinity group if there are
+    # multiple computes but that would just side-step the underlying bug.
+    @decorators.skip_because(bug='1807723',
+                             condition=CONF.compute.min_compute_nodes > 1)
     @utils.services('volume')
     def test_volume_swap_with_multiattach(self):
         # Create two volumes.
diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py
index 37ce266..80d7469 100644
--- a/tempest/api/identity/admin/v3/test_groups.py
+++ b/tempest/api/identity/admin/v3/test_groups.py
@@ -12,6 +12,7 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
+import testtools
 
 from tempest.api.identity import base
 from tempest import config
@@ -68,6 +69,10 @@
 
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('1598521a-2f36-4606-8df9-30772bd51339')
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      'Skipped because environment has an '
+                      'immutable user source and solely '
+                      'provides read-only access to users.')
     def test_group_users_add_list_delete(self):
         group = self.setup_test_group(domain_id=self.domain['id'])
         # add user into group
@@ -90,6 +95,10 @@
         self.assertEqual(len(group_users), 0)
 
     @decorators.idempotent_id('64573281-d26a-4a52-b899-503cb0f4e4ec')
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      'Skipped because environment has an '
+                      'immutable user source and solely '
+                      'provides read-only access to users.')
     def test_list_user_groups(self):
         # create a user
         user = self.create_test_user()
diff --git a/tempest/api/identity/admin/v3/test_regions.py b/tempest/api/identity/admin/v3/test_regions.py
index f22a528..c8c0151 100644
--- a/tempest/api/identity/admin/v3/test_regions.py
+++ b/tempest/api/identity/admin/v3/test_regions.py
@@ -20,6 +20,10 @@
 
 
 class RegionsTestJSON(base.BaseIdentityV3AdminTest):
+    # NOTE: force_tenant_isolation is true in the base class by default but
+    # overridden to false here to allow test execution for clouds using the
+    # pre-provisioned credentials provider.
+    force_tenant_isolation = False
 
     @classmethod
     def setup_clients(cls):
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index 2f54f9a..8e68698 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -309,9 +309,9 @@
             f.write(json.dumps(data,
                     sort_keys=True, indent=2, separators=(',', ': ')))
 
-    def _load_json(self):
+    def _load_json(self, saved_state_json=SAVED_STATE_JSON):
         try:
-            with open(SAVED_STATE_JSON) as json_file:
+            with open(saved_state_json, 'rb') as json_file:
                 self.json_data = json.load(json_file)
 
         except IOError as ex:
diff --git a/tempest/tests/cmd/test_cleanup.py b/tempest/tests/cmd/test_cleanup.py
new file mode 100644
index 0000000..e4e8525
--- /dev/null
+++ b/tempest/tests/cmd/test_cleanup.py
@@ -0,0 +1,26 @@
+# Copyright 2018 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from tempest.cmd import cleanup
+from tempest.tests import base
+
+
+class TestTempestCleanup(base.TestCase):
+
+    def test_load_json(self):
+        # instatiate "empty" TempestCleanup
+        c = cleanup.TempestCleanup(None, None, 'test')
+        test_saved_json = 'tempest/tests/cmd/test_saved_state_json.json'
+        # test if the file is loaded without any issues/exceptions
+        c._load_json(test_saved_json)
diff --git a/tempest/tests/cmd/test_saved_state_json.json b/tempest/tests/cmd/test_saved_state_json.json
new file mode 100644
index 0000000..5c55331
--- /dev/null
+++ b/tempest/tests/cmd/test_saved_state_json.json
@@ -0,0 +1,16 @@
+{
+  "domains": {
+    "default": "Default"
+  },
+  "flavors": {
+    "1": "m1.tiny"
+  },
+  "images": {},
+  "projects": {
+    "268bcb63488b4aa2942ecaac0f85ed62": "demo"
+  },
+  "roles": {},
+  "users": {
+    "023e65a5922a454585a91c6af8310968": "demo"
+  }
+}