Merge "Add access rules restriction tests"
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index 87b53e3..0a98ad5 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -40,7 +40,7 @@
"This value is only used to validate the versions "
"response from Manila."),
cfg.StrOpt("max_api_microversion",
- default="2.81",
+ default="2.82",
help="The maximum api microversion is configured to be the "
"value of the latest microversion supported by Manila."),
cfg.StrOpt("region",
diff --git a/manila_tempest_tests/services/share/v2/json/shares_client.py b/manila_tempest_tests/services/share/v2/json/shares_client.py
index d72c098..e3a022e 100644
--- a/manila_tempest_tests/services/share/v2/json/shares_client.py
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -819,7 +819,8 @@
def create_access_rule(self, share_id, access_type="ip",
access_to="0.0.0.0", access_level=None,
version=LATEST_MICROVERSION, metadata=None,
- action_name=None):
+ action_name=None, lock_visibility=False,
+ lock_deletion=False):
post_body = {
self._get_access_action_name(version, 'os-allow_access'): {
"access_type": access_type,
@@ -829,6 +830,10 @@
}
if metadata is not None:
post_body['allow_access']['metadata'] = metadata
+ if lock_visibility:
+ post_body['allow_access']['lock_visibility'] = True
+ if lock_deletion:
+ post_body['allow_access']['lock_deletion'] = True
body = json.dumps(post_body)
resp, body = self.post(
"shares/%s/action" % share_id, body, version=version,
@@ -872,12 +877,15 @@
return rest_client.ResponseBody(resp, body)
def delete_access_rule(self, share_id, rule_id,
- version=LATEST_MICROVERSION, action_name=None):
+ version=LATEST_MICROVERSION, action_name=None,
+ unrestrict=False):
post_body = {
self._get_access_action_name(version, 'os-deny_access'): {
"access_id": rule_id,
}
}
+ if unrestrict:
+ post_body['deny_access']['unrestrict'] = True
body = json.dumps(post_body)
resp, body = self.post(
"shares/%s/action" % share_id, body, version=version)
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index cb64ec8..2db2353 100755
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -1045,7 +1045,8 @@
def allow_access(self, share_id, client=None, access_type=None,
access_level='rw', access_to=None, metadata=None,
version=LATEST_MICROVERSION, status='active',
- raise_rule_in_error_state=True, cleanup=True):
+ raise_rule_in_error_state=True, lock_visibility=False,
+ lock_deletion=False, cleanup=True):
client = client or self.shares_v2_client
a_type, a_to = utils.get_access_rule_data_from_config(
@@ -1058,8 +1059,15 @@
'access_to': access_to,
'access_level': access_level
}
+ delete_kwargs = (
+ {'unrestrict': True} if lock_deletion else {}
+ )
if client is self.shares_v2_client:
kwargs.update({'metadata': metadata, 'version': version})
+ if lock_visibility:
+ kwargs.update({'lock_visibility': True})
+ if lock_deletion:
+ kwargs.update({'lock_deletion': True})
rule = client.create_access_rule(share_id, **kwargs)['access']
waiters.wait_for_resource_status(
@@ -1070,7 +1078,9 @@
self.addCleanup(
client.wait_for_resource_deletion, rule_id=rule['id'],
share_id=share_id, version=version)
- self.addCleanup(client.delete_access_rule, share_id, rule['id'])
+ self.addCleanup(
+ client.delete_access_rule, share_id, rule['id'],
+ **delete_kwargs)
return rule
diff --git a/manila_tempest_tests/tests/api/test_rules.py b/manila_tempest_tests/tests/api/test_rules.py
index 925b725..5f39852 100644
--- a/manila_tempest_tests/tests/api/test_rules.py
+++ b/manila_tempest_tests/tests/api/test_rules.py
@@ -28,6 +28,7 @@
CONF = config.CONF
LATEST_MICROVERSION = CONF.share.max_api_microversion
+RESTRICTED_RULES_VERSION = '2.82'
def _create_delete_ro_access_rule(self, version):
@@ -444,6 +445,10 @@
cls.share_type = cls.create_share_type()
cls.share_type_id = cls.share_type['id']
cls.share = cls.create_share(share_type_id=cls.share_type_id)
+ cls.user_project = cls.os_admin.projects_client.show_project(
+ cls.shares_v2_client.project_id)['project']
+ cls.new_user = cls.create_user_and_get_client(
+ project=cls.user_project)
@decorators.idempotent_id('c52e95cc-d6ea-4d02-9b52-cd7c1913dfff')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -519,6 +524,92 @@
msg = "expected id lists %s times in rule list" % (len(gen))
self.assertEqual(1, len(gen), msg)
+ @decorators.idempotent_id('3bca373e-e54f-49e1-8789-99a383cf4df3')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ @utils.skip_if_microversion_not_supported(RESTRICTED_RULES_VERSION)
+ @ddt.data(
+ *itertools.product(utils.deduplicate(
+ ["2.81", CONF.share.max_api_microversion]), (True, False))
+ )
+ @ddt.unpack
+ def test_list_restricted_rules_from_other_user(
+ self, older_version, lock_visibility):
+ # create rule
+ self.allow_access(
+ self.share["id"], client=self.shares_v2_client,
+ access_type=self.access_type, access_to=self.access_to,
+ lock_visibility=lock_visibility, lock_deletion=True)
+
+ rule = (
+ self.shares_v2_client.list_access_rules(
+ self.share["id"])["access_list"][0])
+
+ rules = self.new_user.shares_v2_client.list_access_rules(
+ self.share['id'])['access_list']
+ rules_get_lower_version = (
+ self.new_user.shares_v2_client.list_access_rules(
+ self.share['id'], version=older_version)['access_list'])
+ expected_access_to = '******' if lock_visibility else self.access_to
+ expected_access_key = (
+ '******' if lock_visibility else rule['access_key'])
+
+ # verify values
+ rule_latest_rules_api = [r for r in rules if r['id'] == rule['id']][0]
+ rule_lower_version_rules_api = [r for r in rules_get_lower_version
+ if r['id'] == rule['id']][0]
+ self.assertEqual(
+ expected_access_to, rule_latest_rules_api["access_to"])
+ self.assertEqual(
+ expected_access_to,
+ rule_lower_version_rules_api['access_to'])
+ if self.access_type == 'cephx':
+ self.assertEqual(expected_access_key,
+ rule_latest_rules_api['access_key'])
+ self.assertEqual(
+ expected_access_key,
+ rule_lower_version_rules_api['access_key'])
+
+ @decorators.idempotent_id('4829265a-eb32-400d-91a0-be06ce31a2ef')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ def test_admin_listing_restricted_rules(self):
+ utils.check_skip_if_microversion_not_supported(
+ RESTRICTED_RULES_VERSION)
+
+ # create rule
+ self.allow_access(
+ self.share["id"], client=self.shares_v2_client,
+ access_type=self.access_type, access_to=self.access_to,
+ lock_visibility=True)
+
+ rules = self.admin_shares_v2_client.list_access_rules(
+ self.share["id"])['access_list']
+
+ # ensure admin can see rules even if locked
+ self.assertEqual(self.access_to, rules[0]["access_to"])
+ if self.access_type == 'cephx':
+ self.assertIsNotNone(rules[0]['access_key'])
+ self.assertFalse(rules[0]['access_key'] == '******')
+ else:
+ self.assertIsNone(rules[0]['access_key'])
+
+ @decorators.idempotent_id('00202c6c-b4c7-4fa6-933a-562fbffde405')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ def test_admin_delete_restricted_rules(self):
+ utils.check_skip_if_microversion_not_supported(
+ RESTRICTED_RULES_VERSION)
+
+ # create rule
+ rule = self.allow_access(
+ self.share["id"], client=self.shares_v2_client,
+ access_type=self.access_type, access_to=self.access_to,
+ lock_visibility=True, lock_deletion=True, cleanup=False)
+
+ self.admin_shares_v2_client.delete_access_rule(
+ self.share['id'], rule['id'], unrestrict=True)
+
+ self.shares_v2_client.wait_for_resource_deletion(
+ rule_id=rule['id'], share_id=self.share['id'])
+
@decorators.idempotent_id('b77bcbda-9754-48f0-9be6-79341ad1af64')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@ddt.data(*utils.deduplicate(['1.0', '2.9', '2.27', '2.28',
diff --git a/manila_tempest_tests/tests/api/test_rules_negative.py b/manila_tempest_tests/tests/api/test_rules_negative.py
index a4b53f5..32c4e9f 100644
--- a/manila_tempest_tests/tests/api/test_rules_negative.py
+++ b/manila_tempest_tests/tests/api/test_rules_negative.py
@@ -28,6 +28,7 @@
CONF = config.CONF
LATEST_MICROVERSION = CONF.share.max_api_microversion
+RESTRICTED_RULES_VERSION = '2.82'
@ddt.ddt
@@ -60,6 +61,11 @@
# create snapshot
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
+ cls.user_project = cls.os_admin.projects_client.show_project(
+ cls.shares_v2_client.project_id)['project']
+ cls.new_user = cls.create_user_and_get_client(
+ project=cls.user_project)
+
@decorators.idempotent_id('16781b45-d2bb-4891-aa97-c28c0769d5bd')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@ddt.data('1.2.3.256',
@@ -170,6 +176,93 @@
self.admin_client.create_access_rule,
share["id"], access_type, access_to)
+ @decorators.idempotent_id('478d3c84-b0ea-41c8-a860-e87f182d991c')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+ def test_deny_access_unrestrict_other_user_rule(self):
+ utils.check_skip_if_microversion_not_supported(
+ RESTRICTED_RULES_VERSION)
+
+ access_type, access_to = utils.get_access_rule_data_from_config(
+ self.protocol)
+
+ # create rule
+ rule = self.allow_access(
+ self.share["id"], client=self.shares_v2_client,
+ access_type=access_type, access_to=access_to,
+ lock_visibility=True, lock_deletion=True)
+
+ self.assertRaises(
+ lib_exc.Forbidden,
+ self.new_user.shares_v2_client.delete_access_rule,
+ self.share['id'],
+ rule['id'],
+ unrestrict=True
+ )
+
+ @decorators.idempotent_id('c107b0b7-7a3e-4114-af64-ca8fe6e836c9')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ @ddt.data(True, False)
+ def test_deny_access_without_unrestrict_as_owner_user(self, same_user):
+ utils.check_skip_if_microversion_not_supported(
+ RESTRICTED_RULES_VERSION)
+ access_type, access_to = utils.get_access_rule_data_from_config(
+ self.protocol)
+
+ # create rule
+ rule = self.allow_access(
+ self.share["id"], client=self.shares_v2_client,
+ access_type=access_type, access_to=access_to,
+ lock_visibility=True, lock_deletion=True)
+
+ client = (
+ self.shares_v2_client
+ if same_user else self.new_user.shares_v2_client
+ )
+ self.assertRaises(
+ lib_exc.Forbidden,
+ client.delete_access_rule,
+ self.share['id'],
+ rule['id'])
+ self.assertRaises(
+ lib_exc.Forbidden,
+ client.delete_access_rule,
+ self.share['id'],
+ rule['id'],
+ version='2.81'
+ )
+
+ @decorators.idempotent_id('f5b9e7c9-7e6b-4918-a1c4-e03c8d82c46a')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+ def test_allow_access_multiple_visibility_locks_not_allowed(self):
+ utils.check_skip_if_microversion_not_supported(
+ RESTRICTED_RULES_VERSION)
+ access_type, access_to = utils.get_access_rule_data_from_config(
+ self.protocol)
+
+ # create rule
+ rule = self.allow_access(
+ self.share["id"], client=self.shares_v2_client,
+ access_type=access_type, access_to=access_to,
+ lock_visibility=True, lock_deletion=True)
+
+ self.assertRaises(
+ lib_exc.Conflict,
+ self.shares_v2_client.create_resource_lock,
+ rule['id'],
+ "access_rule",
+ resource_action="show",
+ lock_reason="locked for testing"
+ )
+
+ self.assertRaises(
+ lib_exc.Conflict,
+ self.new_user.shares_v2_client.create_resource_lock,
+ rule['id'],
+ "access_rule",
+ resource_action="show",
+ lock_reason="locked for testing"
+ )
+
@ddt.ddt
class ShareIpRulesForCIFSNegativeTest(ShareIpRulesForNFSNegativeTest):