Merge "Enhance test_server_actions_rbac with index/detail/show server actions."
diff --git a/patrole_tempest_plugin/tests/api/compute/test_quota_sets_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_quota_sets_rbac.py
new file mode 100644
index 0000000..a7f8447
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_quota_sets_rbac.py
@@ -0,0 +1,106 @@
+#    Copyright 2017 AT&T Corporation.
+#    All Rights Reserved.
+#
+#    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.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+from tempest import test
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.compute import rbac_base
+
+
+class QuotaSetsRbacTest(rbac_base.BaseV2ComputeRbacTest):
+
+    @classmethod
+    def setup_clients(cls):
+        super(QuotaSetsRbacTest, cls).setup_clients()
+        cls.client = cls.quotas_client
+        cls.projects_client = cls.os.projects_client
+
+    @classmethod
+    def skip_checks(cls):
+        super(QuotaSetsRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('os-quota-sets', 'compute'):
+            msg = "%s skipped as quotas extension not enabled."\
+                  % cls.__name__
+            raise cls.skipException(msg)
+
+    @classmethod
+    def resource_setup(cls):
+        super(QuotaSetsRbacTest, cls).resource_setup()
+        cls.tenant_id = cls.quotas_client.tenant_id
+        cls.user_id = cls.quotas_client.user_id
+        cls.quota_set = set(('injected_file_content_bytes',
+                             'metadata_items', 'injected_files',
+                             'ram', 'floating_ips', 'fixed_ips', 'key_pair',
+                             'injected_file_path_bytes', 'instances',
+                             'security_group_rules', 'cores',
+                             'security_groups'))
+
+    @decorators.idempotent_id('8229ceb0-db6a-4a2c-99c2-de226905d8b6')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-quota-sets:update")
+    def test_update_quota_set(self):
+        default_quota_set = self.client.show_default_quota_set(
+            self.tenant_id)['quota_set']
+        default_quota_set.pop('id')
+        new_quota_set = {'injected_file_content_bytes': 20480}
+
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.client.update_quota_set(self.tenant_id,
+                                     force=True,
+                                     **new_quota_set)['quota_set']
+        self.addCleanup(self.client.update_quota_set, self.tenant_id,
+                        **default_quota_set)
+
+    @decorators.idempotent_id('58df5613-8f3c-400a-8b4b-2bae624d05e9')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-quota-sets:defaults")
+    def test_show_default_quota_set(self):
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.client.show_default_quota_set(self.tenant_id)['quota_set']
+
+    @decorators.idempotent_id('e8169ac4-c402-4864-894e-aba74e3a459c')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-quota-sets:show")
+    def test_show_quota_set(self):
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.client.show_quota_set(self.tenant_id)['quota_set']
+
+    @decorators.idempotent_id('4e240644-bf61-4872-9c32-8289ee2fdbbd')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-quota-sets:delete")
+    def test_delete_quota_set(self):
+        project_name = data_utils.rand_name('project')
+        project = self.projects_client.create_project(name=project_name)
+        project_id = project['project']['id']
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.projects_client.delete_project, project_id)
+
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.client.delete_quota_set(project_id)
+
+    @decorators.idempotent_id('ac9184b6-f3b3-4e17-a632-4b92c6500f86')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-quota-sets:detail")
+    def test_show_quota_set_details(self):
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.client.show_quota_set(self.tenant_id, detail=True)['quota_set']
diff --git a/patrole_tempest_plugin/tests/api/volume/admin/test_volumes_backup_admin_rbac.py b/patrole_tempest_plugin/tests/api/volume/admin/test_volumes_backup_admin_rbac.py
index e78f80d..a89aa87 100644
--- a/patrole_tempest_plugin/tests/api/volume/admin/test_volumes_backup_admin_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/admin/test_volumes_backup_admin_rbac.py
@@ -13,7 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from oslo_serialization import base64
+from oslo_serialization import jsonutils as json
 from tempest import config
+from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 from tempest import test
 
@@ -36,6 +39,18 @@
         super(VolumesBackupsAdminRbacTest, cls).resource_setup()
         cls.volume = cls.create_volume()
 
+    def _decode_url(self, backup_url):
+        return json.loads(base64.decode_as_text(backup_url))
+
+    def _encode_backup(self, backup):
+        retval = json.dumps(backup)
+        return base64.encode_as_text(retval)
+
+    def _modify_backup_url(self, backup_url, changes):
+        backup = self._decode_url(backup_url)
+        backup.update(changes)
+        return self._encode_backup(backup)
+
     @test.attr(type='slow')
     @rbac_rule_validation.action(service="cinder",
                                  rule="backup:backup-export")
@@ -58,11 +73,14 @@
         # Export a temp backup
         export_backup = self.backups_client.export_backup(
             backup['id'])['backup-record']
+        new_id = data_utils.rand_uuid()
+        new_url = self._modify_backup_url(
+            export_backup['backup_url'], {'id': new_id})
         # Import the temp backup
         self.rbac_utils.switch_role(self, switchToRbacRole=True)
         import_backup = self.backups_client.import_backup(
             backup_service=export_backup['backup_service'],
-            backup_url=export_backup['backup_url'])['backup']
+            backup_url=new_url)['backup']
         self.addCleanup(self.backups_client.delete_backup, import_backup['id'])
 
 
diff --git a/patrole_tempest_plugin/tests/api/volume/rbac_base.py b/patrole_tempest_plugin/tests/api/volume/rbac_base.py
index c762473..2a14b19 100644
--- a/patrole_tempest_plugin/tests/api/volume/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/volume/rbac_base.py
@@ -57,7 +57,8 @@
         cls.rbac_utils.switch_role(cls, switchToRbacRole=False)
         version_checker = {
             1: [cls.os.volume_hosts_client, cls.os.volume_types_client],
-            2: [cls.os.volume_hosts_v2_client, cls.os.volume_types_v2_client]
+            2: [cls.os.volume_hosts_v2_client, cls.os.volume_types_v2_client],
+            3: [cls.os.volume_hosts_v2_client, cls.os.volume_types_v2_client]
         }
         cls.volume_hosts_client, cls.volume_types_client = \
             version_checker[cls._api_version]
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py
index d4ede3d..996e2b7 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py
@@ -13,6 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
+from tempest.common import compute
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import data_utils
@@ -28,58 +31,56 @@
 class VolumesActionsRbacTest(rbac_base.BaseVolumeRbacTest):
 
     @classmethod
-    def skip_checks(cls):
-        super(VolumesActionsRbacTest, cls).skip_checks()
-        # Nova is needed to create a server
-        if not CONF.service_available.nova:
-            skip_msg = ("%s skipped as nova is not available" % cls.__name__)
-            raise cls.skipException(skip_msg)
-        # Glance is needed to create an image
-        if not CONF.service_available.glance:
-            skip_msg = ("%s skipped as glance is not available" % cls.__name__)
-            raise cls.skipException(skip_msg)
-
-    @classmethod
     def setup_clients(cls):
         super(VolumesActionsRbacTest, cls).setup_clients()
         cls.client = cls.os.volumes_client
-        cls.image_client = cls.os.image_client
 
     @classmethod
     def resource_setup(cls):
         super(VolumesActionsRbacTest, cls).resource_setup()
         cls.volume = cls.create_volume()
 
-    def _attach_volume(self):
-        server = self.create_server(wait_until='ACTIVE')
+    def _create_server(self):
+        body, _ = compute.create_test_server(self.os, wait_until='ACTIVE')
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.servers_client.delete_server, body['id'])
+        return body
+
+    def _attach_volume(self, server):
         self.servers_client.attach_volume(
             server['id'], volumeId=self.volume['id'],
             device='/dev/%s' % CONF.compute.volume_device_name)
-        waiters.wait_for_volume_status(self.client,
-                                       self.volume['id'], 'in-use')
+        waiters.wait_for_volume_resource_status(
+            self.client, self.volume['id'], 'in-use')
         self.addCleanup(self._detach_volume)
 
     def _detach_volume(self):
         self.client.detach_volume(self.volume['id'])
-        waiters.wait_for_volume_status(self.client, self.volume['id'],
-                                       'available')
+        waiters.wait_for_volume_resource_status(
+            self.client, self.volume['id'], 'available')
 
+    @testtools.skipUnless(CONF.service_available.nova,
+                          "Nova is required to create a server")
     @rbac_rule_validation.action(service="cinder", rule="volume:attach")
     @decorators.idempotent_id('f97b10e4-2eed-4f8b-8632-71c02cb9fe42')
     def test_attach_volume_to_instance(self):
+        server = self._create_server()
         self.rbac_utils.switch_role(self, switchToRbacRole=True)
         # Attach the volume
-        self._attach_volume()
+        self._attach_volume(server)
 
     @rbac_rule_validation.action(service="cinder", rule="volume:detach")
     @decorators.idempotent_id('5a042f6a-688b-42e6-a02e-fe5c47b89b07')
     def test_detach_volume_to_instance(self):
         # Attach the volume
-        self._attach_volume()
+        server = self._create_server()
+        self._attach_volume(server)
         self.rbac_utils.switch_role(self, switchToRbacRole=True)
         # Detach the volume
         self._detach_volume()
 
+    @testtools.skipUnless(CONF.service_available.nova,
+                          "Nova is needed to create a server")
     @rbac_rule_validation.action(service="cinder", rule="volume:get")
     @decorators.idempotent_id('c4c3fdd5-b1b1-49c3-b977-a9f40ee9257a')
     def test_get_volume_attachment(self):
@@ -87,20 +88,22 @@
         # Get attachment
         self.client.show_volume(self.volume['id'])
 
+    @testtools.skipIf(True, "Patrole bug #1672799")
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:copy_volume_to_image")
     @decorators.idempotent_id('b0d0da46-903c-4445-893e-20e680d68b50')
     def test_volume_upload(self):
+        self.image_client = self.os.image_client
         image_name = data_utils.rand_name('image')
         self.rbac_utils.switch_role(self, switchToRbacRole=True)
         body = self.client.upload_volume(
             self.volume['id'], image_name=image_name,
             disk_format=CONF.volume.disk_format)['os-volume_upload_image']
-        image_id = body['image_id']
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.image_client.delete_image,
-                        image_id)
-        waiters.wait_for_image_status(self.image_client, image_id, 'active')
+                        body['image_id'])
+        waiters.wait_for_volume_resource_status(
+            self.client, self.volume['id'], 'available')
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:update_readonly_flag")
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_transfers_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_transfers_rbac.py
index 5c86da4..358733f 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_transfers_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_transfers_rbac.py
@@ -26,7 +26,7 @@
 
 class VolumesTransfersRbacTest(rbac_base.BaseVolumeRbacTest):
 
-    credentials = ['alt', 'admin']
+    credentials = ['primary', 'admin', 'alt']
 
     @classmethod
     def setup_clients(cls):
@@ -46,8 +46,8 @@
         # the test to fail
         test_utils.call_and_ignore_notfound_exc(
             self.client.delete_volume_transfer, transfer['id'])
-        waiters.wait_for_volume_status(self.client, self.volume['id'],
-                                       'available')
+        waiters.wait_for_volume_resource_status(
+            self.client, self.volume['id'], 'available')
 
     def _create_transfer(self):
         transfer = self.client.create_volume_transfer(
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py
index 9902f0d..8480d01 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py
@@ -16,6 +16,7 @@
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
@@ -34,7 +35,7 @@
 
     def create_backup(self, volume_id):
         backup_name = data_utils.rand_name(
-            self.__class__.__name__ + '-Backup')
+            self.__class__.__name__ + '-backup')
         backup = self.backups_client.create_backup(
             volume_id=volume_id, name=backup_name)['backup']
         self.addCleanup(self.backups_client.delete_backup, backup['id'])
@@ -47,19 +48,30 @@
         super(VolumesBackupsRbacTest, cls).resource_setup()
         cls.volume = cls.create_volume()
 
+    def _create_backup(self, volume_id):
+        backup_name = data_utils.rand_name('backup')
+        backup = self.backups_client.create_backup(
+            volume_id=volume_id, name=backup_name)['backup']
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.backups_client.delete_backup, backup['id'])
+        waiters.wait_for_volume_resource_status(
+            self.backups_client, backup['id'], 'available')
+        return backup
+
     @rbac_rule_validation.action(service="cinder",
                                  rule="backup:create")
     @decorators.idempotent_id('6887ec94-0bcf-4ab7-b30f-3808a4b5a2a5')
     def test_volume_backup_create(self):
         self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.create_backup(volume_id=self.volume['id'])
+        self._create_backup(volume_id=self.volume['id'])
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="backup:get")
     @decorators.idempotent_id('abd92bdd-b0fb-4dc4-9cfc-de9e968f8c8a')
     def test_volume_backup_get(self):
         # Create a temp backup
-        backup = self.create_backup(volume_id=self.volume['id'])
+        backup = self._create_backup(volume_id=self.volume['id'])
         # Get a given backup
         self.rbac_utils.switch_role(self, switchToRbacRole=True)
         self.backups_client.show_backup(backup['id'])
@@ -76,17 +88,19 @@
     @decorators.idempotent_id('9c794bf9-2446-4f41-8fe0-80b71e757f9d')
     def test_volume_backup_restore(self):
         # Create a temp backup
-        backup = self.create_backup(volume_id=self.volume['id'])
+        backup = self._create_backup(volume_id=self.volume['id'])
         # Restore backup
         self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.backups_client.restore_backup(backup['id'])['restore']
+        restore = self.backups_client.restore_backup(backup['id'])['restore']
+        waiters.wait_for_volume_resource_status(
+            self.backups_client, restore['backup_id'], 'available')
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="backup:delete")
     @decorators.idempotent_id('d5d0c6a2-413d-437e-a73f-4bf2b41a20ed')
     def test_volume_backup_delete(self):
         # Create a temp backup
-        backup = self.create_backup(volume_id=self.volume['id'])
+        backup = self._create_backup(volume_id=self.volume['id'])
         self.rbac_utils.switch_role(self, switchToRbacRole=True)
         # Delete backup
         self.backups_client.delete_backup(backup['id'])
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volumes_extend_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volumes_extend_rbac.py
index e8c620f..64493c5 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volumes_extend_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volumes_extend_rbac.py
@@ -39,8 +39,8 @@
         self.rbac_utils.switch_role(self, switchToRbacRole=True)
         self.volumes_client.extend_volume(self.volume['id'],
                                           new_size=extend_size)
-        waiters.wait_for_volume_status(self.volumes_client, self.volume['id'],
-                                       'available')
+        waiters.wait_for_volume_resource_status(
+            self.volumes_client, self.volume['id'], 'available')
 
 
 class VolumesExtendV3RbacTest(VolumesExtendRbacTest):