diff --git a/README-automountmap.md b/README-automountmap.md index 0fdcede60610030939749496a425cb218a71de40..208dd53deb5e6b7ddba8a42d85204577889c7ce9 100644 --- a/README-automountmap.md +++ b/README-automountmap.md @@ -4,7 +4,7 @@ Automountmap module Description ----------- -The automountmap module allows the addition and removal of maps within automount locations. +The automountmap module allows the addition and removal of maps within automount locations. It is desgined to follow the IPA api as closely as possible while ensuring ease of use. @@ -37,14 +37,13 @@ Example inventory file ipaserver.test.local ``` - Example playbook to ensure presence of an automount map: ```yaml --- - name: Playbook to add an automount map hosts: ipaserver - become: true + become: no tasks: - name: ensure map named auto.DMZ in location DMZ is created @@ -55,20 +54,20 @@ Example playbook to ensure presence of an automount map: desc: "this is a map for servers in the DMZ" ``` +Example playbook to ensure auto.DMZi is absent: -Example playbook to ensure auto.DMZi does not exist ```yaml --- - name: Playbook to remove an automount map hosts: ipaserver - become: true + become: no tasks: - name: ensure map auto.DMZ has been removed ipaautomountmap: ipaadmin_password: SomeADMINpassword name: auto.DMZ - location: DMX + location: DMZ state: absent ``` @@ -76,9 +75,6 @@ Example playbook to ensure auto.DMZi does not exist Variables ========= -ipaautomountmap -------- - Variable | Description | Required -------- | ----------- | -------- `ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no @@ -89,6 +85,11 @@ Variable | Description | Required `state` | The state to ensure. It can be one of `present`, or `absent`, default: `present`. | no +Notes +===== + +Creation of indirect mount points are not supported. + Authors ======= diff --git a/playbooks/automount/automount-map-absent.yaml b/playbooks/automount/automount-map-absent.yaml index 91c4b67ead86e2e354ae2750728d9d8ad12dea51..344fb20556907b4cd2015b82c391bf7ab63c819e 100644 --- a/playbooks/automount/automount-map-absent.yaml +++ b/playbooks/automount/automount-map-absent.yaml @@ -1,7 +1,8 @@ --- - name: Automount map absent example hosts: ipaserver - become: true + become: no + tasks: - name: ensure map TestMap is absent ipaautomountmap: @@ -9,4 +10,3 @@ name: TestMap location: TestLocation state: absent - diff --git a/playbooks/automount/automount-map-present.yaml b/playbooks/automount/automount-map-present.yaml index 3cc92ba35902e8ec7396fc6ce232de0cdf10fa41..88f4bb7b2fcb5550c762d1ca41a5c9ba7cc76c54 100644 --- a/playbooks/automount/automount-map-present.yaml +++ b/playbooks/automount/automount-map-present.yaml @@ -1,7 +1,8 @@ --- - name: Automount map present example hosts: ipaserver - become: true + become: no + tasks: - name: ensure map TestMap is present ipaautomountmap: @@ -9,4 +10,3 @@ name: TestMap location: TestLocation desc: "this is a test map" - diff --git a/plugins/modules/ipaautomountmap.py b/plugins/modules/ipaautomountmap.py index 654986ccb0275ad1bede3024ed8b0e0808b28ec1..72084396668be2b9ebe381c4973029846944e520 100644 --- a/plugins/modules/ipaautomountmap.py +++ b/plugins/modules/ipaautomountmap.py @@ -19,6 +19,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + ANSIBLE_METADATA = { "metadata_version": "1.0", "supported_by": "community", @@ -29,27 +33,27 @@ ANSIBLE_METADATA = { DOCUMENTATION = ''' --- module: ipaautomountmap -author: chris procter +author: Chris Procter short_description: Manage FreeIPA autommount map description: - Add, delete, and modify an IPA automount map options: ipaadmin_principal: - description: The admin principal + description: The admin principal. default: admin ipaadmin_password: - description: The admin password + description: The admin password. required: false automountlocation: description: automount location map is anchored to choices: ["location", "automountlocationcn"] required: True name: - description: automount map to be managed + description: automount map to be managed. choices: ["mapname", "map", "automountmapname"] required: True desc: - description: description of automount map + description: description of automount map. choices: ["description"] required: false state: @@ -78,84 +82,85 @@ EXAMPLES = ''' RETURN = ''' ''' -from ansible.module_utils.ansible_freeipa_module import FreeIPABaseModule +from ansible.module_utils.ansible_freeipa_module import ( + IPAAnsibleModule, compare_args_ipa +) -class AutomountMap(FreeIPABaseModule): +class AutomountMap(IPAAnsibleModule): - ipa_param_mapping = { - "automountmapname": "name", - } + def __init__(self, *args, **kwargs): + # pylint: disable=super-with-arguments + super(AutomountMap, self).__init__(*args, **kwargs) + self.commands = [] - def get_map(self, location, name): - response = dict() + def get_automountmap(self, location, name): try: - response = self.api_command("automountmap_show", - location, - {"automountmapname": name}) - except Exception: - pass - - return response.get("result", None) + response = self.ipa_command( + "automountmap_show", + location, + {"automountmapname": name, "all": True} + ) + except Exception: # pylint: disable=broad-except + return None + else: + return response["result"] def check_ipa_params(self): - - if self.ipa_params.state == "present": - if len(self.ipa_params.name) != 1: + invalid = [] + name = self.params_get("name") + state = self.params_get("state") + if state == "present": + if len(name) != 1: self.fail_json(msg="Exactly one name must be provided \ for state=present.") - else: - if len(self.ipa_params.name) == 0 : - self.fail_json(msg="At least one name must be provided \ - when state=absent.") + if state == "absent": + if len(name) == 0 : + self.fail_json(msg="Argument 'map_type' can not be used with " + "state 'absent'") + invalid = ["desc"] + + self.params_fail_used_invalid(invalid, state) + + def get_args(self, mapname, desc): # pylint: disable=no-self-use + _args = {} + if mapname: + _args["automountmapname"] = mapname + if desc: + _args["description"] = desc + return _args def define_ipa_commands(self): - args = self.get_ipa_command_args() - - if self.ipa_params.state == "present": - automountmap = self.get_map(self.ipa_params.location, - self.ipa_params.name[0]) - args['automountmapname'] = self.ipa_params.name[0] - if automountmap is None: - # does not exist and is wanted - self.add_ipa_command( - "automountmap_add", - name=self.ipa_params.location, - args=args - ) - else: - # exists and is wanted, check for changes - if self.ipa_params.desc != \ - automountmap.get('description', [None])[0]: - args['description'] = self.ipa_params.desc - self.add_ipa_command( - "automountmap_mod", - name=self.ipa_params.location, - args=args - ) - else: - # exists and is not wanted (i.e. self.ipa_params.state == "absent") - to_del = [x for x in self.ipa_params.name - if self.get_map(self.ipa_params.location, x) is not None] - - if len(to_del) > 0: - self.add_ipa_command( - "automountmap_del", - name=self.ipa_params.location, - args={"automountmapname": to_del} - ) + name = self.params_get("name") + state = self.params_get("state") + location = self.params_get("location") + desc = self.params_get("desc") + + for mapname in name: + automountmap = self.get_automountmap(location, mapname) + + if state == "present": + args = self.get_args(mapname, desc) + if automountmap is None: + self.commands.append([location, "automountmap_add", args]) + else: + if not compare_args_ipa(self, args, automountmap): + self.commands.append( + [location, "automountmap_mod", args] + ) + + if state == "absent": + if automountmap is not None: + self.commands.append([ + location, + "automountmap_del", + {"automountmapname": [mapname]} + ]) def main(): ipa_module = AutomountMap( argument_spec=dict( - ipaadmin_principal=dict(type="str", - default="admin" - ), - ipaadmin_password=dict(type="str", - required=False, - no_log=True - ), state=dict(type='str', default='present', choices=['present', 'absent'] @@ -177,7 +182,13 @@ def main(): ), ), ) - ipa_module.ipa_run() + changed = False + ipaapi_context = ipa_module.params_get("ipaapi_context") + with ipa_module.ipa_connect(context=ipaapi_context): + ipa_module.check_ipa_params() + ipa_module.define_ipa_commands() + changed = ipa_module.execute_ipa_commands(ipa_module.commands) + ipa_module.exit_json(changed=changed) if __name__ == "__main__": diff --git a/tests/automount/test_automountmap.yml b/tests/automount/test_automountmap.yml index 5c0b379cc23d28010d82fd37ac10f8913891106b..cbf5db406f9f8b468e7702b85be20df4f0c6c143 100644 --- a/tests/automount/test_automountmap.yml +++ b/tests/automount/test_automountmap.yml @@ -1,135 +1,147 @@ --- - name: Test automountmap hosts: ipaserver - become: true - gather_facts: false + become: no + gather_facts: no tasks: - - name: ensure location TestLocation is absent - ipaautomountlocation: - ipaadmin_password: SomeADMINpassword - name: TestLocation - state: absent - - - name: ensure map TestMap is absent + # setup environment + - name: ensure test maps are absent ipaautomountmap: ipaadmin_password: SomeADMINpassword - name: TestMap + name: + - TestMap01 + - TestMap02 location: TestLocation state: absent - - name: ensure location TestLocation is present + - name: ensure location TestLocation is absent ipaautomountlocation: ipaadmin_password: SomeADMINpassword name: TestLocation - state: present - - - name: ensure map TestMap is present - ipaautomountmap: - ipaadmin_password: SomeADMINpassword - name: TestMap - location: TestLocation - desc: "this is a test map that should be deleted by the test" - register: result - failed_when: result.failed or not result.changed - - - name: ensure map TestMap is present again - ipaautomountmap: - ipaadmin_password: SomeADMINpassword - name: TestMap - location: TestLocation - register: result - failed_when: result.failed or result.changed - - - name: ensure map TestMap has a different description - ipaautomountmap: - ipaadmin_password: SomeADMINpassword - name: TestMap - location: TestLocation - desc: "this is a changed description that should be deleted by the test" - register: result - failed_when: result.failed or not result.changed - - - name: ensure map TestMap has a different description - ipaautomountmap: - ipaadmin_password: SomeADMINpassword - name: TestMap - location: TestLocation - desc: "this is a changed description that should be deleted by the test" - register: result - failed_when: result.failed or result.changed - - - name: ensure map TestMap is removed - ipaautomountmap: - ipaadmin_password: SomeADMINpassword - name: TestMap - location: TestLocation state: absent - register: result - failed_when: result.failed or not result.changed - - name: ensure map TestMap has been removed + - name: ensure map TestMap is absent ipaautomountmap: ipaadmin_password: SomeADMINpassword name: TestMap location: TestLocation state: absent - register: result - failed_when: result.failed or result.changed - - - name: ensure map TestMap01 is present - ipaautomountmap: - ipaadmin_password: SomeADMINpassword - name: TestMap01 - location: TestLocation - desc: "this is a changed description that should be deleted by the test" - register: result - failed_when: result.failed or not result.changed - - - name: ensure map TestMap02 is present - ipaautomountmap: - ipaadmin_password: SomeADMINpassword - name: TestMap02 - location: TestLocation - desc: "this is a changed description that should be deleted by the test" - register: result - failed_when: result.failed or not result.changed - - - name: ensure TestMap01 and TestMap02 are both absent - ipaautomountmap: - ipaadmin_password: SomeADMINpassword - name: - - TestMap01 - - TestMap02 - location: TestLocation - state: absent - register: result - failed_when: result.failed or not result.changed - - - name: ensure TestMap01 and TestMap02 are both absent again - ipaautomountmap: - ipaadmin_password: SomeADMINpassword - name: - - TestMap01 - - TestMap02 - location: TestLocation - state: absent - register: result - failed_when: result.failed or result.changed - - name: ensure location TestLocation is absent - ipaautomountlocation: - ipaadmin_password: SomeADMINpassword - name: TestLocation - state: absent - register: result - failed_when: result.failed or not result.changed - - - name: ensure location TestLocation is absent again + - name: ensure location TestLocation is present ipaautomountlocation: ipaadmin_password: SomeADMINpassword name: TestLocation - state: absent - register: result - failed_when: result.failed or result.changed + state: present + # TESTS + - block: + - name: ensure map TestMap is present + ipaautomountmap: + ipaadmin_password: SomeADMINpassword + name: TestMap + location: TestLocation + desc: "this is a test map that should be deleted by the test" + register: result + failed_when: result.failed or not result.changed + + - name: ensure map TestMap is present again + ipaautomountmap: + ipaadmin_password: SomeADMINpassword + name: TestMap + location: TestLocation + register: result + failed_when: result.failed or result.changed + + - name: ensure map TestMap has a different description + ipaautomountmap: + ipaadmin_password: SomeADMINpassword + name: TestMap + location: TestLocation + desc: "this is a changed description that should be deleted by the test" + register: result + failed_when: result.failed or not result.changed + + - name: ensure map TestMap has a different description, again + ipaautomountmap: + ipaadmin_password: SomeADMINpassword + name: TestMap + location: TestLocation + desc: "this is a changed description that should be deleted by the test" + register: result + failed_when: result.failed or result.changed + + - name: ensure map TestMap is removed + ipaautomountmap: + ipaadmin_password: SomeADMINpassword + name: TestMap + location: TestLocation + state: absent + register: result + failed_when: result.failed or not result.changed + + - name: ensure map TestMap has been removed + ipaautomountmap: + ipaadmin_password: SomeADMINpassword + name: TestMap + location: TestLocation + state: absent + register: result + failed_when: result.failed or result.changed + + - name: ensure map TestMap01 is present + ipaautomountmap: + ipaadmin_password: SomeADMINpassword + name: TestMap01 + location: TestLocation + desc: "this is a changed description that should be deleted by the test" + register: result + failed_when: result.failed or not result.changed + + - name: ensure map TestMap02 is present + ipaautomountmap: + ipaadmin_password: SomeADMINpassword + name: TestMap02 + location: TestLocation + desc: "this is a changed description that should be deleted by the test" + register: result + failed_when: result.failed or not result.changed + + - name: ensure TestMap01 and TestMap02 are both absent + ipaautomountmap: + ipaadmin_password: SomeADMINpassword + name: + - TestMap01 + - TestMap02 + location: TestLocation + state: absent + register: result + failed_when: result.failed or not result.changed + + - name: ensure TestMap01 and TestMap02 are both absent again + ipaautomountmap: + ipaadmin_password: SomeADMINpassword + name: + - TestMap01 + - TestMap02 + location: TestLocation + state: absent + register: result + failed_when: result.failed or result.changed + + # CLEAN UP + always: + - name: ensure test maps are absent + ipaautomountmap: + ipaadmin_password: SomeADMINpassword + name: + - TestMap01 + - TestMap02 + location: TestLocation + state: absent + + - name: ensure location TestLocation is absent + ipaautomountlocation: + ipaadmin_password: SomeADMINpassword + name: TestLocation + state: absent