1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Add ipa_pwpolicy module (#1147)

* Add ipa_pwpolicy module

Used for modifying FreeIPA password policies

Functions similarly to the existing IPA modules

* Add sample return value to ipa_pwpolicy module

* Add unit tests for the ipa_pwpolicy module

Also moves the `exit_json` call in the main module outside of the try
clause because it was stopping the tests from working

* Update version added for the ipa_pwpolicy module

* Add check_mode note for the ipa_pwpolicy module

* Add missing period in ipa_pwpolicy module doc

* Fix tense of the ipa_pwpolicy module description

* Reword ipa_pwpolicy documentation

Improve the wording of the ipa_pwpolicy documentation to make it more
clear

* Rename ipa_pwpolicy options to use shorter names
This commit is contained in:
adralioh 2021-01-06 16:17:07 +00:00 committed by GitHub
parent e7b16a96b9
commit 74fcb0335e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 869 additions and 0 deletions

View file

@ -0,0 +1,255 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2020, Ansible Project
# 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
DOCUMENTATION = r'''
---
module: ipa_pwpolicy
author: Adralioh (@adralioh)
short_description: Manage FreeIPA password policies
description:
- Add, modify, or delete a password policy using the IPA API.
version_added: 2.0.0
options:
group:
description:
- Name of the group that the policy applies to.
- If omitted, the global policy is used.
aliases: ["name"]
type: str
state:
description: State to ensure.
default: "present"
choices: ["absent", "present"]
type: str
maxpwdlife:
description: Maximum password lifetime (in days).
type: str
minpwdlife:
description: Minimum password lifetime (in hours).
type: str
historylength:
description:
- Number of previous passwords that are remembered.
- Users cannot reuse remembered passwords.
type: str
minclasses:
description: Minimum number of character classes.
type: str
minlength:
description: Minimum password length.
type: str
priority:
description:
- Priority of the policy.
- High number means lower priority.
- Required when C(cn) is not the global policy.
type: str
maxfailcount:
description: Maximum number of consecutive failures before lockout.
type: str
failinterval:
description: Period (in seconds) after which the number of failed login attempts is reset.
type: str
lockouttime:
description: Period (in seconds) for which users are locked out.
type: str
extends_documentation_fragment:
- community.general.ipa.documentation
notes:
- Supports C(check_mode).
'''
EXAMPLES = r'''
- name: Modify the global password policy
community.general.ipa_pwpolicy:
maxpwdlife: '90'
minpwdlife: '1'
historylength: '8'
minclasses: '3'
minlength: '16'
maxfailcount: '6'
failinterval: '60'
lockouttime: '600'
ipa_host: ipa.example.com
ipa_user: admin
ipa_pass: topsecret
- name: Ensure the password policy for the group admins is present
community.general.ipa_pwpolicy:
group: admins
state: present
maxpwdlife: '60'
minpwdlife: '24'
historylength: '16'
minclasses: '4'
priority: '10'
maxfailcount: '4'
failinterval: '600'
lockouttime: '1200'
ipa_host: ipa.example.com
ipa_user: admin
ipa_pass: topsecret
- name: Ensure that the group sysops does not have a unique password policy
community.general.ipa_pwpolicy:
group: sysops
state: absent
ipa_host: ipa.example.com
ipa_user: admin
ipa_pass: topsecret
'''
RETURN = r'''
pwpolicy:
description: Password policy as returned by IPA API.
returned: always
type: dict
sample:
cn: ['admins']
cospriority: ['10']
dn: 'cn=admins,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com'
krbmaxpwdlife: ['60']
krbminpwdlife: ['24']
krbpwdfailurecountinterval: ['600']
krbpwdhistorylength: ['16']
krbpwdlockoutduration: ['1200']
krbpwdmaxfailure: ['4']
krbpwdmindiffchars: ['4']
objectclass: ['top', 'nscontainer', 'krbpwdpolicy']
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.ipa import IPAClient, ipa_argument_spec
from ansible.module_utils._text import to_native
class PwPolicyIPAClient(IPAClient):
'''The global policy will be selected when `name` is `None`'''
def __init__(self, module, host, port, protocol):
super(PwPolicyIPAClient, self).__init__(module, host, port, protocol)
def pwpolicy_find(self, name):
if name is None:
# Manually set the cn to the global policy because pwpolicy_find will return a random
# different policy if cn is `None`
name = 'global_policy'
return self._post_json(method='pwpolicy_find', name=None, item={'all': True, 'cn': name})
def pwpolicy_add(self, name, item):
return self._post_json(method='pwpolicy_add', name=name, item=item)
def pwpolicy_mod(self, name, item):
return self._post_json(method='pwpolicy_mod', name=name, item=item)
def pwpolicy_del(self, name):
return self._post_json(method='pwpolicy_del', name=name)
def get_pwpolicy_dict(maxpwdlife=None, minpwdlife=None, historylength=None, minclasses=None,
minlength=None, priority=None, maxfailcount=None, failinterval=None,
lockouttime=None):
pwpolicy = {}
if maxpwdlife is not None:
pwpolicy['krbmaxpwdlife'] = maxpwdlife
if minpwdlife is not None:
pwpolicy['krbminpwdlife'] = minpwdlife
if historylength is not None:
pwpolicy['krbpwdhistorylength'] = historylength
if minclasses is not None:
pwpolicy['krbpwdmindiffchars'] = minclasses
if minlength is not None:
pwpolicy['krbpwdminlength'] = minlength
if priority is not None:
pwpolicy['cospriority'] = priority
if maxfailcount is not None:
pwpolicy['krbpwdmaxfailure'] = maxfailcount
if failinterval is not None:
pwpolicy['krbpwdfailurecountinterval'] = failinterval
if lockouttime is not None:
pwpolicy['krbpwdlockoutduration'] = lockouttime
return pwpolicy
def get_pwpolicy_diff(client, ipa_pwpolicy, module_pwpolicy):
return client.get_diff(ipa_data=ipa_pwpolicy, module_data=module_pwpolicy)
def ensure(module, client):
state = module.params['state']
name = module.params['group']
module_pwpolicy = get_pwpolicy_dict(maxpwdlife=module.params.get('maxpwdlife'),
minpwdlife=module.params.get('minpwdlife'),
historylength=module.params.get('historylength'),
minclasses=module.params.get('minclasses'),
minlength=module.params.get('minlength'),
priority=module.params.get('priority'),
maxfailcount=module.params.get('maxfailcount'),
failinterval=module.params.get('failinterval'),
lockouttime=module.params.get('lockouttime'))
ipa_pwpolicy = client.pwpolicy_find(name=name)
changed = False
if state == 'present':
if not ipa_pwpolicy:
changed = True
if not module.check_mode:
ipa_pwpolicy = client.pwpolicy_add(name=name, item=module_pwpolicy)
else:
diff = get_pwpolicy_diff(client, ipa_pwpolicy, module_pwpolicy)
if len(diff) > 0:
changed = True
if not module.check_mode:
ipa_pwpolicy = client.pwpolicy_mod(name=name, item=module_pwpolicy)
else:
if ipa_pwpolicy:
changed = True
if not module.check_mode:
client.pwpolicy_del(name=name)
return changed, ipa_pwpolicy
def main():
argument_spec = ipa_argument_spec()
argument_spec.update(group=dict(type='str', aliases=['name']),
state=dict(type='str', default='present', choices=['present', 'absent']),
maxpwdlife=dict(type='str'),
minpwdlife=dict(type='str'),
historylength=dict(type='str'),
minclasses=dict(type='str'),
minlength=dict(type='str'),
priority=dict(type='str'),
maxfailcount=dict(type='str'),
failinterval=dict(type='str'),
lockouttime=dict(type='str'))
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
client = PwPolicyIPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
try:
client.login(username=module.params['ipa_user'],
password=module.params['ipa_pass'])
changed, pwpolicy = ensure(module, client)
except Exception as e:
module.fail_json(msg=to_native(e), exception=traceback.format_exc())
module.exit_json(changed=changed, pwpolicy=pwpolicy)
if __name__ == '__main__':
main()

View file

@ -0,0 +1 @@
./identity/ipa/ipa_pwpolicy.py

View file

@ -0,0 +1,613 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2020, Ansible Project
# 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
from contextlib import contextmanager
from ansible_collections.community.general.tests.unit.compat import unittest
from ansible_collections.community.general.tests.unit.compat.mock import call, patch
from ansible_collections.community.general.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
from ansible_collections.community.general.plugins.modules.identity.ipa import ipa_pwpolicy
@contextmanager
def patch_ipa(**kwargs):
"""Mock context manager for patching the methods in PwPolicyIPAClient that contact the IPA server
Patches the `login` and `_post_json` methods
Keyword arguments are passed to the mock object that patches `_post_json`
No arguments are passed to the mock object that patches `login` because no tests require it
Example::
with patch_ipa(return_value={}) as (mock_login, mock_post):
...
"""
obj = ipa_pwpolicy.PwPolicyIPAClient
with patch.object(obj, 'login') as mock_login:
with patch.object(obj, '_post_json', **kwargs) as mock_post:
yield mock_login, mock_post
class TestIPAPwPolicy(ModuleTestCase):
def setUp(self):
super(TestIPAPwPolicy, self).setUp()
self.module = ipa_pwpolicy
def _test_base(self, module_args, return_value, mock_calls, changed):
"""Base function that's called by all the other test functions
module_args (dict):
Arguments passed to the module
return_value (dict):
Mocked return value of PwPolicyIPAClient.pwpolicy_find, as returned by the IPA API.
This should be set to the current state. It will be changed to the desired state using the above arguments.
(Technically, this is the return value of _post_json, but it's only checked by pwpolicy_find).
An empty dict means that the policy doesn't exist.
mock_calls (list/tuple of dicts):
List of calls made to PwPolicyIPAClient._post_json, in order.
_post_json is called by all of the pwpolicy_* methods of the class.
Pass an empty list if no calls are expected.
changed (bool):
Whether or not the module is supposed to be marked as changed
"""
set_module_args(module_args)
# Run the module
with patch_ipa(return_value=return_value) as (mock_login, mock_post):
with self.assertRaises(AnsibleExitJson) as exec_info:
self.module.main()
# Verify that the calls to _post_json match what is expected
expected_call_count = len(mock_calls)
if expected_call_count > 1:
# Convert the call dicts to unittest.mock.call instances because `assert_has_calls` only accepts them
converted_calls = []
for call_dict in mock_calls:
converted_calls.append(call(**call_dict))
mock_post.assert_has_calls(converted_calls)
self.assertEqual(len(mock_post.mock_calls), expected_call_count)
elif expected_call_count == 1:
mock_post.assert_called_once_with(**mock_calls[0])
else: # expected_call_count is 0
mock_post.assert_not_called()
# Verify that the module's changed status matches what is expected
self.assertIs(exec_info.exception.args[0]['changed'], changed)
def test_add(self):
"""Add a new policy"""
module_args = {
'group': 'admins',
'state': 'present',
'priority': '10',
'maxpwdlife': '90',
'minpwdlife': '1',
'historylength': '8',
'minclasses': '3',
'minlength': '16',
'maxfailcount': '6',
'failinterval': '60',
'lockouttime': '600'
}
return_value = {}
mock_calls = (
{
'method': 'pwpolicy_find',
'name': None,
'item': {
'all': True,
'cn': 'admins'
}
},
{
'method': 'pwpolicy_add',
'name': 'admins',
'item': {
'cospriority': '10',
'krbmaxpwdlife': '90',
'krbminpwdlife': '1',
'krbpwdhistorylength': '8',
'krbpwdmindiffchars': '3',
'krbpwdminlength': '16',
'krbpwdmaxfailure': '6',
'krbpwdfailurecountinterval': '60',
'krbpwdlockoutduration': '600'
}
}
)
changed = True
self._test_base(module_args, return_value, mock_calls, changed)
def test_aliases(self):
"""Same as test_add, but uses the `name` alias for the `group` option"""
module_args = {
'name': 'admins',
'state': 'present',
'priority': '10',
'maxpwdlife': '90',
'minpwdlife': '1',
'historylength': '8',
'minclasses': '3',
'minlength': '16',
'maxfailcount': '6',
'failinterval': '60',
'lockouttime': '600'
}
return_value = {}
mock_calls = (
{
'method': 'pwpolicy_find',
'name': None,
'item': {
'all': True,
'cn': 'admins'
}
},
{
'method': 'pwpolicy_add',
'name': 'admins',
'item': {
'cospriority': '10',
'krbmaxpwdlife': '90',
'krbminpwdlife': '1',
'krbpwdhistorylength': '8',
'krbpwdmindiffchars': '3',
'krbpwdminlength': '16',
'krbpwdmaxfailure': '6',
'krbpwdfailurecountinterval': '60',
'krbpwdlockoutduration': '600'
}
}
)
changed = True
self._test_base(module_args, return_value, mock_calls, changed)
def test_mod_different_args(self):
"""Policy exists, but some of the args are different and need to be modified"""
module_args = {
'group': 'sysops',
'state': 'present',
'priority': '10',
'maxpwdlife': '60',
'minpwdlife': '24',
'historylength': '8',
'minclasses': '3',
'minlength': '12',
'maxfailcount': '8',
'failinterval': '60',
'lockouttime': '600'
}
return_value = {
'cn': ['sysops'],
'cospriority': ['10'],
'krbmaxpwdlife': ['90'],
'krbminpwdlife': ['1'],
'krbpwdhistorylength': ['8'],
'krbpwdmindiffchars': ['3'],
'krbpwdminlength': ['16'],
'krbpwdmaxfailure': ['6'],
'krbpwdfailurecountinterval': ['60'],
'krbpwdlockoutduration': ['600'],
'dn': 'cn=sysops,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
mock_calls = (
{
'method': 'pwpolicy_find',
'name': None,
'item': {
'all': True,
'cn': 'sysops'
}
},
{
'method': 'pwpolicy_mod',
'name': 'sysops',
'item': {
'cospriority': '10',
'krbmaxpwdlife': '60',
'krbminpwdlife': '24',
'krbpwdhistorylength': '8',
'krbpwdmindiffchars': '3',
'krbpwdminlength': '12',
'krbpwdmaxfailure': '8',
'krbpwdfailurecountinterval': '60',
'krbpwdlockoutduration': '600'
}
}
)
changed = True
self._test_base(module_args, return_value, mock_calls, changed)
def test_mod_missing_args(self):
"""Policy exists, but some of the args aren't set, so need to be added"""
module_args = {
'group': 'sysops',
'state': 'present',
'priority': '10',
'maxpwdlife': '90',
'minpwdlife': '1',
'historylength': '8',
'minclasses': '3',
'minlength': '16',
'maxfailcount': '6',
'failinterval': '60',
'lockouttime': '600'
}
return_value = {
'cn': ['sysops'],
'cospriority': ['10'],
'krbmaxpwdlife': ['90'],
'krbpwdhistorylength': ['8'],
'krbpwdminlength': ['16'],
'krbpwdmaxfailure': ['6'],
'dn': 'cn=sysops,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
mock_calls = (
{
'method': 'pwpolicy_find',
'name': None,
'item': {
'all': True,
'cn': 'sysops'
}
},
{
'method': 'pwpolicy_mod',
'name': 'sysops',
'item': {
'cospriority': '10',
'krbmaxpwdlife': '90',
'krbminpwdlife': '1',
'krbpwdhistorylength': '8',
'krbpwdmindiffchars': '3',
'krbpwdminlength': '16',
'krbpwdmaxfailure': '6',
'krbpwdfailurecountinterval': '60',
'krbpwdlockoutduration': '600'
}
}
)
changed = True
self._test_base(module_args, return_value, mock_calls, changed)
def test_del(self):
"""Policy exists, and state is absent. Needs to be deleted"""
module_args = {
'group': 'sysops',
'state': 'absent',
# other arguments are ignored when state is `absent`
'priority': '10',
'maxpwdlife': '90',
'historylength': '8',
'minlength': '16',
'maxfailcount': '6'
}
return_value = {
'cn': ['sysops'],
'cospriority': ['10'],
'krbmaxpwdlife': ['90'],
'krbpwdhistorylength': ['8'],
'krbpwdminlength': ['16'],
'krbpwdmaxfailure': ['6'],
'dn': 'cn=sysops,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
mock_calls = (
{
'method': 'pwpolicy_find',
'name': None,
'item': {
'all': True,
'cn': 'sysops'
}
},
{
'method': 'pwpolicy_del',
'name': 'sysops',
}
)
changed = True
self._test_base(module_args, return_value, mock_calls, changed)
def test_no_change(self):
"""Policy already exists. No changes needed"""
module_args = {
'group': 'admins',
'state': 'present',
'priority': '10',
'maxpwdlife': '90',
'minpwdlife': '1',
'historylength': '8',
'minclasses': '3',
'minlength': '16',
'maxfailcount': '6',
'failinterval': '60',
'lockouttime': '600'
}
return_value = {
'cn': ['admins'],
'cospriority': ['10'],
'krbmaxpwdlife': ['90'],
'krbminpwdlife': ['1'],
'krbpwdhistorylength': ['8'],
'krbpwdmindiffchars': ['3'],
'krbpwdminlength': ['16'],
'krbpwdmaxfailure': ['6'],
'krbpwdfailurecountinterval': ['60'],
'krbpwdlockoutduration': ['600'],
'dn': 'cn=admins,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
mock_calls = [
{
'method': 'pwpolicy_find',
'name': None,
'item': {
'all': True,
'cn': 'admins'
}
}
]
changed = False
self._test_base(module_args, return_value, mock_calls, changed)
def test_del_no_change(self):
"""Policy doesn't exist, and state is absent. No change needed"""
module_args = {
'group': 'sysops',
'state': 'absent',
# other arguments are ignored when state is `absent`
'priority': '10',
'maxpwdlife': '90',
'historylength': '8',
'minlength': '16',
'maxfailcount': '6'
}
return_value = {}
mock_calls = [
{
'method': 'pwpolicy_find',
'name': None,
'item': {
'all': True,
'cn': 'sysops'
}
}
]
changed = False
self._test_base(module_args, return_value, mock_calls, changed)
def test_global(self):
"""Modify the global policy"""
module_args = {
'maxpwdlife': '60',
'minpwdlife': '24',
'historylength': '8',
'minclasses': '3',
'minlength': '12',
'maxfailcount': '8',
'failinterval': '60',
'lockouttime': '600'
}
return_value = {
'cn': ['global_policy'],
'krbmaxpwdlife': ['90'],
'krbminpwdlife': ['1'],
'krbpwdmindiffchars': ['3'],
'krbpwdminlength': ['16'],
'krbpwdmaxfailure': ['6'],
'krbpwdfailurecountinterval': ['60'],
'krbpwdlockoutduration': ['600'],
'dn': 'cn=global_policy,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
mock_calls = (
{
'method': 'pwpolicy_find',
'name': None,
'item': {
'all': True,
'cn': 'global_policy'
}
},
{
'method': 'pwpolicy_mod',
'name': None,
'item': {
'krbmaxpwdlife': '60',
'krbminpwdlife': '24',
'krbpwdhistorylength': '8',
'krbpwdmindiffchars': '3',
'krbpwdminlength': '12',
'krbpwdmaxfailure': '8',
'krbpwdfailurecountinterval': '60',
'krbpwdlockoutduration': '600'
}
}
)
changed = True
self._test_base(module_args, return_value, mock_calls, changed)
def test_global_no_change(self):
"""Global policy already matches the given arguments. No change needed"""
module_args = {
'maxpwdlife': '90',
'minpwdlife': '1',
'historylength': '8',
'minclasses': '3',
'minlength': '16',
'maxfailcount': '6',
'failinterval': '60',
'lockouttime': '600'
}
return_value = {
'cn': ['global_policy'],
'krbmaxpwdlife': ['90'],
'krbminpwdlife': ['1'],
'krbpwdhistorylength': ['8'],
'krbpwdmindiffchars': ['3'],
'krbpwdminlength': ['16'],
'krbpwdmaxfailure': ['6'],
'krbpwdfailurecountinterval': ['60'],
'krbpwdlockoutduration': ['600'],
'dn': 'cn=global_policy,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
mock_calls = [
{
'method': 'pwpolicy_find',
'name': None,
'item': {
'all': True,
'cn': 'global_policy'
}
}
]
changed = False
self._test_base(module_args, return_value, mock_calls, changed)
def test_check_add(self):
"""Add a new policy in check mode. pwpolicy_add shouldn't be called"""
module_args = {
'_ansible_check_mode': True,
'group': 'admins',
'state': 'present',
'priority': '10',
'maxpwdlife': '90',
'minpwdlife': '1',
'historylength': '8',
'minclasses': '3',
'minlength': '16',
'maxfailcount': '6',
'failinterval': '60',
'lockouttime': '600'
}
return_value = {}
mock_calls = [
{
'method': 'pwpolicy_find',
'name': None,
'item': {
'all': True,
'cn': 'admins'
}
}
]
changed = True
self._test_base(module_args, return_value, mock_calls, changed)
def test_check_mod(self):
"""Modify a policy in check mode. pwpolicy_mod shouldn't be called"""
module_args = {
'_ansible_check_mode': True,
'group': 'sysops',
'state': 'present',
'priority': '10',
'maxpwdlife': '60',
'minpwdlife': '24',
'historylength': '8',
'minclasses': '3',
'minlength': '12',
'maxfailcount': '8',
'failinterval': '60',
'lockouttime': '600'
}
return_value = {
'cn': ['sysops'],
'cospriority': ['10'],
'krbmaxpwdlife': ['90'],
'krbminpwdlife': ['1'],
'krbpwdhistorylength': ['8'],
'krbpwdmindiffchars': ['3'],
'krbpwdminlength': ['16'],
'krbpwdmaxfailure': ['6'],
'krbpwdfailurecountinterval': ['60'],
'krbpwdlockoutduration': ['600'],
'dn': 'cn=sysops,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
mock_calls = [
{
'method': 'pwpolicy_find',
'name': None,
'item': {
'all': True,
'cn': 'sysops'
}
}
]
changed = True
self._test_base(module_args, return_value, mock_calls, changed)
def test_check_del(self):
"""Delete a policy in check mode. pwpolicy_del shouldn't be called"""
module_args = {
'_ansible_check_mode': True,
'group': 'sysops',
'state': 'absent'
}
return_value = {
'cn': ['sysops'],
'cospriority': ['10'],
'krbmaxpwdlife': ['90'],
'krbpwdhistorylength': ['8'],
'krbpwdminlength': ['16'],
'krbpwdmaxfailure': ['6'],
'dn': 'cn=sysops,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
mock_calls = [
{
'method': 'pwpolicy_find',
'name': None,
'item': {
'all': True,
'cn': 'sysops'
}
}
]
changed = True
self._test_base(module_args, return_value, mock_calls, changed)
def test_fail_post(self):
"""Fail due to an exception raised from _post_json"""
set_module_args({
'group': 'admins',
'state': 'absent'
})
with patch_ipa(side_effect=Exception('ERROR MESSAGE')) as (mock_login, mock_post):
with self.assertRaises(AnsibleFailJson) as exec_info:
self.module.main()
self.assertEqual(exec_info.exception.args[0]['msg'], 'ERROR MESSAGE')
if __name__ == '__main__':
unittest.main()