Merge "Add Access Rules tests"
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 282343c..5722f0e 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -192,6 +192,7 @@
cls.os_primary.identity_versions_v3_client
cls.non_admin_app_creds_client = \
cls.os_primary.application_credentials_client
+ cls.non_admin_access_rules_client = cls.os_primary.access_rules_client
class BaseIdentityV3AdminTest(BaseIdentityV3Test):
diff --git a/tempest/api/identity/v3/test_access_rules.py b/tempest/api/identity/v3/test_access_rules.py
new file mode 100644
index 0000000..608eb59
--- /dev/null
+++ b/tempest/api/identity/v3/test_access_rules.py
@@ -0,0 +1,84 @@
+# Copyright 2019 SUSE LLC
+#
+# 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.api.identity import base
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+CONF = config.CONF
+
+
+class AccessRulesV3Test(base.BaseIdentityV3Test):
+
+ @classmethod
+ def skip_checks(cls):
+ super(AccessRulesV3Test, cls).skip_checks()
+ if not CONF.identity_feature_enabled.access_rules:
+ raise cls.skipException("Application credential access rules are "
+ "not available in this environment")
+
+ @classmethod
+ def resource_setup(cls):
+ super(AccessRulesV3Test, cls).resource_setup()
+ cls.user_id = cls.os_primary.credentials.user_id
+ cls.project_id = cls.os_primary.credentials.project_id
+
+ def setUp(self):
+ super(AccessRulesV3Test, self).setUp()
+ ac = self.non_admin_app_creds_client
+ access_rules = [
+ {
+ "path": "/v2.1/servers/*/ips",
+ "method": "GET",
+ "service": "compute"
+ }
+ ]
+ self.app_cred = ac.create_application_credential(
+ self.user_id,
+ name=data_utils.rand_name('application_credential'),
+ access_rules=access_rules
+ )['application_credential']
+
+ @decorators.idempotent_id('2354c498-5119-4ba5-9f0d-44f16f78fb0e')
+ def test_list_access_rules(self):
+ ar = self.non_admin_access_rules_client.list_access_rules(self.user_id)
+ self.assertEqual(1, len(ar['access_rules']))
+
+ @decorators.idempotent_id('795dd507-ca1e-40e9-ba90-ff0a08689ba4')
+ def test_show_access_rule(self):
+ access_rule_id = self.app_cred['access_rules'][0]['id']
+ self.non_admin_access_rules_client.show_access_rule(
+ self.user_id, access_rule_id)
+
+ @decorators.idempotent_id('278757e9-e193-4bf8-adf2-0b0a229a17d0')
+ def test_delete_access_rule(self):
+ access_rule_id = self.app_cred['access_rules'][0]['id']
+ app_cred_id = self.app_cred['id']
+ self.assertRaises(
+ lib_exc.Forbidden,
+ self.non_admin_access_rules_client.delete_access_rule,
+ self.user_id,
+ access_rule_id)
+ self.non_admin_app_creds_client.delete_application_credential(
+ self.user_id, app_cred_id)
+ ar = self.non_admin_access_rules_client.list_access_rules(self.user_id)
+ self.assertEqual(1, len(ar['access_rules']))
+ self.non_admin_access_rules_client.delete_access_rule(
+ self.user_id, access_rule_id)
+ ar = self.non_admin_access_rules_client.list_access_rules(self.user_id)
+ self.assertEqual(0, len(ar['access_rules']))
diff --git a/tempest/api/identity/v3/test_application_credentials.py b/tempest/api/identity/v3/test_application_credentials.py
index ef1bbdf..77ad720 100644
--- a/tempest/api/identity/v3/test_application_credentials.py
+++ b/tempest/api/identity/v3/test_application_credentials.py
@@ -19,8 +19,11 @@
from oslo_utils import timeutils
from tempest.api.identity import base
+from tempest import config
from tempest.lib import decorators
+CONF = config.CONF
+
class ApplicationCredentialsV3Test(base.BaseApplicationCredentialsV3Test):
"""Test application credentials"""
@@ -65,6 +68,24 @@
expires_str = expires_at.isoformat()
self.assertEqual(expires_str, app_cred['expires_at'])
+ @decorators.idempotent_id('529936eb-aa5d-463d-9f79-01c113d3b88f')
+ def test_create_application_credential_access_rules(self):
+ if not CONF.identity_feature_enabled.access_rules:
+ raise self.skipException("Application credential access rules are "
+ "not available in this environment")
+ access_rules = [
+ {
+ "path": "/v2.1/servers/*/ips",
+ "method": "GET",
+ "service": "compute"
+ }
+ ]
+ app_cred = self.create_application_credential(
+ access_rules=access_rules)
+ access_rule_resp = app_cred['access_rules'][0]
+ access_rule_resp.pop('id')
+ self.assertDictEqual(access_rules[0], access_rule_resp)
+
@decorators.idempotent_id('ff0cd457-6224-46e7-b79e-0ada4964a8a6')
def test_list_application_credentials(self):
"""Test listing application credentials"""
diff --git a/tempest/clients.py b/tempest/clients.py
index 1db93a0..8363a8d 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -203,6 +203,8 @@
**params_v3)
self.application_credentials_client = \
self.identity_v3.ApplicationCredentialsClient(**params_v3)
+ self.access_rules_client = \
+ self.identity_v3.AccessRulesClient(**params_v3)
# Token clients do not use the catalog. They only need default_params.
# They read auth_url, so they should only be set if the corresponding
diff --git a/tempest/config.py b/tempest/config.py
index 36ad405..5b7efa5 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -250,6 +250,11 @@
default=False,
help='Does the environment have application credentials '
'enabled?'),
+ # Access rules for application credentials is a default feature in Train.
+ # This config option can removed once Stein is EOL.
+ cfg.BoolOpt('access_rules',
+ default=False,
+ help='Does the environment have access rules enabled?'),
cfg.BoolOpt('immutable_user_source',
default=False,
help='Set to True if the environment has a read-only '
diff --git a/tempest/lib/services/identity/v3/__init__.py b/tempest/lib/services/identity/v3/__init__.py
index da1c51c..86fa991 100644
--- a/tempest/lib/services/identity/v3/__init__.py
+++ b/tempest/lib/services/identity/v3/__init__.py
@@ -12,6 +12,8 @@
# License for the specific language governing permissions and limitations under
# the License.
+from tempest.lib.services.identity.v3.access_rules_client import \
+ AccessRulesClient
from tempest.lib.services.identity.v3.application_credentials_client import \
ApplicationCredentialsClient
from tempest.lib.services.identity.v3.catalog_client import \
@@ -48,9 +50,10 @@
from tempest.lib.services.identity.v3.users_client import UsersClient
from tempest.lib.services.identity.v3.versions_client import VersionsClient
-__all__ = ['ApplicationCredentialsClient', 'CatalogClient',
- 'CredentialsClient', 'DomainsClient', 'DomainConfigurationClient',
- 'EndPointGroupsClient', 'EndPointsClient', 'EndPointsFilterClient',
+__all__ = ['AccessRulesClient', 'ApplicationCredentialsClient',
+ 'CatalogClient', 'CredentialsClient', 'DomainsClient',
+ 'DomainConfigurationClient', 'EndPointGroupsClient',
+ 'EndPointsClient', 'EndPointsFilterClient',
'GroupsClient', 'IdentityClient', 'InheritedRolesClient',
'OAUTHConsumerClient', 'OAUTHTokenClient', 'PoliciesClient',
'ProjectsClient', 'ProjectTagsClient', 'RegionsClient',
diff --git a/tempest/lib/services/identity/v3/access_rules_client.py b/tempest/lib/services/identity/v3/access_rules_client.py
new file mode 100644
index 0000000..4f13e47
--- /dev/null
+++ b/tempest/lib/services/identity/v3/access_rules_client.py
@@ -0,0 +1,68 @@
+# Copyright 2019 SUSE LLC
+#
+# 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.
+
+"""
+https://docs.openstack.org/api-ref/identity/v3/index.html#application-credentials
+"""
+
+from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
+
+from tempest.lib.common import rest_client
+
+
+class AccessRulesClient(rest_client.RestClient):
+ api_version = "v3"
+
+ def show_access_rule(self, user_id, access_rule_id):
+ """Gets details of an access rule.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://docs.openstack.org/api-ref/identity/v3/index.html#show-access-rule-details
+ """
+ resp, body = self.get('users/%s/access_rules/%s' %
+ (user_id, access_rule_id))
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def list_access_rules(self, user_id, **params):
+ """Lists out all of a user's access rules.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://docs.openstack.org/api-ref/identity/v3/index.html#list-access-rules
+ """
+ url = 'users/%s/access_rules' % user_id
+ if params:
+ url += '?%s' % urllib.urlencode(params)
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_access_rule(self, user_id, access_rule_id):
+ """Deletes an access rule.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://docs.openstack.org/api-ref/identity/v3/index.html#delete-access-rule
+ """
+ resp, body = self.delete('users/%s/access_rules/%s' %
+ (user_id, access_rule_id))
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/tests/lib/services/identity/v3/test_access_rules_client.py b/tempest/tests/lib/services/identity/v3/test_access_rules_client.py
new file mode 100644
index 0000000..71c9cde
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_access_rules_client.py
@@ -0,0 +1,97 @@
+# Copyright 2019 SUSE LLC
+#
+# 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.services.identity.v3 import access_rules_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestAccessRulesClient(base.BaseServiceTest):
+ FAKE_LIST_ACCESS_RULES = {
+ "links": {
+ "self": "https://example.com/identity/v3/users/" +
+ "3e0716ae/access_rules",
+ "previous": None,
+ "next": None
+ },
+ "access_rules": [
+ {
+ "path": "/v2.0/metrics",
+ "links": {
+ "self": "https://example.com/identity/v3/access_rules/" +
+ "07d719df00f349ef8de77d542edf010c"
+ },
+ "id": "07d719df00f349ef8de77d542edf010c",
+ "service": "monitoring",
+ "method": "GET"
+ }
+ ]
+ }
+
+ FAKE_ACCESS_RULE_INFO = {
+ "access_rule": {
+ "path": "/v2.0/metrics",
+ "links": {
+ "self": "https://example.com/identity/v3/access_rules/" +
+ "07d719df00f349ef8de77d542edf010c"
+ },
+ "id": "07d719df00f349ef8de77d542edf010c",
+ "service": "monitoring",
+ "method": "GET"
+ }
+ }
+
+ def setUp(self):
+ super(TestAccessRulesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = access_rules_client.AccessRulesClient(
+ fake_auth, 'identity', 'regionOne')
+
+ def _test_show_access_rule(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_access_rule,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_ACCESS_RULE_INFO,
+ bytes_body,
+ user_id="123456",
+ access_rule_id="5499a186")
+
+ def _test_list_access_rules(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_access_rules,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_ACCESS_RULES,
+ bytes_body,
+ user_id="123456")
+
+ def test_show_access_rule_with_str_body(self):
+ self._test_show_access_rule()
+
+ def test_show_access_rule_with_bytes_body(self):
+ self._test_show_access_rule(bytes_body=True)
+
+ def test_list_access_rule_with_str_body(self):
+ self._test_list_access_rules()
+
+ def test_list_access_rule_with_bytes_body(self):
+ self._test_list_access_rules(bytes_body=True)
+
+ def test_delete_access_rule(self):
+ self.check_service_client_function(
+ self.client.delete_access_rule,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ user_id="123456",
+ access_rule_id="5499a186",
+ status=204)