Adapt automount to IPAAnsibleModule and add code review modifications.

This commit is contained in:
Rafael Guterres Jeffman
2022-01-05 15:23:38 -03:00
parent 0d47429000
commit e1e8ff5916
5 changed files with 203 additions and 179 deletions

View File

@@ -4,7 +4,7 @@ Automountmap module
Description 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. 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 ipaserver.test.local
``` ```
Example playbook to ensure presence of an automount map: Example playbook to ensure presence of an automount map:
```yaml ```yaml
--- ---
- name: Playbook to add an automount map - name: Playbook to add an automount map
hosts: ipaserver hosts: ipaserver
become: true become: no
tasks: tasks:
- name: ensure map named auto.DMZ in location DMZ is created - 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" 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 ```yaml
--- ---
- name: Playbook to remove an automount map - name: Playbook to remove an automount map
hosts: ipaserver hosts: ipaserver
become: true become: no
tasks: tasks:
- name: ensure map auto.DMZ has been removed - name: ensure map auto.DMZ has been removed
ipaautomountmap: ipaautomountmap:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
name: auto.DMZ name: auto.DMZ
location: DMX location: DMZ
state: absent state: absent
``` ```
@@ -76,9 +75,6 @@ Example playbook to ensure auto.DMZi does not exist
Variables Variables
========= =========
ipaautomountmap
-------
Variable | Description | Required Variable | Description | Required
-------- | ----------- | -------- -------- | ----------- | --------
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no `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 `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 Authors
======= =======

View File

@@ -1,7 +1,8 @@
--- ---
- name: Automount map absent example - name: Automount map absent example
hosts: ipaserver hosts: ipaserver
become: true become: no
tasks: tasks:
- name: ensure map TestMap is absent - name: ensure map TestMap is absent
ipaautomountmap: ipaautomountmap:
@@ -9,4 +10,3 @@
name: TestMap name: TestMap
location: TestLocation location: TestLocation
state: absent state: absent

View File

@@ -1,7 +1,8 @@
--- ---
- name: Automount map present example - name: Automount map present example
hosts: ipaserver hosts: ipaserver
become: true become: no
tasks: tasks:
- name: ensure map TestMap is present - name: ensure map TestMap is present
ipaautomountmap: ipaautomountmap:
@@ -9,4 +10,3 @@
name: TestMap name: TestMap
location: TestLocation location: TestLocation
desc: "this is a test map" desc: "this is a test map"

View File

@@ -19,6 +19,10 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = { ANSIBLE_METADATA = {
"metadata_version": "1.0", "metadata_version": "1.0",
"supported_by": "community", "supported_by": "community",
@@ -29,27 +33,27 @@ ANSIBLE_METADATA = {
DOCUMENTATION = ''' DOCUMENTATION = '''
--- ---
module: ipaautomountmap module: ipaautomountmap
author: chris procter author: Chris Procter
short_description: Manage FreeIPA autommount map short_description: Manage FreeIPA autommount map
description: description:
- Add, delete, and modify an IPA automount map - Add, delete, and modify an IPA automount map
options: options:
ipaadmin_principal: ipaadmin_principal:
description: The admin principal description: The admin principal.
default: admin default: admin
ipaadmin_password: ipaadmin_password:
description: The admin password description: The admin password.
required: false required: false
automountlocation: automountlocation:
description: automount location map is anchored to description: automount location map is anchored to
choices: ["location", "automountlocationcn"] choices: ["location", "automountlocationcn"]
required: True required: True
name: name:
description: automount map to be managed description: automount map to be managed.
choices: ["mapname", "map", "automountmapname"] choices: ["mapname", "map", "automountmapname"]
required: True required: True
desc: desc:
description: description of automount map description: description of automount map.
choices: ["description"] choices: ["description"]
required: false required: false
state: state:
@@ -78,84 +82,85 @@ EXAMPLES = '''
RETURN = ''' 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 = { def __init__(self, *args, **kwargs):
"automountmapname": "name", # pylint: disable=super-with-arguments
} super(AutomountMap, self).__init__(*args, **kwargs)
self.commands = []
def get_map(self, location, name): def get_automountmap(self, location, name):
response = dict()
try: try:
response = self.api_command("automountmap_show", response = self.ipa_command(
location, "automountmap_show",
{"automountmapname": name}) location,
except Exception: {"automountmapname": name, "all": True}
pass )
except Exception: # pylint: disable=broad-except
return response.get("result", None) return None
else:
return response["result"]
def check_ipa_params(self): def check_ipa_params(self):
invalid = []
if self.ipa_params.state == "present": name = self.params_get("name")
if len(self.ipa_params.name) != 1: state = self.params_get("state")
if state == "present":
if len(name) != 1:
self.fail_json(msg="Exactly one name must be provided \ self.fail_json(msg="Exactly one name must be provided \
for state=present.") for state=present.")
else: if state == "absent":
if len(self.ipa_params.name) == 0 : if len(name) == 0 :
self.fail_json(msg="At least one name must be provided \ self.fail_json(msg="Argument 'map_type' can not be used with "
when state=absent.") "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): def define_ipa_commands(self):
args = self.get_ipa_command_args() name = self.params_get("name")
state = self.params_get("state")
location = self.params_get("location")
desc = self.params_get("desc")
if self.ipa_params.state == "present": for mapname in name:
automountmap = self.get_map(self.ipa_params.location, automountmap = self.get_automountmap(location, mapname)
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: if state == "present":
self.add_ipa_command( args = self.get_args(mapname, desc)
"automountmap_del", if automountmap is None:
name=self.ipa_params.location, self.commands.append([location, "automountmap_add", args])
args={"automountmapname": to_del} 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(): def main():
ipa_module = AutomountMap( ipa_module = AutomountMap(
argument_spec=dict( argument_spec=dict(
ipaadmin_principal=dict(type="str",
default="admin"
),
ipaadmin_password=dict(type="str",
required=False,
no_log=True
),
state=dict(type='str', state=dict(type='str',
default='present', default='present',
choices=['present', 'absent'] 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__": if __name__ == "__main__":

View File

@@ -1,10 +1,20 @@
--- ---
- name: Test automountmap - name: Test automountmap
hosts: ipaserver hosts: ipaserver
become: true become: no
gather_facts: false gather_facts: no
tasks: tasks:
# setup environment
- name: ensure test maps are absent
ipaautomountmap:
ipaadmin_password: SomeADMINpassword
name:
- TestMap01
- TestMap02
location: TestLocation
state: absent
- name: ensure location TestLocation is absent - name: ensure location TestLocation is absent
ipaautomountlocation: ipaautomountlocation:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
@@ -24,112 +34,114 @@
name: TestLocation name: TestLocation
state: present state: present
- name: ensure map TestMap is present # TESTS
ipaautomountmap: - block:
ipaadmin_password: SomeADMINpassword - name: ensure map TestMap is present
name: TestMap ipaautomountmap:
location: TestLocation ipaadmin_password: SomeADMINpassword
desc: "this is a test map that should be deleted by the test" name: TestMap
register: result location: TestLocation
failed_when: result.failed or not result.changed 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 - name: ensure map TestMap is present again
ipaautomountmap: ipaautomountmap:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
name: TestMap name: TestMap
location: TestLocation location: TestLocation
register: result register: result
failed_when: result.failed or result.changed failed_when: result.failed or result.changed
- name: ensure map TestMap has a different description - name: ensure map TestMap has a different description
ipaautomountmap: ipaautomountmap:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
name: TestMap name: TestMap
location: TestLocation location: TestLocation
desc: "this is a changed description that should be deleted by the test" desc: "this is a changed description that should be deleted by the test"
register: result register: result
failed_when: result.failed or not result.changed failed_when: result.failed or not result.changed
- name: ensure map TestMap has a different description - name: ensure map TestMap has a different description, again
ipaautomountmap: ipaautomountmap:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
name: TestMap name: TestMap
location: TestLocation location: TestLocation
desc: "this is a changed description that should be deleted by the test" desc: "this is a changed description that should be deleted by the test"
register: result register: result
failed_when: result.failed or result.changed failed_when: result.failed or result.changed
- name: ensure map TestMap is removed - name: ensure map TestMap is removed
ipaautomountmap: ipaautomountmap:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
name: TestMap name: TestMap
location: TestLocation location: TestLocation
state: absent state: absent
register: result register: result
failed_when: result.failed or not result.changed failed_when: result.failed or not result.changed
- name: ensure map TestMap has been removed - name: ensure map TestMap has been removed
ipaautomountmap: ipaautomountmap:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
name: TestMap name: TestMap
location: TestLocation location: TestLocation
state: absent state: absent
register: result register: result
failed_when: result.failed or result.changed failed_when: result.failed or result.changed
- name: ensure map TestMap01 is present - name: ensure map TestMap01 is present
ipaautomountmap: ipaautomountmap:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
name: TestMap01 name: TestMap01
location: TestLocation location: TestLocation
desc: "this is a changed description that should be deleted by the test" desc: "this is a changed description that should be deleted by the test"
register: result register: result
failed_when: result.failed or not result.changed failed_when: result.failed or not result.changed
- name: ensure map TestMap02 is present - name: ensure map TestMap02 is present
ipaautomountmap: ipaautomountmap:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
name: TestMap02 name: TestMap02
location: TestLocation location: TestLocation
desc: "this is a changed description that should be deleted by the test" desc: "this is a changed description that should be deleted by the test"
register: result register: result
failed_when: result.failed or not result.changed failed_when: result.failed or not result.changed
- name: ensure TestMap01 and TestMap02 are both absent - name: ensure TestMap01 and TestMap02 are both absent
ipaautomountmap: ipaautomountmap:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
name: name:
- TestMap01 - TestMap01
- TestMap02 - TestMap02
location: TestLocation location: TestLocation
state: absent state: absent
register: result register: result
failed_when: result.failed or not result.changed failed_when: result.failed or not result.changed
- name: ensure TestMap01 and TestMap02 are both absent again - name: ensure TestMap01 and TestMap02 are both absent again
ipaautomountmap: ipaautomountmap:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
name: name:
- TestMap01 - TestMap01
- TestMap02 - TestMap02
location: TestLocation location: TestLocation
state: absent state: absent
register: result register: result
failed_when: result.failed or result.changed failed_when: result.failed or result.changed
- name: ensure location TestLocation is absent # CLEAN UP
ipaautomountlocation: always:
ipaadmin_password: SomeADMINpassword - name: ensure test maps are absent
name: TestLocation ipaautomountmap:
state: absent ipaadmin_password: SomeADMINpassword
register: result name:
failed_when: result.failed or not result.changed - TestMap01
- TestMap02
- name: ensure location TestLocation is absent again location: TestLocation
ipaautomountlocation: state: absent
ipaadmin_password: SomeADMINpassword
name: 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