Merge "Enhance validation decorator with error code"
diff --git a/patrole_tempest_plugin/rbac_utils.py b/patrole_tempest_plugin/rbac_utils.py
index abbb435..18f132e 100644
--- a/patrole_tempest_plugin/rbac_utils.py
+++ b/patrole_tempest_plugin/rbac_utils.py
@@ -87,12 +87,18 @@
raise
finally:
- if BaseTestCase.get_identity_version() != 'v3':
- test_obj.auth_provider.clear_auth()
- # Sleep to avoid 401 errors caused by rounding in timing of
- # fernet token creation.
- time.sleep(1)
- test_obj.auth_provider.set_auth()
+ # NOTE(felipemonteiro): These two comments below are copied from
+ # tempest.api.identity.v2/v3.test_users.
+ #
+ # Reset auth again to verify the password restore does work.
+ # Clear auth restores the original credentials and deletes
+ # cached auth data.
+ test_obj.auth_provider.clear_auth()
+ # Fernet tokens are not subsecond aware and Keystone should only be
+ # precise to the second. Sleep to ensure we are passing the second
+ # boundary before attempting to authenticate.
+ time.sleep(1)
+ test_obj.auth_provider.set_auth()
def _clear_user_roles(cls, user_id, tenant_id):
roles = cls.creds_client.roles_client.list_user_roles_on_project(
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py
index 0e1b00b..d466ded 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py
@@ -18,6 +18,8 @@
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 tempest.lib import exceptions as lib_exc
from tempest import test
@@ -36,17 +38,34 @@
def setup_clients(cls):
super(ServerActionsRbacTest, cls).setup_clients()
cls.client = cls.servers_client
+ cls.snapshots_client = cls.snapshots_extensions_client
@classmethod
def resource_setup(cls):
cls.set_validation_resources()
super(ServerActionsRbacTest, cls).resource_setup()
+ # Create test server
cls.server_id = cls.create_test_server(wait_until='ACTIVE',
validatable=True)['id']
cls.flavor_ref = CONF.compute.flavor_ref
cls.flavor_ref_alt = CONF.compute.flavor_ref_alt
cls.image_ref = CONF.compute.image_ref
+ # Create a volume
+ volume_name = data_utils.rand_name(cls.__name__ + '-volume')
+ name_field = 'name'
+ if not CONF.volume_feature_enabled.api_v2:
+ name_field = 'display_name'
+
+ params = {name_field: volume_name,
+ 'imageRef': CONF.compute.image_ref,
+ 'size': CONF.volume.volume_size}
+ volume = cls.volumes_client.create_volume(**params)['volume']
+ waiters.wait_for_volume_resource_status(cls.volumes_client,
+ volume['id'], 'available')
+ cls.volumes.append(volume)
+ cls.volume_id = volume['id']
+
def setUp(self):
super(ServerActionsRbacTest, self).setUp()
try:
@@ -64,6 +83,56 @@
self.__class__.server_id = self.rebuild_server(
self.server_id, validatable=True)
+ @classmethod
+ def resource_cleanup(cls):
+ # If a test case creates an image from a server that is created with
+ # a volume, a volume snapshot will automatically be created by default.
+ # We need to delete the volume snapshot.
+ try:
+ body = cls.snapshots_extensions_client.list_snapshots()
+ volume_snapshots = body['snapshots']
+ except Exception:
+ LOG.info("Cannot retrieve snapshots for cleanup.")
+ else:
+ for snapshot in volume_snapshots:
+ if snapshot['volumeId'] == cls.volume_id:
+ # Wait for snapshot status to become 'available' before
+ # deletion
+ waiters.wait_for_volume_resource_status(
+ cls.snapshots_client, snapshot['id'], 'available')
+ test_utils.call_and_ignore_notfound_exc(
+ cls.snapshots_client.delete_snapshot, snapshot['id'])
+
+ for snapshot in volume_snapshots:
+ if snapshot['volumeId'] == cls.volume_id:
+ test_utils.call_and_ignore_notfound_exc(
+ cls.snapshots_client.wait_for_resource_deletion,
+ snapshot['id'])
+
+ super(ServerActionsRbacTest, cls).resource_cleanup()
+
+ def _create_test_server_with_volume(self, volume_id):
+ # Create a server with the volume created earlier
+ server_name = data_utils.rand_name(self.__class__.__name__ + "-server")
+ bd_map_v2 = [{'uuid': volume_id,
+ 'source_type': 'volume',
+ 'destination_type': 'volume',
+ 'boot_index': 0,
+ 'delete_on_termination': True}]
+ device_mapping = {'block_device_mapping_v2': bd_map_v2}
+
+ # Since the server is booted from volume, the imageRef does not need
+ # to be specified.
+ server = self.client.create_server(name=server_name,
+ imageRef='',
+ flavorRef=CONF.compute.flavor_ref,
+ **device_mapping)['server']
+
+ waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE')
+
+ self.servers.append(server)
+ return server
+
def _test_start_server(self):
self.client.start_server(self.server_id)
waiters.wait_for_server_status(self.client, self.server_id,
@@ -206,6 +275,29 @@
self.rbac_utils.switch_role(self, switchToRbacRole=True)
self.client.show_server(self.server_id)
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:servers:create_image")
+ @decorators.idempotent_id('ba0ac859-99f4-4055-b5e0-e0905a44d331')
+ def test_create_image(self):
+ self.rbac_utils.switch_role(self, switchToRbacRole=True)
+
+ # This function will also call show image
+ self.create_image_from_server(self.server_id,
+ wait_until='ACTIVE')
+
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:servers:create_image:allow_volume_backed")
+ @decorators.idempotent_id('8b869f73-49b3-4cc4-a0ce-ef64f8e1d6f9')
+ def test_create_image_volume_backed(self):
+ server = self._create_test_server_with_volume(self.volume_id)
+ self.rbac_utils.switch_role(self, switchToRbacRole=True)
+
+ # This function will also call show image
+ self.create_image_from_server(server['id'],
+ wait_until='ACTIVE')
+
class ServerActionsV216RbacTest(rbac_base.BaseV2ComputeRbacTest):
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py
index 66798cd..3ae4c21 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py
@@ -26,6 +26,10 @@
class IdentityUserV3AdminRbacTest(
rbac_base.BaseIdentityV3RbacAdminTest):
+ def setUp(self):
+ super(IdentityUserV3AdminRbacTest, self).setUp()
+ self.default_user_id = self.auth_provider.credentials.user_id
+
@rbac_rule_validation.action(service="keystone",
rule="identity:create_user")
@decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d904')
@@ -82,16 +86,13 @@
@rbac_rule_validation.action(service="keystone",
rule="identity:get_user")
@decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d908')
- def test_show_user(self):
+ def test_show_own_user(self):
"""Get one user.
RBAC test for Keystone: identity:get_user
"""
- user_name = data_utils.rand_name('test_get_user')
- user = self._create_test_user(name=user_name, password=None)
-
self.rbac_utils.switch_role(self, switchToRbacRole=True)
- self.non_admin_users_client.show_user(user['id'])
+ self.non_admin_users_client.show_user(self.default_user_id)
@rbac_rule_validation.action(service="keystone",
rule="identity:change_password")
@@ -102,37 +103,33 @@
RBAC test for Keystone: identity:change_password
"""
user_name = data_utils.rand_name('test_change_password')
- user = self._create_test_user(name=user_name, password='nova')
+ original_password = data_utils.rand_password()
+ user = self._create_test_user(name=user_name,
+ password=original_password)
self.rbac_utils.switch_role(self, switchToRbacRole=True)
- self.non_admin_users_client \
- .update_user_password(user['id'],
- original_password='nova',
- password='neutron')
+ self.non_admin_users_client.update_user_password(
+ user['id'], original_password=original_password,
+ password=data_utils.rand_password())
@rbac_rule_validation.action(service="keystone",
rule="identity:list_groups_for_user")
@decorators.idempotent_id('bd5946d4-46d2-423d-a800-a3e7aabc18b3')
- def test_list_group_user(self):
+ def test_list_own_user_group(self):
"""Lists groups which a user belongs to.
RBAC test for Keystone: identity:list_groups_for_user
"""
- user_name = data_utils.rand_name('User')
- user = self._create_test_user(name=user_name, password=None)
-
self.rbac_utils.switch_role(self, switchToRbacRole=True)
- self.non_admin_users_client.list_user_groups(user['id'])
+ self.non_admin_users_client.list_user_groups(self.default_user_id)
@rbac_rule_validation.action(service="keystone",
rule="identity:list_user_projects")
@decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d909')
- def test_list_user_projects(self):
+ def test_list_own_user_projects(self):
"""List User's Projects.
RBAC test for Keystone: identity:list_user_projects
"""
- user = self.setup_test_user()
-
self.rbac_utils.switch_role(self, switchToRbacRole=True)
- self.non_admin_users_client.list_user_projects(user['id'])
+ self.non_admin_users_client.list_user_projects(self.default_user_id)
diff --git a/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py b/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
index 203384e..69aa32a 100644
--- a/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
@@ -94,6 +94,7 @@
create_router:external_gateway_info:external_fixed_ips policy
"""
name = data_utils.rand_name('snat-router')
+
# Pick an ip address within the allocation_pools range
ip_address = random.choice(list(self.admin_ip_range))
external_fixed_ips = {'subnet_id': self.admin_subnet['id'],
@@ -161,6 +162,10 @@
self.routers_client.update_router(
self.admin_router['id'],
external_gateway_info={'network_id': self.admin_network['id']})
+ self.addCleanup(
+ self.routers_client.update_router,
+ self.admin_router['id'],
+ external_gateway_info=None)
@rbac_rule_validation.action(
service="neutron",
@@ -177,6 +182,10 @@
self.admin_router['id'],
external_gateway_info={'network_id': self.admin_network['id'],
'enable_snat': True})
+ self.addCleanup(
+ self.routers_client.update_router,
+ self.admin_router['id'],
+ external_gateway_info=None)
@rbac_rule_validation.action(
service="neutron",