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:
Henry Nash
2014-09-18 09:59:38 +01:00
parent 118763cbe0
commit 98b240fe50
4 changed files with 418 additions and 12 deletions

View File

@@ -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)

View 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)

View File

@@ -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)

View 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)