mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-05-06 21:33:14 +00:00
Merge pull request #497 from chr15p/ipaautomountmap
add module to create and manage automount maps
This commit is contained in:
96
README-automountmap.md
Normal file
96
README-automountmap.md
Normal file
@@ -0,0 +1,96 @@
|
||||
Automountmap module
|
||||
=====================
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
* Automount map management
|
||||
|
||||
Supported FreeIPA Versions
|
||||
--------------------------
|
||||
|
||||
FreeIPA versions 4.4.0 and up are supported by the ipaautomountmap module.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
**Controller**
|
||||
* Ansible version: 2.8+
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Example inventory file
|
||||
|
||||
```ini
|
||||
[ipaserver]
|
||||
ipaserver.test.local
|
||||
```
|
||||
|
||||
Example playbook to ensure presence of an automount map:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to add an automount map
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: ensure map named auto.DMZ in location DMZ is created
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: auto.DMZ
|
||||
location: DMZ
|
||||
desc: "this is a map for servers in the DMZ"
|
||||
```
|
||||
|
||||
Example playbook to ensure auto.DMZi is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to remove an automount map
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: ensure map auto.DMZ has been removed
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: auto.DMZ
|
||||
location: DMZ
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Variables
|
||||
=========
|
||||
|
||||
Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
`name` \| `mapname` \| `map` \| `automountmapname` | Name of the map to manage | yes
|
||||
`location` \| `automountlocation` \| `automountlocationcn` | Location name. | yes
|
||||
`desc` \| `description` | Description of the map | yes
|
||||
`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
|
||||
=======
|
||||
|
||||
Chris Procter
|
||||
12
playbooks/automount/automount-map-absent.yaml
Normal file
12
playbooks/automount/automount-map-absent.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Automount map absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: ensure map TestMap is absent
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestMap
|
||||
location: TestLocation
|
||||
state: absent
|
||||
12
playbooks/automount/automount-map-present.yaml
Normal file
12
playbooks/automount/automount-map-present.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Automount map present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: ensure map TestMap is present
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestMap
|
||||
location: TestLocation
|
||||
desc: "this is a test map"
|
||||
195
plugins/modules/ipaautomountmap.py
Normal file
195
plugins/modules/ipaautomountmap.py
Normal file
@@ -0,0 +1,195 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Authors:
|
||||
# Chris Procter <cprocter@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2021 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# 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",
|
||||
"status": ["preview"],
|
||||
}
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: ipaautomountmap
|
||||
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.
|
||||
default: admin
|
||||
ipaadmin_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.
|
||||
choices: ["mapname", "map", "automountmapname"]
|
||||
required: True
|
||||
desc:
|
||||
description: description of automount map.
|
||||
choices: ["description"]
|
||||
required: false
|
||||
state:
|
||||
description: State to ensure
|
||||
required: false
|
||||
default: present
|
||||
choices: ["present", "absent"]
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: ensure map named auto.DMZ in location DMZ is present
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: auto.DMZ
|
||||
location: DMZ
|
||||
desc: "this is a map for servers in the DMZ"
|
||||
|
||||
- name: remove a map named auto.DMZ in location DMZ if it exists
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: auto.DMZ
|
||||
location: DMZ
|
||||
state: absent
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
'''
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import (
|
||||
IPAAnsibleModule, compare_args_ipa
|
||||
)
|
||||
|
||||
|
||||
class AutomountMap(IPAAnsibleModule):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# pylint: disable=super-with-arguments
|
||||
super(AutomountMap, self).__init__(*args, **kwargs)
|
||||
self.commands = []
|
||||
|
||||
def get_automountmap(self, location, name):
|
||||
try:
|
||||
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):
|
||||
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.")
|
||||
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):
|
||||
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(
|
||||
state=dict(type='str',
|
||||
default='present',
|
||||
choices=['present', 'absent']
|
||||
),
|
||||
location=dict(type="str",
|
||||
aliases=["automountlocation", "automountlocationcn"],
|
||||
default=None,
|
||||
required=True
|
||||
),
|
||||
name=dict(type="list",
|
||||
aliases=["mapname", "map", "automountmapname"],
|
||||
default=None,
|
||||
required=True
|
||||
),
|
||||
desc=dict(type="str",
|
||||
aliases=["description"],
|
||||
required=False,
|
||||
default=None
|
||||
),
|
||||
),
|
||||
)
|
||||
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__":
|
||||
main()
|
||||
147
tests/automount/test_automountmap.yml
Normal file
147
tests/automount/test_automountmap.yml
Normal file
@@ -0,0 +1,147 @@
|
||||
---
|
||||
- name: Test automountmap
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
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
|
||||
ipaautomountlocation:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestLocation
|
||||
state: absent
|
||||
|
||||
- name: ensure map TestMap is absent
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestMap
|
||||
location: TestLocation
|
||||
state: absent
|
||||
|
||||
- name: ensure location TestLocation is present
|
||||
ipaautomountlocation:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestLocation
|
||||
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
|
||||
Reference in New Issue
Block a user