diff --git a/lib/ansible/modules/cloud/azure/azure_rm_roleassignment_facts.py b/lib/ansible/modules/cloud/azure/azure_rm_roleassignment_facts.py new file mode 100644 index 0000000000..19999edbf8 --- /dev/null +++ b/lib/ansible/modules/cloud/azure/azure_rm_roleassignment_facts.py @@ -0,0 +1,250 @@ +#!/usr/bin/python +# +# Copyright (c) 2019 Yunge Zhu, (@yungezz) +# +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + + +DOCUMENTATION = ''' +--- +module: azure_rm_roleassignment_facts +version_added: "2.8" +short_description: Gets Azure Role Assignment facts. +description: + - Gets facts of Azure Role Assignment. + +options: + scope: + description: + - The scope that the role assignment applies to. + - For example, use /subscriptions/{subscription-id}/ for a subscription, + - /subscriptions/{subscription-id}/resourceGroups/{resourcegroup-name} for a resource group, + - /subscriptions/{subscription-id}/resourceGroups/{resourcegroup-name}/providers/{resource-provider}/{resource-type}/{resource-name} for a resource + name: + description: + - Name of role assignment. + - Mutual exclusive with I(assignee). + assignee: + description: + - Object id of a user, group or service principal. + - Mutually exclusive with I(name). + +extends_documentation_fragment: + - azure + +author: + - "Yunge Zhu(@yungezz)" + +''' + +EXAMPLES = ''' + - name: Get role assignments for specific service principal + azure_rm_roleassignment_facts: + assignee: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + + - name: Get role assignments for specific scope + azure_rm_roleassignment_facts: + scope: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +''' + +RETURN = ''' +roleassignments: + description: List of role assignments. + returned: always + type: complex + contains: + id: + description: + - Id of role assignment. + type: str + returned: always + sample: "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Authorization/roleAssignments/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + name: + description: + - Name of role assignment. + type: str + returned: always + sample: myRoleAssignment + type: + descripition: + - Type of role assignment. + type: str + returned: always + sample: custom + principal_id: + description: + - Principal Id of the role assigned to. + type: str + returned: always + sample: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + role_definition_id: + description: + - Role definition id that was assigned to principal_id. + type: str + returned: always + sample: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + scope: + description: + - The role assignment scope + type: str + returned: always + sample: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +''' + +import time +from ansible.module_utils.azure_rm_common import AzureRMModuleBase + +try: + from msrestazure.azure_exceptions import CloudError + from msrest.serialization import Model + from azure.mgmt.authorization import AuthorizationManagementClient + +except ImportError: + # This is handled in azure_rm_common + pass + + +def roleassignment_to_dict(assignment): + return dict( + id=assignment.id, + name=assignment.name, + type=assignment.type, + principal_id=assignment.principal_id, + role_definition_id=assignment.role_definition_id, + scope=assignment.scope + ) + + +class AzureRMRoleAssignmentFacts(AzureRMModuleBase): + + def __init__(self): + self.module_arg_spec = dict( + name=dict( + type='str' + ), + scope=dict( + type='str' + ), + assignee=dict( + type='str' + ) + ) + + self.name = None + self.scope = None + self.assignee = None + + self.results = dict( + changed=False + ) + + self._client = None + + mutually_exclusive = [['name', 'assignee']] + + super(AzureRMRoleAssignmentFacts, self).__init__(derived_arg_spec=self.module_arg_spec, + supports_tags=False, + mutually_exclusive=mutually_exclusive) + + def exec_module(self, **kwargs): + """Main module execution method""" + + for key in list(self.module_arg_spec.keys()): + if hasattr(self, key): + setattr(self, key, kwargs[key]) + + # get management client + self._client = self.get_mgmt_svc_client(AuthorizationManagementClient, + base_url=self._cloud_environment.endpoints.resource_manager, + api_version="2018-01-01-preview") + + if self.name: + self.results['roleassignments'] = self.get_by_name() + elif self.assignee: + self.results['roleassignments'] = self.get_by_assignee() + elif self.resource_group: + self.results['roleassignments'] = self.list_by_resource_group() + elif self.scope: + self.results['roleassignments'] = self.list_by_scope() + else: + self.fail("Please specify name or assignee") + + return self.results + + def get_by_name(self): + ''' + Gets the properties of the specified role assignment by name. + + :return: deserialized role assignment dictionary + ''' + self.log("Gets role assignment {0} by name".format(self.name)) + + response = None + + try: + response = self._client.role_assignments.get(scope=self.scope, role_assignment_name=self.name) + + return [roleassignment_to_dict(response)] + + except CloudError as ex: + self.log("Didn't find role assignment {0} in scope {1}".format(self.name, self.scope)) + + return [] + + def get_by_assignee(self): + ''' + Gets the role assignments by assignee. + + :return: deserialized role assignment dictionary + ''' + self.log("Gets role assignment {0} by name".format(self.name)) + + response = None + filter = "principalId eq '{0}'".format(self.assignee) + try: + response = list(self._client.role_assignments.list(filter=filter)) + + if response and len(response) > 0: + return [roleassignment_to_dict(a) for a in response] + + except CloudError as ex: + self.log("Didn't find role assignments to assignee {0}".format(self.assignee)) + + return [] + + def list_by_scope(self): + ''' + Lists the role assignments by specific scope. + + :return: deserialized role assignment dictionary + ''' + self.log("Lists role assignment by resource group {0}".format(self.resource_group)) + + response = None + try: + response = list(self._client.role_assignments.list_for_scope(scope=self.scope, filter='atScope()')) + + if response and len(response) > 0: + return [roleassignment_to_dict(a) for a in response] + + except CloudError as ex: + self.log("Didn't find role assignments to scope {0}".format(self.scope)) + + return [] + + +def main(): + """Main execution""" + AzureRMRoleAssignmentFacts() + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/azure_rm_roledefinition/tasks/main.yml b/test/integration/targets/azure_rm_roledefinition/tasks/main.yml index bdf1431c04..d44586500e 100644 --- a/test/integration/targets/azure_rm_roledefinition/tasks/main.yml +++ b/test/integration/targets/azure_rm_roledefinition/tasks/main.yml @@ -2,6 +2,7 @@ set_fact: role_name: "{{ (resource_group | replace('-','x'))[-8:] }}{{ 1000 | random }}testrole" subscription_id: "{{ lookup('env','AZURE_SUBSCRIPTION_ID') }}" + principal_id: "{{ lookup('env','AZURE_CLIENT_ID') }}" run_once: yes - name: Create a role definition (Check Mode) @@ -117,6 +118,62 @@ that: - output.changed +- name: Get role definition facts + azure_rm_roledefinition_facts: + role_name: "{{ role_name }}" + scope: "/subscriptions/{{ subscription_id }}/resourceGroups/{{ resource_group }}" + type: custom + register: roledef + +- name: Assert role definition facts + assert: + that: + - roledef['roledefinitions'] | length > 1 + - roledef['roledefinitions'][0]['id'] + +- name: Create a role assignment (Check Mode) + azure_rm_roleassignment: + scope: "/subscriptions/{{ subscription_id }}/resourceGroups/{{ resource_group }}" + assignee_object_id: "{{ principal_id }}" + role_definition_id: "{{ roledef['roledefinitions'][0]['id'] }}" + check_mode: yes + register: output + +- name: Assert creating role definition check mode + assert: + that: + - output.changed + +- name: Create a role assignment + azure_rm_roleassignment: + scope: "/subscriptions/{{ subscription_id }}/resourceGroups/{{ resource_group }}" + assignee_object_id: "{{ principal_id }}" + role_definition_id: "{{ roledef['roledefinitions'][0]['id'] }}" + register: output + +- name: Assert creating role definition + assert: + that: + - output.changed + +- name: Get facts + azure_rm_roleassignment_facts: + scope: "/subscriptions/{{ subscription_id }}/resourceGroups/{{ resource_group }}" + assignee: "{{ principal_id }}" + register: facts + +- name: assert role assignment facts + assert: + that: + - facts['roleassignments'] | length > 1 + - facts['roleassignments'][0]['id'] + +- name: delete role assignment + azure_rm_roleassignment: + name: facts['roleassignments'][0]['id'] + scope: "/subscriptions/{{ subscription_id }}/resourceGroups/{{ resource_group }}" + state: absent + - name: Delete the role definition (Check Mode) azure_rm_roledefinition: name: "{{ role_name }}"