#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright (c) 2016 IBM # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) DOCUMENTATION = r''' --- module: role_assignment short_description: Assign OpenStack identity groups and users to roles author: OpenStack Ansible SIG description: - Grant and revoke roles in either project or domain context for OpenStack identity (Keystone) users and groups. options: domain: description: - Name or ID of the domain to scope the role association to. - 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. 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 association. When I(domain) is specified, then I(system) will not be used for role association." type: str group: description: - Name or ID for the group. - 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. 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. choices: [present, absent] default: present type: str system: description: - Name of system to scope the role association to. - Valid only with keystone version 3. - Required if I(project) and I(domain) are not specified. - "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 user: description: - Name or ID for the user. - 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 ''' EXAMPLES = r''' - name: Grant an admin role on the user admin in the project project1 openstack.cloud.role_assignment: cloud: mycloud user: admin role: admin project: project1 - name: Revoke the admin role from the user barney in the newyork domain openstack.cloud.role_assignment: cloud: mycloud state: absent user: barney role: admin domain: newyork ''' from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule 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( required_one_of=[ ('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 = {} 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, **role_find_filters) filters['role_id'] = role['id'] domain_name_or_id = self.params['domain'] if domain_name_or_id is not None: domain = self.conn.identity.find_domain( domain_name_or_id, ignore_missing=False) filters['scope_domain_id'] = 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, **user_find_filters) filters['user_id'] = 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, **group_find_filters) filters['group_id'] = group['id'] else: group = None system_name = self.params['system'] if system_name is not None: # domain has precedence over system if 'scope_domain_id' not in filters: filters['scope.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, **project_find_filters) filters['scope_project_id'] = project['id'] # project has precedence over domain and system filters.pop('scope_domain_id', None) filters.pop('scope.system', None) role_assignments = list(self.conn.identity.role_assignments(**filters)) state = self.params['state'] if self.ansible.check_mode: self.exit_json( changed=((state == 'present' and not role_assignments) or (state == 'absent' and role_assignments))) if state == 'present' and not role_assignments: 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: 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) def main(): module = IdentityRoleAssignmentModule() module() if __name__ == '__main__': main()