mirror of
https://opendev.org/openstack/ansible-collections-openstack.git
synced 2026-03-26 21:43:02 +00:00
Allow role_assignment module to work cross domain
The role_assignment module always looks up the user, group and project so to support cross-domain assignments we should add extra parameters like OSC to look them up from the correct domains. Switch to using the service proxy interface to grant or revoke the roles as well. Partial-Bug: #2052448 Partial-Bug: #2047151 Partial-Bug: #2097203 Change-Id: Id023cb9e7017c749bc39bba2091921154a413723
This commit is contained in:
@@ -45,12 +45,6 @@
|
||||
state: absent
|
||||
user: admin
|
||||
|
||||
- name: Delete project
|
||||
openstack.cloud.project:
|
||||
cloud: "{{ cloud }}"
|
||||
state: absent
|
||||
name: ansible_project
|
||||
|
||||
- name: Create domain
|
||||
openstack.cloud.identity_domain:
|
||||
cloud: "{{ cloud }}"
|
||||
@@ -78,6 +72,7 @@
|
||||
state: present
|
||||
name: ansible_user
|
||||
domain: default
|
||||
register: specific_user
|
||||
|
||||
- name: Create user in specific domain
|
||||
openstack.cloud.identity_user:
|
||||
@@ -138,6 +133,45 @@
|
||||
that:
|
||||
- role_assignment is changed
|
||||
|
||||
- name: Assign role to user in specific domain on default domain project
|
||||
openstack.cloud.role_assignment:
|
||||
cloud: "{{ cloud }}"
|
||||
role: anotherrole
|
||||
user: "{{ specific_user.user.id }}"
|
||||
domain: default
|
||||
project: ansible_project
|
||||
register: role_assignment
|
||||
|
||||
- name: Assert role assignment
|
||||
assert:
|
||||
that:
|
||||
- role_assignment is changed
|
||||
|
||||
- name: Revoke role to user in specific domain
|
||||
openstack.cloud.role_assignment:
|
||||
cloud: "{{ cloud }}"
|
||||
role: anotherrole
|
||||
user: "{{ specific_user.user.id }}"
|
||||
domain: default
|
||||
project: ansible_project
|
||||
state: absent
|
||||
register: role_assignment
|
||||
|
||||
- name: Assert role assignment revoked
|
||||
assert:
|
||||
that:
|
||||
- role_assignment is changed
|
||||
|
||||
- name: Assign role to user in specific domain on default domain project
|
||||
openstack.cloud.role_assignment:
|
||||
cloud: "{{ cloud }}"
|
||||
role: anotherrole
|
||||
user: ansible_user
|
||||
user_domain: "{{ specific_user.user.domain_id }}"
|
||||
project: ansible_project
|
||||
project_domain: default
|
||||
register: role_assignment
|
||||
|
||||
- name: Delete group in default domain
|
||||
openstack.cloud.identity_group:
|
||||
cloud: "{{ cloud }}"
|
||||
@@ -171,3 +205,10 @@
|
||||
cloud: "{{ cloud }}"
|
||||
state: absent
|
||||
name: ansible_domain
|
||||
|
||||
- name: Delete project
|
||||
openstack.cloud.project:
|
||||
cloud: "{{ cloud }}"
|
||||
state: absent
|
||||
name: ansible_project
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ options:
|
||||
- Valid only with keystone version 3.
|
||||
- Required if I(project) is not specified.
|
||||
- When I(project) is specified, then I(domain) will not be used for
|
||||
scoping the role association, only for finding resources.
|
||||
scoping the role association, only for finding resources. Deprecated
|
||||
for finding resources, please use I(group_domain), I(project_domain),
|
||||
I(role_domain), or I(user_domain).
|
||||
- "When scoping the role association, I(project) has precedence over
|
||||
I(domain) and I(domain) has precedence over I(system): When I(project)
|
||||
is specified, then I(domain) and I(system) are not used for role
|
||||
@@ -32,24 +34,45 @@ options:
|
||||
- Valid only with keystone version 3.
|
||||
- If I(group) is not specified, then I(user) is required. Both may not be
|
||||
specified at the same time.
|
||||
- You can supply I(group_domain) or the deprecated usage of I(domain) to
|
||||
find group resources.
|
||||
type: str
|
||||
group_domain:
|
||||
description:
|
||||
- Name or ID for the domain.
|
||||
- Valid only with keystone version 3.
|
||||
- Only valid for finding group resources.
|
||||
type: str
|
||||
project:
|
||||
description:
|
||||
- Name or ID of the project to scope the role association to.
|
||||
- If you are using keystone version 2, then this value is required.
|
||||
- When I(project) is specified, then I(domain) will not be used for
|
||||
scoping the role association, only for finding resources.
|
||||
scoping the role association, only for finding resources. Prefer
|
||||
I(group_domain) over I(domain).
|
||||
- "When scoping the role association, I(project) has precedence over
|
||||
I(domain) and I(domain) has precedence over I(system): When I(project)
|
||||
is specified, then I(domain) and I(system) are not used for role
|
||||
association. When I(domain) is specified, then I(system) will not be
|
||||
used for role association."
|
||||
type: str
|
||||
project_domain:
|
||||
description:
|
||||
- Name or ID for the domain.
|
||||
- Valid only with keystone version 3.
|
||||
- Only valid for finding project resources.
|
||||
type: str
|
||||
role:
|
||||
description:
|
||||
- Name or ID for the role.
|
||||
required: true
|
||||
type: str
|
||||
role_domain:
|
||||
description:
|
||||
- Name or ID for the domain.
|
||||
- Valid only with keystone version 3.
|
||||
- Only valid for finding role resources.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Should the roles be present or absent on the user.
|
||||
@@ -73,6 +96,12 @@ options:
|
||||
- If I(user) is not specified, then I(group) is required. Both may not be
|
||||
specified at the same time.
|
||||
type: str
|
||||
user_domain:
|
||||
description:
|
||||
- Name or ID for the domain.
|
||||
- Valid only with keystone version 3.
|
||||
- Only valid for finding user resources.
|
||||
type: str
|
||||
extends_documentation_fragment:
|
||||
- openstack.cloud.openstack
|
||||
'''
|
||||
@@ -101,11 +130,15 @@ class IdentityRoleAssignmentModule(OpenStackModule):
|
||||
argument_spec = dict(
|
||||
domain=dict(),
|
||||
group=dict(),
|
||||
group_domain=dict(type='str'),
|
||||
project=dict(),
|
||||
project_domain=dict(type='str'),
|
||||
role=dict(required=True),
|
||||
role_domain=dict(type='str'),
|
||||
state=dict(default='present', choices=['absent', 'present']),
|
||||
system=dict(),
|
||||
user=dict(),
|
||||
user_domain=dict(type='str'),
|
||||
)
|
||||
|
||||
module_kwargs = dict(
|
||||
@@ -113,17 +146,33 @@ class IdentityRoleAssignmentModule(OpenStackModule):
|
||||
('user', 'group'),
|
||||
('domain', 'project', 'system'),
|
||||
],
|
||||
mutually_exclusive=[
|
||||
('user', 'group'),
|
||||
('project', 'system'), # domain should be part of this
|
||||
],
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
def _find_domain_id(self, domain):
|
||||
if domain is not None:
|
||||
domain = self.conn.identity.find_domain(domain,
|
||||
ignore_missing=False)
|
||||
return dict(domain_id=domain['id'])
|
||||
return dict()
|
||||
|
||||
def run(self):
|
||||
filters = {}
|
||||
find_filters = {}
|
||||
kwargs = {}
|
||||
group_find_filters = {}
|
||||
project_find_filters = {}
|
||||
role_find_filters = {}
|
||||
user_find_filters = {}
|
||||
|
||||
role_find_filters.update(self._find_domain_id(
|
||||
self.params['role_domain']))
|
||||
role_name_or_id = self.params['role']
|
||||
role = self.conn.identity.find_role(role_name_or_id,
|
||||
ignore_missing=False)
|
||||
ignore_missing=False,
|
||||
**role_find_filters)
|
||||
filters['role_id'] = role['id']
|
||||
|
||||
domain_name_or_id = self.params['domain']
|
||||
@@ -131,22 +180,31 @@ class IdentityRoleAssignmentModule(OpenStackModule):
|
||||
domain = self.conn.identity.find_domain(
|
||||
domain_name_or_id, ignore_missing=False)
|
||||
filters['scope_domain_id'] = domain['id']
|
||||
find_filters['domain_id'] = domain['id']
|
||||
kwargs['domain'] = domain['id']
|
||||
group_find_filters['domain_id'] = domain['id']
|
||||
project_find_filters['domain_id'] = domain['id']
|
||||
user_find_filters['domain_id'] = domain['id']
|
||||
|
||||
user_name_or_id = self.params['user']
|
||||
if user_name_or_id is not None:
|
||||
user_find_filters.update(self._find_domain_id(
|
||||
self.params['user_domain']))
|
||||
user = self.conn.identity.find_user(
|
||||
user_name_or_id, ignore_missing=False, **find_filters)
|
||||
user_name_or_id, ignore_missing=False,
|
||||
**user_find_filters)
|
||||
filters['user_id'] = user['id']
|
||||
kwargs['user'] = user['id']
|
||||
else:
|
||||
user = None
|
||||
|
||||
group_name_or_id = self.params['group']
|
||||
if group_name_or_id is not None:
|
||||
group_find_filters.update(self._find_domain_id(
|
||||
self.params['group_domain']))
|
||||
group = self.conn.identity.find_group(
|
||||
group_name_or_id, ignore_missing=False, **find_filters)
|
||||
group_name_or_id, ignore_missing=False,
|
||||
**group_find_filters)
|
||||
filters['group_id'] = group['id']
|
||||
kwargs['group'] = group['id']
|
||||
else:
|
||||
group = None
|
||||
|
||||
system_name = self.params['system']
|
||||
if system_name is not None:
|
||||
@@ -154,14 +212,14 @@ class IdentityRoleAssignmentModule(OpenStackModule):
|
||||
if 'scope_domain_id' not in filters:
|
||||
filters['scope.system'] = system_name
|
||||
|
||||
kwargs['system'] = system_name
|
||||
|
||||
project_name_or_id = self.params['project']
|
||||
if project_name_or_id is not None:
|
||||
project_find_filters.update(self._find_domain_id(
|
||||
self.params['project_domain']))
|
||||
project = self.conn.identity.find_project(
|
||||
project_name_or_id, ignore_missing=False, **find_filters)
|
||||
project_name_or_id, ignore_missing=False,
|
||||
**project_find_filters)
|
||||
filters['scope_project_id'] = project['id']
|
||||
kwargs['project'] = project['id']
|
||||
|
||||
# project has precedence over domain and system
|
||||
filters.pop('scope_domain_id', None)
|
||||
@@ -176,10 +234,50 @@ class IdentityRoleAssignmentModule(OpenStackModule):
|
||||
or (state == 'absent' and role_assignments)))
|
||||
|
||||
if state == 'present' and not role_assignments:
|
||||
self.conn.grant_role(role['id'], **kwargs)
|
||||
if 'scope_domain_id' in filters:
|
||||
if user is not None:
|
||||
self.conn.identity.assign_domain_role_to_user(
|
||||
filters['scope_domain_id'], user, role)
|
||||
else:
|
||||
self.conn.identity.assign_domain_role_to_group(
|
||||
filters['scope_domain_id'], group, role)
|
||||
elif 'scope_project_id' in filters:
|
||||
if user is not None:
|
||||
self.conn.identity.assign_project_role_to_user(
|
||||
filters['scope_project_id'], user, role)
|
||||
else:
|
||||
self.conn.identity.assign_project_role_to_group(
|
||||
filters['scope_project_id'], group, role)
|
||||
elif 'scope.system' in filters:
|
||||
if user is not None:
|
||||
self.conn.identity.assign_system_role_to_user(
|
||||
user, role, filters['scope.system'])
|
||||
else:
|
||||
self.conn.identity.assign_system_role_to_group(
|
||||
group, role, filters['scope.system'])
|
||||
self.exit_json(changed=True)
|
||||
elif state == 'absent' and role_assignments:
|
||||
self.conn.revoke_role(role['id'], **kwargs)
|
||||
if 'scope_domain_id' in filters:
|
||||
if user is not None:
|
||||
self.conn.identity.unassign_domain_role_from_user(
|
||||
filters['scope_domain_id'], user, role)
|
||||
else:
|
||||
self.conn.identity.unassign_domain_role_from_group(
|
||||
filters['scope_domain_id'], group, role)
|
||||
elif 'scope_project_id' in filters:
|
||||
if user is not None:
|
||||
self.conn.identity.unassign_project_role_from_user(
|
||||
filters['scope_project_id'], user, role)
|
||||
else:
|
||||
self.conn.identity.unassign_project_role_from_group(
|
||||
filters['scope_project_id'], group, role)
|
||||
elif 'scope.system' in filters:
|
||||
if user is not None:
|
||||
self.conn.identity.unassign_system_role_from_user(
|
||||
user, role, filters['scope.system'])
|
||||
else:
|
||||
self.conn.identity.unassign_system_role_from_group(
|
||||
group, role, filters['scope.system'])
|
||||
self.exit_json(changed=True)
|
||||
else:
|
||||
self.exit_json(changed=False)
|
||||
|
||||
Reference in New Issue
Block a user