Merge "Implement endpoint filtering functionality on the client side."
This commit is contained in:
153
keystoneclient/tests/v3/test_endpoint_filter.py
Normal file
153
keystoneclient/tests/v3/test_endpoint_filter.py
Normal file
@@ -0,0 +1,153 @@
|
||||
# Copyright 2014 OpenStack Foundation
|
||||
#
|
||||
# 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
|
||||
|
||||
import httpretty
|
||||
|
||||
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
|
||||
|
||||
def new_ref(self, **kwargs):
|
||||
# copied from CrudTests as we need to create endpoint and project
|
||||
# refs for our tests. EndpointFilter is not exactly CRUD API.
|
||||
kwargs.setdefault('id', uuid.uuid4().hex)
|
||||
kwargs.setdefault('enabled', True)
|
||||
return kwargs
|
||||
|
||||
def new_endpoint_ref(self, **kwargs):
|
||||
# copied from EndpointTests as we need endpoint refs for our tests
|
||||
kwargs = self.new_ref(**kwargs)
|
||||
kwargs.setdefault('interface', 'public')
|
||||
kwargs.setdefault('region', uuid.uuid4().hex)
|
||||
kwargs.setdefault('service_id', uuid.uuid4().hex)
|
||||
kwargs.setdefault('url', uuid.uuid4().hex)
|
||||
return kwargs
|
||||
|
||||
def new_project_ref(self, **kwargs):
|
||||
# copied from ProjectTests as we need project refs for our tests
|
||||
kwargs = self.new_ref(**kwargs)
|
||||
kwargs.setdefault('domain_id', uuid.uuid4().hex)
|
||||
kwargs.setdefault('name', uuid.uuid4().hex)
|
||||
return kwargs
|
||||
|
||||
@httpretty.activate
|
||||
def test_add_endpoint_to_project_via_id(self):
|
||||
endpoint_id = uuid.uuid4().hex
|
||||
project_id = uuid.uuid4().hex
|
||||
|
||||
self.stub_url(httpretty.PUT,
|
||||
[self.manager.OS_EP_FILTER_EXT, 'projects', project_id,
|
||||
'endpoints', endpoint_id],
|
||||
status=201)
|
||||
|
||||
self.manager.add_endpoint_to_project(project=project_id,
|
||||
endpoint=endpoint_id)
|
||||
|
||||
@httpretty.activate
|
||||
def test_add_endpoint_to_project_via_obj(self):
|
||||
project_ref = self.new_project_ref()
|
||||
endpoint_ref = self.new_endpoint_ref()
|
||||
project = self.client.projects.resource_class(self.client.projects,
|
||||
project_ref,
|
||||
loaded=True)
|
||||
endpoint = self.client.endpoints.resource_class(self.client.endpoints,
|
||||
endpoint_ref,
|
||||
loaded=True)
|
||||
|
||||
self.stub_url(httpretty.PUT,
|
||||
[self.manager.OS_EP_FILTER_EXT,
|
||||
'projects', project_ref['id'],
|
||||
'endpoints', endpoint_ref['id']],
|
||||
status=201)
|
||||
|
||||
self.manager.add_endpoint_to_project(project=project,
|
||||
endpoint=endpoint)
|
||||
|
||||
@httpretty.activate
|
||||
def test_delete_endpoint_from_project(self):
|
||||
endpoint_id = uuid.uuid4().hex
|
||||
project_id = uuid.uuid4().hex
|
||||
|
||||
self.stub_url(httpretty.DELETE,
|
||||
[self.manager.OS_EP_FILTER_EXT, 'projects', project_id,
|
||||
'endpoints', endpoint_id],
|
||||
status=201)
|
||||
|
||||
self.manager.delete_endpoint_from_project(project=project_id,
|
||||
endpoint=endpoint_id)
|
||||
|
||||
@httpretty.activate
|
||||
def test_check_endpoint_in_project(self):
|
||||
endpoint_id = uuid.uuid4().hex
|
||||
project_id = uuid.uuid4().hex
|
||||
|
||||
self.stub_url(httpretty.HEAD,
|
||||
[self.manager.OS_EP_FILTER_EXT, 'projects', project_id,
|
||||
'endpoints', endpoint_id],
|
||||
status=201)
|
||||
|
||||
self.manager.check_endpoint_in_project(project=project_id,
|
||||
endpoint=endpoint_id)
|
||||
|
||||
@httpretty.activate
|
||||
def test_list_endpoints_for_project(self):
|
||||
project_id = uuid.uuid4().hex
|
||||
endpoints = {'endpoints': [self.new_endpoint_ref(),
|
||||
self.new_endpoint_ref()]}
|
||||
self.stub_url(httpretty.GET,
|
||||
[self.manager.OS_EP_FILTER_EXT, 'projects', project_id,
|
||||
'endpoints'],
|
||||
json=endpoints,
|
||||
status=200)
|
||||
|
||||
endpoints_resp = self.manager.list_endpoints_for_project(
|
||||
project=project_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)
|
||||
|
||||
@httpretty.activate
|
||||
def test_list_projects_for_endpoint(self):
|
||||
endpoint_id = uuid.uuid4().hex
|
||||
projects = {'projects': [self.new_project_ref(),
|
||||
self.new_project_ref()]}
|
||||
self.stub_url(httpretty.GET,
|
||||
[self.manager.OS_EP_FILTER_EXT, 'endpoints', endpoint_id,
|
||||
'projects'],
|
||||
json=projects,
|
||||
status=200)
|
||||
|
||||
projects_resp = self.manager.list_projects_for_endpoint(
|
||||
endpoint=endpoint_id)
|
||||
|
||||
expected_project_ids = [
|
||||
project['id'] for project in projects['projects']]
|
||||
actual_project_ids = [project.id for project in projects_resp]
|
||||
self.assertEqual(expected_project_ids, actual_project_ids)
|
@@ -19,6 +19,7 @@ from keystoneclient.auth.identity import v3 as v3_auth
|
||||
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 federation
|
||||
from keystoneclient.v3.contrib import trusts
|
||||
from keystoneclient.v3 import credentials
|
||||
@@ -104,6 +105,7 @@ class Client(httpclient.HTTPClient):
|
||||
self.services = services.ServiceManager(self)
|
||||
self.users = users.UserManager(self)
|
||||
self.trusts = trusts.TrustManager(self)
|
||||
self.endpoint_filter = endpoint_filter.EndpointFilterManager(self)
|
||||
|
||||
# DEPRECATED: if session is passed then we go to the new behaviour of
|
||||
# authenticating on the first required call.
|
||||
|
86
keystoneclient/v3/contrib/endpoint_filter.py
Normal file
86
keystoneclient/v3/contrib/endpoint_filter.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# Copyright 2014 OpenStack Foundation
|
||||
#
|
||||
# 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 import exceptions
|
||||
|
||||
|
||||
class EndpointFilterManager(base.Manager):
|
||||
"""Manager class for manipulating project-endpoint associations."""
|
||||
OS_EP_FILTER_EXT = '/OS-EP-FILTER'
|
||||
|
||||
def _build_base_url(self, project=None, endpoint=None):
|
||||
project_id = base.getid(project)
|
||||
endpoint_id = base.getid(endpoint)
|
||||
|
||||
if project_id and endpoint_id:
|
||||
api_path = '/projects/%s/endpoints/%s' % (project_id, endpoint_id)
|
||||
elif project_id:
|
||||
api_path = '/projects/%s/endpoints' % (project_id)
|
||||
elif endpoint_id:
|
||||
api_path = '/endpoints/%s/projects' % (endpoint_id)
|
||||
else:
|
||||
msg = 'Must specify a project, an endpoint, or both'
|
||||
raise exceptions.ValidationError(msg)
|
||||
|
||||
return self.OS_EP_FILTER_EXT + api_path
|
||||
|
||||
def add_endpoint_to_project(self, project, endpoint):
|
||||
"""Create a project-endpoint association."""
|
||||
if not (project and endpoint):
|
||||
raise ValueError('project and endpoint are required')
|
||||
|
||||
base_url = self._build_base_url(project=project,
|
||||
endpoint=endpoint)
|
||||
return super(EndpointFilterManager, self)._put(url=base_url)
|
||||
|
||||
def delete_endpoint_from_project(self, project, endpoint):
|
||||
"""Remove a project-endpoint association."""
|
||||
if not (project and endpoint):
|
||||
raise ValueError('project and endpoint are required')
|
||||
|
||||
base_url = self._build_base_url(project=project,
|
||||
endpoint=endpoint)
|
||||
return super(EndpointFilterManager, self)._delete(url=base_url)
|
||||
|
||||
def check_endpoint_in_project(self, project, endpoint):
|
||||
"""Checks if project-endpoint association exist."""
|
||||
if not (project and endpoint):
|
||||
raise ValueError('project and endpoint are required')
|
||||
|
||||
base_url = self._build_base_url(project=project,
|
||||
endpoint=endpoint)
|
||||
return super(EndpointFilterManager, self)._head(url=base_url)
|
||||
|
||||
def list_endpoints_for_project(self, project):
|
||||
"""List all endpoints for a given project."""
|
||||
if not project:
|
||||
raise ValueError('project is required')
|
||||
|
||||
base_url = self._build_base_url(project=project)
|
||||
return super(EndpointFilterManager, self)._list(
|
||||
base_url,
|
||||
self.client.endpoints.collection_key,
|
||||
obj_class=self.client.endpoints.resource_class)
|
||||
|
||||
def list_projects_for_endpoint(self, endpoint):
|
||||
"""List all projects for a given endpoint."""
|
||||
if not endpoint:
|
||||
raise ValueError('endpoint is required')
|
||||
|
||||
base_url = self._build_base_url(endpoint=endpoint)
|
||||
return super(EndpointFilterManager, self)._list(
|
||||
base_url,
|
||||
self.client.projects.collection_key,
|
||||
obj_class=self.client.projects.resource_class)
|
Reference in New Issue
Block a user