From 2e7b4f2027a1147ca28301e4f88adf8274b39a1f Mon Sep 17 00:00:00 2001 From: DUVAL Thomas Date: Thu, 9 Jun 2016 09:11:50 +0200 Subject: Update Keystone core to Mitaka. Change-Id: Ia10d6add16f4a9d25d1f42d420661c46332e69db --- keystone-moon/keystone/assignment/backends/sql.py | 252 ++++------------------ 1 file changed, 36 insertions(+), 216 deletions(-) (limited to 'keystone-moon/keystone/assignment/backends/sql.py') diff --git a/keystone-moon/keystone/assignment/backends/sql.py b/keystone-moon/keystone/assignment/backends/sql.py index e249ba34..e089726a 100644 --- a/keystone-moon/keystone/assignment/backends/sql.py +++ b/keystone-moon/keystone/assignment/backends/sql.py @@ -12,21 +12,12 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_config import cfg -from oslo_log import log -import sqlalchemy -from sqlalchemy.sql.expression import false - from keystone import assignment as keystone_assignment from keystone.common import sql from keystone import exception from keystone.i18n import _ -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - class AssignmentType(object): USER_PROJECT = 'UserProject' GROUP_PROJECT = 'GroupProject' @@ -49,7 +40,7 @@ class AssignmentType(object): raise exception.AssignmentTypeCalculationError(**locals()) -class Assignment(keystone_assignment.AssignmentDriverV8): +class Assignment(keystone_assignment.AssignmentDriverV9): def default_role_driver(self): return 'sql' @@ -57,60 +48,6 @@ class Assignment(keystone_assignment.AssignmentDriverV8): def default_resource_driver(self): return 'sql' - def list_user_ids_for_project(self, tenant_id): - with sql.transaction() 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 _get_metadata(self, user_id=None, tenant_id=None, - domain_id=None, group_id=None, session=None): - # TODO(henry-nash): This method represents the last vestiges of the old - # metadata concept in this driver. Although we no longer need it here, - # since the Manager layer uses the metadata concept across all - # assignment drivers, we need to remove it from all of them in order to - # finally remove this method. - - # We aren't given a session when called by the manager directly. - if session is None: - session = sql.get_session() - - q = session.query(RoleAssignment) - - def _calc_assignment_type(): - # Figure out the assignment type we're checking for from the args. - if user_id: - if tenant_id: - return AssignmentType.USER_PROJECT - else: - return AssignmentType.USER_DOMAIN - else: - if tenant_id: - return AssignmentType.GROUP_PROJECT - else: - return AssignmentType.GROUP_DOMAIN - - q = q.filter_by(type=_calc_assignment_type()) - q = q.filter_by(actor_id=user_id or group_id) - q = q.filter_by(target_id=tenant_id or domain_id) - refs = q.all() - if not refs: - raise exception.MetadataNotFound() - - metadata_ref = {} - metadata_ref['roles'] = [] - for assignment in refs: - role_ref = {} - role_ref['id'] = assignment.role_id - if assignment.inherited: - role_ref['inherited_to'] = 'projects' - metadata_ref['roles'].append(role_ref) - - return metadata_ref - def create_grant(self, role_id, user_id=None, group_id=None, domain_id=None, project_id=None, inherited_to_projects=False): @@ -118,21 +55,21 @@ class Assignment(keystone_assignment.AssignmentDriverV8): assignment_type = AssignmentType.calculate_type( user_id, group_id, project_id, domain_id) try: - with sql.transaction() as session: + 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: - # The v3 grant APIs are silent if the assignment already exists + 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.transaction() as session: + 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)) @@ -151,7 +88,7 @@ class Assignment(keystone_assignment.AssignmentDriverV8): 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.transaction() as session: + with sql.session_for_read() as session: try: q = self._build_grant_filter( session, role_id, user_id, group_id, domain_id, project_id, @@ -167,7 +104,7 @@ class Assignment(keystone_assignment.AssignmentDriverV8): def delete_grant(self, role_id, user_id=None, group_id=None, domain_id=None, project_id=None, inherited_to_projects=False): - with sql.transaction() as session: + 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) @@ -178,143 +115,9 @@ class Assignment(keystone_assignment.AssignmentDriverV8): 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.transaction() 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.transaction() 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.transaction() 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.transaction() 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.transaction() 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.transaction() as session: + with sql.session_for_write() as session: session.add(RoleAssignment( type=AssignmentType.USER_PROJECT, actor_id=user_id, target_id=tenant_id, @@ -325,7 +128,7 @@ class Assignment(keystone_assignment.AssignmentDriverV8): raise exception.Conflict(type='role grant', details=msg) def remove_role_from_user_and_project(self, user_id, tenant_id, role_id): - with sql.transaction() as session: + 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) @@ -415,7 +218,7 @@ class Assignment(keystone_assignment.AssignmentDriverV8): assignment['inherited_to_projects'] = 'projects' return assignment - with sql.transaction() as session: + with sql.session_for_read() as session: assignment_types = self._get_assignment_types( user_id, group_ids, project_ids, domain_id) @@ -447,34 +250,51 @@ class Assignment(keystone_assignment.AssignmentDriverV8): return [denormalize_role(ref) for ref in query.all()] def delete_project_assignments(self, project_id): - with sql.transaction() as session: + with sql.session_for_write() as session: q = session.query(RoleAssignment) - q = q.filter_by(target_id=project_id) + q = q.filter_by(target_id=project_id).filter( + RoleAssignment.type.in_((AssignmentType.USER_PROJECT, + AssignmentType.GROUP_PROJECT)) + ) q.delete(False) def delete_role_assignments(self, role_id): - with sql.transaction() as session: + with sql.session_for_write() as session: q = session.query(RoleAssignment) q = q.filter_by(role_id=role_id) q.delete(False) + def delete_domain_assignments(self, domain_id): + with sql.session_for_write() as session: + q = session.query(RoleAssignment) + q = q.filter(RoleAssignment.target_id == domain_id).filter( + (RoleAssignment.type == AssignmentType.USER_DOMAIN) | + (RoleAssignment.type == AssignmentType.GROUP_DOMAIN)) + q.delete(False) + def delete_user_assignments(self, user_id): - with sql.transaction() as session: + with sql.session_for_write() as session: q = session.query(RoleAssignment) - q = q.filter_by(actor_id=user_id) + q = q.filter_by(actor_id=user_id).filter( + RoleAssignment.type.in_((AssignmentType.USER_PROJECT, + AssignmentType.USER_DOMAIN)) + ) q.delete(False) def delete_group_assignments(self, group_id): - with sql.transaction() as session: + with sql.session_for_write() as session: q = session.query(RoleAssignment) - q = q.filter_by(actor_id=group_id) + q = q.filter_by(actor_id=group_id).filter( + RoleAssignment.type.in_((AssignmentType.GROUP_PROJECT, + AssignmentType.GROUP_DOMAIN)) + ) 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 + # 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, @@ -491,7 +311,7 @@ class RoleAssignment(sql.ModelBase, sql.DictBase): ) def to_dict(self): - """Override parent to_dict() method with a simpler implementation. + """Override parent method with a simpler implementation. RoleAssignment doesn't have non-indexed 'extra' attributes, so the parent implementation is not applicable. -- cgit 1.2.3-korg