summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry Nash <henryn@linux.vnet.ibm.com>2014-09-18 09:59:38 +0100
committerHenry Nash <henryn@linux.vnet.ibm.com>2014-09-18 22:27:15 +0100
commit98b240fe50a4c25f8baf67a9f1192d6637910631 (patch)
treefee85d970352da8353acc7977122bf1f50f149ea
parent118763cbe00e00e7b78b926e21e69ec479212b1b (diff)
downloadpython-keystoneclient-98b240fe50a4c25f8baf67a9f1192d6637910631.tar.gz
Add support for endpoint policy.
This adds the client library class for the endpoint policy extension. Implements: bp endpoint-policy Change-Id: I7153d7a093f4299d7f912b0b4a9a02ffacdb9e69
-rw-r--r--keystoneclient/tests/v3/test_endpoint_filter.py28
-rw-r--r--keystoneclient/tests/v3/test_endpoint_policy.py242
-rw-r--r--keystoneclient/v3/client.py7
-rw-r--r--keystoneclient/v3/contrib/endpoint_policy.py153
4 files changed, 418 insertions, 12 deletions
diff --git a/keystoneclient/tests/v3/test_endpoint_filter.py b/keystoneclient/tests/v3/test_endpoint_filter.py
index f4be431..867193a 100644
--- a/keystoneclient/tests/v3/test_endpoint_filter.py
+++ b/keystoneclient/tests/v3/test_endpoint_filter.py
@@ -17,18 +17,8 @@ import uuid
from keystoneclient.tests.v3 import utils
-class EndpointFilterTests(utils.TestCase):
- """Test project-endpoint associations (a.k.a. EndpointFilter Extension).
-
- Endpoint filter provides associations between service endpoints and
- projects. These assciations are then used to create ad-hoc catalogs for
- each project-scoped token request.
-
- """
-
- def setUp(self):
- super(EndpointFilterTests, self).setUp()
- self.manager = self.client.endpoint_filter
+class EndpointTestUtils(object):
+ """Mixin class with shared methods between Endpoint Filter & Policy."""
def new_ref(self, **kwargs):
# copied from CrudTests as we need to create endpoint and project
@@ -46,6 +36,20 @@ class EndpointFilterTests(utils.TestCase):
kwargs.setdefault('url', uuid.uuid4().hex)
return kwargs
+
+class EndpointFilterTests(utils.TestCase, EndpointTestUtils):
+ """Test project-endpoint associations (a.k.a. EndpointFilter Extension).
+
+ Endpoint filter provides associations between service endpoints and
+ projects. These assciations are then used to create ad-hoc catalogs for
+ each project-scoped token request.
+
+ """
+
+ def setUp(self):
+ super(EndpointFilterTests, self).setUp()
+ self.manager = self.client.endpoint_filter
+
def new_project_ref(self, **kwargs):
# copied from ProjectTests as we need project refs for our tests
kwargs = self.new_ref(**kwargs)
diff --git a/keystoneclient/tests/v3/test_endpoint_policy.py b/keystoneclient/tests/v3/test_endpoint_policy.py
new file mode 100644
index 0000000..59a9079
--- /dev/null
+++ b/keystoneclient/tests/v3/test_endpoint_policy.py
@@ -0,0 +1,242 @@
+# Copyright 2014 IBM Corp.
+#
+# 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.
+
+import uuid
+
+from keystoneclient.tests.v3 import test_endpoint_filter
+from keystoneclient.tests.v3 import utils
+
+
+class EndpointPolicyTests(utils.TestCase,
+ test_endpoint_filter.EndpointTestUtils):
+ """Test policy-endpoint associations (a.k.a. EndpointPolicy Extension)."""
+
+ def setUp(self):
+ super(EndpointPolicyTests, self).setUp()
+ self.manager = self.client.endpoint_policy
+
+ def new_policy_ref(self, **kwargs):
+ kwargs.setdefault('id', uuid.uuid4().hex)
+ kwargs.setdefault('type', uuid.uuid4().hex)
+ kwargs.setdefault('blob', uuid.uuid4().hex)
+ return kwargs
+
+ def new_region_ref(self, **kwargs):
+ kwargs = self.new_ref(**kwargs)
+ return kwargs
+
+ def new_service_ref(self, **kwargs):
+ kwargs = self.new_ref(**kwargs)
+ kwargs.setdefault('name', uuid.uuid4().hex)
+ kwargs.setdefault('type', uuid.uuid4().hex)
+ return kwargs
+
+ def _crud_policy_association_for_endpoint_via_id(
+ self, http_action, manager_action):
+ policy_id = uuid.uuid4().hex
+ endpoint_id = uuid.uuid4().hex
+
+ self.stub_url(http_action,
+ ['policies', policy_id, self.manager.OS_EP_POLICY_EXT,
+ 'endpoints', endpoint_id],
+ status_code=204)
+ manager_action(policy=policy_id, endpoint=endpoint_id)
+
+ def _crud_policy_association_for_endpoint_via_obj(
+ self, http_action, manager_action):
+ policy_ref = self.new_policy_ref()
+ endpoint_ref = self.new_endpoint_ref()
+ policy = self.client.projects.resource_class(
+ self.client.policies, policy_ref, loaded=True)
+ endpoint = self.client.endpoints.resource_class(
+ self.client.endpoints, endpoint_ref, loaded=True)
+
+ self.stub_url(http_action,
+ ['policies', policy_ref['id'],
+ self.manager.OS_EP_POLICY_EXT,
+ 'endpoints', endpoint_ref['id']],
+ status_code=204)
+ manager_action(policy=policy, endpoint=endpoint)
+
+ def test_create_policy_association_for_endpoint_via_id(self):
+ self._crud_policy_association_for_endpoint_via_id(
+ 'PUT', self.manager.create_policy_association_for_endpoint)
+
+ def test_create_policy_association_for_endpoint_via_obj(self):
+ self._crud_policy_association_for_endpoint_via_obj(
+ 'PUT', self.manager.create_policy_association_for_endpoint)
+
+ def test_check_policy_association_for_endpoint_via_id(self):
+ self._crud_policy_association_for_endpoint_via_id(
+ 'HEAD', self.manager.check_policy_association_for_endpoint)
+
+ def test_check_policy_association_for_endpoint_via_obj(self):
+ self._crud_policy_association_for_endpoint_via_obj(
+ 'HEAD', self.manager.check_policy_association_for_endpoint)
+
+ def test_delete_policy_association_for_endpoint_via_id(self):
+ self._crud_policy_association_for_endpoint_via_id(
+ 'DELETE', self.manager.delete_policy_association_for_endpoint)
+
+ def test_delete_policy_association_for_endpoint_via_obj(self):
+ self._crud_policy_association_for_endpoint_via_obj(
+ 'DELETE', self.manager.delete_policy_association_for_endpoint)
+
+ def _crud_policy_association_for_service_via_id(
+ self, http_action, manager_action):
+ policy_id = uuid.uuid4().hex
+ service_id = uuid.uuid4().hex
+
+ self.stub_url(http_action,
+ ['policies', policy_id, self.manager.OS_EP_POLICY_EXT,
+ 'services', service_id],
+ status_code=204)
+ manager_action(policy=policy_id, service=service_id)
+
+ def _crud_policy_association_for_service_via_obj(
+ self, http_action, manager_action):
+ policy_ref = self.new_policy_ref()
+ service_ref = self.new_service_ref()
+ policy = self.client.projects.resource_class(
+ self.client.policies, policy_ref, loaded=True)
+ service = self.client.services.resource_class(
+ self.client.services, service_ref, loaded=True)
+
+ self.stub_url(http_action,
+ ['policies', policy_ref['id'],
+ self.manager.OS_EP_POLICY_EXT,
+ 'services', service_ref['id']],
+ status_code=204)
+ manager_action(policy=policy, service=service)
+
+ def test_create_policy_association_for_service_via_id(self):
+ self._crud_policy_association_for_service_via_id(
+ 'PUT', self.manager.create_policy_association_for_service)
+
+ def test_create_policy_association_for_service_via_obj(self):
+ self._crud_policy_association_for_service_via_obj(
+ 'PUT', self.manager.create_policy_association_for_service)
+
+ def test_check_policy_association_for_service_via_id(self):
+ self._crud_policy_association_for_service_via_id(
+ 'HEAD', self.manager.check_policy_association_for_service)
+
+ def test_check_policy_association_for_service_via_obj(self):
+ self._crud_policy_association_for_service_via_obj(
+ 'HEAD', self.manager.check_policy_association_for_service)
+
+ def test_delete_policy_association_for_service_via_id(self):
+ self._crud_policy_association_for_service_via_id(
+ 'DELETE', self.manager.delete_policy_association_for_service)
+
+ def test_delete_policy_association_for_service_via_obj(self):
+ self._crud_policy_association_for_service_via_obj(
+ 'DELETE', self.manager.delete_policy_association_for_service)
+
+ def _crud_policy_association_for_region_and_service_via_id(
+ self, http_action, manager_action):
+ policy_id = uuid.uuid4().hex
+ region_id = uuid.uuid4().hex
+ service_id = uuid.uuid4().hex
+
+ self.stub_url(http_action,
+ ['policies', policy_id, self.manager.OS_EP_POLICY_EXT,
+ 'services', service_id, 'regions', region_id],
+ status_code=204)
+ manager_action(policy=policy_id, region=region_id, service=service_id)
+
+ def _crud_policy_association_for_region_and_service_via_obj(
+ self, http_action, manager_action):
+ policy_ref = self.new_policy_ref()
+ region_ref = self.new_region_ref()
+ service_ref = self.new_service_ref()
+ policy = self.client.projects.resource_class(
+ self.client.policies, policy_ref, loaded=True)
+ region = self.client.regions.resource_class(
+ self.client.regions, region_ref, loaded=True)
+ service = self.client.services.resource_class(
+ self.client.services, service_ref, loaded=True)
+
+ self.stub_url(http_action,
+ ['policies', policy_ref['id'],
+ self.manager.OS_EP_POLICY_EXT,
+ 'services', service_ref['id'],
+ 'regions', region_ref['id']],
+ status_code=204)
+ manager_action(policy=policy, region=region, service=service)
+
+ def test_create_policy_association_for_region_and_service_via_id(self):
+ self._crud_policy_association_for_region_and_service_via_id(
+ 'PUT',
+ self.manager.create_policy_association_for_region_and_service)
+
+ def test_create_policy_association_for_region_and_service_via_obj(self):
+ self._crud_policy_association_for_region_and_service_via_obj(
+ 'PUT',
+ self.manager.create_policy_association_for_region_and_service)
+
+ def test_check_policy_association_for_region_and_service_via_id(self):
+ self._crud_policy_association_for_region_and_service_via_id(
+ 'HEAD',
+ self.manager.check_policy_association_for_region_and_service)
+
+ def test_check_policy_association_for_region_and_service_via_obj(self):
+ self._crud_policy_association_for_region_and_service_via_obj(
+ 'HEAD',
+ self.manager.check_policy_association_for_region_and_service)
+
+ def test_delete_policy_association_for_region_and_service_via_id(self):
+ self._crud_policy_association_for_region_and_service_via_id(
+ 'DELETE',
+ self.manager.delete_policy_association_for_region_and_service)
+
+ def test_delete_policy_association_for_region_and_service_via_obj(self):
+ self._crud_policy_association_for_region_and_service_via_obj(
+ 'DELETE',
+ self.manager.delete_policy_association_for_region_and_service)
+
+ def test_get_policy_for_endpoint(self):
+ endpoint_id = uuid.uuid4().hex
+ expected_policy = self.new_policy_ref()
+
+ self.stub_url('GET',
+ ['endpoints', endpoint_id, self.manager.OS_EP_POLICY_EXT,
+ 'policy'],
+ json={'policy': expected_policy},
+ status_code=200)
+
+ policy_resp = self.manager.get_policy_for_endpoint(
+ endpoint=endpoint_id)
+
+ self.assertEqual(expected_policy['id'], policy_resp.id)
+ self.assertEqual(expected_policy['blob'], policy_resp.blob)
+ self.assertEqual(expected_policy['type'], policy_resp.type)
+
+ def test_list_endpoints_for_policy(self):
+ policy_id = uuid.uuid4().hex
+ endpoints = {'endpoints': [self.new_endpoint_ref(),
+ self.new_endpoint_ref()]}
+ self.stub_url('GET',
+ ['policies', policy_id, self.manager.OS_EP_POLICY_EXT,
+ 'endpoints'],
+ json=endpoints,
+ status_code=200)
+
+ endpoints_resp = self.manager.list_endpoints_for_policy(
+ policy=policy_id)
+
+ expected_endpoint_ids = [
+ endpoint['id'] for endpoint in endpoints['endpoints']]
+ actual_endpoint_ids = [endpoint.id for endpoint in endpoints_resp]
+ self.assertEqual(expected_endpoint_ids, actual_endpoint_ids)
diff --git a/keystoneclient/v3/client.py b/keystoneclient/v3/client.py
index 316588c..a271db3 100644
--- a/keystoneclient/v3/client.py
+++ b/keystoneclient/v3/client.py
@@ -20,6 +20,7 @@ from keystoneclient import exceptions
from keystoneclient import httpclient
from keystoneclient.openstack.common import jsonutils
from keystoneclient.v3.contrib import endpoint_filter
+from keystoneclient.v3.contrib import endpoint_policy
from keystoneclient.v3.contrib import federation
from keystoneclient.v3.contrib import oauth1
from keystoneclient.v3.contrib import trusts
@@ -101,6 +102,11 @@ class Client(httpclient.HTTPClient):
:py:class:`keystoneclient.v3.contrib.endpoint_filter.\
EndpointFilterManager`
+ .. py:attribute:: endpoint_policy
+
+ :py:class:`keystoneclient.v3.contrib.endpoint_policy.\
+EndpointPolicyManager`
+
.. py:attribute:: endpoints
:py:class:`keystoneclient.v3.endpoints.EndpointManager`
@@ -163,6 +169,7 @@ EndpointFilterManager`
self.credentials = credentials.CredentialManager(self)
self.endpoint_filter = endpoint_filter.EndpointFilterManager(self)
+ self.endpoint_policy = endpoint_policy.EndpointPolicyManager(self)
self.endpoints = endpoints.EndpointManager(self)
self.domains = domains.DomainManager(self)
self.federation = federation.FederationManager(self)
diff --git a/keystoneclient/v3/contrib/endpoint_policy.py b/keystoneclient/v3/contrib/endpoint_policy.py
new file mode 100644
index 0000000..9d4d997
--- /dev/null
+++ b/keystoneclient/v3/contrib/endpoint_policy.py
@@ -0,0 +1,153 @@
+# Copyright 2014 IBM Corp.
+#
+# 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 keystoneclient import base
+from keystoneclient.v3 import policies
+
+
+class EndpointPolicyManager(base.Manager):
+ """Manager class for manipulating endpoint-policy associations."""
+
+ OS_EP_POLICY_EXT = 'OS-ENDPOINT-POLICY'
+
+ def _act_on_policy_association_for_endpoint(
+ self, policy, endpoint, action):
+ if not (policy and endpoint):
+ raise ValueError('policy and endpoint are required')
+
+ policy_id = base.getid(policy)
+ endpoint_id = base.getid(endpoint)
+ url = ('/policies/%(policy_id)s/%(ext_name)s'
+ '/endpoints/%(endpoint_id)s') % {
+ 'policy_id': policy_id,
+ 'ext_name': self.OS_EP_POLICY_EXT,
+ 'endpoint_id': endpoint_id}
+ return action(url=url)
+
+ def create_policy_association_for_endpoint(self, policy, endpoint):
+ """Create an association between a policy and an endpoint."""
+ self._act_on_policy_association_for_endpoint(
+ policy, endpoint, self._put)
+
+ def check_policy_association_for_endpoint(self, policy, endpoint):
+ """Check an association between a policy and an endpoint."""
+ self._act_on_policy_association_for_endpoint(
+ policy, endpoint, self._head)
+
+ def delete_policy_association_for_endpoint(self, policy, endpoint):
+ """Delete an association between a policy and an endpoint."""
+ self._act_on_policy_association_for_endpoint(
+ policy, endpoint, self._delete)
+
+ def _act_on_policy_association_for_service(self, policy, service, action):
+ if not (policy and service):
+ raise ValueError('policy and service are required')
+
+ policy_id = base.getid(policy)
+ service_id = base.getid(service)
+ url = ('/policies/%(policy_id)s/%(ext_name)s'
+ '/services/%(service_id)s') % {
+ 'policy_id': policy_id,
+ 'ext_name': self.OS_EP_POLICY_EXT,
+ 'service_id': service_id}
+ return action(url=url)
+
+ def create_policy_association_for_service(self, policy, service):
+ """Create an association between a policy and a service."""
+ self._act_on_policy_association_for_service(
+ policy, service, self._put)
+
+ def check_policy_association_for_service(self, policy, service):
+ """Check an association between a policy and a service."""
+ self._act_on_policy_association_for_service(
+ policy, service, self._head)
+
+ def delete_policy_association_for_service(self, policy, service):
+ """Delete an association between a policy and a service."""
+ self._act_on_policy_association_for_service(
+ policy, service, self._delete)
+
+ def _act_on_policy_association_for_region_and_service(
+ self, policy, region, service, action):
+ if not (policy and region and service):
+ raise ValueError('policy, region and service are required')
+
+ policy_id = base.getid(policy)
+ region_id = base.getid(region)
+ service_id = base.getid(service)
+ url = ('/policies/%(policy_id)s/%(ext_name)s'
+ '/services/%(service_id)s/regions/%(region_id)s') % {
+ 'policy_id': policy_id,
+ 'ext_name': self.OS_EP_POLICY_EXT,
+ 'service_id': service_id,
+ 'region_id': region_id}
+ return action(url=url)
+
+ def create_policy_association_for_region_and_service(
+ self, policy, region, service):
+ """Create an association between a policy and a service in a region."""
+ self._act_on_policy_association_for_region_and_service(
+ policy, region, service, self._put)
+
+ def check_policy_association_for_region_and_service(
+ self, policy, region, service):
+ """Check an association between a policy and a service in a region."""
+ self._act_on_policy_association_for_region_and_service(
+ policy, region, service, self._head)
+
+ def delete_policy_association_for_region_and_service(
+ self, policy, region, service):
+ """Delete an association between a policy and a service in a region."""
+ self._act_on_policy_association_for_region_and_service(
+ policy, region, service, self._delete)
+
+ def get_policy_for_endpoint(self, endpoint):
+ """Get the effective policy for an endpoint.
+
+ :param endpoint: endpoint object or ID
+
+ :returns: policies.Policy object
+
+ """
+ if not endpoint:
+ raise ValueError('endpoint is required')
+
+ endpoint_id = base.getid(endpoint)
+ url = ('/endpoints/%(endpoint_id)s/%(ext_name)s/policy') % {
+ 'endpoint_id': endpoint_id,
+ 'ext_name': self.OS_EP_POLICY_EXT}
+
+ _resp, body = self.client.get(url)
+ return policies.Policy(
+ self, body[policies.PolicyManager.key], loaded=True)
+
+ def list_endpoints_for_policy(self, policy):
+ """List endpoints with the effective association to a policy.
+
+ :param policy: policy object or ID
+
+ :returns: list of endpoints that are associated with the policy
+
+ """
+ if not policy:
+ raise ValueError('policy is required')
+
+ policy_id = base.getid(policy)
+ url = ('/policies/%(policy_id)s/%(ext_name)s/endpoints') % {
+ 'policy_id': policy_id,
+ 'ext_name': self.OS_EP_POLICY_EXT}
+ return self._list(
+ url,
+ self.client.endpoints.collection_key,
+ obj_class=self.client.endpoints.resource_class)