Merge "Move endpoint filter into keystone core"
This commit is contained in:
commit
e2fc9edd4f
@ -33,9 +33,6 @@ use = egg:keystone#ec2_extension_v3
|
||||
[filter:s3_extension]
|
||||
use = egg:keystone#s3_extension
|
||||
|
||||
[filter:endpoint_filter_extension]
|
||||
use = egg:keystone#endpoint_filter_extension
|
||||
|
||||
[filter:simple_cert_extension]
|
||||
use = egg:keystone#simple_cert_extension
|
||||
|
||||
@ -67,7 +64,7 @@ pipeline = sizelimit url_normalize request_id build_auth_context token_auth admi
|
||||
[pipeline:api_v3]
|
||||
# The last item in this pipeline must be service_v3 or an equivalent
|
||||
# application. It cannot be a filter.
|
||||
pipeline = sizelimit url_normalize request_id build_auth_context token_auth admin_token_auth json_body ec2_extension_v3 s3_extension simple_cert_extension endpoint_filter_extension service_v3
|
||||
pipeline = sizelimit url_normalize request_id build_auth_context token_auth admin_token_auth json_body ec2_extension_v3 s3_extension simple_cert_extension service_v3
|
||||
|
||||
[app:public_version_service]
|
||||
use = egg:keystone#public_version_service
|
||||
|
@ -152,3 +152,213 @@ class Catalog(kvs.Base, catalog.CatalogDriverV8):
|
||||
def _create_catalog(self, user_id, tenant_id, data):
|
||||
self.db.set('catalog-%s-%s' % (tenant_id, user_id), data)
|
||||
return data
|
||||
|
||||
# TODO(davechen): Apparently, these methods are not implemented but
|
||||
# we cannot raise exception.NotImplemented() just because the notification
|
||||
# to those resource will break some testcases, will look into CADF to
|
||||
# see if there is any better way to do this.
|
||||
def add_endpoint_to_project(self, endpoint_id, project_id):
|
||||
"""Create an endpoint to project association.
|
||||
|
||||
:param endpoint_id: identity of endpoint to associate
|
||||
:type endpoint_id: string
|
||||
:param project_id: identity of the project to be associated with
|
||||
:type project_id: string
|
||||
:raises: keystone.exception.Conflict,
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def remove_endpoint_from_project(self, endpoint_id, project_id):
|
||||
"""Removes an endpoint to project association.
|
||||
|
||||
:param endpoint_id: identity of endpoint to remove
|
||||
:type endpoint_id: string
|
||||
:param project_id: identity of the project associated with
|
||||
:type project_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def check_endpoint_in_project(self, endpoint_id, project_id):
|
||||
"""Checks if an endpoint is associated with a project.
|
||||
|
||||
:param endpoint_id: identity of endpoint to check
|
||||
:type endpoint_id: string
|
||||
:param project_id: identity of the project associated with
|
||||
:type project_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def list_endpoints_for_project(self, project_id):
|
||||
"""List all endpoints associated with a project.
|
||||
|
||||
:param project_id: identity of the project to check
|
||||
:type project_id: string
|
||||
:returns: a list of identity endpoint ids or an empty list.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def list_projects_for_endpoint(self, endpoint_id):
|
||||
"""List all projects associated with an endpoint.
|
||||
|
||||
:param endpoint_id: identity of endpoint to check
|
||||
:type endpoint_id: string
|
||||
:returns: a list of projects or an empty list.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def delete_association_by_endpoint(self, endpoint_id):
|
||||
"""Removes all the endpoints to project association with endpoint.
|
||||
|
||||
:param endpoint_id: identity of endpoint to check
|
||||
:type endpoint_id: string
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def delete_association_by_project(self, project_id):
|
||||
"""Removes all the endpoints to project association with project.
|
||||
|
||||
:param project_id: identity of the project to check
|
||||
:type project_id: string
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def create_endpoint_group(self, endpoint_group):
|
||||
"""Create an endpoint group.
|
||||
|
||||
:param endpoint_group: endpoint group to create
|
||||
:type endpoint_group: dictionary
|
||||
:raises: keystone.exception.Conflict,
|
||||
:returns: an endpoint group representation.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_endpoint_group(self, endpoint_group_id):
|
||||
"""Get an endpoint group.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint group to retrieve
|
||||
:type endpoint_group_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: an endpoint group representation.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def update_endpoint_group(self, endpoint_group_id, endpoint_group):
|
||||
"""Update an endpoint group.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint group to retrieve
|
||||
:type endpoint_group_id: string
|
||||
:param endpoint_group: A full or partial endpoint_group
|
||||
:type endpoint_group: dictionary
|
||||
:raises: exception.NotFound
|
||||
:returns: an endpoint group representation.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def delete_endpoint_group(self, endpoint_group_id):
|
||||
"""Delete an endpoint group.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint group to delete
|
||||
:type endpoint_group_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def add_endpoint_group_to_project(self, endpoint_group_id, project_id):
|
||||
"""Adds an endpoint group to project association.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint to associate
|
||||
:type endpoint_group_id: string
|
||||
:param project_id: identity of project to associate
|
||||
:type project_id: string
|
||||
:raises: keystone.exception.Conflict,
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_endpoint_group_in_project(self, endpoint_group_id, project_id):
|
||||
"""Get endpoint group to project association.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint group to retrieve
|
||||
:type endpoint_group_id: string
|
||||
:param project_id: identity of project to associate
|
||||
:type project_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: a project endpoint group representation.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def list_endpoint_groups(self):
|
||||
"""List all endpoint groups.
|
||||
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def list_endpoint_groups_for_project(self, project_id):
|
||||
"""List all endpoint group to project associations for a project.
|
||||
|
||||
:param project_id: identity of project to associate
|
||||
:type project_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def list_projects_associated_with_endpoint_group(self, endpoint_group_id):
|
||||
"""List all projects associated with endpoint group.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint to associate
|
||||
:type endpoint_group_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def remove_endpoint_group_from_project(self, endpoint_group_id,
|
||||
project_id):
|
||||
"""Remove an endpoint to project association.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint to associate
|
||||
:type endpoint_group_id: string
|
||||
:param project_id: identity of project to associate
|
||||
:type project_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def delete_endpoint_group_association_by_project(self, project_id):
|
||||
"""Remove endpoint group to project associations.
|
||||
|
||||
:param project_id: identity of the project to check
|
||||
:type project_id: string
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
pass
|
||||
|
@ -23,6 +23,7 @@ from keystone import catalog
|
||||
from keystone.catalog import core
|
||||
from keystone.common import sql
|
||||
from keystone import exception
|
||||
from keystone.i18n import _
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -381,3 +382,210 @@ class Catalog(catalog.CatalogDriverV8):
|
||||
return service
|
||||
|
||||
return [make_v3_service(svc) for svc in services]
|
||||
|
||||
@sql.handle_conflicts(conflict_type='project_endpoint')
|
||||
def add_endpoint_to_project(self, endpoint_id, project_id):
|
||||
session = sql.get_session()
|
||||
with session.begin():
|
||||
endpoint_filter_ref = ProjectEndpoint(endpoint_id=endpoint_id,
|
||||
project_id=project_id)
|
||||
session.add(endpoint_filter_ref)
|
||||
|
||||
def _get_project_endpoint_ref(self, session, endpoint_id, project_id):
|
||||
endpoint_filter_ref = session.query(ProjectEndpoint).get(
|
||||
(endpoint_id, project_id))
|
||||
if endpoint_filter_ref is None:
|
||||
msg = _('Endpoint %(endpoint_id)s not found in project '
|
||||
'%(project_id)s') % {'endpoint_id': endpoint_id,
|
||||
'project_id': project_id}
|
||||
raise exception.NotFound(msg)
|
||||
return endpoint_filter_ref
|
||||
|
||||
def check_endpoint_in_project(self, endpoint_id, project_id):
|
||||
session = sql.get_session()
|
||||
self._get_project_endpoint_ref(session, endpoint_id, project_id)
|
||||
|
||||
def remove_endpoint_from_project(self, endpoint_id, project_id):
|
||||
session = sql.get_session()
|
||||
endpoint_filter_ref = self._get_project_endpoint_ref(
|
||||
session, endpoint_id, project_id)
|
||||
with session.begin():
|
||||
session.delete(endpoint_filter_ref)
|
||||
|
||||
def list_endpoints_for_project(self, project_id):
|
||||
session = sql.get_session()
|
||||
query = session.query(ProjectEndpoint)
|
||||
query = query.filter_by(project_id=project_id)
|
||||
endpoint_filter_refs = query.all()
|
||||
return [ref.to_dict() for ref in endpoint_filter_refs]
|
||||
|
||||
def list_projects_for_endpoint(self, endpoint_id):
|
||||
session = sql.get_session()
|
||||
query = session.query(ProjectEndpoint)
|
||||
query = query.filter_by(endpoint_id=endpoint_id)
|
||||
endpoint_filter_refs = query.all()
|
||||
return [ref.to_dict() for ref in endpoint_filter_refs]
|
||||
|
||||
def delete_association_by_endpoint(self, endpoint_id):
|
||||
session = sql.get_session()
|
||||
with session.begin():
|
||||
query = session.query(ProjectEndpoint)
|
||||
query = query.filter_by(endpoint_id=endpoint_id)
|
||||
query.delete(synchronize_session=False)
|
||||
|
||||
def delete_association_by_project(self, project_id):
|
||||
session = sql.get_session()
|
||||
with session.begin():
|
||||
query = session.query(ProjectEndpoint)
|
||||
query = query.filter_by(project_id=project_id)
|
||||
query.delete(synchronize_session=False)
|
||||
|
||||
def create_endpoint_group(self, endpoint_group_id, endpoint_group):
|
||||
session = sql.get_session()
|
||||
with session.begin():
|
||||
endpoint_group_ref = EndpointGroup.from_dict(endpoint_group)
|
||||
session.add(endpoint_group_ref)
|
||||
return endpoint_group_ref.to_dict()
|
||||
|
||||
def _get_endpoint_group(self, session, endpoint_group_id):
|
||||
endpoint_group_ref = session.query(EndpointGroup).get(
|
||||
endpoint_group_id)
|
||||
if endpoint_group_ref is None:
|
||||
raise exception.EndpointGroupNotFound(
|
||||
endpoint_group_id=endpoint_group_id)
|
||||
return endpoint_group_ref
|
||||
|
||||
def get_endpoint_group(self, endpoint_group_id):
|
||||
session = sql.get_session()
|
||||
endpoint_group_ref = self._get_endpoint_group(session,
|
||||
endpoint_group_id)
|
||||
return endpoint_group_ref.to_dict()
|
||||
|
||||
def update_endpoint_group(self, endpoint_group_id, endpoint_group):
|
||||
session = sql.get_session()
|
||||
with session.begin():
|
||||
endpoint_group_ref = self._get_endpoint_group(session,
|
||||
endpoint_group_id)
|
||||
old_endpoint_group = endpoint_group_ref.to_dict()
|
||||
old_endpoint_group.update(endpoint_group)
|
||||
new_endpoint_group = EndpointGroup.from_dict(old_endpoint_group)
|
||||
for attr in EndpointGroup.mutable_attributes:
|
||||
setattr(endpoint_group_ref, attr,
|
||||
getattr(new_endpoint_group, attr))
|
||||
return endpoint_group_ref.to_dict()
|
||||
|
||||
def delete_endpoint_group(self, endpoint_group_id):
|
||||
session = sql.get_session()
|
||||
endpoint_group_ref = self._get_endpoint_group(session,
|
||||
endpoint_group_id)
|
||||
with session.begin():
|
||||
self._delete_endpoint_group_association_by_endpoint_group(
|
||||
session, endpoint_group_id)
|
||||
session.delete(endpoint_group_ref)
|
||||
|
||||
def get_endpoint_group_in_project(self, endpoint_group_id, project_id):
|
||||
session = sql.get_session()
|
||||
ref = self._get_endpoint_group_in_project(session,
|
||||
endpoint_group_id,
|
||||
project_id)
|
||||
return ref.to_dict()
|
||||
|
||||
@sql.handle_conflicts(conflict_type='project_endpoint_group')
|
||||
def add_endpoint_group_to_project(self, endpoint_group_id, project_id):
|
||||
session = sql.get_session()
|
||||
|
||||
with session.begin():
|
||||
# Create a new Project Endpoint group entity
|
||||
endpoint_group_project_ref = ProjectEndpointGroupMembership(
|
||||
endpoint_group_id=endpoint_group_id, project_id=project_id)
|
||||
session.add(endpoint_group_project_ref)
|
||||
|
||||
def _get_endpoint_group_in_project(self, session,
|
||||
endpoint_group_id, project_id):
|
||||
endpoint_group_project_ref = session.query(
|
||||
ProjectEndpointGroupMembership).get((endpoint_group_id,
|
||||
project_id))
|
||||
if endpoint_group_project_ref is None:
|
||||
msg = _('Endpoint Group Project Association not found')
|
||||
raise exception.NotFound(msg)
|
||||
else:
|
||||
return endpoint_group_project_ref
|
||||
|
||||
def list_endpoint_groups(self):
|
||||
session = sql.get_session()
|
||||
query = session.query(EndpointGroup)
|
||||
endpoint_group_refs = query.all()
|
||||
return [e.to_dict() for e in endpoint_group_refs]
|
||||
|
||||
def list_endpoint_groups_for_project(self, project_id):
|
||||
session = sql.get_session()
|
||||
query = session.query(ProjectEndpointGroupMembership)
|
||||
query = query.filter_by(project_id=project_id)
|
||||
endpoint_group_refs = query.all()
|
||||
return [ref.to_dict() for ref in endpoint_group_refs]
|
||||
|
||||
def remove_endpoint_group_from_project(self, endpoint_group_id,
|
||||
project_id):
|
||||
session = sql.get_session()
|
||||
endpoint_group_project_ref = self._get_endpoint_group_in_project(
|
||||
session, endpoint_group_id, project_id)
|
||||
with session.begin():
|
||||
session.delete(endpoint_group_project_ref)
|
||||
|
||||
def list_projects_associated_with_endpoint_group(self, endpoint_group_id):
|
||||
session = sql.get_session()
|
||||
query = session.query(ProjectEndpointGroupMembership)
|
||||
query = query.filter_by(endpoint_group_id=endpoint_group_id)
|
||||
endpoint_group_refs = query.all()
|
||||
return [ref.to_dict() for ref in endpoint_group_refs]
|
||||
|
||||
def _delete_endpoint_group_association_by_endpoint_group(
|
||||
self, session, endpoint_group_id):
|
||||
query = session.query(ProjectEndpointGroupMembership)
|
||||
query = query.filter_by(endpoint_group_id=endpoint_group_id)
|
||||
query.delete()
|
||||
|
||||
def delete_endpoint_group_association_by_project(self, project_id):
|
||||
session = sql.get_session()
|
||||
with session.begin():
|
||||
query = session.query(ProjectEndpointGroupMembership)
|
||||
query = query.filter_by(project_id=project_id)
|
||||
query.delete()
|
||||
|
||||
|
||||
class ProjectEndpoint(sql.ModelBase, sql.ModelDictMixin):
|
||||
"""project-endpoint relationship table."""
|
||||
|
||||
__tablename__ = 'project_endpoint'
|
||||
attributes = ['endpoint_id', 'project_id']
|
||||
endpoint_id = sql.Column(sql.String(64),
|
||||
primary_key=True,
|
||||
nullable=False)
|
||||
project_id = sql.Column(sql.String(64),
|
||||
primary_key=True,
|
||||
nullable=False)
|
||||
|
||||
|
||||
class EndpointGroup(sql.ModelBase, sql.ModelDictMixin):
|
||||
"""Endpoint Groups table."""
|
||||
|
||||
__tablename__ = 'endpoint_group'
|
||||
attributes = ['id', 'name', 'description', 'filters']
|
||||
mutable_attributes = frozenset(['name', 'description', 'filters'])
|
||||
id = sql.Column(sql.String(64), primary_key=True)
|
||||
name = sql.Column(sql.String(255), nullable=False)
|
||||
description = sql.Column(sql.Text, nullable=True)
|
||||
filters = sql.Column(sql.JsonBlob(), nullable=False)
|
||||
|
||||
|
||||
class ProjectEndpointGroupMembership(sql.ModelBase, sql.ModelDictMixin):
|
||||
"""Project to Endpoint group relationship table."""
|
||||
|
||||
__tablename__ = 'project_endpoint_group'
|
||||
attributes = ['endpoint_group_id', 'project_id']
|
||||
endpoint_group_id = sql.Column(sql.String(64),
|
||||
sql.ForeignKey('endpoint_group.id'),
|
||||
nullable=False)
|
||||
project_id = sql.Column(sql.String(64), nullable=False)
|
||||
__table_args__ = (sql.PrimaryKeyConstraint('endpoint_group_id',
|
||||
'project_id'), {})
|
||||
|
@ -15,6 +15,8 @@
|
||||
|
||||
import uuid
|
||||
|
||||
import six
|
||||
|
||||
from keystone.catalog import core
|
||||
from keystone.catalog import schema
|
||||
from keystone.common import controller
|
||||
@ -24,6 +26,7 @@ from keystone.common import wsgi
|
||||
from keystone import exception
|
||||
from keystone.i18n import _
|
||||
from keystone import notifications
|
||||
from keystone import resource
|
||||
|
||||
|
||||
INTERFACES = ['public', 'internal', 'admin']
|
||||
@ -379,3 +382,277 @@ class EndpointV3(controller.V3Controller):
|
||||
def delete_endpoint(self, context, endpoint_id):
|
||||
initiator = notifications._get_request_audit_info(context)
|
||||
return self.catalog_api.delete_endpoint(endpoint_id, initiator)
|
||||
|
||||
|
||||
@dependency.requires('catalog_api', 'resource_api')
|
||||
class _ControllerBase(controller.V3Controller):
|
||||
"""Base behaviors for endpoint filter controllers."""
|
||||
|
||||
def _get_endpoint_groups_for_project(self, project_id):
|
||||
# recover the project endpoint group memberships and for each
|
||||
# membership recover the endpoint group
|
||||
self.resource_api.get_project(project_id)
|
||||
try:
|
||||
refs = self.catalog_api.list_endpoint_groups_for_project(
|
||||
project_id)
|
||||
endpoint_groups = [self.catalog_api.get_endpoint_group(
|
||||
ref['endpoint_group_id']) for ref in refs]
|
||||
return endpoint_groups
|
||||
except exception.EndpointGroupNotFound:
|
||||
return []
|
||||
|
||||
def _get_endpoints_filtered_by_endpoint_group(self, endpoint_group_id):
|
||||
endpoints = self.catalog_api.list_endpoints()
|
||||
filters = self.catalog_api.get_endpoint_group(
|
||||
endpoint_group_id)['filters']
|
||||
filtered_endpoints = []
|
||||
|
||||
for endpoint in endpoints:
|
||||
is_candidate = True
|
||||
for key, value in filters.items():
|
||||
if endpoint[key] != value:
|
||||
is_candidate = False
|
||||
break
|
||||
if is_candidate:
|
||||
filtered_endpoints.append(endpoint)
|
||||
return filtered_endpoints
|
||||
|
||||
|
||||
class EndpointFilterV3Controller(_ControllerBase):
|
||||
|
||||
def __init__(self):
|
||||
super(EndpointFilterV3Controller, self).__init__()
|
||||
notifications.register_event_callback(
|
||||
notifications.ACTIONS.deleted, 'project',
|
||||
self._on_project_or_endpoint_delete)
|
||||
notifications.register_event_callback(
|
||||
notifications.ACTIONS.deleted, 'endpoint',
|
||||
self._on_project_or_endpoint_delete)
|
||||
|
||||
def _on_project_or_endpoint_delete(self, service, resource_type, operation,
|
||||
payload):
|
||||
project_or_endpoint_id = payload['resource_info']
|
||||
if resource_type == 'project':
|
||||
self.catalog_api.delete_association_by_project(
|
||||
project_or_endpoint_id)
|
||||
else:
|
||||
self.catalog_api.delete_association_by_endpoint(
|
||||
project_or_endpoint_id)
|
||||
|
||||
@controller.protected()
|
||||
def add_endpoint_to_project(self, context, project_id, endpoint_id):
|
||||
"""Establishes an association between an endpoint and a project."""
|
||||
# NOTE(gyee): we just need to make sure endpoint and project exist
|
||||
# first. We don't really care whether if project is disabled.
|
||||
# The relationship can still be established even with a disabled
|
||||
# project as there are no security implications.
|
||||
self.catalog_api.get_endpoint(endpoint_id)
|
||||
self.resource_api.get_project(project_id)
|
||||
self.catalog_api.add_endpoint_to_project(endpoint_id,
|
||||
project_id)
|
||||
|
||||
@controller.protected()
|
||||
def check_endpoint_in_project(self, context, project_id, endpoint_id):
|
||||
"""Verifies endpoint is currently associated with given project."""
|
||||
self.catalog_api.get_endpoint(endpoint_id)
|
||||
self.resource_api.get_project(project_id)
|
||||
self.catalog_api.check_endpoint_in_project(endpoint_id,
|
||||
project_id)
|
||||
|
||||
@controller.protected()
|
||||
def list_endpoints_for_project(self, context, project_id):
|
||||
"""List all endpoints currently associated with a given project."""
|
||||
self.resource_api.get_project(project_id)
|
||||
refs = self.catalog_api.list_endpoints_for_project(project_id)
|
||||
filtered_endpoints = {ref['endpoint_id']:
|
||||
self.catalog_api.get_endpoint(ref['endpoint_id'])
|
||||
for ref in refs}
|
||||
|
||||
# need to recover endpoint_groups associated with project
|
||||
# then for each endpoint group return the endpoints.
|
||||
endpoint_groups = self._get_endpoint_groups_for_project(project_id)
|
||||
for endpoint_group in endpoint_groups:
|
||||
endpoint_refs = self._get_endpoints_filtered_by_endpoint_group(
|
||||
endpoint_group['id'])
|
||||
# now check if any endpoints for current endpoint group are not
|
||||
# contained in the list of filtered endpoints
|
||||
for endpoint_ref in endpoint_refs:
|
||||
if endpoint_ref['id'] not in filtered_endpoints:
|
||||
filtered_endpoints[endpoint_ref['id']] = endpoint_ref
|
||||
|
||||
return EndpointV3.wrap_collection(
|
||||
context, [v for v in six.itervalues(filtered_endpoints)])
|
||||
|
||||
@controller.protected()
|
||||
def remove_endpoint_from_project(self, context, project_id, endpoint_id):
|
||||
"""Remove the endpoint from the association with given project."""
|
||||
self.catalog_api.remove_endpoint_from_project(endpoint_id,
|
||||
project_id)
|
||||
|
||||
@controller.protected()
|
||||
def list_projects_for_endpoint(self, context, endpoint_id):
|
||||
"""Return a list of projects associated with the endpoint."""
|
||||
self.catalog_api.get_endpoint(endpoint_id)
|
||||
refs = self.catalog_api.list_projects_for_endpoint(endpoint_id)
|
||||
|
||||
projects = [self.resource_api.get_project(
|
||||
ref['project_id']) for ref in refs]
|
||||
return resource.controllers.ProjectV3.wrap_collection(context,
|
||||
projects)
|
||||
|
||||
|
||||
class EndpointGroupV3Controller(_ControllerBase):
|
||||
collection_name = 'endpoint_groups'
|
||||
member_name = 'endpoint_group'
|
||||
|
||||
VALID_FILTER_KEYS = ['service_id', 'region_id', 'interface']
|
||||
|
||||
def __init__(self):
|
||||
super(EndpointGroupV3Controller, self).__init__()
|
||||
|
||||
@classmethod
|
||||
def base_url(cls, context, path=None):
|
||||
"""Construct a path and pass it to V3Controller.base_url method."""
|
||||
path = '/OS-EP-FILTER/' + cls.collection_name
|
||||
return super(EndpointGroupV3Controller, cls).base_url(context,
|
||||
path=path)
|
||||
|
||||
@controller.protected()
|
||||
@validation.validated(schema.endpoint_group_create, 'endpoint_group')
|
||||
def create_endpoint_group(self, context, endpoint_group):
|
||||
"""Creates an Endpoint Group with the associated filters."""
|
||||
ref = self._assign_unique_id(self._normalize_dict(endpoint_group))
|
||||
self._require_attribute(ref, 'filters')
|
||||
self._require_valid_filter(ref)
|
||||
ref = self.catalog_api.create_endpoint_group(ref['id'], ref)
|
||||
return EndpointGroupV3Controller.wrap_member(context, ref)
|
||||
|
||||
def _require_valid_filter(self, endpoint_group):
|
||||
filters = endpoint_group.get('filters')
|
||||
for key in six.iterkeys(filters):
|
||||
if key not in self.VALID_FILTER_KEYS:
|
||||
raise exception.ValidationError(
|
||||
attribute=self._valid_filter_keys(),
|
||||
target='endpoint_group')
|
||||
|
||||
def _valid_filter_keys(self):
|
||||
return ' or '.join(self.VALID_FILTER_KEYS)
|
||||
|
||||
@controller.protected()
|
||||
def get_endpoint_group(self, context, endpoint_group_id):
|
||||
"""Retrieve the endpoint group associated with the id if exists."""
|
||||
ref = self.catalog_api.get_endpoint_group(endpoint_group_id)
|
||||
return EndpointGroupV3Controller.wrap_member(
|
||||
context, ref)
|
||||
|
||||
@controller.protected()
|
||||
@validation.validated(schema.endpoint_group_update, 'endpoint_group')
|
||||
def update_endpoint_group(self, context, endpoint_group_id,
|
||||
endpoint_group):
|
||||
"""Update fixed values and/or extend the filters."""
|
||||
if 'filters' in endpoint_group:
|
||||
self._require_valid_filter(endpoint_group)
|
||||
ref = self.catalog_api.update_endpoint_group(endpoint_group_id,
|
||||
endpoint_group)
|
||||
return EndpointGroupV3Controller.wrap_member(
|
||||
context, ref)
|
||||
|
||||
@controller.protected()
|
||||
def delete_endpoint_group(self, context, endpoint_group_id):
|
||||
"""Delete endpoint_group."""
|
||||
self.catalog_api.delete_endpoint_group(endpoint_group_id)
|
||||
|
||||
@controller.protected()
|
||||
def list_endpoint_groups(self, context):
|
||||
"""List all endpoint groups."""
|
||||
refs = self.catalog_api.list_endpoint_groups()
|
||||
return EndpointGroupV3Controller.wrap_collection(
|
||||
context, refs)
|
||||
|
||||
@controller.protected()
|
||||
def list_endpoint_groups_for_project(self, context, project_id):
|
||||
"""List all endpoint groups associated with a given project."""
|
||||
return EndpointGroupV3Controller.wrap_collection(
|
||||
context, self._get_endpoint_groups_for_project(project_id))
|
||||
|
||||
@controller.protected()
|
||||
def list_projects_associated_with_endpoint_group(self,
|
||||
context,
|
||||
endpoint_group_id):
|
||||
"""List all projects associated with endpoint group."""
|
||||
endpoint_group_refs = (self.catalog_api.
|
||||
list_projects_associated_with_endpoint_group(
|
||||
endpoint_group_id))
|
||||
projects = []
|
||||
for endpoint_group_ref in endpoint_group_refs:
|
||||
project = self.resource_api.get_project(
|
||||
endpoint_group_ref['project_id'])
|
||||
if project:
|
||||
projects.append(project)
|
||||
return resource.controllers.ProjectV3.wrap_collection(context,
|
||||
projects)
|
||||
|
||||
@controller.protected()
|
||||
def list_endpoints_associated_with_endpoint_group(self,
|
||||
context,
|
||||
endpoint_group_id):
|
||||
"""List all the endpoints filtered by a specific endpoint group."""
|
||||
filtered_endpoints = self._get_endpoints_filtered_by_endpoint_group(
|
||||
endpoint_group_id)
|
||||
return EndpointV3.wrap_collection(context, filtered_endpoints)
|
||||
|
||||
|
||||
class ProjectEndpointGroupV3Controller(_ControllerBase):
|
||||
collection_name = 'project_endpoint_groups'
|
||||
member_name = 'project_endpoint_group'
|
||||
|
||||
def __init__(self):
|
||||
super(ProjectEndpointGroupV3Controller, self).__init__()
|
||||
notifications.register_event_callback(
|
||||
notifications.ACTIONS.deleted, 'project',
|
||||
self._on_project_delete)
|
||||
|
||||
def _on_project_delete(self, service, resource_type,
|
||||
operation, payload):
|
||||
project_id = payload['resource_info']
|
||||
(self.catalog_api.
|
||||
delete_endpoint_group_association_by_project(
|
||||
project_id))
|
||||
|
||||
@controller.protected()
|
||||
def get_endpoint_group_in_project(self, context, endpoint_group_id,
|
||||
project_id):
|
||||
"""Retrieve the endpoint group associated with the id if exists."""
|
||||
self.resource_api.get_project(project_id)
|
||||
self.catalog_api.get_endpoint_group(endpoint_group_id)
|
||||
ref = self.catalog_api.get_endpoint_group_in_project(
|
||||
endpoint_group_id, project_id)
|
||||
return ProjectEndpointGroupV3Controller.wrap_member(
|
||||
context, ref)
|
||||
|
||||
@controller.protected()
|
||||
def add_endpoint_group_to_project(self, context, endpoint_group_id,
|
||||
project_id):
|
||||
"""Creates an association between an endpoint group and project."""
|
||||
self.resource_api.get_project(project_id)
|
||||
self.catalog_api.get_endpoint_group(endpoint_group_id)
|
||||
self.catalog_api.add_endpoint_group_to_project(
|
||||
endpoint_group_id, project_id)
|
||||
|
||||
@controller.protected()
|
||||
def remove_endpoint_group_from_project(self, context, endpoint_group_id,
|
||||
project_id):
|
||||
"""Remove the endpoint group from associated project."""
|
||||
self.resource_api.get_project(project_id)
|
||||
self.catalog_api.get_endpoint_group(endpoint_group_id)
|
||||
self.catalog_api.remove_endpoint_group_from_project(
|
||||
endpoint_group_id, project_id)
|
||||
|
||||
@classmethod
|
||||
def _add_self_referential_link(cls, context, ref):
|
||||
url = ('/OS-EP-FILTER/endpoint_groups/%(endpoint_group_id)s'
|
||||
'/projects/%(project_id)s' % {
|
||||
'endpoint_group_id': ref['endpoint_group_id'],
|
||||
'project_id': ref['project_id']})
|
||||
ref.setdefault('links', {})
|
||||
ref['links']['self'] = url
|
||||
|
@ -302,6 +302,25 @@ class Manager(manager.Manager):
|
||||
def get_v3_catalog(self, user_id, tenant_id):
|
||||
return self.driver.get_v3_catalog(user_id, tenant_id)
|
||||
|
||||
def add_endpoint_to_project(self, endpoint_id, project_id):
|
||||
self.driver.add_endpoint_to_project(endpoint_id, project_id)
|
||||
COMPUTED_CATALOG_REGION.invalidate()
|
||||
|
||||
def remove_endpoint_from_project(self, endpoint_id, project_id):
|
||||
self.driver.remove_endpoint_from_project(endpoint_id, project_id)
|
||||
COMPUTED_CATALOG_REGION.invalidate()
|
||||
|
||||
def add_endpoint_group_to_project(self, endpoint_group_id, project_id):
|
||||
self.driver.add_endpoint_group_to_project(
|
||||
endpoint_group_id, project_id)
|
||||
COMPUTED_CATALOG_REGION.invalidate()
|
||||
|
||||
def remove_endpoint_group_from_project(self, endpoint_group_id,
|
||||
project_id):
|
||||
self.driver.remove_endpoint_group_from_project(
|
||||
endpoint_group_id, project_id)
|
||||
COMPUTED_CATALOG_REGION.invalidate()
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class CatalogDriverV8(object):
|
||||
@ -570,5 +589,228 @@ class CatalogDriverV8(object):
|
||||
|
||||
return v3_catalog
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_endpoint_to_project(self, endpoint_id, project_id):
|
||||
"""Create an endpoint to project association.
|
||||
|
||||
:param endpoint_id: identity of endpoint to associate
|
||||
:type endpoint_id: string
|
||||
:param project_id: identity of the project to be associated with
|
||||
:type project_id: string
|
||||
:raises: keystone.exception.Conflict,
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def remove_endpoint_from_project(self, endpoint_id, project_id):
|
||||
"""Removes an endpoint to project association.
|
||||
|
||||
:param endpoint_id: identity of endpoint to remove
|
||||
:type endpoint_id: string
|
||||
:param project_id: identity of the project associated with
|
||||
:type project_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def check_endpoint_in_project(self, endpoint_id, project_id):
|
||||
"""Checks if an endpoint is associated with a project.
|
||||
|
||||
:param endpoint_id: identity of endpoint to check
|
||||
:type endpoint_id: string
|
||||
:param project_id: identity of the project associated with
|
||||
:type project_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def list_endpoints_for_project(self, project_id):
|
||||
"""List all endpoints associated with a project.
|
||||
|
||||
:param project_id: identity of the project to check
|
||||
:type project_id: string
|
||||
:returns: a list of identity endpoint ids or an empty list.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def list_projects_for_endpoint(self, endpoint_id):
|
||||
"""List all projects associated with an endpoint.
|
||||
|
||||
:param endpoint_id: identity of endpoint to check
|
||||
:type endpoint_id: string
|
||||
:returns: a list of projects or an empty list.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_association_by_endpoint(self, endpoint_id):
|
||||
"""Removes all the endpoints to project association with endpoint.
|
||||
|
||||
:param endpoint_id: identity of endpoint to check
|
||||
:type endpoint_id: string
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented()
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_association_by_project(self, project_id):
|
||||
"""Removes all the endpoints to project association with project.
|
||||
|
||||
:param project_id: identity of the project to check
|
||||
:type project_id: string
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented()
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_endpoint_group(self, endpoint_group):
|
||||
"""Create an endpoint group.
|
||||
|
||||
:param endpoint_group: endpoint group to create
|
||||
:type endpoint_group: dictionary
|
||||
:raises: keystone.exception.Conflict,
|
||||
:returns: an endpoint group representation.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_endpoint_group(self, endpoint_group_id):
|
||||
"""Get an endpoint group.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint group to retrieve
|
||||
:type endpoint_group_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: an endpoint group representation.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_endpoint_group(self, endpoint_group_id, endpoint_group):
|
||||
"""Update an endpoint group.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint group to retrieve
|
||||
:type endpoint_group_id: string
|
||||
:param endpoint_group: A full or partial endpoint_group
|
||||
:type endpoint_group: dictionary
|
||||
:raises: exception.NotFound
|
||||
:returns: an endpoint group representation.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_endpoint_group(self, endpoint_group_id):
|
||||
"""Delete an endpoint group.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint group to delete
|
||||
:type endpoint_group_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_endpoint_group_to_project(self, endpoint_group_id, project_id):
|
||||
"""Adds an endpoint group to project association.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint to associate
|
||||
:type endpoint_group_id: string
|
||||
:param project_id: identity of project to associate
|
||||
:type project_id: string
|
||||
:raises: keystone.exception.Conflict,
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_endpoint_group_in_project(self, endpoint_group_id, project_id):
|
||||
"""Get endpoint group to project association.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint group to retrieve
|
||||
:type endpoint_group_id: string
|
||||
:param project_id: identity of project to associate
|
||||
:type project_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: a project endpoint group representation.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def list_endpoint_groups(self):
|
||||
"""List all endpoint groups.
|
||||
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def list_endpoint_groups_for_project(self, project_id):
|
||||
"""List all endpoint group to project associations for a project.
|
||||
|
||||
:param project_id: identity of project to associate
|
||||
:type project_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def list_projects_associated_with_endpoint_group(self, endpoint_group_id):
|
||||
"""List all projects associated with endpoint group.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint to associate
|
||||
:type endpoint_group_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def remove_endpoint_group_from_project(self, endpoint_group_id,
|
||||
project_id):
|
||||
"""Remove an endpoint to project association.
|
||||
|
||||
:param endpoint_group_id: identity of endpoint to associate
|
||||
:type endpoint_group_id: string
|
||||
:param project_id: identity of project to associate
|
||||
:type project_id: string
|
||||
:raises: exception.NotFound
|
||||
:returns: None.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_endpoint_group_association_by_project(self, project_id):
|
||||
"""Remove endpoint group to project associations.
|
||||
|
||||
:param project_id: identity of the project to check
|
||||
:type project_id: string
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
Driver = manager.create_legacy_driver(CatalogDriverV8)
|
||||
|
@ -12,15 +12,72 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import functools
|
||||
|
||||
from keystone.catalog import controllers
|
||||
from keystone.common import json_home
|
||||
from keystone.common import router
|
||||
from keystone.common import wsgi
|
||||
|
||||
|
||||
build_resource_relation = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-EP-FILTER', extension_version='1.0')
|
||||
|
||||
build_parameter_relation = functools.partial(
|
||||
json_home.build_v3_extension_parameter_relation,
|
||||
extension_name='OS-EP-FILTER', extension_version='1.0')
|
||||
|
||||
ENDPOINT_GROUP_PARAMETER_RELATION = build_parameter_relation(
|
||||
parameter_name='endpoint_group_id')
|
||||
|
||||
|
||||
class Routers(wsgi.RoutersBase):
|
||||
"""API for the keystone catalog.
|
||||
|
||||
The API Endpoint Filter looks like::
|
||||
|
||||
PUT /OS-EP-FILTER/projects/{project_id}/endpoints/{endpoint_id}
|
||||
GET /OS-EP-FILTER/projects/{project_id}/endpoints/{endpoint_id}
|
||||
HEAD /OS-EP-FILTER/projects/{project_id}/endpoints/{endpoint_id}
|
||||
DELETE /OS-EP-FILTER/projects/{project_id}/endpoints/{endpoint_id}
|
||||
GET /OS-EP-FILTER/endpoints/{endpoint_id}/projects
|
||||
GET /OS-EP-FILTER/projects/{project_id}/endpoints
|
||||
GET /OS-EP-FILTER/projects/{project_id}/endpoint_groups
|
||||
|
||||
GET /OS-EP-FILTER/endpoint_groups
|
||||
POST /OS-EP-FILTER/endpoint_groups
|
||||
GET /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}
|
||||
HEAD /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}
|
||||
PATCH /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}
|
||||
DELETE /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}
|
||||
|
||||
GET /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}/projects
|
||||
GET /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}/endpoints
|
||||
|
||||
PUT /OS-EP-FILTER/endpoint_groups/{endpoint_group}/projects/
|
||||
{project_id}
|
||||
GET /OS-EP-FILTER/endpoint_groups/{endpoint_group}/projects/
|
||||
{project_id}
|
||||
HEAD /OS-EP-FILTER/endpoint_groups/{endpoint_group}/projects/
|
||||
{project_id}
|
||||
DELETE /OS-EP-FILTER/endpoint_groups/{endpoint_group}/projects/
|
||||
{project_id}
|
||||
|
||||
"""
|
||||
|
||||
PATH_PREFIX = '/OS-EP-FILTER'
|
||||
PATH_PROJECT_ENDPOINT = '/projects/{project_id}/endpoints/{endpoint_id}'
|
||||
PATH_ENDPOINT_GROUPS = '/endpoint_groups/{endpoint_group_id}'
|
||||
PATH_ENDPOINT_GROUP_PROJECTS = PATH_ENDPOINT_GROUPS + (
|
||||
'/projects/{project_id}')
|
||||
|
||||
def append_v3_routers(self, mapper, routers):
|
||||
regions_controller = controllers.RegionV3()
|
||||
endpoint_filter_controller = controllers.EndpointFilterV3Controller()
|
||||
endpoint_group_controller = controllers.EndpointGroupV3Controller()
|
||||
project_endpoint_group_controller = (
|
||||
controllers.ProjectEndpointGroupV3Controller())
|
||||
routers.append(router.Router(regions_controller,
|
||||
'regions', 'region',
|
||||
resource_descriptions=self.v3_resources))
|
||||
@ -38,3 +95,88 @@ class Routers(wsgi.RoutersBase):
|
||||
routers.append(router.Router(controllers.EndpointV3(),
|
||||
'endpoints', 'endpoint',
|
||||
resource_descriptions=self.v3_resources))
|
||||
|
||||
self._add_resource(
|
||||
mapper, endpoint_filter_controller,
|
||||
path=self.PATH_PREFIX + '/endpoints/{endpoint_id}/projects',
|
||||
get_action='list_projects_for_endpoint',
|
||||
rel=build_resource_relation(resource_name='endpoint_projects'),
|
||||
path_vars={
|
||||
'endpoint_id': json_home.Parameters.ENDPOINT_ID,
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, endpoint_filter_controller,
|
||||
path=self.PATH_PREFIX + self.PATH_PROJECT_ENDPOINT,
|
||||
get_head_action='check_endpoint_in_project',
|
||||
put_action='add_endpoint_to_project',
|
||||
delete_action='remove_endpoint_from_project',
|
||||
rel=build_resource_relation(resource_name='project_endpoint'),
|
||||
path_vars={
|
||||
'endpoint_id': json_home.Parameters.ENDPOINT_ID,
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, endpoint_filter_controller,
|
||||
path=self.PATH_PREFIX + '/projects/{project_id}/endpoints',
|
||||
get_action='list_endpoints_for_project',
|
||||
rel=build_resource_relation(resource_name='project_endpoints'),
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, endpoint_group_controller,
|
||||
path=self.PATH_PREFIX + '/projects/{project_id}/endpoint_groups',
|
||||
get_action='list_endpoint_groups_for_project',
|
||||
rel=build_resource_relation(
|
||||
resource_name='project_endpoint_groups'),
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, endpoint_group_controller,
|
||||
path=self.PATH_PREFIX + '/endpoint_groups',
|
||||
get_action='list_endpoint_groups',
|
||||
post_action='create_endpoint_group',
|
||||
rel=build_resource_relation(resource_name='endpoint_groups'))
|
||||
self._add_resource(
|
||||
mapper, endpoint_group_controller,
|
||||
path=self.PATH_PREFIX + self.PATH_ENDPOINT_GROUPS,
|
||||
get_head_action='get_endpoint_group',
|
||||
patch_action='update_endpoint_group',
|
||||
delete_action='delete_endpoint_group',
|
||||
rel=build_resource_relation(resource_name='endpoint_group'),
|
||||
path_vars={
|
||||
'endpoint_group_id': ENDPOINT_GROUP_PARAMETER_RELATION
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, project_endpoint_group_controller,
|
||||
path=self.PATH_PREFIX + self.PATH_ENDPOINT_GROUP_PROJECTS,
|
||||
get_head_action='get_endpoint_group_in_project',
|
||||
put_action='add_endpoint_group_to_project',
|
||||
delete_action='remove_endpoint_group_from_project',
|
||||
rel=build_resource_relation(
|
||||
resource_name='endpoint_group_to_project_association'),
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
'endpoint_group_id': ENDPOINT_GROUP_PARAMETER_RELATION
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, endpoint_group_controller,
|
||||
path=self.PATH_PREFIX + self.PATH_ENDPOINT_GROUPS + (
|
||||
'/projects'),
|
||||
get_action='list_projects_associated_with_endpoint_group',
|
||||
rel=build_resource_relation(
|
||||
resource_name='projects_associated_with_endpoint_group'),
|
||||
path_vars={
|
||||
'endpoint_group_id': ENDPOINT_GROUP_PARAMETER_RELATION
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, endpoint_group_controller,
|
||||
path=self.PATH_PREFIX + self.PATH_ENDPOINT_GROUPS + (
|
||||
'/endpoints'),
|
||||
get_action='list_endpoints_associated_with_endpoint_group',
|
||||
rel=build_resource_relation(
|
||||
resource_name='endpoints_in_endpoint_group'),
|
||||
path_vars={
|
||||
'endpoint_group_id': ENDPOINT_GROUP_PARAMETER_RELATION
|
||||
})
|
||||
|
@ -10,6 +10,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from keystone.common import validation
|
||||
from keystone.common.validation import parameter_types
|
||||
|
||||
|
||||
@ -96,3 +97,23 @@ endpoint_update = {
|
||||
'minProperties': 1,
|
||||
'additionalProperties': True
|
||||
}
|
||||
|
||||
_endpoint_group_properties = {
|
||||
'description': validation.nullable(parameter_types.description),
|
||||
'filters': {
|
||||
'type': 'object'
|
||||
},
|
||||
'name': parameter_types.name
|
||||
}
|
||||
|
||||
endpoint_group_create = {
|
||||
'type': 'object',
|
||||
'properties': _endpoint_group_properties,
|
||||
'required': ['name', 'filters']
|
||||
}
|
||||
|
||||
endpoint_group_update = {
|
||||
'type': 'object',
|
||||
'properties': _endpoint_group_properties,
|
||||
'minProperties': 1
|
||||
}
|
||||
|
@ -472,6 +472,9 @@ FILE_OPTIONS = {
|
||||
'in a policy collection.'),
|
||||
],
|
||||
'endpoint_filter': [
|
||||
cfg.BoolOpt('enabled',
|
||||
default=True,
|
||||
help='Enable endpoint filtering functionality.'),
|
||||
cfg.StrOpt('driver',
|
||||
default='sql',
|
||||
help='Entrypoint for the endpoint filter backend driver in '
|
||||
|
@ -1,15 +0,0 @@
|
||||
# Copyright 2013 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 keystone.contrib.endpoint_filter.core import * # noqa
|
@ -23,7 +23,7 @@ from keystone import exception
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
@dependency.requires('endpoint_filter_api')
|
||||
@dependency.requires('catalog_api')
|
||||
class EndpointFilterCatalog(sql.Catalog):
|
||||
def get_v3_catalog(self, user_id, project_id):
|
||||
substitutions = dict(CONF.items())
|
||||
@ -31,7 +31,7 @@ class EndpointFilterCatalog(sql.Catalog):
|
||||
|
||||
services = {}
|
||||
|
||||
refs = self.endpoint_filter_api.list_endpoints_for_project(project_id)
|
||||
refs = self.catalog_api.list_endpoints_for_project(project_id)
|
||||
|
||||
if (not refs and
|
||||
CONF.endpoint_filter.return_all_endpoints_if_no_filter):
|
||||
@ -61,7 +61,7 @@ class EndpointFilterCatalog(sql.Catalog):
|
||||
service['endpoints'] = [endpoint]
|
||||
except exception.EndpointNotFound:
|
||||
# remove bad reference from association
|
||||
self.endpoint_filter_api.remove_endpoint_from_project(
|
||||
self.catalog_api.remove_endpoint_from_project(
|
||||
entry['endpoint_id'], project_id)
|
||||
|
||||
# format catalog
|
||||
|
@ -12,217 +12,19 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from keystone.common import sql
|
||||
from keystone.contrib import endpoint_filter
|
||||
from keystone import exception
|
||||
from keystone.i18n import _
|
||||
from oslo_log import versionutils
|
||||
|
||||
from keystone.catalog.backends import sql
|
||||
|
||||
_OLD = 'keystone.contrib.endpoint_filter.backends.sql.EndpointFilter'
|
||||
_NEW = 'sql'
|
||||
|
||||
|
||||
class ProjectEndpoint(sql.ModelBase, sql.ModelDictMixin):
|
||||
"""project-endpoint relationship table."""
|
||||
|
||||
__tablename__ = 'project_endpoint'
|
||||
attributes = ['endpoint_id', 'project_id']
|
||||
endpoint_id = sql.Column(sql.String(64),
|
||||
primary_key=True,
|
||||
nullable=False)
|
||||
project_id = sql.Column(sql.String(64),
|
||||
primary_key=True,
|
||||
nullable=False)
|
||||
|
||||
|
||||
class EndpointGroup(sql.ModelBase, sql.ModelDictMixin):
|
||||
"""Endpoint Groups table."""
|
||||
|
||||
__tablename__ = 'endpoint_group'
|
||||
attributes = ['id', 'name', 'description', 'filters']
|
||||
mutable_attributes = frozenset(['name', 'description', 'filters'])
|
||||
id = sql.Column(sql.String(64), primary_key=True)
|
||||
name = sql.Column(sql.String(255), nullable=False)
|
||||
description = sql.Column(sql.Text, nullable=True)
|
||||
filters = sql.Column(sql.JsonBlob(), nullable=False)
|
||||
|
||||
|
||||
class ProjectEndpointGroupMembership(sql.ModelBase, sql.ModelDictMixin):
|
||||
"""Project to Endpoint group relationship table."""
|
||||
|
||||
__tablename__ = 'project_endpoint_group'
|
||||
attributes = ['endpoint_group_id', 'project_id']
|
||||
endpoint_group_id = sql.Column(sql.String(64),
|
||||
sql.ForeignKey('endpoint_group.id'),
|
||||
nullable=False)
|
||||
project_id = sql.Column(sql.String(64), nullable=False)
|
||||
__table_args__ = (sql.PrimaryKeyConstraint('endpoint_group_id',
|
||||
'project_id'), {})
|
||||
|
||||
|
||||
class EndpointFilter(endpoint_filter.EndpointFilterDriverV8):
|
||||
|
||||
@sql.handle_conflicts(conflict_type='project_endpoint')
|
||||
def add_endpoint_to_project(self, endpoint_id, project_id):
|
||||
session = sql.get_session()
|
||||
with session.begin():
|
||||
endpoint_filter_ref = ProjectEndpoint(endpoint_id=endpoint_id,
|
||||
project_id=project_id)
|
||||
session.add(endpoint_filter_ref)
|
||||
|
||||
def _get_project_endpoint_ref(self, session, endpoint_id, project_id):
|
||||
endpoint_filter_ref = session.query(ProjectEndpoint).get(
|
||||
(endpoint_id, project_id))
|
||||
if endpoint_filter_ref is None:
|
||||
msg = _('Endpoint %(endpoint_id)s not found in project '
|
||||
'%(project_id)s') % {'endpoint_id': endpoint_id,
|
||||
'project_id': project_id}
|
||||
raise exception.NotFound(msg)
|
||||
return endpoint_filter_ref
|
||||
|
||||
def check_endpoint_in_project(self, endpoint_id, project_id):
|
||||
session = sql.get_session()
|
||||
self._get_project_endpoint_ref(session, endpoint_id, project_id)
|
||||
|
||||
def remove_endpoint_from_project(self, endpoint_id, project_id):
|
||||
session = sql.get_session()
|
||||
endpoint_filter_ref = self._get_project_endpoint_ref(
|
||||
session, endpoint_id, project_id)
|
||||
with session.begin():
|
||||
session.delete(endpoint_filter_ref)
|
||||
|
||||
def list_endpoints_for_project(self, project_id):
|
||||
session = sql.get_session()
|
||||
query = session.query(ProjectEndpoint)
|
||||
query = query.filter_by(project_id=project_id)
|
||||
endpoint_filter_refs = query.all()
|
||||
return [ref.to_dict() for ref in endpoint_filter_refs]
|
||||
|
||||
def list_projects_for_endpoint(self, endpoint_id):
|
||||
session = sql.get_session()
|
||||
query = session.query(ProjectEndpoint)
|
||||
query = query.filter_by(endpoint_id=endpoint_id)
|
||||
endpoint_filter_refs = query.all()
|
||||
return [ref.to_dict() for ref in endpoint_filter_refs]
|
||||
|
||||
def delete_association_by_endpoint(self, endpoint_id):
|
||||
session = sql.get_session()
|
||||
with session.begin():
|
||||
query = session.query(ProjectEndpoint)
|
||||
query = query.filter_by(endpoint_id=endpoint_id)
|
||||
query.delete(synchronize_session=False)
|
||||
|
||||
def delete_association_by_project(self, project_id):
|
||||
session = sql.get_session()
|
||||
with session.begin():
|
||||
query = session.query(ProjectEndpoint)
|
||||
query = query.filter_by(project_id=project_id)
|
||||
query.delete(synchronize_session=False)
|
||||
|
||||
def create_endpoint_group(self, endpoint_group_id, endpoint_group):
|
||||
session = sql.get_session()
|
||||
with session.begin():
|
||||
endpoint_group_ref = EndpointGroup.from_dict(endpoint_group)
|
||||
session.add(endpoint_group_ref)
|
||||
return endpoint_group_ref.to_dict()
|
||||
|
||||
def _get_endpoint_group(self, session, endpoint_group_id):
|
||||
endpoint_group_ref = session.query(EndpointGroup).get(
|
||||
endpoint_group_id)
|
||||
if endpoint_group_ref is None:
|
||||
raise exception.EndpointGroupNotFound(
|
||||
endpoint_group_id=endpoint_group_id)
|
||||
return endpoint_group_ref
|
||||
|
||||
def get_endpoint_group(self, endpoint_group_id):
|
||||
session = sql.get_session()
|
||||
endpoint_group_ref = self._get_endpoint_group(session,
|
||||
endpoint_group_id)
|
||||
return endpoint_group_ref.to_dict()
|
||||
|
||||
def update_endpoint_group(self, endpoint_group_id, endpoint_group):
|
||||
session = sql.get_session()
|
||||
with session.begin():
|
||||
endpoint_group_ref = self._get_endpoint_group(session,
|
||||
endpoint_group_id)
|
||||
old_endpoint_group = endpoint_group_ref.to_dict()
|
||||
old_endpoint_group.update(endpoint_group)
|
||||
new_endpoint_group = EndpointGroup.from_dict(old_endpoint_group)
|
||||
for attr in EndpointGroup.mutable_attributes:
|
||||
setattr(endpoint_group_ref, attr,
|
||||
getattr(new_endpoint_group, attr))
|
||||
return endpoint_group_ref.to_dict()
|
||||
|
||||
def delete_endpoint_group(self, endpoint_group_id):
|
||||
session = sql.get_session()
|
||||
endpoint_group_ref = self._get_endpoint_group(session,
|
||||
endpoint_group_id)
|
||||
with session.begin():
|
||||
self._delete_endpoint_group_association_by_endpoint_group(
|
||||
session, endpoint_group_id)
|
||||
session.delete(endpoint_group_ref)
|
||||
|
||||
def get_endpoint_group_in_project(self, endpoint_group_id, project_id):
|
||||
session = sql.get_session()
|
||||
ref = self._get_endpoint_group_in_project(session,
|
||||
endpoint_group_id,
|
||||
project_id)
|
||||
return ref.to_dict()
|
||||
|
||||
@sql.handle_conflicts(conflict_type='project_endpoint_group')
|
||||
def add_endpoint_group_to_project(self, endpoint_group_id, project_id):
|
||||
session = sql.get_session()
|
||||
|
||||
with session.begin():
|
||||
# Create a new Project Endpoint group entity
|
||||
endpoint_group_project_ref = ProjectEndpointGroupMembership(
|
||||
endpoint_group_id=endpoint_group_id, project_id=project_id)
|
||||
session.add(endpoint_group_project_ref)
|
||||
|
||||
def _get_endpoint_group_in_project(self, session,
|
||||
endpoint_group_id, project_id):
|
||||
endpoint_group_project_ref = session.query(
|
||||
ProjectEndpointGroupMembership).get((endpoint_group_id,
|
||||
project_id))
|
||||
if endpoint_group_project_ref is None:
|
||||
msg = _('Endpoint Group Project Association not found')
|
||||
raise exception.NotFound(msg)
|
||||
else:
|
||||
return endpoint_group_project_ref
|
||||
|
||||
def list_endpoint_groups(self):
|
||||
session = sql.get_session()
|
||||
query = session.query(EndpointGroup)
|
||||
endpoint_group_refs = query.all()
|
||||
return [e.to_dict() for e in endpoint_group_refs]
|
||||
|
||||
def list_endpoint_groups_for_project(self, project_id):
|
||||
session = sql.get_session()
|
||||
query = session.query(ProjectEndpointGroupMembership)
|
||||
query = query.filter_by(project_id=project_id)
|
||||
endpoint_group_refs = query.all()
|
||||
return [ref.to_dict() for ref in endpoint_group_refs]
|
||||
|
||||
def remove_endpoint_group_from_project(self, endpoint_group_id,
|
||||
project_id):
|
||||
session = sql.get_session()
|
||||
endpoint_group_project_ref = self._get_endpoint_group_in_project(
|
||||
session, endpoint_group_id, project_id)
|
||||
with session.begin():
|
||||
session.delete(endpoint_group_project_ref)
|
||||
|
||||
def list_projects_associated_with_endpoint_group(self, endpoint_group_id):
|
||||
session = sql.get_session()
|
||||
query = session.query(ProjectEndpointGroupMembership)
|
||||
query = query.filter_by(endpoint_group_id=endpoint_group_id)
|
||||
endpoint_group_refs = query.all()
|
||||
return [ref.to_dict() for ref in endpoint_group_refs]
|
||||
|
||||
def _delete_endpoint_group_association_by_endpoint_group(
|
||||
self, session, endpoint_group_id):
|
||||
query = session.query(ProjectEndpointGroupMembership)
|
||||
query = query.filter_by(endpoint_group_id=endpoint_group_id)
|
||||
query.delete()
|
||||
|
||||
def delete_endpoint_group_association_by_project(self, project_id):
|
||||
session = sql.get_session()
|
||||
with session.begin():
|
||||
query = session.query(ProjectEndpointGroupMembership)
|
||||
query = query.filter_by(project_id=project_id)
|
||||
query.delete()
|
||||
class EndpointFilter(sql.Catalog):
|
||||
@versionutils.deprecated(
|
||||
as_of=versionutils.deprecated.MITAKA,
|
||||
in_favor_of=_NEW,
|
||||
what=_OLD,
|
||||
remove_in=2)
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(EndpointFilter, self).__init__(*args, **kwargs)
|
||||
|
@ -1,299 +0,0 @@
|
||||
# Copyright 2013 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 six
|
||||
|
||||
from keystone.catalog import controllers as catalog_controllers
|
||||
from keystone.common import controller
|
||||
from keystone.common import dependency
|
||||
from keystone.common import validation
|
||||
from keystone.contrib.endpoint_filter import schema
|
||||
from keystone import exception
|
||||
from keystone import notifications
|
||||
from keystone import resource
|
||||
|
||||
|
||||
@dependency.requires('catalog_api', 'endpoint_filter_api', 'resource_api')
|
||||
class _ControllerBase(controller.V3Controller):
|
||||
"""Base behaviors for endpoint filter controllers."""
|
||||
|
||||
def _get_endpoint_groups_for_project(self, project_id):
|
||||
# recover the project endpoint group memberships and for each
|
||||
# membership recover the endpoint group
|
||||
self.resource_api.get_project(project_id)
|
||||
try:
|
||||
refs = self.endpoint_filter_api.list_endpoint_groups_for_project(
|
||||
project_id)
|
||||
endpoint_groups = [self.endpoint_filter_api.get_endpoint_group(
|
||||
ref['endpoint_group_id']) for ref in refs]
|
||||
return endpoint_groups
|
||||
except exception.EndpointGroupNotFound:
|
||||
return []
|
||||
|
||||
def _get_endpoints_filtered_by_endpoint_group(self, endpoint_group_id):
|
||||
endpoints = self.catalog_api.list_endpoints()
|
||||
filters = self.endpoint_filter_api.get_endpoint_group(
|
||||
endpoint_group_id)['filters']
|
||||
filtered_endpoints = []
|
||||
|
||||
for endpoint in endpoints:
|
||||
is_candidate = True
|
||||
for key, value in filters.items():
|
||||
if endpoint[key] != value:
|
||||
is_candidate = False
|
||||
break
|
||||
if is_candidate:
|
||||
filtered_endpoints.append(endpoint)
|
||||
return filtered_endpoints
|
||||
|
||||
|
||||
class EndpointFilterV3Controller(_ControllerBase):
|
||||
|
||||
def __init__(self):
|
||||
super(EndpointFilterV3Controller, self).__init__()
|
||||
notifications.register_event_callback(
|
||||
notifications.ACTIONS.deleted, 'project',
|
||||
self._on_project_or_endpoint_delete)
|
||||
notifications.register_event_callback(
|
||||
notifications.ACTIONS.deleted, 'endpoint',
|
||||
self._on_project_or_endpoint_delete)
|
||||
|
||||
def _on_project_or_endpoint_delete(self, service, resource_type, operation,
|
||||
payload):
|
||||
project_or_endpoint_id = payload['resource_info']
|
||||
if resource_type == 'project':
|
||||
self.endpoint_filter_api.delete_association_by_project(
|
||||
project_or_endpoint_id)
|
||||
else:
|
||||
self.endpoint_filter_api.delete_association_by_endpoint(
|
||||
project_or_endpoint_id)
|
||||
|
||||
@controller.protected()
|
||||
def add_endpoint_to_project(self, context, project_id, endpoint_id):
|
||||
"""Establishes an association between an endpoint and a project."""
|
||||
# NOTE(gyee): we just need to make sure endpoint and project exist
|
||||
# first. We don't really care whether if project is disabled.
|
||||
# The relationship can still be established even with a disabled
|
||||
# project as there are no security implications.
|
||||
self.catalog_api.get_endpoint(endpoint_id)
|
||||
self.resource_api.get_project(project_id)
|
||||
self.endpoint_filter_api.add_endpoint_to_project(endpoint_id,
|
||||
project_id)
|
||||
|
||||
@controller.protected()
|
||||
def check_endpoint_in_project(self, context, project_id, endpoint_id):
|
||||
"""Verifies endpoint is currently associated with given project."""
|
||||
self.catalog_api.get_endpoint(endpoint_id)
|
||||
self.resource_api.get_project(project_id)
|
||||
self.endpoint_filter_api.check_endpoint_in_project(endpoint_id,
|
||||
project_id)
|
||||
|
||||
@controller.protected()
|
||||
def list_endpoints_for_project(self, context, project_id):
|
||||
"""List all endpoints currently associated with a given project."""
|
||||
self.resource_api.get_project(project_id)
|
||||
refs = self.endpoint_filter_api.list_endpoints_for_project(project_id)
|
||||
filtered_endpoints = {ref['endpoint_id']:
|
||||
self.catalog_api.get_endpoint(ref['endpoint_id'])
|
||||
for ref in refs}
|
||||
|
||||
# need to recover endpoint_groups associated with project
|
||||
# then for each endpoint group return the endpoints.
|
||||
endpoint_groups = self._get_endpoint_groups_for_project(project_id)
|
||||
for endpoint_group in endpoint_groups:
|
||||
endpoint_refs = self._get_endpoints_filtered_by_endpoint_group(
|
||||
endpoint_group['id'])
|
||||
# now check if any endpoints for current endpoint group are not
|
||||
# contained in the list of filtered endpoints
|
||||
for endpoint_ref in endpoint_refs:
|
||||
if endpoint_ref['id'] not in filtered_endpoints:
|
||||
filtered_endpoints[endpoint_ref['id']] = endpoint_ref
|
||||
|
||||
return catalog_controllers.EndpointV3.wrap_collection(
|
||||
context, [v for v in six.itervalues(filtered_endpoints)])
|
||||
|
||||
@controller.protected()
|
||||
def remove_endpoint_from_project(self, context, project_id, endpoint_id):
|
||||
"""Remove the endpoint from the association with given project."""
|
||||
self.endpoint_filter_api.remove_endpoint_from_project(endpoint_id,
|
||||
project_id)
|
||||
|
||||
@controller.protected()
|
||||
def list_projects_for_endpoint(self, context, endpoint_id):
|
||||
"""Return a list of projects associated with the endpoint."""
|
||||
self.catalog_api.get_endpoint(endpoint_id)
|
||||
refs = self.endpoint_filter_api.list_projects_for_endpoint(endpoint_id)
|
||||
|
||||
projects = [self.resource_api.get_project(
|
||||
ref['project_id']) for ref in refs]
|
||||
return resource.controllers.ProjectV3.wrap_collection(context,
|
||||
projects)
|
||||
|
||||
|
||||
class EndpointGroupV3Controller(_ControllerBase):
|
||||
collection_name = 'endpoint_groups'
|
||||
member_name = 'endpoint_group'
|
||||
|
||||
VALID_FILTER_KEYS = ['service_id', 'region_id', 'interface']
|
||||
|
||||
def __init__(self):
|
||||
super(EndpointGroupV3Controller, self).__init__()
|
||||
|
||||
@classmethod
|
||||
def base_url(cls, context, path=None):
|
||||
"""Construct a path and pass it to V3Controller.base_url method."""
|
||||
path = '/OS-EP-FILTER/' + cls.collection_name
|
||||
return super(EndpointGroupV3Controller, cls).base_url(context,
|
||||
path=path)
|
||||
|
||||
@controller.protected()
|
||||
@validation.validated(schema.endpoint_group_create, 'endpoint_group')
|
||||
def create_endpoint_group(self, context, endpoint_group):
|
||||
"""Creates an Endpoint Group with the associated filters."""
|
||||
ref = self._assign_unique_id(self._normalize_dict(endpoint_group))
|
||||
self._require_attribute(ref, 'filters')
|
||||
self._require_valid_filter(ref)
|
||||
ref = self.endpoint_filter_api.create_endpoint_group(ref['id'], ref)
|
||||
return EndpointGroupV3Controller.wrap_member(context, ref)
|
||||
|
||||
def _require_valid_filter(self, endpoint_group):
|
||||
filters = endpoint_group.get('filters')
|
||||
for key in six.iterkeys(filters):
|
||||
if key not in self.VALID_FILTER_KEYS:
|
||||
raise exception.ValidationError(
|
||||
attribute=self._valid_filter_keys(),
|
||||
target='endpoint_group')
|
||||
|
||||
def _valid_filter_keys(self):
|
||||
return ' or '.join(self.VALID_FILTER_KEYS)
|
||||
|
||||
@controller.protected()
|
||||
def get_endpoint_group(self, context, endpoint_group_id):
|
||||
"""Retrieve the endpoint group associated with the id if exists."""
|
||||
ref = self.endpoint_filter_api.get_endpoint_group(endpoint_group_id)
|
||||
return EndpointGroupV3Controller.wrap_member(
|
||||
context, ref)
|
||||
|
||||
@controller.protected()
|
||||
@validation.validated(schema.endpoint_group_update, 'endpoint_group')
|
||||
def update_endpoint_group(self, context, endpoint_group_id,
|
||||
endpoint_group):
|
||||
"""Update fixed values and/or extend the filters."""
|
||||
if 'filters' in endpoint_group:
|
||||
self._require_valid_filter(endpoint_group)
|
||||
ref = self.endpoint_filter_api.update_endpoint_group(endpoint_group_id,
|
||||
endpoint_group)
|
||||
return EndpointGroupV3Controller.wrap_member(
|
||||
context, ref)
|
||||
|
||||
@controller.protected()
|
||||
def delete_endpoint_group(self, context, endpoint_group_id):
|
||||
"""Delete endpoint_group."""
|
||||
self.endpoint_filter_api.delete_endpoint_group(endpoint_group_id)
|
||||
|
||||
@controller.protected()
|
||||
def list_endpoint_groups(self, context):
|
||||
"""List all endpoint groups."""
|
||||
refs = self.endpoint_filter_api.list_endpoint_groups()
|
||||
return EndpointGroupV3Controller.wrap_collection(
|
||||
context, refs)
|
||||
|
||||
@controller.protected()
|
||||
def list_endpoint_groups_for_project(self, context, project_id):
|
||||
"""List all endpoint groups associated with a given project."""
|
||||
return EndpointGroupV3Controller.wrap_collection(
|
||||
context, self._get_endpoint_groups_for_project(project_id))
|
||||
|
||||
@controller.protected()
|
||||
def list_projects_associated_with_endpoint_group(self,
|
||||
context,
|
||||
endpoint_group_id):
|
||||
"""List all projects associated with endpoint group."""
|
||||
endpoint_group_refs = (self.endpoint_filter_api.
|
||||
list_projects_associated_with_endpoint_group(
|
||||
endpoint_group_id))
|
||||
projects = []
|
||||
for endpoint_group_ref in endpoint_group_refs:
|
||||
project = self.resource_api.get_project(
|
||||
endpoint_group_ref['project_id'])
|
||||
if project:
|
||||
projects.append(project)
|
||||
return resource.controllers.ProjectV3.wrap_collection(context,
|
||||
projects)
|
||||
|
||||
@controller.protected()
|
||||
def list_endpoints_associated_with_endpoint_group(self,
|
||||
context,
|
||||
endpoint_group_id):
|
||||
"""List all the endpoints filtered by a specific endpoint group."""
|
||||
filtered_endpoints = self._get_endpoints_filtered_by_endpoint_group(
|
||||
endpoint_group_id)
|
||||
return catalog_controllers.EndpointV3.wrap_collection(
|
||||
context, filtered_endpoints)
|
||||
|
||||
|
||||
class ProjectEndpointGroupV3Controller(_ControllerBase):
|
||||
collection_name = 'project_endpoint_groups'
|
||||
member_name = 'project_endpoint_group'
|
||||
|
||||
def __init__(self):
|
||||
super(ProjectEndpointGroupV3Controller, self).__init__()
|
||||
notifications.register_event_callback(
|
||||
notifications.ACTIONS.deleted, 'project',
|
||||
self._on_project_delete)
|
||||
|
||||
def _on_project_delete(self, service, resource_type,
|
||||
operation, payload):
|
||||
project_id = payload['resource_info']
|
||||
(self.endpoint_filter_api.
|
||||
delete_endpoint_group_association_by_project(
|
||||
project_id))
|
||||
|
||||
@controller.protected()
|
||||
def get_endpoint_group_in_project(self, context, endpoint_group_id,
|
||||
project_id):
|
||||
"""Retrieve the endpoint group associated with the id if exists."""
|
||||
self.resource_api.get_project(project_id)
|
||||
self.endpoint_filter_api.get_endpoint_group(endpoint_group_id)
|
||||
ref = self.endpoint_filter_api.get_endpoint_group_in_project(
|
||||
endpoint_group_id, project_id)
|
||||
return ProjectEndpointGroupV3Controller.wrap_member(
|
||||
context, ref)
|
||||
|
||||
@controller.protected()
|
||||
def add_endpoint_group_to_project(self, context, endpoint_group_id,
|
||||
project_id):
|
||||
"""Creates an association between an endpoint group and project."""
|
||||
self.resource_api.get_project(project_id)
|
||||
self.endpoint_filter_api.get_endpoint_group(endpoint_group_id)
|
||||
self.endpoint_filter_api.add_endpoint_group_to_project(
|
||||
endpoint_group_id, project_id)
|
||||
|
||||
@controller.protected()
|
||||
def remove_endpoint_group_from_project(self, context, endpoint_group_id,
|
||||
project_id):
|
||||
"""Remove the endpoint group from associated project."""
|
||||
self.resource_api.get_project(project_id)
|
||||
self.endpoint_filter_api.get_endpoint_group(endpoint_group_id)
|
||||
self.endpoint_filter_api.remove_endpoint_group_from_project(
|
||||
endpoint_group_id, project_id)
|
||||
|
||||
@classmethod
|
||||
def _add_self_referential_link(cls, context, ref):
|
||||
url = ('/OS-EP-FILTER/endpoint_groups/%(endpoint_group_id)s'
|
||||
'/projects/%(project_id)s' % {
|
||||
'endpoint_group_id': ref['endpoint_group_id'],
|
||||
'project_id': ref['project_id']})
|
||||
ref.setdefault('links', {})
|
||||
ref['links']['self'] = url
|
@ -12,152 +12,22 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import functools
|
||||
from oslo_log import log
|
||||
from oslo_log import versionutils
|
||||
|
||||
from keystone.common import json_home
|
||||
from keystone.common import wsgi
|
||||
from keystone.contrib.endpoint_filter import controllers
|
||||
from keystone.i18n import _
|
||||
|
||||
|
||||
build_resource_relation = functools.partial(
|
||||
json_home.build_v3_extension_resource_relation,
|
||||
extension_name='OS-EP-FILTER', extension_version='1.0')
|
||||
|
||||
build_parameter_relation = functools.partial(
|
||||
json_home.build_v3_extension_parameter_relation,
|
||||
extension_name='OS-EP-FILTER', extension_version='1.0')
|
||||
|
||||
ENDPOINT_GROUP_PARAMETER_RELATION = build_parameter_relation(
|
||||
parameter_name='endpoint_group_id')
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class EndpointFilterExtension(wsgi.V3ExtensionRouter):
|
||||
"""API Endpoints for the Endpoint Filter extension.
|
||||
class EndpointFilterExtension(wsgi.Middleware):
|
||||
|
||||
The API looks like::
|
||||
|
||||
PUT /OS-EP-FILTER/projects/{project_id}/endpoints/{endpoint_id}
|
||||
GET /OS-EP-FILTER/projects/{project_id}/endpoints/{endpoint_id}
|
||||
HEAD /OS-EP-FILTER/projects/{project_id}/endpoints/{endpoint_id}
|
||||
DELETE /OS-EP-FILTER/projects/{project_id}/endpoints/{endpoint_id}
|
||||
GET /OS-EP-FILTER/endpoints/{endpoint_id}/projects
|
||||
GET /OS-EP-FILTER/projects/{project_id}/endpoints
|
||||
GET /OS-EP-FILTER/projects/{project_id}/endpoint_groups
|
||||
|
||||
GET /OS-EP-FILTER/endpoint_groups
|
||||
POST /OS-EP-FILTER/endpoint_groups
|
||||
GET /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}
|
||||
HEAD /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}
|
||||
PATCH /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}
|
||||
DELETE /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}
|
||||
|
||||
GET /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}/projects
|
||||
GET /OS-EP-FILTER/endpoint_groups/{endpoint_group_id}/endpoints
|
||||
|
||||
PUT /OS-EP-FILTER/endpoint_groups/{endpoint_group}/projects/
|
||||
{project_id}
|
||||
GET /OS-EP-FILTER/endpoint_groups/{endpoint_group}/projects/
|
||||
{project_id}
|
||||
HEAD /OS-EP-FILTER/endpoint_groups/{endpoint_group}/projects/
|
||||
{project_id}
|
||||
DELETE /OS-EP-FILTER/endpoint_groups/{endpoint_group}/projects/
|
||||
{project_id}
|
||||
|
||||
"""
|
||||
|
||||
PATH_PREFIX = '/OS-EP-FILTER'
|
||||
PATH_PROJECT_ENDPOINT = '/projects/{project_id}/endpoints/{endpoint_id}'
|
||||
PATH_ENDPOINT_GROUPS = '/endpoint_groups/{endpoint_group_id}'
|
||||
PATH_ENDPOINT_GROUP_PROJECTS = PATH_ENDPOINT_GROUPS + (
|
||||
'/projects/{project_id}')
|
||||
|
||||
def add_routes(self, mapper):
|
||||
endpoint_filter_controller = controllers.EndpointFilterV3Controller()
|
||||
endpoint_group_controller = controllers.EndpointGroupV3Controller()
|
||||
project_endpoint_group_controller = (
|
||||
controllers.ProjectEndpointGroupV3Controller())
|
||||
|
||||
self._add_resource(
|
||||
mapper, endpoint_filter_controller,
|
||||
path=self.PATH_PREFIX + '/endpoints/{endpoint_id}/projects',
|
||||
get_action='list_projects_for_endpoint',
|
||||
rel=build_resource_relation(resource_name='endpoint_projects'),
|
||||
path_vars={
|
||||
'endpoint_id': json_home.Parameters.ENDPOINT_ID,
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, endpoint_filter_controller,
|
||||
path=self.PATH_PREFIX + self.PATH_PROJECT_ENDPOINT,
|
||||
get_head_action='check_endpoint_in_project',
|
||||
put_action='add_endpoint_to_project',
|
||||
delete_action='remove_endpoint_from_project',
|
||||
rel=build_resource_relation(resource_name='project_endpoint'),
|
||||
path_vars={
|
||||
'endpoint_id': json_home.Parameters.ENDPOINT_ID,
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, endpoint_filter_controller,
|
||||
path=self.PATH_PREFIX + '/projects/{project_id}/endpoints',
|
||||
get_action='list_endpoints_for_project',
|
||||
rel=build_resource_relation(resource_name='project_endpoints'),
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, endpoint_group_controller,
|
||||
path=self.PATH_PREFIX + '/projects/{project_id}/endpoint_groups',
|
||||
get_action='list_endpoint_groups_for_project',
|
||||
rel=build_resource_relation(
|
||||
resource_name='project_endpoint_groups'),
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, endpoint_group_controller,
|
||||
path=self.PATH_PREFIX + '/endpoint_groups',
|
||||
get_action='list_endpoint_groups',
|
||||
post_action='create_endpoint_group',
|
||||
rel=build_resource_relation(resource_name='endpoint_groups'))
|
||||
self._add_resource(
|
||||
mapper, endpoint_group_controller,
|
||||
path=self.PATH_PREFIX + self.PATH_ENDPOINT_GROUPS,
|
||||
get_head_action='get_endpoint_group',
|
||||
patch_action='update_endpoint_group',
|
||||
delete_action='delete_endpoint_group',
|
||||
rel=build_resource_relation(resource_name='endpoint_group'),
|
||||
path_vars={
|
||||
'endpoint_group_id': ENDPOINT_GROUP_PARAMETER_RELATION
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, project_endpoint_group_controller,
|
||||
path=self.PATH_PREFIX + self.PATH_ENDPOINT_GROUP_PROJECTS,
|
||||
get_head_action='get_endpoint_group_in_project',
|
||||
put_action='add_endpoint_group_to_project',
|
||||
delete_action='remove_endpoint_group_from_project',
|
||||
rel=build_resource_relation(
|
||||
resource_name='endpoint_group_to_project_association'),
|
||||
path_vars={
|
||||
'project_id': json_home.Parameters.PROJECT_ID,
|
||||
'endpoint_group_id': ENDPOINT_GROUP_PARAMETER_RELATION
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, endpoint_group_controller,
|
||||
path=self.PATH_PREFIX + self.PATH_ENDPOINT_GROUPS + (
|
||||
'/projects'),
|
||||
get_action='list_projects_associated_with_endpoint_group',
|
||||
rel=build_resource_relation(
|
||||
resource_name='projects_associated_with_endpoint_group'),
|
||||
path_vars={
|
||||
'endpoint_group_id': ENDPOINT_GROUP_PARAMETER_RELATION
|
||||
})
|
||||
self._add_resource(
|
||||
mapper, endpoint_group_controller,
|
||||
path=self.PATH_PREFIX + self.PATH_ENDPOINT_GROUPS + (
|
||||
'/endpoints'),
|
||||
get_action='list_endpoints_associated_with_endpoint_group',
|
||||
rel=build_resource_relation(
|
||||
resource_name='endpoints_in_endpoint_group'),
|
||||
path_vars={
|
||||
'endpoint_group_id': ENDPOINT_GROUP_PARAMETER_RELATION
|
||||
})
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(EndpointFilterExtension, self).__init__(*args, **kwargs)
|
||||
msg = _("Remove endpoint_filter_extension from the paste pipeline, "
|
||||
"the endpoint filter extension is now always available. "
|
||||
"Update the [pipeline:api_v3] section in keystone-paste.ini "
|
||||
"accordingly as it will be removed in the O release.")
|
||||
versionutils.report_deprecated_feature(LOG, msg)
|
||||
|
@ -1,35 +0,0 @@
|
||||
# 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 keystone.common import validation
|
||||
from keystone.common.validation import parameter_types
|
||||
|
||||
|
||||
_endpoint_group_properties = {
|
||||
'description': validation.nullable(parameter_types.description),
|
||||
'filters': {
|
||||
'type': 'object'
|
||||
},
|
||||
'name': parameter_types.name
|
||||
}
|
||||
|
||||
endpoint_group_create = {
|
||||
'type': 'object',
|
||||
'properties': _endpoint_group_properties,
|
||||
'required': ['name', 'filters']
|
||||
}
|
||||
|
||||
endpoint_group_update = {
|
||||
'type': 'object',
|
||||
'properties': _endpoint_group_properties,
|
||||
'minProperties': 1
|
||||
}
|
@ -14,7 +14,6 @@ from keystone import assignment
|
||||
from keystone import auth
|
||||
from keystone import catalog
|
||||
from keystone.common import cache
|
||||
from keystone.contrib import endpoint_filter
|
||||
from keystone import credential
|
||||
from keystone import endpoint_policy
|
||||
from keystone import federation
|
||||
@ -45,7 +44,6 @@ def load_backends():
|
||||
catalog_api=catalog.Manager(),
|
||||
credential_api=credential.Manager(),
|
||||
domain_config_api=resource.DomainConfigManager(),
|
||||
endpoint_filter_api=endpoint_filter.Manager(),
|
||||
endpoint_policy_api=endpoint_policy.Manager(),
|
||||
federation_api=federation.Manager(),
|
||||
id_generator_api=identity.generator.Manager(),
|
||||
|
@ -15,25 +15,25 @@
|
||||
import copy
|
||||
import uuid
|
||||
|
||||
import mock
|
||||
from oslo_log import versionutils
|
||||
from six.moves import http_client
|
||||
from testtools import matchers
|
||||
|
||||
from keystone.contrib.endpoint_filter import routers
|
||||
from keystone.tests import unit
|
||||
from keystone.tests.unit import test_v3
|
||||
|
||||
|
||||
class TestExtensionCase(test_v3.RestfulTestCase):
|
||||
|
||||
EXTENSION_NAME = 'endpoint_filter'
|
||||
EXTENSION_TO_ADD = 'endpoint_filter_extension'
|
||||
class EndpointFilterTestCase(test_v3.RestfulTestCase):
|
||||
|
||||
def config_overrides(self):
|
||||
super(TestExtensionCase, self).config_overrides()
|
||||
super(EndpointFilterTestCase, self).config_overrides()
|
||||
self.config_fixture.config(
|
||||
group='catalog', driver='endpoint_filter.sql')
|
||||
|
||||
def setUp(self):
|
||||
super(TestExtensionCase, self).setUp()
|
||||
super(EndpointFilterTestCase, self).setUp()
|
||||
self.default_request_url = (
|
||||
'/OS-EP-FILTER/projects/%(project_id)s'
|
||||
'/endpoints/%(endpoint_id)s' % {
|
||||
@ -41,7 +41,17 @@ class TestExtensionCase(test_v3.RestfulTestCase):
|
||||
'endpoint_id': self.endpoint_id})
|
||||
|
||||
|
||||
class EndpointFilterCRUDTestCase(TestExtensionCase):
|
||||
class EndpointFilterDeprecateTestCase(test_v3.RestfulTestCase):
|
||||
|
||||
@mock.patch.object(versionutils, 'report_deprecated_feature')
|
||||
def test_exception_happens(self, mock_deprecator):
|
||||
routers.EndpointFilterExtension(mock.ANY)
|
||||
mock_deprecator.assert_called_once_with(mock.ANY, mock.ANY)
|
||||
args, _kwargs = mock_deprecator.call_args
|
||||
self.assertIn("Remove endpoint_filter_extension from", args[1])
|
||||
|
||||
|
||||
class EndpointFilterCRUDTestCase(EndpointFilterTestCase):
|
||||
|
||||
def test_create_endpoint_project_association(self):
|
||||
"""PUT /OS-EP-FILTER/projects/{project_id}/endpoints/{endpoint_id}
|
||||
@ -269,8 +279,8 @@ class EndpointFilterCRUDTestCase(TestExtensionCase):
|
||||
self.assertEqual(self.endpoint_id, catalog[0]['endpoints'][0]['id'])
|
||||
|
||||
# add the second endpoint to default project, bypassing
|
||||
# endpoint_filter_api API manager.
|
||||
self.endpoint_filter_api.driver.add_endpoint_to_project(
|
||||
# catalog_api API manager.
|
||||
self.catalog_api.driver.add_endpoint_to_project(
|
||||
endpoint_id2,
|
||||
self.default_domain_project_id)
|
||||
|
||||
@ -283,13 +293,13 @@ class EndpointFilterCRUDTestCase(TestExtensionCase):
|
||||
self.assertEqual(1, len(catalog[0]['endpoints']))
|
||||
|
||||
# remove the endpoint2 from the default project, and add it again via
|
||||
# endpoint_filter_api API manager.
|
||||
self.endpoint_filter_api.driver.remove_endpoint_from_project(
|
||||
# catalog_api API manager.
|
||||
self.catalog_api.driver.remove_endpoint_from_project(
|
||||
endpoint_id2,
|
||||
self.default_domain_project_id)
|
||||
|
||||
# add second endpoint to default project, this can be done by calling
|
||||
# the endpoint_filter_api API manager directly but call the REST API
|
||||
# the catalog_api API manager directly but call the REST API
|
||||
# instead for consistency.
|
||||
self.put('/OS-EP-FILTER/projects/%(project_id)s'
|
||||
'/endpoints/%(endpoint_id)s' % {
|
||||
@ -340,8 +350,8 @@ class EndpointFilterCRUDTestCase(TestExtensionCase):
|
||||
self.assertListEqual([self.endpoint_id, endpoint_id2], ep_id_list)
|
||||
|
||||
# remove the endpoint2 from the default project, bypassing
|
||||
# endpoint_filter_api API manager.
|
||||
self.endpoint_filter_api.driver.remove_endpoint_from_project(
|
||||
# catalog_api API manager.
|
||||
self.catalog_api.driver.remove_endpoint_from_project(
|
||||
endpoint_id2,
|
||||
self.default_domain_project_id)
|
||||
|
||||
@ -355,13 +365,13 @@ class EndpointFilterCRUDTestCase(TestExtensionCase):
|
||||
self.assertEqual(2, len(catalog[0]['endpoints']))
|
||||
|
||||
# add back the endpoint2 to the default project, and remove it by
|
||||
# endpoint_filter_api API manage.
|
||||
self.endpoint_filter_api.driver.add_endpoint_to_project(
|
||||
# catalog_api API manage.
|
||||
self.catalog_api.driver.add_endpoint_to_project(
|
||||
endpoint_id2,
|
||||
self.default_domain_project_id)
|
||||
|
||||
# remove the endpoint2 from the default project, this can be done
|
||||
# by calling the endpoint_filter_api API manager directly but call
|
||||
# by calling the catalog_api API manager directly but call
|
||||
# the REST API instead for consistency.
|
||||
self.delete('/OS-EP-FILTER/projects/%(project_id)s'
|
||||
'/endpoints/%(endpoint_id)s' % {
|
||||
@ -378,7 +388,7 @@ class EndpointFilterCRUDTestCase(TestExtensionCase):
|
||||
self.assertEqual(self.endpoint_id, catalog[0]['endpoints'][0]['id'])
|
||||
|
||||
|
||||
class EndpointFilterTokenRequestTestCase(TestExtensionCase):
|
||||
class EndpointFilterTokenRequestTestCase(EndpointFilterTestCase):
|
||||
|
||||
def test_project_scoped_token_using_endpoint_filter(self):
|
||||
"""Verify endpoints from project scoped token filtered."""
|
||||
@ -595,7 +605,7 @@ class EndpointFilterTokenRequestTestCase(TestExtensionCase):
|
||||
auth_catalog.result['catalog'])
|
||||
|
||||
|
||||
class JsonHomeTests(TestExtensionCase, test_v3.JsonHomeTestMixin):
|
||||
class JsonHomeTests(EndpointFilterTestCase, test_v3.JsonHomeTestMixin):
|
||||
JSON_HOME_DATA = {
|
||||
'http://docs.openstack.org/api/openstack-identity/3/ext/OS-EP-FILTER/'
|
||||
'1.0/rel/endpoint_projects': {
|
||||
@ -666,7 +676,7 @@ class JsonHomeTests(TestExtensionCase, test_v3.JsonHomeTestMixin):
|
||||
}
|
||||
|
||||
|
||||
class EndpointGroupCRUDTestCase(TestExtensionCase):
|
||||
class EndpointGroupCRUDTestCase(EndpointFilterTestCase):
|
||||
|
||||
DEFAULT_ENDPOINT_GROUP_BODY = {
|
||||
'endpoint_group': {
|
||||
|
@ -21,7 +21,6 @@ from keystone.catalog import schema as catalog_schema
|
||||
from keystone.common import validation
|
||||
from keystone.common.validation import parameter_types
|
||||
from keystone.common.validation import validators
|
||||
from keystone.contrib.endpoint_filter import schema as endpoint_filter_schema
|
||||
from keystone.credential import schema as credential_schema
|
||||
from keystone import exception
|
||||
from keystone.federation import schema as federation_schema
|
||||
@ -1298,8 +1297,8 @@ class EndpointGroupValidationTestCase(unit.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(EndpointGroupValidationTestCase, self).setUp()
|
||||
|
||||
create = endpoint_filter_schema.endpoint_group_create
|
||||
update = endpoint_filter_schema.endpoint_group_update
|
||||
create = catalog_schema.endpoint_group_create
|
||||
update = catalog_schema.endpoint_group_update
|
||||
self.create_endpoint_grp_validator = validators.SchemaValidator(create)
|
||||
self.update_endpoint_grp_validator = validators.SchemaValidator(update)
|
||||
|
||||
|
@ -156,7 +156,7 @@ keystone.trust =
|
||||
sql = keystone.trust.backends.sql:Trust
|
||||
|
||||
keystone.endpoint_filter =
|
||||
sql = keystone.contrib.endpoint_filter.backends.sql:EndpointFilter
|
||||
sql = keystone.catalog.backends.sql:Catalog
|
||||
|
||||
keystone.endpoint_policy =
|
||||
sql = keystone.endpoint_policy.backends.sql:EndpointPolicy
|
||||
|
Loading…
Reference in New Issue
Block a user