Add support for endpoint policy.
This adds the client library class for the endpoint policy extension. Implements: bp endpoint-policy Change-Id: I7153d7a093f4299d7f912b0b4a9a02ffacdb9e69
This commit is contained in:
@@ -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)
|
||||
|
242
keystoneclient/tests/v3/test_endpoint_policy.py
Normal file
242
keystoneclient/tests/v3/test_endpoint_policy.py
Normal file
@@ -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)
|
@@ -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)
|
||||
|
153
keystoneclient/v3/contrib/endpoint_policy.py
Normal file
153
keystoneclient/v3/contrib/endpoint_policy.py
Normal file
@@ -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)
|
Reference in New Issue
Block a user