new module: aix_devices, manage AIX devices (#32290)

* new module: aix_devices AIX devices management

This module discovery, defines, removes and modifies attributes of AIX
devices.

* Added hide attributes that can be used for aliases

Added hid attributes that can be used to manage aliases on en
interfaces.

* After tests: docs and attributes tests

Fixed attributes tests and doc explaining how to use
attributes with comma.

* Fixed grammar on module description

Fixed grammar on module description

* Included test/legacy/aix_devices.yml for tests

As discussed on IRC ansible-devel channes, was include the
legacy tests for further manual tests.

* Added 'attributes' as dictionary

Added 'attributes' as a dictionary makes the configuration
simple.

* Changed the added version from 2.5 to 2.7

Fixed the shippable error from 2.5 to 2.7

```
2018-06-01 08:28:02 ERROR: Found 1 validate-modules issue(s) which
need to be resolved:
2018-06-01 08:28:02 ERROR:
lib/ansible/modules/system/aix_devices.py:0:0: E307 version_added
should be 2.7. Currently 2.5 (75%)
```

* Various changes

* Revert

* Changed the tests to integration dir

* Implement 'available' state

'available' state is the AIX state used, that works same as 'present'

* The states were changed to AIX expressions and kept Ansible states.

Makes sense keep the states names to AIX and use the Ansible 'standards'
states.

'available' is 'present'
'removed' is 'absent'

It makes easy to AIX sysadmins use the module, however it keep the
Ansible meanings.

* Fixed choices according with latest patchset (commit)

* A few doc changes

Nothing material
pull/51682/head
Kairo Araujo 5 years ago committed by Dag Wieers
parent de67b8e5ee
commit a355686987

@ -0,0 +1,377 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, 2018 Kairo Araujo <kairo@kairo.eti.br>
# 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 = r'''
---
author:
- Kairo Araujo (@kairoaraujo)
module: aix_devices
short_description: Manages AIX devices
description:
- This module discovers, defines, removes and modifies attributes of AIX devices.
version_added: '2.8'
options:
attributes:
description:
- A list of device attributes.
type: list
device:
description:
- The name of the device.
- C(all) is valid to rescan C(available) all devices (AIX cfgmgr command).
type: str
required: true
force:
description:
- Forces action.
type: bool
default: no
recursive:
description:
- Removes or defines a device and children devices.
type: bool
default: no
state:
description:
- Controls the device state.
- C(available) (alias C(present)) rescan a specific device or all devices (when C(device) is not specified).
- C(removed) (alias C(absent) removes a device.
- C(defined) changes device to Defined state.
type: str
choices: [ available, defined, removed ]
default: available
'''
EXAMPLES = r'''
- name: Scan new devices
aix_devices:
device: all
state: available
- name: Scan new virtual devices (vio0)
aix_devices:
device: vio0
state: available
- name: Removing IP alias to en0
aix_devices:
device: en0
attributes:
delalias4: 10.0.0.100,255.255.255.0
- name: Removes ent2
aix_devices:
device: ent2
state: removed
- name: Put device en2 in Defined
aix_devices:
device: en2
state: defined
- name: Removes ent4 (inexistent).
aix_devices:
device: ent4
state: removed
- name: Put device en4 in Defined (inexistent)
aix_devices:
device: en4
state: defined
- name: Put vscsi1 and children devices in Defined state.
aix_devices:
device: vscsi1
recursive: yes
state: defined
- name: Removes vscsi1 and children devices.
aix_devices:
device: vscsi1
recursive: yes
state: removed
- name: Changes en1 mtu to 9000 and disables arp.
aix_devices:
device: en1
attributes:
mtu: 900
arp: off
state: available
- name: Configure IP, netmask and set en1 up.
aix_devices:
device: en1
attributes:
netaddr: 192.168.0.100
netmask: 255.255.255.0
state: up
state: available
- name: Adding IP alias to en0
aix_devices:
device: en0
attributes:
alias4: 10.0.0.100,255.255.255.0
state: available
'''
RETURN = r''' # '''
from ansible.module_utils.basic import AnsibleModule
def _check_device(module, device):
"""
Check if device already exists and the state.
Args:
module: Ansible module.
device: device to be checked.
Returns: bool, device state
"""
lsdev_cmd = module.get_bin_path('lsdev', True)
rc, lsdev_out, err = module.run_command(["%s" % lsdev_cmd, '-C', '-l', "%s" % device])
if rc != 0:
module.fail_json(msg="Failed to run lsdev", rc=rc, err=err)
if lsdev_out:
device_state = lsdev_out.split()[1]
return True, device_state
device_state = None
return False, device_state
def _check_device_attr(module, device, attr):
"""
Args:
module: Ansible module.
device: device to check attributes.
attr: attribute to be checked.
Returns:
"""
lsattr_cmd = module.get_bin_path('lsattr', True)
rc, lsattr_out, err = module.run_command(["%s" % lsattr_cmd, '-El', "%s" % device, '-a', "%s" % attr])
hidden_attrs = ['delalias4', 'delalias6']
if rc == 255:
if attr in hidden_attrs:
current_param = ''
else:
current_param = None
return current_param
elif rc != 0:
module.fail_json(msg="Failed to run lsattr: %s" % err, rc=rc, err=err)
current_param = lsattr_out.split()[1]
return current_param
def discover_device(module, device):
""" Discover AIX devices."""
cfgmgr_cmd = module.get_bin_path('cfgmgr', True)
if device is not None:
device = "-l %s" % device
else:
device = ''
changed = True
msg = ''
if not module.check_mode:
rc, cfgmgr_out, err = module.run_command(["%s" % cfgmgr_cmd, "%s" % device])
changed = True
msg = cfgmgr_out
return changed, msg
def change_device_attr(module, attributes, device, force):
""" Change AIX device attribute. """
attr_changed = []
attr_not_changed = []
attr_invalid = []
chdev_cmd = module.get_bin_path('chdev', True)
for attr in list(attributes.keys()):
new_param = attributes[attr]
current_param = _check_device_attr(module, device, attr)
if current_param is None:
attr_invalid.append(attr)
elif current_param != new_param:
if force:
cmd = ["%s" % chdev_cmd, '-l', "%s" % device, '-a', "%s=%s" % (attr, attributes[attr]), "%s" % force]
else:
cmd = ["%s" % chdev_cmd, '-l', "%s" % device, '-a', "%s=%s" % (attr, attributes[attr])]
if not module.check_mode:
rc, chdev_out, err = module.run_command(cmd)
if rc != 0:
module.exit_json(msg="Failed to run chdev.", rc=rc, err=err)
attr_changed.append(attributes[attr])
else:
attr_not_changed.append(attributes[attr])
if len(attr_changed) > 0:
changed = True
attr_changed_msg = "Attributes changed: %s. " % ','.join(attr_changed)
else:
changed = False
attr_changed_msg = ''
if len(attr_not_changed) > 0:
attr_not_changed_msg = "Attributes already set: %s. " % ','.join(attr_not_changed)
else:
attr_not_changed_msg = ''
if len(attr_invalid) > 0:
attr_invalid_msg = "Invalid attributes: %s " % ', '.join(attr_invalid)
else:
attr_invalid_msg = ''
msg = "%s%s%s" % (attr_changed_msg, attr_not_changed_msg, attr_invalid_msg)
return changed, msg
def remove_device(module, device, force, recursive, state):
""" Puts device in defined state or removes device. """
state_opt = {
'removed': '-d',
'absent': '-d',
'defined': ''
}
recursive_opt = {
True: '-R',
False: ''
}
recursive = recursive_opt[recursive]
state = state_opt[state]
changed = True
msg = ''
rmdev_cmd = module.get_bin_path('rmdev', True)
if not module.check_mode:
if state:
rc, rmdev_out, err = module.run_command(["%s" % rmdev_cmd, "-l", "%s" % device, "%s" % recursive, "%s" % force])
else:
rc, rmdev_out, err = module.run_command(["%s" % rmdev_cmd, "-l", "%s" % device, "%s" % recursive])
if rc != 0:
module.fail_json(msg="Failed to run rmdev", rc=rc, err=err)
msg = rmdev_out
return changed, msg
def main():
module = AnsibleModule(
argument_spec=dict(
attributes=dict(type='dict'),
device=dict(type='str'),
force=dict(type='bool', default=False),
recursive=dict(type='bool', default=False),
state=dict(type='str', default='available', choices=['available', 'defined', 'removed']),
),
supports_check_mode=True,
)
force_opt = {
True: '-f',
False: '',
}
attributes = module.params['attributes']
device = module.params['device']
force = force_opt[module.params['force']]
recursive = module.params['recursive']
state = module.params['state']
result = dict(
changed=False,
msg='',
)
if state == 'available' or state == 'present':
if attributes:
# change attributes on device
device_status, device_state = _check_device(module, device)
if device_status:
result['changed'], result['msg'] = change_device_attr(module, attributes, device, force)
else:
result['msg'] = "Device %s does not exist." % device
else:
# discovery devices (cfgmgr)
if device and device != 'all':
device_status, device_state = _check_device(module, device)
if device_status:
# run cfgmgr on specific device
result['changed'], result['msg'] = discover_device(module, device)
else:
result['msg'] = "Device %s does not exist." % device
else:
result['changed'], result['msg'] = discover_device(module, device)
elif state == 'removed' or state == 'absent' or state == 'defined':
if not device:
result['msg'] = "device is required to removed or defined state."
else:
# Remove device
check_device, device_state = _check_device(module, device)
if check_device:
if state == 'defined' and device_state == 'Defined':
result['changed'] = False
result['msg'] = 'Device %s already in Defined' % device
else:
result['changed'], result['msg'] = remove_device(module, device, force, recursive, state)
else:
result['msg'] = "Device %s does not exist." % device
else:
result['msg'] = "Unexpected state %s." % state
module.fail_json(**result)
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -0,0 +1,2 @@
# No AIX LPAR available
unsupported

@ -0,0 +1,77 @@
---
- name: AIX devices tests
hosts: localhost
connection: local
tasks:
- name: Scan new devices.
aix_devices:
device: all
state: present
- name: Scan new virtual devices (vio0).
aix_devices:
device: vio0
state: present
- name: Removing IP alias to en0
aix_devices:
device: en0
attributes:
delalias4: 10.0.0.100,255.255.255.0
- name: Removes ent2.
aix_devices:
device: ent2
state: absent
- name: Put device en2 in Defined
aix_devices:
device: en2
state: defined
- name: Removes ent4 (inexistent).
aix_devices:
device: ent4
state: absent
- name: Put device en4 in Defined (inexistent)
aix_devices:
device: en4
state: defined
- name: Put vscsi1 and children devices in Defined state.
aix_devices:
device: vscsi1
recursive: yes
state: defined
- name: Removes vscsi1 and children devices.
aix_devices:
device: vscsi1
recursive: yes
state: absent
- name: Changes en1 mtu to 9000 and disables arp.
aix_devices:
device: en1
attributes:
mtu: 900
arp: off
state: present
- name: Configure IP, netmask and set en1 up.
aix_devices:
device: en1
attributes:
netaddr: 192.168.0.100
netmask: 255.255.255.0
state: up
state: present
- name: Adding IP alias to en0
aix_devices:
device: en0
attributes:
alias4: 10.0.0.100,255.255.255.0
state: present
Loading…
Cancel
Save