From 810e15689b200f92980e04e233523d72d885d4bd Mon Sep 17 00:00:00 2001 From: Steve Martinelli Date: Sat, 24 Sep 2016 21:04:01 -0700 Subject: [PATCH] Remove stable driver interfaces bp removed-as-of-ocata Change-Id: I4672cf7d9d72ef725212085972dbcd90db0e47cf --- keystone/assignment/V8_backends/__init__.py | 0 keystone/assignment/V8_backends/sql.py | 452 ------------------ .../assignment/V8_role_backends/__init__.py | 0 keystone/assignment/V8_role_backends/sql.py | 80 ---- keystone/assignment/backends/base.py | 251 ---------- keystone/assignment/backends/sql.py | 2 +- keystone/assignment/core.py | 96 ---- keystone/assignment/role_backends/base.py | 134 ------ keystone/assignment/role_backends/sql.py | 2 +- keystone/auth/core.py | 26 - keystone/catalog/backends/base.py | 2 +- keystone/catalog/backends/sql.py | 2 +- keystone/catalog/backends/templated.py | 2 +- keystone/catalog/core.py | 15 - keystone/common/manager.py | 32 -- keystone/credential/backends/base.py | 2 +- keystone/credential/backends/sql.py | 2 +- keystone/credential/core.py | 15 - keystone/endpoint_policy/backends/base.py | 2 +- keystone/endpoint_policy/backends/sql.py | 2 +- keystone/endpoint_policy/core.py | 15 - keystone/federation/V8_backends/__init__.py | 0 keystone/federation/V8_backends/sql.py | 389 --------------- keystone/federation/backends/base.py | 162 +------ keystone/federation/backends/sql.py | 2 +- keystone/federation/core.py | 52 -- keystone/identity/backends/base.py | 30 +- keystone/identity/backends/ldap/core.py | 2 +- keystone/identity/backends/sql.py | 2 +- keystone/identity/core.py | 42 -- keystone/identity/mapping_backends/base.py | 2 +- keystone/identity/mapping_backends/sql.py | 2 +- keystone/identity/shadow_backends/base.py | 26 - keystone/identity/shadow_backends/sql.py | 2 +- keystone/oauth1/backends/base.py | 2 +- keystone/oauth1/backends/sql.py | 2 +- keystone/oauth1/core.py | 14 - keystone/policy/backends/base.py | 2 +- keystone/policy/backends/rules.py | 2 +- keystone/policy/core.py | 15 - keystone/resource/V8_backends/__init__.py | 0 keystone/resource/V8_backends/sql.py | 260 ---------- keystone/resource/backends/base.py | 370 -------------- keystone/resource/backends/sql.py | 2 +- keystone/resource/config_backends/base.py | 2 +- keystone/resource/config_backends/sql.py | 2 +- keystone/resource/core.py | 60 --- keystone/revoke/backends/base.py | 2 +- keystone/revoke/backends/sql.py | 2 +- keystone/revoke/core.py | 15 - .../unit/backend/legacy_drivers/__init__.py | 0 .../legacy_drivers/assignment/V8/__init__.py | 0 .../legacy_drivers/assignment/V8/sql.py | 39 -- .../legacy_drivers/assignment/__init__.py | 0 .../legacy_drivers/federation/V8/__init__.py | 0 .../legacy_drivers/federation/V8/api_v3.py | 108 ----- .../legacy_drivers/federation/__init__.py | 0 .../legacy_drivers/resource/V8/__init__.py | 0 .../backend/legacy_drivers/resource/V8/sql.py | 71 --- .../legacy_drivers/resource/__init__.py | 0 .../legacy_drivers/role/V8/__init__.py | 0 .../backend/legacy_drivers/role/V8/sql.py | 30 -- .../backend/legacy_drivers/role/__init__.py | 0 keystone/tests/unit/catalog/test_backends.py | 2 +- keystone/tests/unit/common/test_manager.py | 78 --- keystone/tests/unit/test_backend_templated.py | 4 +- keystone/token/persistence/backends/kvs.py | 2 +- keystone/token/persistence/backends/sql.py | 2 +- keystone/token/persistence/core.py | 5 +- keystone/trust/backends/base.py | 2 +- keystone/trust/backends/sql.py | 2 +- keystone/trust/core.py | 14 - tox.ini | 9 +- 73 files changed, 50 insertions(+), 2917 deletions(-) delete mode 100644 keystone/assignment/V8_backends/__init__.py delete mode 100644 keystone/assignment/V8_backends/sql.py delete mode 100644 keystone/assignment/V8_role_backends/__init__.py delete mode 100644 keystone/assignment/V8_role_backends/sql.py delete mode 100644 keystone/auth/core.py delete mode 100644 keystone/federation/V8_backends/__init__.py delete mode 100644 keystone/federation/V8_backends/sql.py delete mode 100644 keystone/resource/V8_backends/__init__.py delete mode 100644 keystone/resource/V8_backends/sql.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/__init__.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/assignment/V8/__init__.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/assignment/V8/sql.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/assignment/__init__.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/federation/V8/__init__.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/federation/V8/api_v3.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/federation/__init__.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/resource/V8/__init__.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/resource/V8/sql.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/resource/__init__.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/role/V8/__init__.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/role/V8/sql.py delete mode 100644 keystone/tests/unit/backend/legacy_drivers/role/__init__.py delete mode 100644 keystone/tests/unit/common/test_manager.py diff --git a/keystone/assignment/V8_backends/__init__.py b/keystone/assignment/V8_backends/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/assignment/V8_backends/sql.py b/keystone/assignment/V8_backends/sql.py deleted file mode 100644 index aaa1cf218c..0000000000 --- a/keystone/assignment/V8_backends/sql.py +++ /dev/null @@ -1,452 +0,0 @@ -# Copyright 2012-13 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 sqlalchemy -from sqlalchemy.sql.expression import false - -from keystone.assignment.backends import base -from keystone.common import sql -import keystone.conf -from keystone import exception -from keystone.i18n import _ - - -CONF = keystone.conf.CONF - - -class AssignmentType(object): - USER_PROJECT = 'UserProject' - GROUP_PROJECT = 'GroupProject' - USER_DOMAIN = 'UserDomain' - GROUP_DOMAIN = 'GroupDomain' - - @classmethod - def calculate_type(cls, user_id, group_id, project_id, domain_id): - if user_id: - if project_id: - return cls.USER_PROJECT - if domain_id: - return cls.USER_DOMAIN - if group_id: - if project_id: - return cls.GROUP_PROJECT - if domain_id: - return cls.GROUP_DOMAIN - # Invalid parameters combination - raise exception.AssignmentTypeCalculationError(**locals()) - - -class Assignment(base.AssignmentDriverV8): - - def default_role_driver(self): - return 'sql' - - def default_resource_driver(self): - return 'sql' - - def list_user_ids_for_project(self, tenant_id): - with sql.session_for_read() as session: - query = session.query(RoleAssignment.actor_id) - query = query.filter_by(type=AssignmentType.USER_PROJECT) - query = query.filter_by(target_id=tenant_id) - query = query.distinct('actor_id') - assignments = query.all() - return [assignment.actor_id for assignment in assignments] - - def create_grant(self, role_id, user_id=None, group_id=None, - domain_id=None, project_id=None, - inherited_to_projects=False): - - assignment_type = AssignmentType.calculate_type( - user_id, group_id, project_id, domain_id) - try: - with sql.session_for_write() as session: - session.add(RoleAssignment( - type=assignment_type, - actor_id=user_id or group_id, - target_id=project_id or domain_id, - role_id=role_id, - inherited=inherited_to_projects)) - except sql.DBDuplicateEntry: # nosec : The v3 grant APIs are silent if - # the assignment already exists - pass - - def list_grant_role_ids(self, user_id=None, group_id=None, - domain_id=None, project_id=None, - inherited_to_projects=False): - with sql.session_for_read() as session: - q = session.query(RoleAssignment.role_id) - q = q.filter(RoleAssignment.actor_id == (user_id or group_id)) - q = q.filter(RoleAssignment.target_id == (project_id or domain_id)) - q = q.filter(RoleAssignment.inherited == inherited_to_projects) - return [x.role_id for x in q.all()] - - def _build_grant_filter(self, session, role_id, user_id, group_id, - domain_id, project_id, inherited_to_projects): - q = session.query(RoleAssignment) - q = q.filter_by(actor_id=user_id or group_id) - q = q.filter_by(target_id=project_id or domain_id) - q = q.filter_by(role_id=role_id) - q = q.filter_by(inherited=inherited_to_projects) - return q - - def check_grant_role_id(self, role_id, user_id=None, group_id=None, - domain_id=None, project_id=None, - inherited_to_projects=False): - with sql.session_for_read() as session: - try: - q = self._build_grant_filter( - session, role_id, user_id, group_id, domain_id, project_id, - inherited_to_projects) - q.one() - except sql.NotFound: - actor_id = user_id or group_id - target_id = domain_id or project_id - raise exception.RoleAssignmentNotFound(role_id=role_id, - actor_id=actor_id, - target_id=target_id) - - def delete_grant(self, role_id, user_id=None, group_id=None, - domain_id=None, project_id=None, - inherited_to_projects=False): - with sql.session_for_write() as session: - q = self._build_grant_filter( - session, role_id, user_id, group_id, domain_id, project_id, - inherited_to_projects) - if not q.delete(False): - actor_id = user_id or group_id - target_id = domain_id or project_id - raise exception.RoleAssignmentNotFound(role_id=role_id, - actor_id=actor_id, - target_id=target_id) - - def _list_project_ids_for_actor(self, actors, hints, inherited, - group_only=False): - # TODO(henry-nash): Now that we have a single assignment table, we - # should be able to honor the hints list that is provided. - - assignment_type = [AssignmentType.GROUP_PROJECT] - if not group_only: - assignment_type.append(AssignmentType.USER_PROJECT) - - sql_constraints = sqlalchemy.and_( - RoleAssignment.type.in_(assignment_type), - RoleAssignment.inherited == inherited, - RoleAssignment.actor_id.in_(actors)) - - with sql.session_for_read() as session: - query = session.query(RoleAssignment.target_id).filter( - sql_constraints).distinct() - - return [x.target_id for x in query.all()] - - def list_project_ids_for_user(self, user_id, group_ids, hints, - inherited=False): - actor_list = [user_id] - if group_ids: - actor_list = actor_list + group_ids - - return self._list_project_ids_for_actor(actor_list, hints, inherited) - - def list_domain_ids_for_user(self, user_id, group_ids, hints, - inherited=False): - with sql.session_for_read() as session: - query = session.query(RoleAssignment.target_id) - filters = [] - - if user_id: - sql_constraints = sqlalchemy.and_( - RoleAssignment.actor_id == user_id, - RoleAssignment.inherited == inherited, - RoleAssignment.type == AssignmentType.USER_DOMAIN) - filters.append(sql_constraints) - - if group_ids: - sql_constraints = sqlalchemy.and_( - RoleAssignment.actor_id.in_(group_ids), - RoleAssignment.inherited == inherited, - RoleAssignment.type == AssignmentType.GROUP_DOMAIN) - filters.append(sql_constraints) - - if not filters: - return [] - - query = query.filter(sqlalchemy.or_(*filters)).distinct() - - return [assignment.target_id for assignment in query.all()] - - def list_role_ids_for_groups_on_domain(self, group_ids, domain_id): - if not group_ids: - # If there's no groups then there will be no domain roles. - return [] - - sql_constraints = sqlalchemy.and_( - RoleAssignment.type == AssignmentType.GROUP_DOMAIN, - RoleAssignment.target_id == domain_id, - RoleAssignment.inherited == false(), - RoleAssignment.actor_id.in_(group_ids)) - - with sql.session_for_read() as session: - query = session.query(RoleAssignment.role_id).filter( - sql_constraints).distinct() - return [role.role_id for role in query.all()] - - def list_role_ids_for_groups_on_project( - self, group_ids, project_id, project_domain_id, project_parents): - - if not group_ids: - # If there's no groups then there will be no project roles. - return [] - - # NOTE(rodrigods): First, we always include projects with - # non-inherited assignments - sql_constraints = sqlalchemy.and_( - RoleAssignment.type == AssignmentType.GROUP_PROJECT, - RoleAssignment.inherited == false(), - RoleAssignment.target_id == project_id) - - if CONF.os_inherit.enabled: - # Inherited roles from domains - sql_constraints = sqlalchemy.or_( - sql_constraints, - sqlalchemy.and_( - RoleAssignment.type == AssignmentType.GROUP_DOMAIN, - RoleAssignment.inherited, - RoleAssignment.target_id == project_domain_id)) - - # Inherited roles from projects - if project_parents: - sql_constraints = sqlalchemy.or_( - sql_constraints, - sqlalchemy.and_( - RoleAssignment.type == AssignmentType.GROUP_PROJECT, - RoleAssignment.inherited, - RoleAssignment.target_id.in_(project_parents))) - - sql_constraints = sqlalchemy.and_( - sql_constraints, RoleAssignment.actor_id.in_(group_ids)) - - with sql.session_for_read() as session: - # NOTE(morganfainberg): Only select the columns we actually care - # about here, in this case role_id. - query = session.query(RoleAssignment.role_id).filter( - sql_constraints).distinct() - - return [result.role_id for result in query.all()] - - def list_project_ids_for_groups(self, group_ids, hints, - inherited=False): - return self._list_project_ids_for_actor( - group_ids, hints, inherited, group_only=True) - - def list_domain_ids_for_groups(self, group_ids, inherited=False): - if not group_ids: - # If there's no groups then there will be no domains. - return [] - - group_sql_conditions = sqlalchemy.and_( - RoleAssignment.type == AssignmentType.GROUP_DOMAIN, - RoleAssignment.inherited == inherited, - RoleAssignment.actor_id.in_(group_ids)) - - with sql.session_for_read() as session: - query = session.query(RoleAssignment.target_id).filter( - group_sql_conditions).distinct() - return [x.target_id for x in query.all()] - - def add_role_to_user_and_project(self, user_id, tenant_id, role_id): - try: - with sql.session_for_write() as session: - session.add(RoleAssignment( - type=AssignmentType.USER_PROJECT, - actor_id=user_id, target_id=tenant_id, - role_id=role_id, inherited=False)) - except sql.DBDuplicateEntry: - msg = ('User %s already has role %s in tenant %s' - % (user_id, role_id, tenant_id)) - raise exception.Conflict(type='role grant', details=msg) - - def remove_role_from_user_and_project(self, user_id, tenant_id, role_id): - with sql.session_for_write() as session: - q = session.query(RoleAssignment) - q = q.filter_by(actor_id=user_id) - q = q.filter_by(target_id=tenant_id) - q = q.filter_by(role_id=role_id) - if q.delete() == 0: - raise exception.RoleNotFound(message=_( - 'Cannot remove role that has not been granted, %s') % - role_id) - - def _get_user_assignment_types(self): - return [AssignmentType.USER_PROJECT, AssignmentType.USER_DOMAIN] - - def _get_group_assignment_types(self): - return [AssignmentType.GROUP_PROJECT, AssignmentType.GROUP_DOMAIN] - - def _get_project_assignment_types(self): - return [AssignmentType.USER_PROJECT, AssignmentType.GROUP_PROJECT] - - def _get_domain_assignment_types(self): - return [AssignmentType.USER_DOMAIN, AssignmentType.GROUP_DOMAIN] - - def _get_assignment_types(self, user, group, project, domain): - """Return a list of role assignment types based on provided entities. - - If one of user or group (the "actor") as well as one of project or - domain (the "target") are provided, the list will contain the role - assignment type for that specific pair of actor and target. - - If only an actor or target is provided, the list will contain the - role assignment types that satisfy the specified entity. - - For example, if user and project are provided, the return will be: - - [AssignmentType.USER_PROJECT] - - However, if only user was provided, the return would be: - - [AssignmentType.USER_PROJECT, AssignmentType.USER_DOMAIN] - - It is not expected that user and group (or project and domain) are - specified - but if they are, the most fine-grained value will be - chosen (i.e. user over group, project over domain). - - """ - actor_types = [] - if user: - actor_types = self._get_user_assignment_types() - elif group: - actor_types = self._get_group_assignment_types() - - target_types = [] - if project: - target_types = self._get_project_assignment_types() - elif domain: - target_types = self._get_domain_assignment_types() - - if actor_types and target_types: - return list(set(actor_types).intersection(target_types)) - - return actor_types or target_types - - def list_role_assignments(self, role_id=None, - user_id=None, group_ids=None, - domain_id=None, project_ids=None, - inherited_to_projects=None): - - def denormalize_role(ref): - assignment = {} - if ref.type == AssignmentType.USER_PROJECT: - assignment['user_id'] = ref.actor_id - assignment['project_id'] = ref.target_id - elif ref.type == AssignmentType.USER_DOMAIN: - assignment['user_id'] = ref.actor_id - assignment['domain_id'] = ref.target_id - elif ref.type == AssignmentType.GROUP_PROJECT: - assignment['group_id'] = ref.actor_id - assignment['project_id'] = ref.target_id - elif ref.type == AssignmentType.GROUP_DOMAIN: - assignment['group_id'] = ref.actor_id - assignment['domain_id'] = ref.target_id - else: - raise exception.Error(message=_( - 'Unexpected assignment type encountered, %s') % - ref.type) - assignment['role_id'] = ref.role_id - if ref.inherited: - assignment['inherited_to_projects'] = 'projects' - return assignment - - with sql.session_for_read() as session: - assignment_types = self._get_assignment_types( - user_id, group_ids, project_ids, domain_id) - - targets = None - if project_ids: - targets = project_ids - elif domain_id: - targets = [domain_id] - - actors = None - if group_ids: - actors = group_ids - elif user_id: - actors = [user_id] - - query = session.query(RoleAssignment) - - if role_id: - query = query.filter_by(role_id=role_id) - if actors: - query = query.filter(RoleAssignment.actor_id.in_(actors)) - if targets: - query = query.filter(RoleAssignment.target_id.in_(targets)) - if assignment_types: - query = query.filter(RoleAssignment.type.in_(assignment_types)) - if inherited_to_projects is not None: - query = query.filter_by(inherited=inherited_to_projects) - - return [denormalize_role(ref) for ref in query.all()] - - def delete_project_assignments(self, project_id): - with sql.session_for_write() as session: - q = session.query(RoleAssignment) - q = q.filter_by(target_id=project_id) - q.delete(False) - - def delete_role_assignments(self, role_id): - with sql.session_for_write() as session: - q = session.query(RoleAssignment) - q = q.filter_by(role_id=role_id) - q.delete(False) - - def delete_user_assignments(self, user_id): - with sql.session_for_write() as session: - q = session.query(RoleAssignment) - q = q.filter_by(actor_id=user_id) - q.delete(False) - - def delete_group_assignments(self, group_id): - with sql.session_for_write() as session: - q = session.query(RoleAssignment) - q = q.filter_by(actor_id=group_id) - q.delete(False) - - -class RoleAssignment(sql.ModelBase, sql.DictBase): - __tablename__ = 'assignment' - attributes = ['type', 'actor_id', 'target_id', 'role_id', 'inherited'] - # NOTE(henry-nash); Postgres requires a name to be defined for an Enum - type = sql.Column( - sql.Enum(AssignmentType.USER_PROJECT, AssignmentType.GROUP_PROJECT, - AssignmentType.USER_DOMAIN, AssignmentType.GROUP_DOMAIN, - name='type'), - nullable=False) - actor_id = sql.Column(sql.String(64), nullable=False) - target_id = sql.Column(sql.String(64), nullable=False) - role_id = sql.Column(sql.String(64), nullable=False) - inherited = sql.Column(sql.Boolean, default=False, nullable=False) - __table_args__ = ( - sql.PrimaryKeyConstraint('type', 'actor_id', 'target_id', 'role_id', - 'inherited'), - sql.Index('ix_actor_id', 'actor_id'), - ) - - def to_dict(self): - """Override parent method with a simpler implementation. - - RoleAssignment doesn't have non-indexed 'extra' attributes, so the - parent implementation is not applicable. - """ - return dict(self.items()) diff --git a/keystone/assignment/V8_role_backends/__init__.py b/keystone/assignment/V8_role_backends/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/assignment/V8_role_backends/sql.py b/keystone/assignment/V8_role_backends/sql.py deleted file mode 100644 index f150cd27e3..0000000000 --- a/keystone/assignment/V8_role_backends/sql.py +++ /dev/null @@ -1,80 +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.assignment.role_backends import base -from keystone.common import sql -from keystone import exception - - -class Role(base.RoleDriverV8): - - @sql.handle_conflicts(conflict_type='role') - def create_role(self, role_id, role): - with sql.session_for_write() as session: - ref = RoleTable.from_dict(role) - session.add(ref) - return ref.to_dict() - - @sql.truncated - def list_roles(self, hints): - with sql.session_for_read() as session: - query = session.query(RoleTable) - refs = sql.filter_limit_query(RoleTable, query, hints) - return [ref.to_dict() for ref in refs] - - def list_roles_from_ids(self, ids): - if not ids: - return [] - else: - with sql.session_for_read() as session: - query = session.query(RoleTable) - query = query.filter(RoleTable.id.in_(ids)) - role_refs = query.all() - return [role_ref.to_dict() for role_ref in role_refs] - - def _get_role(self, session, role_id): - ref = session.query(RoleTable).get(role_id) - if ref is None: - raise exception.RoleNotFound(role_id=role_id) - return ref - - def get_role(self, role_id): - with sql.session_for_read() as session: - return self._get_role(session, role_id).to_dict() - - @sql.handle_conflicts(conflict_type='role') - def update_role(self, role_id, role): - with sql.session_for_write() as session: - ref = self._get_role(session, role_id) - old_dict = ref.to_dict() - for k in role: - old_dict[k] = role[k] - new_role = RoleTable.from_dict(old_dict) - for attr in RoleTable.attributes: - if attr != 'id': - setattr(ref, attr, getattr(new_role, attr)) - ref.extra = new_role.extra - return ref.to_dict() - - def delete_role(self, role_id): - with sql.session_for_write() as session: - ref = self._get_role(session, role_id) - session.delete(ref) - - -class RoleTable(sql.ModelBase, sql.DictBase): - __tablename__ = 'role' - attributes = ['id', 'name'] - id = sql.Column(sql.String(64), primary_key=True) - name = sql.Column(sql.String(255), unique=True, nullable=False) - extra = sql.Column(sql.JsonBlob()) - __table_args__ = (sql.UniqueConstraint('name'),) diff --git a/keystone/assignment/backends/base.py b/keystone/assignment/backends/base.py index b581fa74fe..c5d00d7c36 100644 --- a/keystone/assignment/backends/base.py +++ b/keystone/assignment/backends/base.py @@ -15,25 +15,16 @@ import abc from oslo_log import log -from oslo_log import versionutils import six import keystone.conf from keystone import exception -from keystone.i18n import _LW CONF = keystone.conf.CONF LOG = log.getLogger(__name__) -# The AssignmentDriverBase class is the set of driver methods from earlier -# drivers that we still support, that have not been removed or modified. This -# class is then used to created the augmented V8 and V9 version abstract driver -# classes, without having to duplicate a lot of abstract method signatures. -# If you remove a method from V9, then move the abstract methods from this Base -# class to the V8 class. Do not modify any of the method signatures in the Base -# class - changes should only be made in the V8 and subsequent classes. @six.add_metaclass(abc.ABCMeta) class AssignmentDriverBase(object): @@ -152,249 +143,7 @@ class AssignmentDriverBase(object): """ raise exception.NotImplemented() # pragma: no cover - -class AssignmentDriverV8(AssignmentDriverBase): - """Removed or redefined methods from V8. - - Move the abstract methods of any methods removed or modified in later - versions of the driver from AssignmentDriverBase to here. We maintain this - so that legacy drivers, which will be a subclass of AssignmentDriverV8, can - still reference them. - - """ - - @abc.abstractmethod - def list_user_ids_for_project(self, tenant_id): - """List all user IDs with a role assignment in the specified project. - - :returns: a list of user_ids or an empty set. - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def list_project_ids_for_user(self, user_id, group_ids, hints, - inherited=False): - """List all project ids associated with a given user. - - :param user_id: the user in question - :param group_ids: the groups this user is a member of. This list is - built in the Manager, so that the driver itself - does not have to call across to identity. - :param hints: filter hints which the driver should - implement if at all possible. - :param inherited: whether assignments marked as inherited should - be included. - - :returns: a list of project ids or an empty list. - - This method should not try and expand any inherited assignments, - just report the projects that have the role for this user. The manager - method is responsible for expanding out inherited assignments. - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def list_domain_ids_for_user(self, user_id, group_ids, hints, - inherited=False): - """List all domain ids associated with a given user. - - :param user_id: the user in question - :param group_ids: the groups this user is a member of. This list is - built in the Manager, so that the driver itself - does not have to call across to identity. - :param hints: filter hints which the driver should - implement if at all possible. - :param inherited: whether to return domain_ids that have inherited - assignments or not. - - :returns: a list of domain ids or an empty list. - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def list_project_ids_for_groups(self, group_ids, hints, - inherited=False): - """List project ids accessible to specified groups. - - :param group_ids: List of group ids. - :param hints: filter hints which the driver should - implement if at all possible. - :param inherited: whether assignments marked as inherited should - be included. - :returns: List of project ids accessible to specified groups. - - This method should not try and expand any inherited assignments, - just report the projects that have the role for this group. The manager - method is responsible for expanding out inherited assignments. - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def list_domain_ids_for_groups(self, group_ids, inherited=False): - """List domain ids accessible to specified groups. - - :param group_ids: List of group ids. - :param inherited: whether to return domain_ids that have inherited - assignments or not. - :returns: List of domain ids accessible to specified groups. - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def list_role_ids_for_groups_on_project( - self, group_ids, project_id, project_domain_id, project_parents): - """List the group role ids for a specific project. - - Supports the ``OS-INHERIT`` role inheritance from the project's domain - if supported by the assignment driver. - - :param group_ids: list of group ids - :type group_ids: list - :param project_id: project identifier - :type project_id: str - :param project_domain_id: project's domain identifier - :type project_domain_id: str - :param project_parents: list of parent ids of this project - :type project_parents: list - :returns: list of role ids for the project - :rtype: list - """ - raise exception.NotImplemented() - - @abc.abstractmethod - def list_role_ids_for_groups_on_domain(self, group_ids, domain_id): - """List the group role ids for a specific domain. - - :param group_ids: list of group ids - :type group_ids: list - :param domain_id: domain identifier - :type domain_id: str - :returns: list of role ids for the project - :rtype: list - """ - raise exception.NotImplemented() - - -class AssignmentDriverV9(AssignmentDriverBase): - """New or redefined methods from V8. - - Add any new V9 abstract methods (or those with modified signatures) to - this class. - - """ - @abc.abstractmethod def delete_domain_assignments(self, domain_id): """Delete all assignments for a domain.""" raise exception.NotImplemented() - - -class V9AssignmentWrapperForV8Driver(AssignmentDriverV9): - """Wrapper class to supported a V8 legacy driver. - - In order to support legacy drivers without having to make the manager code - driver-version aware, we wrap legacy drivers so that they look like the - latest version. For the various changes made in a new driver, here are the - actions needed in this wrapper: - - Method removed from new driver - remove the call-through method from this - class, since the manager will no longer be - calling it. - Method signature (or meaning) changed - wrap the old method in a new - signature here, and munge the input - and output parameters accordingly. - New method added to new driver - add a method to implement the new - functionality here if possible. If that is - not possible, then return NotImplemented, - since we do not guarantee to support new - functionality with legacy drivers. - - """ - - @versionutils.deprecated( - as_of=versionutils.deprecated.MITAKA, - what='keystone.assignment.AssignmentDriverV8', - in_favor_of='keystone.assignment.AssignmentDriverV9', - remove_in=+2) - def __init__(self, wrapped_driver): - self.driver = wrapped_driver - - def delete_domain_assignments(self, domain_id): - """Delete all assignments for a domain.""" - msg = _LW('delete_domain_assignments method not found in custom ' - 'assignment driver. Domain assignments for domain (%s) to ' - 'users from other domains will not be removed. This was ' - 'added in V9 of the assignment driver.') - LOG.warning(msg, domain_id) - - def default_role_driver(self): - return self.driver.default_role_driver() - - def default_resource_driver(self): - return self.driver.default_resource_driver() - - def add_role_to_user_and_project(self, user_id, tenant_id, role_id): - self.driver.add_role_to_user_and_project(user_id, tenant_id, role_id) - - def remove_role_from_user_and_project(self, user_id, tenant_id, role_id): - self.driver.remove_role_from_user_and_project( - user_id, tenant_id, role_id) - - def create_grant(self, role_id, user_id=None, group_id=None, - domain_id=None, project_id=None, - inherited_to_projects=False): - self.driver.create_grant( - role_id, user_id=user_id, group_id=group_id, - domain_id=domain_id, project_id=project_id, - inherited_to_projects=inherited_to_projects) - - def list_grant_role_ids(self, user_id=None, group_id=None, - domain_id=None, project_id=None, - inherited_to_projects=False): - return self.driver.list_grant_role_ids( - user_id=user_id, group_id=group_id, - domain_id=domain_id, project_id=project_id, - inherited_to_projects=inherited_to_projects) - - def check_grant_role_id(self, role_id, user_id=None, group_id=None, - domain_id=None, project_id=None, - inherited_to_projects=False): - self.driver.check_grant_role_id( - role_id, user_id=user_id, group_id=group_id, - domain_id=domain_id, project_id=project_id, - inherited_to_projects=inherited_to_projects) - - def delete_grant(self, role_id, user_id=None, group_id=None, - domain_id=None, project_id=None, - inherited_to_projects=False): - self.driver.delete_grant( - role_id, user_id=user_id, group_id=group_id, - domain_id=domain_id, project_id=project_id, - inherited_to_projects=inherited_to_projects) - - def list_role_assignments(self, role_id=None, - user_id=None, group_ids=None, - domain_id=None, project_ids=None, - inherited_to_projects=None): - return self.driver.list_role_assignments( - role_id=role_id, - user_id=user_id, group_ids=group_ids, - domain_id=domain_id, project_ids=project_ids, - inherited_to_projects=inherited_to_projects) - - def delete_project_assignments(self, project_id): - self.driver.delete_project_assignments(project_id) - - def delete_role_assignments(self, role_id): - self.driver.delete_role_assignments(role_id) - - def delete_user_assignments(self, user_id): - self.driver.delete_user_assignments(user_id) - - def delete_group_assignments(self, group_id): - self.driver.delete_group_assignments(group_id) diff --git a/keystone/assignment/backends/sql.py b/keystone/assignment/backends/sql.py index c6937381c4..3d62e269ac 100644 --- a/keystone/assignment/backends/sql.py +++ b/keystone/assignment/backends/sql.py @@ -40,7 +40,7 @@ class AssignmentType(object): raise exception.AssignmentTypeCalculationError(**locals()) -class Assignment(base.AssignmentDriverV9): +class Assignment(base.AssignmentDriverBase): def default_role_driver(self): return 'sql' diff --git a/keystone/assignment/core.py b/keystone/assignment/core.py index 56c4578091..db75c09a42 100644 --- a/keystone/assignment/core.py +++ b/keystone/assignment/core.py @@ -20,8 +20,6 @@ import functools from oslo_log import log from oslo_log import versionutils -from keystone.assignment.backends import base -from keystone.assignment.role_backends import base as role_base from keystone.common import cache from keystone.common import dependency from keystone.common import driver_hints @@ -92,13 +90,6 @@ class Manager(manager.Manager): raise exception.KeystoneConfigurationError(msg) super(Manager, self).__init__(assignment_driver) - # Make sure it is a driver version we support, and if it is a legacy - # driver, then wrap it. - if isinstance(self.driver, base.AssignmentDriverV8): - self.driver = base.V9AssignmentWrapperForV8Driver(self.driver) - elif not isinstance(self.driver, base.AssignmentDriverV9): - raise exception.UnsupportedDriverVersion(driver=assignment_driver) - self.event_callbacks = { notifications.ACTIONS.deleted: { 'domain': [self._delete_domain_assignments], @@ -1099,46 +1090,6 @@ class Manager(manager.Manager): ) -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.assignment.AssignmentDriverBase', - in_favor_of='keystone.assignment.backends.base.AssignmentDriverBase', - remove_in=+1) -class AssignmentDriverBase(base.AssignmentDriverBase): - pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.assignment.AssignmentDriverV8', - in_favor_of='keystone.assignment.backends.base.AssignmentDriverV8', - remove_in=+1) -class AssignmentDriverV8(base.AssignmentDriverV8): - pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.assignment.AssignmentDriverV9', - in_favor_of='keystone.assignment.backends.base.AssignmentDriverV9', - remove_in=+1) -class AssignmentDriverV9(base.AssignmentDriverV9): - pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.assignment.V9AssignmentWrapperForV8Driver', - in_favor_of=( - 'keystone.assignment.backends.base.V9AssignmentWrapperForV8Driver'), - remove_in=+1) -class V9AssignmentWrapperForV8Driver(base.V9AssignmentWrapperForV8Driver): - pass - - -Driver = manager.create_legacy_driver(base.AssignmentDriverV8) - - @dependency.provider('role_api') @dependency.requires('assignment_api') class RoleManager(manager.Manager): @@ -1159,13 +1110,6 @@ class RoleManager(manager.Manager): super(RoleManager, self).__init__(role_driver) - # Make sure it is a driver version we support, and if it is a legacy - # driver, then wrap it. - if isinstance(self.driver, role_base.RoleDriverV8): - self.driver = role_base.V9RoleWrapperForV8Driver(self.driver) - elif not isinstance(self.driver, role_base.RoleDriverV9): - raise exception.UnsupportedDriverVersion(driver=role_driver) - def _append_null_domain_id(f): """Append a domain_id field to a role dict if it is not already there. @@ -1244,43 +1188,3 @@ class RoleManager(manager.Manager): def delete_implied_role(self, prior_role_id, implied_role_id): self.driver.delete_implied_role(prior_role_id, implied_role_id) COMPUTED_ASSIGNMENTS_REGION.invalidate() - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.assignment.RoleDriverBase', - in_favor_of='keystone.assignment.role_backends.base.RoleDriverBase', - remove_in=+1) -class RoleDriverBase(role_base.RoleDriverBase): - pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.assignment.RoleDriverV8', - in_favor_of='keystone.assignment.role_backends.base.RoleDriverV8', - remove_in=+1) -class RoleDriverV8(role_base.RoleDriverV8): - pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.assignment.RoleDriverV9', - in_favor_of='keystone.assignment.role_backends.base.RoleDriverV9', - remove_in=+1) -class RoleDriverV9(role_base.RoleDriverV9): - pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.assignment.V9RoleWrapperForV8Driver', - in_favor_of=( - 'keystone.assignment.role_backends.base.V9RoleWrapperForV8Driver'), - remove_in=+1) -class V9RoleWrapperForV8Driver(role_base.V9RoleWrapperForV8Driver): - pass - - -RoleDriver = manager.create_legacy_driver(role_base.RoleDriverV8) diff --git a/keystone/assignment/role_backends/base.py b/keystone/assignment/role_backends/base.py index adee9414e7..a3b7eb0ed3 100644 --- a/keystone/assignment/role_backends/base.py +++ b/keystone/assignment/role_backends/base.py @@ -14,24 +14,15 @@ import abc -from oslo_log import versionutils import six import keystone.conf from keystone import exception -from keystone.i18n import _ CONF = keystone.conf.CONF -# The RoleDriverBase class is the set of driver methods from earlier -# drivers that we still support, that have not been removed or modified. This -# class is then used to created the augmented V8 and V9 version abstract driver -# classes, without having to duplicate a lot of abstract method signatures. -# If you remove a method from V9, then move the abstract methods from this Base -# class to the V8 class. Do not modify any of the method signatures in the Base -# class - changes should only be made in the V8 and subsequent classes. @six.add_metaclass(abc.ABCMeta) class RoleDriverBase(object): @@ -102,28 +93,6 @@ class RoleDriverBase(object): """ raise exception.NotImplemented() # pragma: no cover - -class RoleDriverV8(RoleDriverBase): - """Removed or redefined methods from V8. - - Move the abstract methods of any methods removed or modified in later - versions of the driver from RoleDriverBase to here. We maintain this - so that legacy drivers, which will be a subclass of RoleDriverV8, can - still reference them. - - """ - - pass - - -class RoleDriverV9(RoleDriverBase): - """New or redefined methods from V8. - - Add any new V9 abstract methods (or those with modified signatures) to - this class. - - """ - @abc.abstractmethod def get_implied_role(self, prior_role_id, implied_role_id): """Get a role inference rule. @@ -162,106 +131,3 @@ class RoleDriverV9(RoleDriverBase): def list_implied_roles(self, prior_role_id): """List roles implied from the prior role ID.""" raise exception.NotImplemented() # pragma: no cover - - -class V9RoleWrapperForV8Driver(RoleDriverV9): - """Wrapper class to supported a V8 legacy driver. - - In order to support legacy drivers without having to make the manager code - driver-version aware, we wrap legacy drivers so that they look like the - latest version. For the various changes made in a new driver, here are the - actions needed in this wrapper: - - Method removed from new driver - remove the call-through method from this - class, since the manager will no longer be - calling it. - Method signature (or meaning) changed - wrap the old method in a new - signature here, and munge the input - and output parameters accordingly. - New method added to new driver - add a method to implement the new - functionality here if possible. If that is - not possible, then return NotImplemented, - since we do not guarantee to support new - functionality with legacy drivers. - - This V8 wrapper contains the following support for newer manager code: - - - The current manager code expects a role entity to have a domain_id - attribute, with a non-None value indicating a domain specific role. V8 - drivers will only understand global roles, hence if a non-None domain_id - is passed to this wrapper, it will raise a NotImplemented exception. - If a None-valued domain_id is passed in, it will be trimmed off before - the underlying driver is called (and a None-valued domain_id attribute - is added in for any entities returned to the manager. - - """ - - @versionutils.deprecated( - as_of=versionutils.deprecated.MITAKA, - what='keystone.assignment.RoleDriverV8', - in_favor_of='keystone.assignment.RoleDriverV9', - remove_in=+2) - def __init__(self, wrapped_driver): - self.driver = wrapped_driver - - def _append_null_domain_id(self, role_or_list): - def _append_null_domain_id_to_dict(role): - if 'domain_id' not in role: - role['domain_id'] = None - return role - - if isinstance(role_or_list, list): - return [_append_null_domain_id_to_dict(x) for x in role_or_list] - else: - return _append_null_domain_id_to_dict(role_or_list) - - def _trim_and_assert_null_domain_id(self, role): - if 'domain_id' in role: - if role['domain_id'] is not None: - raise exception.NotImplemented( - _('Domain specific roles are not supported in the V8 ' - 'role driver')) - else: - new_role = role.copy() - new_role.pop('domain_id') - return new_role - else: - return role - - def create_role(self, role_id, role): - new_role = self._trim_and_assert_null_domain_id(role) - return self._append_null_domain_id( - self.driver.create_role(role_id, new_role)) - - def list_roles(self, hints): - return self._append_null_domain_id(self.driver.list_roles(hints)) - - def list_roles_from_ids(self, role_ids): - return self._append_null_domain_id( - self.driver.list_roles_from_ids(role_ids)) - - def get_role(self, role_id): - return self._append_null_domain_id(self.driver.get_role(role_id)) - - def update_role(self, role_id, role): - update_role = self._trim_and_assert_null_domain_id(role) - return self._append_null_domain_id( - self.driver.update_role(role_id, update_role)) - - def delete_role(self, role_id): - self.driver.delete_role(role_id) - - def get_implied_role(self, prior_role_id, implied_role_id): - raise exception.NotImplemented() # pragma: no cover - - def create_implied_role(self, prior_role_id, implied_role_id): - raise exception.NotImplemented() # pragma: no cover - - def delete_implied_role(self, prior_role_id, implied_role_id): - raise exception.NotImplemented() # pragma: no cover - - def list_implied_roles(self, prior_role_id): - raise exception.NotImplemented() # pragma: no cover - - def list_role_inference_rules(self): - raise exception.NotImplemented() # pragma: no cover diff --git a/keystone/assignment/role_backends/sql.py b/keystone/assignment/role_backends/sql.py index a5274ace87..52052df0a1 100644 --- a/keystone/assignment/role_backends/sql.py +++ b/keystone/assignment/role_backends/sql.py @@ -25,7 +25,7 @@ from keystone import exception NULL_DOMAIN_ID = '<>' -class Role(base.RoleDriverV9): +class Role(base.RoleDriverBase): @sql.handle_conflicts(conflict_type='role') def create_role(self, role_id, role): diff --git a/keystone/auth/core.py b/keystone/auth/core.py deleted file mode 100644 index 5cc1c4e42f..0000000000 --- a/keystone/auth/core.py +++ /dev/null @@ -1,26 +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 oslo_log import versionutils - -from keystone.auth.plugins import base - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.auth.AuthMethodHandler', - in_favor_of='keystone.auth.plugins.base.AuthMethodHandler', - remove_in=+1) -class AuthMethodHandler(base.AuthMethodHandler): - pass diff --git a/keystone/catalog/backends/base.py b/keystone/catalog/backends/base.py index 34c86dc67f..8afcf4353c 100644 --- a/keystone/catalog/backends/base.py +++ b/keystone/catalog/backends/base.py @@ -24,7 +24,7 @@ CONF = keystone.conf.CONF @six.add_metaclass(abc.ABCMeta) -class CatalogDriverV8(object): +class CatalogDriverBase(object): """Interface description for the Catalog driver.""" def _get_list_limit(self): diff --git a/keystone/catalog/backends/sql.py b/keystone/catalog/backends/sql.py index e9b67f514c..ad1f36b5a1 100644 --- a/keystone/catalog/backends/sql.py +++ b/keystone/catalog/backends/sql.py @@ -81,7 +81,7 @@ class Endpoint(sql.ModelBase, sql.DictBase): extra = sql.Column(sql.JsonBlob()) -class Catalog(base.CatalogDriverV8): +class Catalog(base.CatalogDriverBase): # Regions def list_regions(self, hints): with sql.session_for_read() as session: diff --git a/keystone/catalog/backends/templated.py b/keystone/catalog/backends/templated.py index 386fa1b950..b49f78809f 100644 --- a/keystone/catalog/backends/templated.py +++ b/keystone/catalog/backends/templated.py @@ -56,7 +56,7 @@ def parse_templates(template_lines): return o -class Catalog(base.CatalogDriverV8): +class Catalog(base.CatalogDriverBase): """A backend that generates endpoints for the Catalog based on templates. It is usually configured via config entries that look like: diff --git a/keystone/catalog/core.py b/keystone/catalog/core.py index fbcca45a90..9e8228d292 100644 --- a/keystone/catalog/core.py +++ b/keystone/catalog/core.py @@ -15,9 +15,6 @@ """Main entry point into the Catalog service.""" -from oslo_log import versionutils - -from keystone.catalog.backends import base from keystone.common import cache from keystone.common import dependency from keystone.common import driver_hints @@ -329,15 +326,3 @@ class Manager(manager.Manager): except exception.NotImplemented: # Some catalog drivers don't support this pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.catalog.CatalogDriverV8', - in_favor_of='keystone.catalog.backends.base.CatalogDriverV8', - remove_in=+1) -class CatalogDriverV8(base.CatalogDriverV8): - pass - - -Driver = manager.create_legacy_driver(base.CatalogDriverV8) diff --git a/keystone/common/manager.py b/keystone/common/manager.py index 569f154c6d..926f481b8b 100644 --- a/keystone/common/manager.py +++ b/keystone/common/manager.py @@ -20,7 +20,6 @@ import types from oslo_log import log from oslo_log import versionutils from oslo_utils import importutils -from oslo_utils import reflection import six import stevedore @@ -190,34 +189,3 @@ class Manager(object): # cache this setattr(self, name, f) return f - - -def create_legacy_driver(driver_class): - """Helper function to deprecate the original driver classes. - - The keystone.{subsystem}.Driver classes are deprecated in favor of the - new versioned classes. This function creates a new class based on a - versioned class and adds a deprecation message when it is used. - - This will allow existing custom drivers to work when the Driver class is - renamed to include a version. - - Example usage: - - Driver = create_legacy_driver(CatalogDriverV8) - - """ - module_name = driver_class.__module__ - class_name = reflection.get_class_name(driver_class) - - class Driver(driver_class): - - @versionutils.deprecated( - as_of=versionutils.deprecated.LIBERTY, - what='%s.Driver' % module_name, - in_favor_of=class_name, - remove_in=+2) - def __init__(self, *args, **kwargs): - super(Driver, self).__init__(*args, **kwargs) - - return Driver diff --git a/keystone/credential/backends/base.py b/keystone/credential/backends/base.py index 188251311a..cbe9668189 100644 --- a/keystone/credential/backends/base.py +++ b/keystone/credential/backends/base.py @@ -24,7 +24,7 @@ LOG = log.getLogger(__name__) @six.add_metaclass(abc.ABCMeta) -class CredentialDriverV8(object): +class CredentialDriverBase(object): # credential crud @abc.abstractmethod diff --git a/keystone/credential/backends/sql.py b/keystone/credential/backends/sql.py index 350787a95e..6eb0385f39 100644 --- a/keystone/credential/backends/sql.py +++ b/keystone/credential/backends/sql.py @@ -33,7 +33,7 @@ class CredentialModel(sql.ModelBase, sql.DictBase): extra = sql.Column(sql.JsonBlob()) -class Credential(base.CredentialDriverV8): +class Credential(base.CredentialDriverBase): # credential crud diff --git a/keystone/credential/core.py b/keystone/credential/core.py index 17e9c5bb54..978fda20a1 100644 --- a/keystone/credential/core.py +++ b/keystone/credential/core.py @@ -16,13 +16,10 @@ import json -from oslo_log import versionutils - from keystone.common import dependency from keystone.common import driver_hints from keystone.common import manager import keystone.conf -from keystone.credential.backends import base from keystone import exception @@ -142,15 +139,3 @@ class Manager(manager.Manager): else: ref['blob'] = existing_blob return ref - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.credential.CredentialDriverV8', - in_favor_of='keystone.credential.backends.base.CredentialDriverV8', - remove_in=+1) -class AuthMethodHandler(base.CredentialDriverV8): - pass - - -Driver = manager.create_legacy_driver(base.CredentialDriverV8) diff --git a/keystone/endpoint_policy/backends/base.py b/keystone/endpoint_policy/backends/base.py index f60a86cf11..b8c99a42c7 100644 --- a/keystone/endpoint_policy/backends/base.py +++ b/keystone/endpoint_policy/backends/base.py @@ -17,7 +17,7 @@ from keystone import exception @six.add_metaclass(abc.ABCMeta) -class EndpointPolicyDriverV8(object): +class EndpointPolicyDriverBase(object): """Interface description for an Endpoint Policy driver.""" @abc.abstractmethod diff --git a/keystone/endpoint_policy/backends/sql.py b/keystone/endpoint_policy/backends/sql.py index ebf89f0579..7627375f19 100644 --- a/keystone/endpoint_policy/backends/sql.py +++ b/keystone/endpoint_policy/backends/sql.py @@ -48,7 +48,7 @@ class PolicyAssociation(sql.ModelBase, sql.ModelDictMixin): return d -class EndpointPolicy(base.EndpointPolicyDriverV8): +class EndpointPolicy(base.EndpointPolicyDriverBase): def create_policy_association(self, policy_id, endpoint_id=None, service_id=None, region_id=None): diff --git a/keystone/endpoint_policy/core.py b/keystone/endpoint_policy/core.py index 1288729317..fda3896d28 100644 --- a/keystone/endpoint_policy/core.py +++ b/keystone/endpoint_policy/core.py @@ -13,12 +13,10 @@ # under the License. from oslo_log import log -from oslo_log import versionutils from keystone.common import dependency from keystone.common import manager import keystone.conf -from keystone.endpoint_policy.backends import base from keystone import exception from keystone.i18n import _, _LE, _LW @@ -263,16 +261,3 @@ class Manager(manager.Manager): msg = _('No policy is associated with endpoint ' '%(endpoint_id)s.') % {'endpoint_id': endpoint_id} raise exception.NotFound(msg) - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.endpoint_policy.EndpointPolicyDriverV8', - in_favor_of=( - 'keystone.endpoint_policy.backends.base.EndpointPolicyDriverV8'), - remove_in=+1) -class EndpointPolicyDriverV8(base.EndpointPolicyDriverV8): - pass - - -Driver = manager.create_legacy_driver(base.EndpointPolicyDriverV8) diff --git a/keystone/federation/V8_backends/__init__.py b/keystone/federation/V8_backends/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/federation/V8_backends/sql.py b/keystone/federation/V8_backends/sql.py deleted file mode 100644 index d6b42aa0c7..0000000000 --- a/keystone/federation/V8_backends/sql.py +++ /dev/null @@ -1,389 +0,0 @@ -# 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 oslo_log import log -from oslo_serialization import jsonutils -import six -from sqlalchemy import orm - -from keystone.common import sql -from keystone import exception -from keystone.federation import core -from keystone.i18n import _ - - -LOG = log.getLogger(__name__) - - -class FederationProtocolModel(sql.ModelBase, sql.DictBase): - __tablename__ = 'federation_protocol' - attributes = ['id', 'idp_id', 'mapping_id'] - mutable_attributes = frozenset(['mapping_id']) - - id = sql.Column(sql.String(64), primary_key=True) - idp_id = sql.Column(sql.String(64), sql.ForeignKey('identity_provider.id', - ondelete='CASCADE'), primary_key=True) - mapping_id = sql.Column(sql.String(64), nullable=False) - - @classmethod - def from_dict(cls, dictionary): - new_dictionary = dictionary.copy() - return cls(**new_dictionary) - - def to_dict(self): - """Return a dictionary with model's attributes.""" - d = dict() - for attr in self.__class__.attributes: - d[attr] = getattr(self, attr) - return d - - -class IdentityProviderModel(sql.ModelBase, sql.DictBase): - __tablename__ = 'identity_provider' - attributes = ['id', 'enabled', 'description', 'remote_ids'] - mutable_attributes = frozenset(['description', 'enabled', 'remote_ids']) - - id = sql.Column(sql.String(64), primary_key=True) - enabled = sql.Column(sql.Boolean, nullable=False) - description = sql.Column(sql.Text(), nullable=True) - remote_ids = orm.relationship('IdPRemoteIdsModel', - order_by='IdPRemoteIdsModel.remote_id', - cascade='all, delete-orphan') - - @classmethod - def from_dict(cls, dictionary): - new_dictionary = dictionary.copy() - remote_ids_list = new_dictionary.pop('remote_ids', None) - if not remote_ids_list: - remote_ids_list = [] - identity_provider = cls(**new_dictionary) - remote_ids = [] - # NOTE(fmarco76): the remote_ids_list contains only remote ids - # associated with the IdP because of the "relationship" established in - # sqlalchemy and corresponding to the FK in the idp_remote_ids table - for remote in remote_ids_list: - remote_ids.append(IdPRemoteIdsModel(remote_id=remote)) - identity_provider.remote_ids = remote_ids - return identity_provider - - def to_dict(self): - """Return a dictionary with model's attributes.""" - d = dict() - for attr in self.__class__.attributes: - d[attr] = getattr(self, attr) - d['remote_ids'] = [] - for remote in self.remote_ids: - d['remote_ids'].append(remote.remote_id) - return d - - -class IdPRemoteIdsModel(sql.ModelBase, sql.DictBase): - __tablename__ = 'idp_remote_ids' - attributes = ['idp_id', 'remote_id'] - mutable_attributes = frozenset(['idp_id', 'remote_id']) - - idp_id = sql.Column(sql.String(64), - sql.ForeignKey('identity_provider.id', - ondelete='CASCADE')) - remote_id = sql.Column(sql.String(255), - primary_key=True) - - @classmethod - def from_dict(cls, dictionary): - new_dictionary = dictionary.copy() - return cls(**new_dictionary) - - def to_dict(self): - """Return a dictionary with model's attributes.""" - d = dict() - for attr in self.__class__.attributes: - d[attr] = getattr(self, attr) - return d - - -class MappingModel(sql.ModelBase, sql.DictBase): - __tablename__ = 'mapping' - attributes = ['id', 'rules'] - - id = sql.Column(sql.String(64), primary_key=True) - rules = sql.Column(sql.JsonBlob(), nullable=False) - - @classmethod - def from_dict(cls, dictionary): - new_dictionary = dictionary.copy() - new_dictionary['rules'] = jsonutils.dumps(new_dictionary['rules']) - return cls(**new_dictionary) - - def to_dict(self): - """Return a dictionary with model's attributes.""" - d = dict() - for attr in self.__class__.attributes: - d[attr] = getattr(self, attr) - d['rules'] = jsonutils.loads(d['rules']) - return d - - -class ServiceProviderModel(sql.ModelBase, sql.DictBase): - __tablename__ = 'service_provider' - attributes = ['auth_url', 'id', 'enabled', 'description', - 'relay_state_prefix', 'sp_url'] - mutable_attributes = frozenset(['auth_url', 'description', 'enabled', - 'relay_state_prefix', 'sp_url']) - - id = sql.Column(sql.String(64), primary_key=True) - enabled = sql.Column(sql.Boolean, nullable=False) - description = sql.Column(sql.Text(), nullable=True) - auth_url = sql.Column(sql.String(256), nullable=False) - sp_url = sql.Column(sql.String(256), nullable=False) - relay_state_prefix = sql.Column(sql.String(256), nullable=False) - - @classmethod - def from_dict(cls, dictionary): - new_dictionary = dictionary.copy() - return cls(**new_dictionary) - - def to_dict(self): - """Return a dictionary with model's attributes.""" - d = dict() - for attr in self.__class__.attributes: - d[attr] = getattr(self, attr) - return d - - -class Federation(core.FederationDriverV8): - - _CONFLICT_LOG_MSG = 'Conflict %(conflict_type)s: %(details)s' - - def _handle_idp_conflict(self, e): - conflict_type = 'identity_provider' - details = six.text_type(e) - LOG.debug(self._CONFLICT_LOG_MSG, {'conflict_type': conflict_type, - 'details': details}) - if 'remote_id' in details: - msg = _('Duplicate remote ID: %s') - else: - msg = _('Duplicate entry: %s') - msg = msg % e.value - raise exception.Conflict(type=conflict_type, details=msg) - - # Identity Provider CRUD - @sql.handle_conflicts(conflict_type='identity_provider') - def create_idp(self, idp_id, idp): - idp['id'] = idp_id - with sql.session_for_write() as session: - idp_ref = IdentityProviderModel.from_dict(idp) - session.add(idp_ref) - return idp_ref.to_dict() - - def delete_idp(self, idp_id): - with sql.session_for_write() as session: - self._delete_assigned_protocols(session, idp_id) - idp_ref = self._get_idp(session, idp_id) - session.delete(idp_ref) - - def _get_idp(self, session, idp_id): - idp_ref = session.query(IdentityProviderModel).get(idp_id) - if not idp_ref: - raise exception.IdentityProviderNotFound(idp_id=idp_id) - return idp_ref - - def _get_idp_from_remote_id(self, session, remote_id): - q = session.query(IdPRemoteIdsModel) - q = q.filter_by(remote_id=remote_id) - try: - return q.one() - except sql.NotFound: - raise exception.IdentityProviderNotFound(idp_id=remote_id) - - def list_idps(self): - with sql.session_for_read() as session: - idps = session.query(IdentityProviderModel) - idps_list = [idp.to_dict() for idp in idps] - return idps_list - - def get_idp(self, idp_id): - with sql.session_for_read() as session: - idp_ref = self._get_idp(session, idp_id) - return idp_ref.to_dict() - - def get_idp_from_remote_id(self, remote_id): - with sql.session_for_read() as session: - ref = self._get_idp_from_remote_id(session, remote_id) - return ref.to_dict() - - def update_idp(self, idp_id, idp): - try: - with sql.session_for_write() as session: - idp_ref = self._get_idp(session, idp_id) - old_idp = idp_ref.to_dict() - old_idp.update(idp) - new_idp = IdentityProviderModel.from_dict(old_idp) - for attr in IdentityProviderModel.mutable_attributes: - setattr(idp_ref, attr, getattr(new_idp, attr)) - return idp_ref.to_dict() - except sql.DBDuplicateEntry as e: - self._handle_idp_conflict(e) - - # Protocol CRUD - def _get_protocol(self, session, idp_id, protocol_id): - q = session.query(FederationProtocolModel) - q = q.filter_by(id=protocol_id, idp_id=idp_id) - try: - return q.one() - except sql.NotFound: - kwargs = {'protocol_id': protocol_id, - 'idp_id': idp_id} - raise exception.FederatedProtocolNotFound(**kwargs) - - @sql.handle_conflicts(conflict_type='federation_protocol') - def create_protocol(self, idp_id, protocol_id, protocol): - protocol['id'] = protocol_id - protocol['idp_id'] = idp_id - with sql.session_for_write() as session: - self._get_idp(session, idp_id) - protocol_ref = FederationProtocolModel.from_dict(protocol) - session.add(protocol_ref) - return protocol_ref.to_dict() - - def update_protocol(self, idp_id, protocol_id, protocol): - with sql.session_for_write() as session: - proto_ref = self._get_protocol(session, idp_id, protocol_id) - old_proto = proto_ref.to_dict() - old_proto.update(protocol) - new_proto = FederationProtocolModel.from_dict(old_proto) - for attr in FederationProtocolModel.mutable_attributes: - setattr(proto_ref, attr, getattr(new_proto, attr)) - return proto_ref.to_dict() - - def get_protocol(self, idp_id, protocol_id): - with sql.session_for_read() as session: - protocol_ref = self._get_protocol(session, idp_id, protocol_id) - return protocol_ref.to_dict() - - def list_protocols(self, idp_id): - with sql.session_for_read() as session: - q = session.query(FederationProtocolModel) - q = q.filter_by(idp_id=idp_id) - protocols = [protocol.to_dict() for protocol in q] - return protocols - - def delete_protocol(self, idp_id, protocol_id): - with sql.session_for_write() as session: - key_ref = self._get_protocol(session, idp_id, protocol_id) - session.delete(key_ref) - - def _delete_assigned_protocols(self, session, idp_id): - query = session.query(FederationProtocolModel) - query = query.filter_by(idp_id=idp_id) - query.delete() - - # Mapping CRUD - def _get_mapping(self, session, mapping_id): - mapping_ref = session.query(MappingModel).get(mapping_id) - if not mapping_ref: - raise exception.MappingNotFound(mapping_id=mapping_id) - return mapping_ref - - @sql.handle_conflicts(conflict_type='mapping') - def create_mapping(self, mapping_id, mapping): - ref = {} - ref['id'] = mapping_id - ref['rules'] = mapping.get('rules') - with sql.session_for_write() as session: - mapping_ref = MappingModel.from_dict(ref) - session.add(mapping_ref) - return mapping_ref.to_dict() - - def delete_mapping(self, mapping_id): - with sql.session_for_write() as session: - mapping_ref = self._get_mapping(session, mapping_id) - session.delete(mapping_ref) - - def list_mappings(self): - with sql.session_for_read() as session: - mappings = session.query(MappingModel) - return [x.to_dict() for x in mappings] - - def get_mapping(self, mapping_id): - with sql.session_for_read() as session: - mapping_ref = self._get_mapping(session, mapping_id) - return mapping_ref.to_dict() - - @sql.handle_conflicts(conflict_type='mapping') - def update_mapping(self, mapping_id, mapping): - ref = {} - ref['id'] = mapping_id - ref['rules'] = mapping.get('rules') - with sql.session_for_write() as session: - mapping_ref = self._get_mapping(session, mapping_id) - old_mapping = mapping_ref.to_dict() - old_mapping.update(ref) - new_mapping = MappingModel.from_dict(old_mapping) - for attr in MappingModel.attributes: - setattr(mapping_ref, attr, getattr(new_mapping, attr)) - return mapping_ref.to_dict() - - def get_mapping_from_idp_and_protocol(self, idp_id, protocol_id): - with sql.session_for_read() as session: - protocol_ref = self._get_protocol(session, idp_id, protocol_id) - mapping_id = protocol_ref.mapping_id - mapping_ref = self._get_mapping(session, mapping_id) - return mapping_ref.to_dict() - - # Service Provider CRUD - @sql.handle_conflicts(conflict_type='service_provider') - def create_sp(self, sp_id, sp): - sp['id'] = sp_id - with sql.session_for_write() as session: - sp_ref = ServiceProviderModel.from_dict(sp) - session.add(sp_ref) - return sp_ref.to_dict() - - def delete_sp(self, sp_id): - with sql.session_for_write() as session: - sp_ref = self._get_sp(session, sp_id) - session.delete(sp_ref) - - def _get_sp(self, session, sp_id): - sp_ref = session.query(ServiceProviderModel).get(sp_id) - if not sp_ref: - raise exception.ServiceProviderNotFound(sp_id=sp_id) - return sp_ref - - def list_sps(self): - with sql.session_for_read() as session: - sps = session.query(ServiceProviderModel) - sps_list = [sp.to_dict() for sp in sps] - return sps_list - - def get_sp(self, sp_id): - with sql.session_for_read() as session: - sp_ref = self._get_sp(session, sp_id) - return sp_ref.to_dict() - - def update_sp(self, sp_id, sp): - with sql.session_for_write() as session: - sp_ref = self._get_sp(session, sp_id) - old_sp = sp_ref.to_dict() - old_sp.update(sp) - new_sp = ServiceProviderModel.from_dict(old_sp) - for attr in ServiceProviderModel.mutable_attributes: - setattr(sp_ref, attr, getattr(new_sp, attr)) - return sp_ref.to_dict() - - def get_enabled_service_providers(self): - with sql.session_for_read() as session: - service_providers = session.query(ServiceProviderModel) - service_providers = service_providers.filter_by(enabled=True) - return service_providers diff --git a/keystone/federation/backends/base.py b/keystone/federation/backends/base.py index 242c0fbd1a..3570a090ad 100644 --- a/keystone/federation/backends/base.py +++ b/keystone/federation/backends/base.py @@ -14,20 +14,11 @@ import abc -from oslo_log import versionutils import six from keystone import exception -# The FederationDriverBase class is the set of driver methods from earlier -# drivers that we still support, that have not been removed or modified. This -# class is then used to created the augmented V8 and V9 version abstract driver -# classes, without having to duplicate a lot of abstract method signatures. -# If you remove a method from V9, then move the abstract methods from this Base -# class to the V8 class. Do not modify any of the method signatures in the Base -# class - changes should only be made in the V8 and subsequent classes. - @six.add_metaclass(abc.ABCMeta) class FederationDriverBase(object): @@ -329,6 +320,7 @@ class FederationDriverBase(object): """ raise exception.NotImplemented() # pragma: no cover + @abc.abstractmethod def get_enabled_service_providers(self): """List enabled service providers for Service Catalog. @@ -346,49 +338,6 @@ class FederationDriverBase(object): """ raise exception.NotImplemented() # pragma: no cover - -class FederationDriverV8(FederationDriverBase): - """Removed or redefined methods from V8. - - Move the abstract methods of any methods removed or modified in later - versions of the driver from FederationDriverBase to here. We maintain this - so that legacy drivers, which will be a subclass of FederationDriverV8, can - still reference them. - - """ - - @abc.abstractmethod - def list_idps(self): - """List all identity providers. - - :returns: list of idp refs - :rtype: list of dicts - - :raises keystone.exception.IdentityProviderNotFound: If the IdP - doesn't exist. - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def list_sps(self): - """List all service providers. - - :returns: List of service provider ref objects - :rtype: list of dicts - - """ - raise exception.NotImplemented() # pragma: no cover - - -class FederationDriverV9(FederationDriverBase): - """New or redefined methods from V8. - - Add any new V9 abstract methods (or those with modified signatures) to - this class. - - """ - @abc.abstractmethod def list_idps(self, hints): """List all identity providers. @@ -418,112 +367,3 @@ class FederationDriverV9(FederationDriverBase): """ raise exception.NotImplemented() # pragma: no cover - - -class V9FederationWrapperForV8Driver(FederationDriverV9): - """Wrapper class to supported a V8 legacy driver. - - In order to support legacy drivers without having to make the manager code - driver-version aware, we wrap legacy drivers so that they look like the - latest version. For the various changes made in a new driver, here are the - actions needed in this wrapper: - - Method removed from new driver - remove the call-through method from this - class, since the manager will no longer be - calling it. - Method signature (or meaning) changed - wrap the old method in a new - signature here, and munge the input - and output parameters accordingly. - New method added to new driver - add a method to implement the new - functionality here if possible. If that is - not possible, then return NotImplemented, - since we do not guarantee to support new - functionality with legacy drivers. - - """ - - @versionutils.deprecated( - as_of=versionutils.deprecated.MITAKA, - what='keystone.federation.FederationDriverV8', - in_favor_of='keystone.federation.FederationDriverV9', - remove_in=+2) - def __init__(self, wrapped_driver): - self.driver = wrapped_driver - - def create_idp(self, idp_id, idp): - return self.driver.create_idp(idp_id, idp) - - def delete_idp(self, idp_id): - self.driver.delete_idp(idp_id) - - # NOTE(davechen): The hints is ignored here to support legacy drivers, - # but the filters in hints will be remain unsatisfied and V3Controller - # wrapper will apply these filters at the end. So that the result get - # returned for list IdP will still be filtered with the legacy drivers. - def list_idps(self, hints): - return self.driver.list_idps() - - def get_idp(self, idp_id): - return self.driver.get_idp(idp_id) - - def get_idp_from_remote_id(self, remote_id): - return self.driver.get_idp_from_remote_id(remote_id) - - def update_idp(self, idp_id, idp): - return self.driver.update_idp(idp_id, idp) - - def create_protocol(self, idp_id, protocol_id, protocol): - return self.driver.create_protocol(idp_id, protocol_id, protocol) - - def update_protocol(self, idp_id, protocol_id, protocol): - return self.driver.update_protocol(idp_id, protocol_id, protocol) - - def get_protocol(self, idp_id, protocol_id): - return self.driver.get_protocol(idp_id, protocol_id) - - def list_protocols(self, idp_id): - return self.driver.list_protocols(idp_id) - - def delete_protocol(self, idp_id, protocol_id): - self.driver.delete_protocol(idp_id, protocol_id) - - def create_mapping(self, mapping_id, mapping): - return self.driver.create_mapping(mapping_id, mapping) - - def delete_mapping(self, mapping_id): - self.driver.delete_mapping(mapping_id) - - def update_mapping(self, mapping_id, mapping_ref): - return self.driver.update_mapping(mapping_id, mapping_ref) - - def list_mappings(self): - return self.driver.list_mappings() - - def get_mapping(self, mapping_id): - return self.driver.get_mapping(mapping_id) - - def get_mapping_from_idp_and_protocol(self, idp_id, protocol_id): - return self.driver.get_mapping_from_idp_and_protocol( - idp_id, protocol_id) - - def create_sp(self, sp_id, sp): - return self.driver.create_sp(sp_id, sp) - - def delete_sp(self, sp_id): - self.driver.delete_sp(sp_id) - - # NOTE(davechen): The hints is ignored here to support legacy drivers, - # but the filters in hints will be remain unsatisfied and V3Controller - # wrapper will apply these filters at the end. So that the result get - # returned for list SPs will still be filtered with the legacy drivers. - def list_sps(self, hints): - return self.driver.list_sps() - - def get_sp(self, sp_id): - return self.driver.get_sp(sp_id) - - def update_sp(self, sp_id, sp): - return self.driver.update_sp(sp_id, sp) - - def get_enabled_service_providers(self): - return self.driver.get_enabled_service_providers() diff --git a/keystone/federation/backends/sql.py b/keystone/federation/backends/sql.py index 7e31714c30..c994574576 100644 --- a/keystone/federation/backends/sql.py +++ b/keystone/federation/backends/sql.py @@ -161,7 +161,7 @@ class ServiceProviderModel(sql.ModelBase, sql.DictBase): return d -class Federation(base.FederationDriverV9): +class Federation(base.FederationDriverBase): _CONFLICT_LOG_MSG = 'Conflict %(conflict_type)s: %(details)s' diff --git a/keystone/federation/core.py b/keystone/federation/core.py index 1c4d73e65e..3a5560f9cb 100644 --- a/keystone/federation/core.py +++ b/keystone/federation/core.py @@ -12,15 +12,11 @@ """Main entry point into the Federation service.""" -from oslo_log import versionutils - from keystone.common import cache from keystone.common import dependency from keystone.common import extension from keystone.common import manager import keystone.conf -from keystone import exception -from keystone.federation.backends import base from keystone.federation import utils @@ -58,14 +54,6 @@ class Manager(manager.Manager): def __init__(self): super(Manager, self).__init__(CONF.federation.driver) - # Make sure it is a driver version we support, and if it is a legacy - # driver, then wrap it. - if isinstance(self.driver, base.FederationDriverV8): - self.driver = base.V9FederationWrapperForV8Driver(self.driver) - elif not isinstance(self.driver, base.FederationDriverV9): - raise exception.UnsupportedDriverVersion( - driver=CONF.federation.driver) - @MEMOIZE def get_enabled_service_providers(self): """List enabled service providers for Service Catalog. @@ -113,43 +101,3 @@ class Manager(manager.Manager): rule_processor = utils.RuleProcessor(mapping['id'], rules) mapped_properties = rule_processor.process(assertion_data) return mapped_properties, mapping['id'] - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.federation.FederationDriverBase', - in_favor_of='keystone.federation.backends.base.FederationDriverBase', - remove_in=+1) -class FederationDriverBase(base.FederationDriverBase): - pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.federation.FederationDriverV8', - in_favor_of='keystone.federation.backends.base.FederationDriverV8', - remove_in=+1) -class FederationDriverV8(base.FederationDriverV8): - pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.federation.FederationDriverV9', - in_favor_of='keystone.federation.backends.base.FederationDriverV9', - remove_in=+1) -class FederationDriverV9(base.FederationDriverV9): - pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.federation.V9FederationWrapperForV8Driver', - in_favor_of=( - 'keystone.federation.backends.base.V9FederationWrapperForV8Driver'), - remove_in=+1) -class V9FederationWrapperForV8Driver(base.V9FederationWrapperForV8Driver): - pass - - -Driver = manager.create_legacy_driver(base.FederationDriverV8) diff --git a/keystone/identity/backends/base.py b/keystone/identity/backends/base.py index 902eb06b4d..eb600be9eb 100644 --- a/keystone/identity/backends/base.py +++ b/keystone/identity/backends/base.py @@ -49,7 +49,7 @@ def filter_user(user_ref): @six.add_metaclass(abc.ABCMeta) -class IdentityDriverV8(object): +class IdentityDriverBase(object): """Interface description for an Identity driver. The schema for users and groups is different depending on whether the @@ -180,7 +180,7 @@ class IdentityDriverV8(object): :param str user_id: User ID :param str password: Password - :returns: user. See user schema in :class:`~.IdentityDriverV8`. + :returns: user. See user schema in :class:`~.IdentityDriverBase`. :rtype: dict :raises AssertionError: If user or password is invalid. @@ -195,7 +195,7 @@ class IdentityDriverV8(object): :param str user_id: user ID. The driver can ignore this value. :param dict user: user info. See user schema in - :class:`~.IdentityDriverV8`. + :class:`~.IdentityDriverBase`. :returns: user, matching the user schema. The driver should not return the password. @@ -215,7 +215,7 @@ class IdentityDriverV8(object): :type hints: keystone.common.driver_hints.Hints :returns: a list of users or an empty list. See user schema in - :class:`~.IdentityDriverV8`. + :class:`~.IdentityDriverBase`. :rtype: list of dict """ @@ -231,7 +231,7 @@ class IdentityDriverV8(object): :type hints: keystone.common.driver_hints.Hints :returns: a list of users or an empty list. See user schema in - :class:`~.IdentityDriverV8`. + :class:`~.IdentityDriverBase`. :rtype: list of dict :raises keystone.exception.GroupNotFound: If the group doesn't exist. @@ -245,7 +245,7 @@ class IdentityDriverV8(object): :param str user_id: User ID. - :returns: user. See user schema in :class:`~.IdentityDriverV8`. + :returns: user. See user schema in :class:`~.IdentityDriverBase`. :rtype: dict :raises keystone.exception.UserNotFound: If the user doesn't exist. @@ -259,10 +259,10 @@ class IdentityDriverV8(object): :param str user_id: User ID. :param dict user: User modification. See user schema in - :class:`~.IdentityDriverV8`. Properties set to None will be + :class:`~.IdentityDriverBase`. Properties set to None will be removed. Required properties cannot be removed. - :returns: user. See user schema in :class:`~.IdentityDriverV8`. + :returns: user. See user schema in :class:`~.IdentityDriverBase`. :raises keystone.exception.UserNotFound: If the user doesn't exist. :raises keystone.exception.Conflict: If a duplicate user exists in the @@ -352,7 +352,7 @@ class IdentityDriverV8(object): :param str group_id: group ID. The driver can ignore this value. :param dict group: group info. See group schema in - :class:`~.IdentityDriverV8`. + :class:`~.IdentityDriverBase`. :returns: group, matching the group schema. :rtype: dict @@ -371,7 +371,7 @@ class IdentityDriverV8(object): :type hints: keystone.common.driver_hints.Hints :returns: a list of group_refs or an empty list. See group schema in - :class:`~.IdentityDriverV8`. + :class:`~.IdentityDriverBase`. """ raise exception.NotImplemented() # pragma: no cover @@ -386,7 +386,7 @@ class IdentityDriverV8(object): :type hints: keystone.common.driver_hints.Hints :returns: a list of group_refs or an empty list. See group schema in - :class:`~.IdentityDriverV8`. + :class:`~.IdentityDriverBase`. :raises keystone.exception.UserNotFound: If the user doesn't exist. @@ -399,7 +399,7 @@ class IdentityDriverV8(object): :param str group_id: group ID. - :returns: group info. See group schema in :class:`~.IdentityDriverV8`. + :returns: group info. See group schema in :class:`~.IdentityDriverBase` :rtype: dict :raises keystone.exception.GroupNotFound: If the group doesn't exist. @@ -413,7 +413,8 @@ class IdentityDriverV8(object): :param str group_name: group name. :param str domain_id: domain ID. - :returns: group info. See group schema in :class:`~.IdentityDriverV8`. + :returns: group info. See group schema in + :class:`~.IdentityDriverBase`. :rtype: dict :raises keystone.exception.GroupNotFound: If the group doesn't exist. @@ -426,7 +427,8 @@ class IdentityDriverV8(object): :param str group_id: Group ID. :param dict group: Group modification. See group schema in - :class:`~.IdentityDriverV8`. Required properties cannot be removed. + :class:`~.IdentityDriverBase`. Required properties cannot be + removed. :returns: group, matching the group schema. :rtype: dict diff --git a/keystone/identity/backends/ldap/core.py b/keystone/identity/backends/ldap/core.py index ed10edcbcc..2db2e0eb78 100644 --- a/keystone/identity/backends/ldap/core.py +++ b/keystone/identity/backends/ldap/core.py @@ -36,7 +36,7 @@ _DEPRECATION_MSG = _('%s for the LDAP identity backend has been deprecated in ' 'access. It will be removed in the "O" release.') -class Identity(base.IdentityDriverV8): +class Identity(base.IdentityDriverBase): def __init__(self, conf=None): super(Identity, self).__init__() if conf is None: diff --git a/keystone/identity/backends/sql.py b/keystone/identity/backends/sql.py index bf8c2f7299..a284ef369b 100644 --- a/keystone/identity/backends/sql.py +++ b/keystone/identity/backends/sql.py @@ -29,7 +29,7 @@ from keystone.identity.backends import sql_model as model CONF = keystone.conf.CONF -class Identity(base.IdentityDriverV8): +class Identity(base.IdentityDriverBase): # NOTE(henry-nash): Override the __init__() method so as to take a # config parameter to enable sql to be used as a domain-specific driver. def __init__(self, conf=None): diff --git a/keystone/identity/core.py b/keystone/identity/core.py index ebbec69f55..157f8e1db4 100644 --- a/keystone/identity/core.py +++ b/keystone/identity/core.py @@ -33,10 +33,7 @@ from keystone.common.validation import validators import keystone.conf from keystone import exception from keystone.i18n import _, _LW -from keystone.identity.backends import base as identity_interface -from keystone.identity.mapping_backends import base as mapping_interface from keystone.identity.mapping_backends import mapping -from keystone.identity.shadow_backends import base as shadow_interface from keystone import notifications @@ -1280,17 +1277,6 @@ class Manager(manager.Manager): return user_dict -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.identity.IdentityDriverV8', - in_favor_of='keystone.identity.backends.base.IdentityDriverV8', - remove_in=+1) -class IdentityDriverV8(identity_interface.IdentityDriverV8): - pass - -Driver = manager.create_legacy_driver(identity_interface.IdentityDriverV8) - - @dependency.provider('id_mapping_api') class MappingManager(manager.Manager): """Default pivot point for the ID Mapping backend.""" @@ -1343,18 +1329,6 @@ class MappingManager(manager.Manager): ID_MAPPING_REGION.invalidate() -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.identity.MappingDriverV8', - in_favor_of='keystone.identity.mapping_backends.base.MappingDriverV8', - remove_in=+1) -class MappingDriverV8(mapping_interface.MappingDriverV8): - pass - - -MappingDriver = manager.create_legacy_driver(mapping_interface.MappingDriverV8) - - @dependency.provider('shadow_users_api') class ShadowUsersManager(manager.Manager): """Default pivot point for the Shadow Users backend.""" @@ -1365,19 +1339,3 @@ class ShadowUsersManager(manager.Manager): shadow_driver = CONF.shadow_users.driver super(ShadowUsersManager, self).__init__(shadow_driver) - - if isinstance(self.driver, shadow_interface.ShadowUsersDriverV9): - self.driver = ( - shadow_interface.V10ShadowUsersWrapperForV9Driver(self.driver)) - elif not isinstance(self.driver, - shadow_interface.ShadowUsersDriverV10): - raise exception.UnsupportedDriverVersion(driver=shadow_driver) - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.identity.ShadowUsersDriverV9', - in_favor_of='keystone.identity.shadow_backends.base.ShadowUsersDriverV9', - remove_in=+1) -class ShadowUsersDriverV9(shadow_interface.ShadowUsersDriverV9): - pass diff --git a/keystone/identity/mapping_backends/base.py b/keystone/identity/mapping_backends/base.py index abf09d5676..8ff2bf70aa 100644 --- a/keystone/identity/mapping_backends/base.py +++ b/keystone/identity/mapping_backends/base.py @@ -20,7 +20,7 @@ from keystone import exception @six.add_metaclass(abc.ABCMeta) -class MappingDriverV8(object): +class MappingDriverBase(object): """Interface description for an ID Mapping driver.""" @abc.abstractmethod diff --git a/keystone/identity/mapping_backends/sql.py b/keystone/identity/mapping_backends/sql.py index 7da264dd9e..98f97d91f5 100644 --- a/keystone/identity/mapping_backends/sql.py +++ b/keystone/identity/mapping_backends/sql.py @@ -36,7 +36,7 @@ class IDMapping(sql.ModelBase, sql.ModelDictMixin): @dependency.requires('id_generator_api') -class Mapping(base.MappingDriverV8): +class Mapping(base.MappingDriverBase): def get_public_id(self, local_entity): # NOTE(henry-nash): Since the Public ID is regeneratable, rather diff --git a/keystone/identity/shadow_backends/base.py b/keystone/identity/shadow_backends/base.py index 64b86a3a7c..74e2c52a05 100644 --- a/keystone/identity/shadow_backends/base.py +++ b/keystone/identity/shadow_backends/base.py @@ -14,7 +14,6 @@ import abc -from oslo_log import versionutils import six from keystone import exception @@ -60,20 +59,6 @@ class ShadowUsersDriverBase(object): """ raise exception.NotImplemented() - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.identity.shadow_backends.base.ShadowUsersDriverV9', - in_favor_of='keystone.identity.shadow_backends.base.ShadowUsersDriverV10', - remove_in=+1) -class ShadowUsersDriverV9(ShadowUsersDriverBase): - pass - - -@six.add_metaclass(abc.ABCMeta) -class ShadowUsersDriverV10(ShadowUsersDriverBase): - """Interface description for an Shadow Users V10 driver.""" - @abc.abstractmethod def get_user(self, user_id): """Return the found user. @@ -102,14 +87,3 @@ class ShadowUsersDriverV10(ShadowUsersDriverBase): """ raise exception.NotImplemented() - - -class V10ShadowUsersWrapperForV9Driver(ShadowUsersDriverV10): - def get_user(self, user_id): - raise exception.UserNotFound(user_id=user_id) - - def create_nonlocal_user(self, user_dict): - return user_dict - - def set_last_active_at(self, user_id): - pass diff --git a/keystone/identity/shadow_backends/sql.py b/keystone/identity/shadow_backends/sql.py index 23b6bc5ec1..ce43504587 100644 --- a/keystone/identity/shadow_backends/sql.py +++ b/keystone/identity/shadow_backends/sql.py @@ -26,7 +26,7 @@ from keystone.identity.shadow_backends import base CONF = cfg.CONF -class ShadowUsers(base.ShadowUsersDriverV10): +class ShadowUsers(base.ShadowUsersDriverBase): @sql.handle_conflicts(conflict_type='federated_user') def create_federated_user(self, federated_dict): user = { diff --git a/keystone/oauth1/backends/base.py b/keystone/oauth1/backends/base.py index fc41a61a2f..56f722ddc6 100644 --- a/keystone/oauth1/backends/base.py +++ b/keystone/oauth1/backends/base.py @@ -56,7 +56,7 @@ def filter_consumer(consumer_ref): @six.add_metaclass(abc.ABCMeta) -class Oauth1DriverV8(object): +class Oauth1DriverBase(object): """Interface description for an OAuth1 driver.""" @abc.abstractmethod diff --git a/keystone/oauth1/backends/sql.py b/keystone/oauth1/backends/sql.py index c20c803c7c..89f7b278aa 100644 --- a/keystone/oauth1/backends/sql.py +++ b/keystone/oauth1/backends/sql.py @@ -84,7 +84,7 @@ class AccessToken(sql.ModelBase, sql.DictBase): return dict(self.items()) -class OAuth1(base.Oauth1DriverV8): +class OAuth1(base.Oauth1DriverBase): def _get_consumer(self, session, consumer_id): consumer_ref = session.query(Consumer).get(consumer_id) if consumer_ref is None: diff --git a/keystone/oauth1/core.py b/keystone/oauth1/core.py index 2cb5a36515..5fbc113033 100644 --- a/keystone/oauth1/core.py +++ b/keystone/oauth1/core.py @@ -21,7 +21,6 @@ import uuid import oauthlib.common from oauthlib import oauth1 from oslo_log import log -from oslo_log import versionutils from keystone.common import dependency from keystone.common import extension @@ -30,7 +29,6 @@ import keystone.conf from keystone import exception from keystone.i18n import _, _LE from keystone import notifications -from keystone.oauth1.backends import base RequestValidator = oauth1.RequestValidator @@ -180,15 +178,3 @@ class Manager(manager.Manager): notifications.Audit.created(self._REQUEST_TOKEN, ret['id'], initiator) return ret - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.oauth1.Oauth1DriverV8', - in_favor_of='keystone.oauth1.backends.base.Oauth1DriverV8', - remove_in=+1) -class Oauth1DriverV8(base.Oauth1DriverV8): - pass - - -Driver = manager.create_legacy_driver(base.Oauth1DriverV8) diff --git a/keystone/policy/backends/base.py b/keystone/policy/backends/base.py index 99da1b6481..9251f2482a 100644 --- a/keystone/policy/backends/base.py +++ b/keystone/policy/backends/base.py @@ -21,7 +21,7 @@ CONF = keystone.conf.CONF @six.add_metaclass(abc.ABCMeta) -class PolicyDriverV8(object): +class PolicyDriverBase(object): def _get_list_limit(self): return CONF.policy.list_limit or CONF.list_limit diff --git a/keystone/policy/backends/rules.py b/keystone/policy/backends/rules.py index 506b01783a..36693f7a53 100644 --- a/keystone/policy/backends/rules.py +++ b/keystone/policy/backends/rules.py @@ -69,7 +69,7 @@ def enforce(credentials, action, target, do_raise=True): return _ENFORCER.enforce(action, target, credentials, **extra) -class Policy(base.PolicyDriverV8): +class Policy(base.PolicyDriverBase): def enforce(self, credentials, action, target): msg = 'enforce %(action)s: %(credentials)s' LOG.debug(msg, { diff --git a/keystone/policy/core.py b/keystone/policy/core.py index 96431ab217..0555a449d5 100644 --- a/keystone/policy/core.py +++ b/keystone/policy/core.py @@ -14,14 +14,11 @@ """Main entry point into the Policy service.""" -from oslo_log import versionutils - from keystone.common import dependency from keystone.common import manager import keystone.conf from keystone import exception from keystone import notifications -from keystone.policy.backends import base CONF = keystone.conf.CONF @@ -78,15 +75,3 @@ class Manager(manager.Manager): raise exception.PolicyNotFound(policy_id=policy_id) notifications.Audit.deleted(self._POLICY, policy_id, initiator) return ret - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.policy.PolicyDriverV8', - in_favor_of='keystone.policy.backends.base.PolicyDriverV8', - remove_in=+1) -class PolicyDriverV8(base.PolicyDriverV8): - pass - - -Driver = manager.create_legacy_driver(base.PolicyDriverV8) diff --git a/keystone/resource/V8_backends/__init__.py b/keystone/resource/V8_backends/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/resource/V8_backends/sql.py b/keystone/resource/V8_backends/sql.py deleted file mode 100644 index 0bb1d61882..0000000000 --- a/keystone/resource/V8_backends/sql.py +++ /dev/null @@ -1,260 +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 oslo_log import log - -from keystone.common import clean -from keystone.common import driver_hints -from keystone.common import sql -from keystone import exception -from keystone.i18n import _LE -from keystone.resource.backends import base - - -LOG = log.getLogger(__name__) - - -class Resource(base.ResourceDriverV8): - - def default_assignment_driver(self): - return 'sql' - - def _get_project(self, session, project_id): - project_ref = session.query(Project).get(project_id) - if project_ref is None: - raise exception.ProjectNotFound(project_id=project_id) - return project_ref - - def get_project(self, tenant_id): - with sql.session_for_read() as session: - return self._get_project(session, tenant_id).to_dict() - - def get_project_by_name(self, tenant_name, domain_id): - with sql.session_for_read() as session: - query = session.query(Project) - query = query.filter_by(name=tenant_name) - query = query.filter_by(domain_id=domain_id) - try: - project_ref = query.one() - except sql.NotFound: - raise exception.ProjectNotFound(project_id=tenant_name) - return project_ref.to_dict() - - @driver_hints.truncated - def list_projects(self, hints): - with sql.session_for_read() as session: - query = session.query(Project) - project_refs = sql.filter_limit_query(Project, query, hints) - return [project_ref.to_dict() for project_ref in project_refs] - - def list_projects_from_ids(self, ids): - if not ids: - return [] - else: - with sql.session_for_read() as session: - query = session.query(Project) - query = query.filter(Project.id.in_(ids)) - return [project_ref.to_dict() for project_ref in query.all()] - - def list_project_ids_from_domain_ids(self, domain_ids): - if not domain_ids: - return [] - else: - with sql.session_for_read() as session: - query = session.query(Project.id) - query = ( - query.filter(Project.domain_id.in_(domain_ids))) - return [x.id for x in query.all()] - - def list_projects_in_domain(self, domain_id): - with sql.session_for_read() as session: - self._get_domain(session, domain_id) - query = session.query(Project) - project_refs = query.filter_by(domain_id=domain_id) - return [project_ref.to_dict() for project_ref in project_refs] - - def _get_children(self, session, project_ids): - query = session.query(Project) - query = query.filter(Project.parent_id.in_(project_ids)) - project_refs = query.all() - return [project_ref.to_dict() for project_ref in project_refs] - - def list_projects_in_subtree(self, project_id): - with sql.session_for_read() as session: - children = self._get_children(session, [project_id]) - subtree = [] - examined = set([project_id]) - while children: - children_ids = set() - for ref in children: - if ref['id'] in examined: - msg = _LE('Circular reference or a repeated ' - 'entry found in projects hierarchy - ' - '%(project_id)s.') - LOG.error(msg, {'project_id': ref['id']}) - return - children_ids.add(ref['id']) - - examined.update(children_ids) - subtree += children - children = self._get_children(session, children_ids) - return subtree - - def list_project_parents(self, project_id): - with sql.session_for_read() as session: - project = self._get_project(session, project_id).to_dict() - parents = [] - examined = set() - while project.get('parent_id') is not None: - if project['id'] in examined: - msg = _LE('Circular reference or a repeated ' - 'entry found in projects hierarchy - ' - '%(project_id)s.') - LOG.error(msg, {'project_id': project['id']}) - return - - examined.add(project['id']) - parent_project = self._get_project( - session, project['parent_id']).to_dict() - parents.append(parent_project) - project = parent_project - return parents - - def is_leaf_project(self, project_id): - with sql.session_for_read() as session: - project_refs = self._get_children(session, [project_id]) - return not project_refs - - # CRUD - @sql.handle_conflicts(conflict_type='project') - def create_project(self, tenant_id, tenant): - tenant['name'] = clean.project_name(tenant['name']) - with sql.session_for_write() as session: - tenant_ref = Project.from_dict(tenant) - session.add(tenant_ref) - return tenant_ref.to_dict() - - @sql.handle_conflicts(conflict_type='project') - def update_project(self, tenant_id, tenant): - if 'name' in tenant: - tenant['name'] = clean.project_name(tenant['name']) - - with sql.session_for_write() as session: - tenant_ref = self._get_project(session, tenant_id) - old_project_dict = tenant_ref.to_dict() - for k in tenant: - old_project_dict[k] = tenant[k] - new_project = Project.from_dict(old_project_dict) - for attr in Project.attributes: - if attr != 'id': - setattr(tenant_ref, attr, getattr(new_project, attr)) - tenant_ref.extra = new_project.extra - return tenant_ref.to_dict(include_extra_dict=True) - - @sql.handle_conflicts(conflict_type='project') - def delete_project(self, tenant_id): - with sql.session_for_write() as session: - tenant_ref = self._get_project(session, tenant_id) - session.delete(tenant_ref) - - # domain crud - - @sql.handle_conflicts(conflict_type='domain') - def create_domain(self, domain_id, domain): - with sql.session_for_write() as session: - ref = Domain.from_dict(domain) - session.add(ref) - return ref.to_dict() - - @driver_hints.truncated - def list_domains(self, hints): - with sql.session_for_read() as session: - query = session.query(Domain) - refs = sql.filter_limit_query(Domain, query, hints) - return [ref.to_dict() for ref in refs] - - def list_domains_from_ids(self, ids): - if not ids: - return [] - else: - with sql.session_for_read() as session: - query = session.query(Domain) - query = query.filter(Domain.id.in_(ids)) - domain_refs = query.all() - return [domain_ref.to_dict() for domain_ref in domain_refs] - - def _get_domain(self, session, domain_id): - ref = session.query(Domain).get(domain_id) - if ref is None: - raise exception.DomainNotFound(domain_id=domain_id) - return ref - - def get_domain(self, domain_id): - with sql.session_for_read() as session: - return self._get_domain(session, domain_id).to_dict() - - def get_domain_by_name(self, domain_name): - with sql.session_for_read() as session: - try: - ref = (session.query(Domain). - filter_by(name=domain_name).one()) - except sql.NotFound: - raise exception.DomainNotFound(domain_id=domain_name) - return ref.to_dict() - - @sql.handle_conflicts(conflict_type='domain') - def update_domain(self, domain_id, domain): - with sql.session_for_write() as session: - ref = self._get_domain(session, domain_id) - old_dict = ref.to_dict() - for k in domain: - old_dict[k] = domain[k] - new_domain = Domain.from_dict(old_dict) - for attr in Domain.attributes: - if attr != 'id': - setattr(ref, attr, getattr(new_domain, attr)) - ref.extra = new_domain.extra - return ref.to_dict() - - def delete_domain(self, domain_id): - with sql.session_for_write() as session: - ref = self._get_domain(session, domain_id) - session.delete(ref) - - -class Domain(sql.ModelBase, sql.DictBase): - __tablename__ = 'domain' - attributes = ['id', 'name', 'enabled'] - id = sql.Column(sql.String(64), primary_key=True) - name = sql.Column(sql.String(64), nullable=False) - enabled = sql.Column(sql.Boolean, default=True, nullable=False) - extra = sql.Column(sql.JsonBlob()) - __table_args__ = (sql.UniqueConstraint('name'),) - - -class Project(sql.ModelBase, sql.DictBase): - __tablename__ = 'project' - attributes = ['id', 'name', 'domain_id', 'description', 'enabled', - 'parent_id', 'is_domain'] - id = sql.Column(sql.String(64), primary_key=True) - name = sql.Column(sql.String(64), nullable=False) - domain_id = sql.Column(sql.String(64), sql.ForeignKey('domain.id'), - nullable=False) - description = sql.Column(sql.Text()) - enabled = sql.Column(sql.Boolean) - extra = sql.Column(sql.JsonBlob()) - parent_id = sql.Column(sql.String(64), sql.ForeignKey('project.id')) - is_domain = sql.Column(sql.Boolean, default=False, nullable=False, - server_default='0') - # Unique constraint across two columns to create the separation - # rather than just only 'name' being unique - __table_args__ = (sql.UniqueConstraint('domain_id', 'name'),) diff --git a/keystone/resource/backends/base.py b/keystone/resource/backends/base.py index 37b9f11d95..621c3940c3 100644 --- a/keystone/resource/backends/base.py +++ b/keystone/resource/backends/base.py @@ -13,15 +13,12 @@ # under the License. import abc -import copy from oslo_log import log -from oslo_log import versionutils import six import keystone.conf from keystone import exception -from keystone.i18n import _, _LE CONF = keystone.conf.CONF @@ -38,17 +35,6 @@ def get_project_from_domain(domain_ref): return project_ref -# The ResourceDriverBase class is the set of driver methods from earlier -# drivers that we still support, that have not been removed or modified. This -# class is then used to created the augmented V8 and V9 version abstract driver -# classes, without having to duplicate a lot of abstract method signatures. -# If you remove a method from V9, then move the abstract methods from this Base -# class to the V8 class. Do not modify any of the method signatures in the Base -# class - changes should only be made in the V8 and subsequent classes. - -# Starting with V9, some drivers use a special value to represent a domain_id -# of None. See comment in Project class of resource/backends/sql.py for more -# details. NULL_DOMAIN_ID = '<>' @@ -201,168 +187,6 @@ class ResourceDriverBase(object): if domain_id != CONF.identity.default_domain_id: raise exception.DomainNotFound(domain_id=domain_id) - -class ResourceDriverV8(ResourceDriverBase): - """Removed or redefined methods from V8. - - Move the abstract methods of any methods removed or modified in later - versions of the driver from ResourceDriverBase to here. We maintain this - so that legacy drivers, which will be a subclass of ResourceDriverV8, can - still reference them. - - """ - - @abc.abstractmethod - def create_project(self, tenant_id, tenant): - """Create a new project. - - :param tenant_id: This parameter can be ignored. - :param dict tenant: The new project - - Project schema:: - - type: object - properties: - id: - type: string - name: - type: string - domain_id: - type: string - description: - type: string - enabled: - type: boolean - parent_id: - type: string - is_domain: - type: boolean - required: [id, name, domain_id] - additionalProperties: true - - If project doesn't match the schema the behavior is undefined. - - The driver can impose requirements such as the maximum length of a - field. If these requirements are not met the behavior is undefined. - - :raises keystone.exception.Conflict: if the project id already exists - or the name already exists for the domain_id. - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def get_project_by_name(self, tenant_name, domain_id): - """Get a tenant by name. - - :returns: tenant_ref - :raises keystone.exception.ProjectNotFound: if a project with the - tenant_name does not exist within the domain - - """ - raise exception.NotImplemented() # pragma: no cover - - # Domain management functions for backends that only allow a single - # domain. Although we no longer use this, a custom legacy driver might - # have made use of it, so keep it here in case. - def _set_default_domain(self, ref): - """If the domain ID has not been set, set it to the default.""" - if isinstance(ref, dict): - if 'domain_id' not in ref: - ref = ref.copy() - ref['domain_id'] = CONF.identity.default_domain_id - return ref - elif isinstance(ref, list): - return [self._set_default_domain(x) for x in ref] - else: - raise ValueError(_('Expected dict or list: %s') % type(ref)) - - # domain crud - @abc.abstractmethod - def create_domain(self, domain_id, domain): - """Create a new domain. - - :raises keystone.exception.Conflict: if the domain_id or domain name - already exists - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def list_domains(self, hints): - """List domains in the system. - - :param hints: filter hints which the driver should - implement if at all possible. - - :returns: a list of domain_refs or an empty list. - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def list_domains_from_ids(self, domain_ids): - """List domains for the provided list of ids. - - :param domain_ids: list of ids - - :returns: a list of domain_refs. - - This method is used internally by the assignment manager to bulk read - a set of domains given their ids. - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def get_domain(self, domain_id): - """Get a domain by ID. - - :returns: domain_ref - :raises keystone.exception.DomainNotFound: if domain_id does not exist - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def get_domain_by_name(self, domain_name): - """Get a domain by name. - - :returns: domain_ref - :raises keystone.exception.DomainNotFound: if domain_name does not - exist - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def update_domain(self, domain_id, domain): - """Update an existing domain. - - :raises keystone.exception.DomainNotFound: if domain_id does not exist - :raises keystone.exception.Conflict: if domain name already exists - - """ - raise exception.NotImplemented() # pragma: no cover - - @abc.abstractmethod - def delete_domain(self, domain_id): - """Delete an existing domain. - - :raises keystone.exception.DomainNotFound: if domain_id does not exist - - """ - raise exception.NotImplemented() # pragma: no cover - - -class ResourceDriverV9(ResourceDriverBase): - """New or redefined methods from V8. - - Add any new V9 abstract methods (or those with modified signatures) to - this class. - - """ - @abc.abstractmethod def create_project(self, project_id, project): """Create a new project. @@ -436,197 +260,3 @@ class ResourceDriverV9(ResourceDriverBase): """ raise exception.NotImplemented() # pragma: no cover - - -class V9ResourceWrapperForV8Driver(ResourceDriverV9): - """Wrapper class to supported a V8 legacy driver. - - In order to support legacy drivers without having to make the manager code - driver-version aware, we wrap legacy drivers so that they look like the - latest version. For the various changes made in a new driver, here are the - actions needed in this wrapper: - - Method removed from new driver - remove the call-through method from this - class, since the manager will no longer be - calling it. - Method signature (or meaning) changed - wrap the old method in a new - signature here, and munge the input - and output parameters accordingly. - New method added to new driver - add a method to implement the new - functionality here if possible. If that is - not possible, then return NotImplemented, - since we do not guarantee to support new - functionality with legacy drivers. - - This wrapper contains the following support for newer manager code: - - - The current manager code expects domains to be represented as projects - acting as domains, something that may not be possible in a legacy driver. - Hence the wrapper will map any calls for projects acting as a domain back - onto the driver domain methods. The caveat for this, is that this assumes - that there can not be a clash between a project_id and a domain_id, in - which case it may not be able to locate the correct entry. - - """ - - @versionutils.deprecated( - as_of=versionutils.deprecated.MITAKA, - what='keystone.resource.ResourceDriverV8', - in_favor_of='keystone.resource.ResourceDriverV9', - remove_in=+2) - def __init__(self, wrapped_driver): - self.driver = wrapped_driver - - def _get_domain_from_project(self, project_ref): - """Create a domain ref from a project ref. - - Based on the provided project ref (or partial ref), creates a - domain ref, so that the result can be passed to the driver - domain methods. - """ - domain_ref = project_ref.copy() - for k in ['parent_id', 'domain_id', 'is_domain']: - domain_ref.pop(k, None) - return domain_ref - - def get_project_by_name(self, project_name, domain_id): - if domain_id is None: - try: - domain_ref = self.driver.get_domain_by_name(project_name) - return get_project_from_domain(domain_ref) - except exception.DomainNotFound: - raise exception.ProjectNotFound(project_id=project_name) - else: - return self.driver.get_project_by_name(project_name, domain_id) - - def create_project(self, project_id, project): - if project['is_domain']: - new_domain = self._get_domain_from_project(project) - domain_ref = self.driver.create_domain(project_id, new_domain) - return get_project_from_domain(domain_ref) - else: - return self.driver.create_project(project_id, project) - - def list_projects(self, hints): - """List projects and/or domains. - - We use the hints filter to determine whether we are listing projects, - domains or both. - - If the filter includes domain_id==None, then we should only list - domains (convert to a project acting as a domain) since regular - projects always have a non-None value for domain_id. - - Likewise, if the filter includes domain_id==, then we - should only list projects. - - If there is no domain_id filter, then we need to do a combained listing - of domains and projects, converting domains to projects acting as a - domain. - - """ - domain_listing_filter = None - for f in hints.filters: - if (f['name'] == 'domain_id'): - domain_listing_filter = f - - if domain_listing_filter is not None: - if domain_listing_filter['value'] is not None: - proj_list = self.driver.list_projects(hints) - else: - domains = self.driver.list_domains(hints) - proj_list = [get_project_from_domain(p) for p in domains] - hints.filters.remove(domain_listing_filter) - return proj_list - else: - # No domain_id filter, so combine domains and projects. Although - # we hand any remaining filters into each driver, since each filter - # might need to be carried out more than once, we use copies of the - # filters, allowing the original filters to be passed back up to - # controller level where a final filter will occur. - local_hints = copy.deepcopy(hints) - proj_list = self.driver.list_projects(local_hints) - local_hints = copy.deepcopy(hints) - domains = self.driver.list_domains(local_hints) - for domain in domains: - proj_list.append(get_project_from_domain(domain)) - return proj_list - - def list_projects_from_ids(self, project_ids): - return [self.get_project(id) for id in project_ids] - - def list_project_ids_from_domain_ids(self, domain_ids): - return self.driver.list_project_ids_from_domain_ids(domain_ids) - - def list_projects_in_domain(self, domain_id): - return self.driver.list_projects_in_domain(domain_id) - - def get_project(self, project_id): - try: - domain_ref = self.driver.get_domain(project_id) - return get_project_from_domain(domain_ref) - except exception.DomainNotFound: - return self.driver.get_project(project_id) - - def _is_domain(self, project_id): - ref = self.get_project(project_id) - return ref.get('is_domain', False) - - def update_project(self, project_id, project): - if self._is_domain(project_id): - update_domain = self._get_domain_from_project(project) - domain_ref = self.driver.update_domain(project_id, update_domain) - return get_project_from_domain(domain_ref) - else: - return self.driver.update_project(project_id, project) - - def delete_project(self, project_id): - if self._is_domain(project_id): - try: - self.driver.delete_domain(project_id) - except exception.DomainNotFound: - raise exception.ProjectNotFound(project_id=project_id) - else: - self.driver.delete_project(project_id) - - def delete_projects_from_ids(self, project_ids): - raise exception.NotImplemented() # pragma: no cover - - def list_project_parents(self, project_id): - """List a project's ancestors. - - The current manager expects the ancestor tree to end with the project - acting as the domain (since that's now the top of the tree), but a - legacy driver will not have that top project in their projects table, - since it's still in the domain table. Hence we lift the algorithm for - traversing up the tree from the driver to here, so that our version of - get_project() is called, which will fetch the "project" from the right - table. - - """ - project = self.get_project(project_id) - parents = [] - examined = set() - while project.get('parent_id') is not None: - if project['id'] in examined: - msg = _LE('Circular reference or a repeated ' - 'entry found in projects hierarchy - ' - '%(project_id)s.') - LOG.error(msg, {'project_id': project['id']}) - return - - examined.add(project['id']) - parent_project = self.get_project(project['parent_id']) - parents.append(parent_project) - project = parent_project - return parents - - def list_projects_in_subtree(self, project_id): - return self.driver.list_projects_in_subtree(project_id) - - def is_leaf_project(self, project_id): - return self.driver.is_leaf_project(project_id) - - def list_projects_acting_as_domain(self, hints): - refs = self.driver.list_domains(hints) - return [get_project_from_domain(p) for p in refs] diff --git a/keystone/resource/backends/sql.py b/keystone/resource/backends/sql.py index a3bb5c769e..81f03dcbdd 100644 --- a/keystone/resource/backends/sql.py +++ b/keystone/resource/backends/sql.py @@ -22,7 +22,7 @@ from keystone.resource.backends import base LOG = log.getLogger(__name__) -class Resource(base.ResourceDriverV9): +class Resource(base.ResourceDriverBase): def default_assignment_driver(self): return 'sql' diff --git a/keystone/resource/config_backends/base.py b/keystone/resource/config_backends/base.py index 5a456093a7..7734bb2a6f 100644 --- a/keystone/resource/config_backends/base.py +++ b/keystone/resource/config_backends/base.py @@ -24,7 +24,7 @@ CONF = keystone.conf.CONF @six.add_metaclass(abc.ABCMeta) -class DomainConfigDriverV8(object): +class DomainConfigDriverBase(object): """Interface description for a Domain Config driver.""" @abc.abstractmethod diff --git a/keystone/resource/config_backends/sql.py b/keystone/resource/config_backends/sql.py index 9d18d5e128..16287007de 100644 --- a/keystone/resource/config_backends/sql.py +++ b/keystone/resource/config_backends/sql.py @@ -48,7 +48,7 @@ class ConfigRegister(sql.ModelBase, sql.ModelDictMixin): domain_id = sql.Column(sql.String(64), nullable=False) -class DomainConfig(base.DomainConfigDriverV8): +class DomainConfig(base.DomainConfigDriverBase): def choose_table(self, sensitive): if sensitive: diff --git a/keystone/resource/core.py b/keystone/resource/core.py index abd4e89cc7..11c0feb007 100644 --- a/keystone/resource/core.py +++ b/keystone/resource/core.py @@ -28,7 +28,6 @@ from keystone import exception from keystone.i18n import _, _LE, _LW from keystone import notifications from keystone.resource.backends import base -from keystone.resource.config_backends import base as config_base from keystone.token import provider as token_provider CONF = keystone.conf.CONF @@ -63,13 +62,6 @@ class Manager(manager.Manager): super(Manager, self).__init__(resource_driver) - # Make sure it is a driver version we support, and if it is a legacy - # driver, then wrap it. - if isinstance(self.driver, base.ResourceDriverV8): - self.driver = base.V9ResourceWrapperForV8Driver(self.driver) - elif not isinstance(self.driver, base.ResourceDriverV9): - raise exception.UnsupportedDriverVersion(driver=resource_driver) - def _get_hierarchy_depth(self, parents_list): return len(parents_list) + 1 @@ -903,45 +895,6 @@ class Manager(manager.Manager): raise -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.resource.ResourceDriverBase', - in_favor_of='keystone.resource.backends.base.ResourceDriverBase', - remove_in=+1) -class ResourceDriverBase(base.ResourceDriverBase): - pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.resource.ResourceDriverV8', - in_favor_of='keystone.resource.backends.base.ResourceDriverV8', - remove_in=+1) -class ResourceDriverV8(base.ResourceDriverV8): - pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.resource.ResourceDriverV9', - in_favor_of='keystone.resource.backends.base.ResourceDriverV9', - remove_in=+1) -class ResourceDriverV9(base.ResourceDriverV9): - pass - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.resource.V9ResourceWrapperForV8Driver', - in_favor_of='keystone.resource.backends.base.V9ResourceWrapperForV8Driver', - remove_in=+1) -class V9ResourceWrapperForV8Driver(base.V9ResourceWrapperForV8Driver): - pass - - -Driver = manager.create_legacy_driver(base.ResourceDriverV8) - - MEMOIZE_CONFIG = cache.get_memoization_decorator(group='domain_config') @@ -1439,16 +1392,3 @@ class DomainConfigManager(manager.Manager): config_list.append(_option_dict(each_group, each_option)) return self._list_to_config(config_list, req_option=option) - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.resource.DomainConfigDriverV8', - in_favor_of='keystone.resource.config_backends.base.DomainConfigDriverV8', - remove_in=+1) -class DomainConfigDriverV8(config_base.DomainConfigDriverV8): - pass - - -DomainConfigDriver = manager.create_legacy_driver( - config_base.DomainConfigDriverV8) diff --git a/keystone/revoke/backends/base.py b/keystone/revoke/backends/base.py index 0d65865ad6..949e1cc5e9 100644 --- a/keystone/revoke/backends/base.py +++ b/keystone/revoke/backends/base.py @@ -33,7 +33,7 @@ def revoked_before_cutoff_time(): @six.add_metaclass(abc.ABCMeta) -class RevokeDriverV8(object): +class RevokeDriverBase(object): """Interface for recording and reporting revocation events.""" @abc.abstractmethod diff --git a/keystone/revoke/backends/sql.py b/keystone/revoke/backends/sql.py index bb23d7b300..5070c51785 100644 --- a/keystone/revoke/backends/sql.py +++ b/keystone/revoke/backends/sql.py @@ -38,7 +38,7 @@ class RevocationEvent(sql.ModelBase, sql.ModelDictMixin): audit_chain_id = sql.Column(sql.String(32)) -class Revoke(base.RevokeDriverV8): +class Revoke(base.RevokeDriverBase): def _flush_batch_size(self, dialect): batch_size = 0 if dialect == 'ibm_db_sa': diff --git a/keystone/revoke/core.py b/keystone/revoke/core.py index 12e1b55849..1e0d3c7d29 100644 --- a/keystone/revoke/core.py +++ b/keystone/revoke/core.py @@ -12,8 +12,6 @@ """Main entry point into the Revoke service.""" -from oslo_log import versionutils - from keystone.common import cache from keystone.common import dependency from keystone.common import extension @@ -23,7 +21,6 @@ from keystone import exception from keystone.i18n import _ from keystone.models import revoke_model from keystone import notifications -from keystone.revoke.backends import base CONF = keystone.conf.CONF @@ -209,15 +206,3 @@ class Manager(manager.Manager): def revoke(self, event): self.driver.revoke(event) REVOKE_REGION.invalidate() - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.revoke.RevokeDriverV8', - in_favor_of='keystone.revoke.backends.base.RevokeDriverV8', - remove_in=+1) -class RevokeDriverV8(base.RevokeDriverV8): - pass - - -Driver = manager.create_legacy_driver(base.RevokeDriverV8) diff --git a/keystone/tests/unit/backend/legacy_drivers/__init__.py b/keystone/tests/unit/backend/legacy_drivers/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/tests/unit/backend/legacy_drivers/assignment/V8/__init__.py b/keystone/tests/unit/backend/legacy_drivers/assignment/V8/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/tests/unit/backend/legacy_drivers/assignment/V8/sql.py b/keystone/tests/unit/backend/legacy_drivers/assignment/V8/sql.py deleted file mode 100644 index da1490a722..0000000000 --- a/keystone/tests/unit/backend/legacy_drivers/assignment/V8/sql.py +++ /dev/null @@ -1,39 +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.tests.unit import test_backend_sql - - -class SqlIdentityV8(test_backend_sql.SqlIdentity): - """Test that a V8 driver still passes the same tests. - - We use the SQL driver as an example of a V8 legacy driver. - - """ - - def config_overrides(self): - super(SqlIdentityV8, self).config_overrides() - # V8 SQL specific driver overrides - self.config_fixture.config( - group='assignment', - driver='keystone.assignment.V8_backends.sql.Assignment') - self.use_specific_sql_driver_version( - 'keystone.assignment', 'backends', 'V8_') - - def test_delete_project_assignments_same_id_as_domain(self): - self.skipTest("V8 doesn't support project acting as a domain.") - - def test_delete_user_assignments_user_same_id_as_group(self): - self.skipTest("Groups and users with the same ID are not supported.") - - def test_delete_group_assignments_group_same_id_as_user(self): - self.skipTest("Groups and users with the same ID are not supported.") diff --git a/keystone/tests/unit/backend/legacy_drivers/assignment/__init__.py b/keystone/tests/unit/backend/legacy_drivers/assignment/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/tests/unit/backend/legacy_drivers/federation/V8/__init__.py b/keystone/tests/unit/backend/legacy_drivers/federation/V8/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/tests/unit/backend/legacy_drivers/federation/V8/api_v3.py b/keystone/tests/unit/backend/legacy_drivers/federation/V8/api_v3.py deleted file mode 100644 index d9c4957494..0000000000 --- a/keystone/tests/unit/backend/legacy_drivers/federation/V8/api_v3.py +++ /dev/null @@ -1,108 +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. - -import uuid - -from six.moves import http_client - -from keystone.tests.unit import test_v3_federation - - -class FederatedSetupMixinV8(object): - def useV8driver(self): - # We use the SQL driver as an example V8 driver, so override - # the current driver with that version. - self.config_fixture.config( - group='federation', - driver='keystone.federation.V8_backends.sql.Federation') - self.use_specific_sql_driver_version( - 'keystone.federation', 'backends', 'V8_') - - -class FederatedIdentityProviderTestsV8( - test_v3_federation.FederatedIdentityProviderTests, - FederatedSetupMixinV8): - """Test that a V8 driver still passes the same tests.""" - - def config_overrides(self): - super(FederatedIdentityProviderTestsV8, self).config_overrides() - self.useV8driver() - - def test_create_idp_remote_repeated(self): - """Create two IdentityProvider entities with some remote_ids. - - A remote_id is the same for both so the second IdP is not - created because of the uniqueness of the remote_ids - - Expect HTTP 409 Conflict code for the latter call. - - Note: V9 drivers and later augment the conflict message with - additional information, which won't be present if we are running - a V8 driver - so override the newer tests to just ensure a - conflict message is raised. - """ - body = self.default_body.copy() - repeated_remote_id = uuid.uuid4().hex - body['remote_ids'] = [uuid.uuid4().hex, - uuid.uuid4().hex, - uuid.uuid4().hex, - repeated_remote_id] - self._create_default_idp(body=body) - - url = self.base_url(suffix=uuid.uuid4().hex) - body['remote_ids'] = [uuid.uuid4().hex, - repeated_remote_id] - self.put(url, body={'identity_provider': body}, - expected_status=http_client.CONFLICT) - - def test_check_idp_uniqueness(self): - """Add same IdP twice. - - Expect HTTP 409 Conflict code for the latter call. - - Note: V9 drivers and later augment the conflict message with - additional information, which won't be present if we are running - a V8 driver - so override the newer tests to just ensure a - conflict message is raised. - """ - url = self.base_url(suffix=uuid.uuid4().hex) - body = self._http_idp_input() - self.put(url, body={'identity_provider': body}, - expected_status=http_client.CREATED) - self.put(url, body={'identity_provider': body}, - expected_status=http_client.CONFLICT) - - -class MappingCRUDTestsV8( - test_v3_federation.MappingCRUDTests, - FederatedSetupMixinV8): - """Test that a V8 driver still passes the same tests.""" - - def config_overrides(self): - super(MappingCRUDTestsV8, self).config_overrides() - self.useV8driver() - - -class ServiceProviderTestsV8( - test_v3_federation.ServiceProviderTests, - FederatedSetupMixinV8): - """Test that a V8 driver still passes the same tests.""" - - def config_overrides(self): - super(ServiceProviderTestsV8, self).config_overrides() - self.useV8driver() - - def test_filter_list_sp_by_id(self): - self.skipTest('Operation not supported in v8 and earlier drivers') - - def test_filter_list_sp_by_enabled(self): - self.skipTest('Operation not supported in v8 and earlier drivers') diff --git a/keystone/tests/unit/backend/legacy_drivers/federation/__init__.py b/keystone/tests/unit/backend/legacy_drivers/federation/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/tests/unit/backend/legacy_drivers/resource/V8/__init__.py b/keystone/tests/unit/backend/legacy_drivers/resource/V8/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/tests/unit/backend/legacy_drivers/resource/V8/sql.py b/keystone/tests/unit/backend/legacy_drivers/resource/V8/sql.py deleted file mode 100644 index 16acbdc338..0000000000 --- a/keystone/tests/unit/backend/legacy_drivers/resource/V8/sql.py +++ /dev/null @@ -1,71 +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. - -import unittest - -from keystone.resource.V8_backends import sql -from keystone.tests import unit -from keystone.tests.unit.ksfixtures import database -from keystone.tests.unit.resource import test_backends -from keystone.tests.unit import test_backend_sql - - -class SqlIdentityV8(test_backend_sql.SqlIdentity): - """Test that a V8 driver still passes the same tests. - - We use the SQL driver as an example of a V8 legacy driver. - - """ - - def config_overrides(self): - super(SqlIdentityV8, self).config_overrides() - # V8 SQL specific driver overrides - self.config_fixture.config( - group='resource', - driver='keystone.resource.V8_backends.sql.Resource') - self.use_specific_sql_driver_version( - 'keystone.resource', 'backends', 'V8_') - - def test_delete_projects_from_ids(self): - self.skipTest('Operation not supported in v8 and earlier drivers') - - def test_delete_projects_from_ids_with_no_existing_project_id(self): - self.skipTest('Operation not supported in v8 and earlier drivers') - - def test_delete_project_cascade(self): - self.skipTest('Operation not supported in v8 and earlier drivers') - - def test_delete_large_project_cascade(self): - self.skipTest('Operation not supported in v8 and earlier drivers') - - def test_hidden_project_domain_root_is_really_hidden(self): - self.skipTest('Operation not supported in v8 and earlier drivers') - - -class TestSqlResourceDriverV8(unit.BaseTestCase, - test_backends.ResourceDriverTests): - def setUp(self): - super(TestSqlResourceDriverV8, self).setUp() - - version_specifiers = { - 'keystone.resource': { - 'versionless_backend': 'backends', - 'versioned_backend': 'V8_backends' - } - } - self.useFixture(database.Database(version_specifiers)) - - self.driver = sql.Resource() - - @unittest.skip('Null domain not allowed.') - def test_create_project_null_domain(self): - pass diff --git a/keystone/tests/unit/backend/legacy_drivers/resource/__init__.py b/keystone/tests/unit/backend/legacy_drivers/resource/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/tests/unit/backend/legacy_drivers/role/V8/__init__.py b/keystone/tests/unit/backend/legacy_drivers/role/V8/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/tests/unit/backend/legacy_drivers/role/V8/sql.py b/keystone/tests/unit/backend/legacy_drivers/role/V8/sql.py deleted file mode 100644 index d9378c3085..0000000000 --- a/keystone/tests/unit/backend/legacy_drivers/role/V8/sql.py +++ /dev/null @@ -1,30 +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.tests.unit import test_backend_sql - - -class SqlIdentityV8(test_backend_sql.SqlIdentity): - """Test that a V8 driver still passes the same tests. - - We use the SQL driver as an example of a V8 legacy driver. - - """ - - def config_overrides(self): - super(SqlIdentityV8, self).config_overrides() - # V8 SQL specific driver overrides - self.config_fixture.config( - group='role', - driver='keystone.assignment.V8_role_backends.sql.Role') - self.use_specific_sql_driver_version( - 'keystone.assignment', 'role_backends', 'V8_') diff --git a/keystone/tests/unit/backend/legacy_drivers/role/__init__.py b/keystone/tests/unit/backend/legacy_drivers/role/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/keystone/tests/unit/catalog/test_backends.py b/keystone/tests/unit/catalog/test_backends.py index 79730bcdc1..33b8cffb19 100644 --- a/keystone/tests/unit/catalog/test_backends.py +++ b/keystone/tests/unit/catalog/test_backends.py @@ -187,7 +187,7 @@ class CatalogTests(object): region_two['id'], {'parent_region_id': region_four['id']}) - @mock.patch.object(base.CatalogDriverV8, + @mock.patch.object(base.CatalogDriverBase, "_ensure_no_circle_in_hierarchical_regions") def test_circular_regions_can_be_deleted(self, mock_ensure_on_circle): # turn off the enforcement so that cycles can be created for the test diff --git a/keystone/tests/unit/common/test_manager.py b/keystone/tests/unit/common/test_manager.py deleted file mode 100644 index 1cf2c45d77..0000000000 --- a/keystone/tests/unit/common/test_manager.py +++ /dev/null @@ -1,78 +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. - -import mock - -from keystone import catalog -from keystone.common import manager -from keystone.tests import unit - - -class TestCreateLegacyDriver(unit.BaseTestCase): - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_class_is_properly_deprecated(self, mock_reporter): - Driver = manager.create_legacy_driver(catalog.CatalogDriverV8) - - # NOTE(dstanek): I want to subvert the requirement for this - # class to implement all of the abstract methods. - Driver.__abstractmethods__ = set() - impl = Driver() - - details = { - 'as_of': 'Liberty', - 'what': 'keystone.catalog.core.Driver', - 'in_favor_of': 'keystone.catalog.core.CatalogDriverV8', - 'remove_in': mock.ANY, - } - mock_reporter.assert_called_with(mock.ANY, mock.ANY, details) - self.assertEqual('N', mock_reporter.call_args[0][2]['remove_in'][0]) - - self.assertIsInstance(impl, catalog.CatalogDriverV8) - - class Manager(manager.Manager): - - def __init__(self, driver): - # NOTE(dstanek): I am not calling the parent's __init__ on - # purpose. I don't want to trigger the dynamic loading of a - # driver, I want to provide my own. - self.driver = driver - - def test_property_passthru(self): - """Manager delegating property call to a driver through __getattr__.""" - class Driver(object): - - def __init__(self): - self.counter = 0 - - @property - def p(self): - self.counter += 1 - return self.counter - - mgr = self.Manager(Driver()) - # each property call should return a new value - self.assertNotEqual(mgr.p, mgr.p) - - def test_callable_passthru(self): - class Driver(object): - - class Inner(object): - pass - - def method(self): - pass - - drv = Driver() - mgr = self.Manager(drv) - self.assertEqual(drv.Inner, mgr.Inner) - self.assertEqual(drv.method, mgr.method) diff --git a/keystone/tests/unit/test_backend_templated.py b/keystone/tests/unit/test_backend_templated.py index dcc43a42a6..25428008e2 100644 --- a/keystone/tests/unit/test_backend_templated.py +++ b/keystone/tests/unit/test_backend_templated.py @@ -17,7 +17,7 @@ import uuid import mock from six.moves import zip -from keystone import catalog +from keystone.catalog.backends import base as catalog_base from keystone.tests import unit from keystone.tests.unit.catalog import test_backends as catalog_tests from keystone.tests.unit import default_fixtures @@ -205,7 +205,7 @@ class TestTemplatedCatalog(unit.TestCase, catalog_tests.CatalogTests): def test_avoid_creating_circular_references_in_regions_update(self): self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - @mock.patch.object(catalog.Driver, + @mock.patch.object(catalog_base.CatalogDriverBase, "_ensure_no_circle_in_hierarchical_regions") def test_circular_regions_can_be_deleted(self, mock_ensure_on_circle): self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) diff --git a/keystone/token/persistence/backends/kvs.py b/keystone/token/persistence/backends/kvs.py index e175d45993..051030f572 100644 --- a/keystone/token/persistence/backends/kvs.py +++ b/keystone/token/persistence/backends/kvs.py @@ -36,7 +36,7 @@ LOG = log.getLogger(__name__) STORE_CONF_LOCK = threading.Lock() -class Token(token.persistence.TokenDriverV8): +class Token(token.persistence.TokenDriverBase): """KeyValueStore backend for tokens. This is the base implementation for any/all key-value-stores (e.g. diff --git a/keystone/token/persistence/backends/sql.py b/keystone/token/persistence/backends/sql.py index f74926919c..1853ccbf1e 100644 --- a/keystone/token/persistence/backends/sql.py +++ b/keystone/token/persistence/backends/sql.py @@ -81,7 +81,7 @@ def _expiry_range_all(session, upper_bound_func): yield upper_bound_func() -class Token(token.persistence.TokenDriverV8): +class Token(token.persistence.TokenDriverBase): # Public interface def get_token(self, token_id): if token_id is None: diff --git a/keystone/token/persistence/core.py b/keystone/token/persistence/core.py index 5f91cd818b..78527217f4 100644 --- a/keystone/token/persistence/core.py +++ b/keystone/token/persistence/core.py @@ -225,7 +225,7 @@ class Manager(object): @six.add_metaclass(abc.ABCMeta) -class TokenDriverV8(object): +class TokenDriverBase(object): """Interface description for a Token driver.""" @abc.abstractmethod @@ -352,6 +352,3 @@ class TokenDriverV8(object): def flush_expired_tokens(self): """Archive or delete tokens that have expired.""" raise exception.NotImplemented() # pragma: no cover - - -Driver = manager.create_legacy_driver(TokenDriverV8) diff --git a/keystone/trust/backends/base.py b/keystone/trust/backends/base.py index b184d5acd4..5ebfab1904 100644 --- a/keystone/trust/backends/base.py +++ b/keystone/trust/backends/base.py @@ -20,7 +20,7 @@ from keystone import exception @six.add_metaclass(abc.ABCMeta) -class TrustDriverV8(object): +class TrustDriverBase(object): @abc.abstractmethod def create_trust(self, trust_id, trust, roles): diff --git a/keystone/trust/backends/sql.py b/keystone/trust/backends/sql.py index e67e67ac02..d82474214e 100644 --- a/keystone/trust/backends/sql.py +++ b/keystone/trust/backends/sql.py @@ -56,7 +56,7 @@ class TrustRole(sql.ModelBase): role_id = sql.Column(sql.String(64), primary_key=True, nullable=False) -class Trust(base.TrustDriverV8): +class Trust(base.TrustDriverBase): @sql.handle_conflicts(conflict_type='trust') def create_trust(self, trust_id, trust, roles): with sql.session_for_write() as session: diff --git a/keystone/trust/core.py b/keystone/trust/core.py index 6459cee0e3..32aac05d39 100644 --- a/keystone/trust/core.py +++ b/keystone/trust/core.py @@ -14,7 +14,6 @@ """Main entry point into the Trust service.""" -from oslo_log import versionutils from six.moves import zip from keystone.common import dependency @@ -23,7 +22,6 @@ import keystone.conf from keystone import exception from keystone.i18n import _ from keystone import notifications -from keystone.trust.backends import base CONF = keystone.conf.CONF @@ -200,15 +198,3 @@ class Manager(manager.Manager): self.driver.delete_trust(trust_id) notifications.Audit.deleted(self._TRUST, trust_id, initiator) - - -@versionutils.deprecated( - versionutils.deprecated.NEWTON, - what='keystone.trust.TrustDriverV8', - in_favor_of='keystone.trust.backends.base.TrustDriverV8', - remove_in=+1) -class TrustDriverV8(base.TrustDriverV8): - pass - - -Driver = manager.create_legacy_driver(base.TrustDriverV8) diff --git a/tox.ini b/tox.ini index 6acf3a3457..c31e084c15 100644 --- a/tox.ini +++ b/tox.ini @@ -31,14 +31,7 @@ deps = -r{toxinidir}/test-requirements.txt commands = # Run each legacy test separately, to avoid SQL model redefinitions find keystone -type f -name "*.pyc" -delete - nosetests -v -m '^[Tt]est' \ - keystone/tests/unit/backend/legacy_drivers/assignment/V8/sql.py - nosetests -v -m '^[Tt]est' \ - keystone/tests/unit/backend/legacy_drivers/role/V8/sql.py - nosetests -v -m '^[Tt]est' \ - keystone/tests/unit/backend/legacy_drivers/federation/V8/api_v3.py - nosetests -v -m '^[Tt]est' \ - keystone/tests/unit/backend/legacy_drivers/resource/V8/sql.py + # TODO(stevemar): Remove this test once we remove the infra job [testenv:pep8] deps =