diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py index 45e956d08c6c5d89f5c2f08c93d4e94154cefb2c..45eabb88d322b4f97812facf1c9bb075c2eca80d 100644 --- a/plugins/module_utils/ansible_freeipa_module.py +++ b/plugins/module_utils/ansible_freeipa_module.py @@ -45,6 +45,7 @@ else: import gssapi from datetime import datetime from contextlib import contextmanager + import inspect # ansible-freeipa requires locale to be C, IPA requires utf-8. os.environ["LANGUAGE"] = "C" @@ -716,8 +717,21 @@ else: """ return api_check_ipa_version(oper, requested_version) - def execute_ipa_commands(self, commands, handle_result=None, - **handle_result_user_args): + # pylint: disable=unused-argument + @staticmethod + def member_error_handler(module, result, command, name, args, errors): + # Get all errors + for failed_item in result.get("failed", []): + failed = result["failed"][failed_item] + for member_type in failed: + for member, failure in failed[member_type]: + errors.append("%s: %s %s: %s" % ( + command, member_type, member, failure)) + + def execute_ipa_commands(self, commands, result_handler=None, + exception_handler=None, + fail_on_member_errors=False, + **handlers_user_args): """ Execute IPA API commands from command list. @@ -727,30 +741,56 @@ else: The list of commands in the form (name, command and args) For commands that do not require a 'name', None needs be used. - handle_result: function + result_handler: function The user function to handle results of the single commands - handle_result_user_args: dict (user args mapping) - The user args to pass to handle_result function + exception_handler: function + The user function to handle exceptions of the single commands + Returns True to continue to next command, else False + fail_on_member_errors: bool + Use default member error handler handler member_error_handler + handlers_user_args: dict (user args mapping) + The user args to pass to result_handler and exception_handler + functions Example (ipauser module): - def handle_result(module, result, command, name, args, exit_args): + def result_handler(module, result, command, name, args, exit_args, + one_name): if "random" in args and command in ["user_add", "user_mod"] \ and "randompassword" in result["result"]: - exit_args.setdefault(name, {})["randompassword"] = \ - result["result"]["randompassword"] + if one_name: + exit_args["randompassword"] = \ + result["result"]["randompassword"] + else: + exit_args.setdefault(name, {})["randompassword"] = \ + result["result"]["randompassword"] + + def exception_handler(module, ex, exit_args, one_name): + if ex.exception == ipalib_errors.EmptyModlist: + result = {} + return False exit_args = {} - changed = module.execute_ipa_commands(commands, handle_result, - exit_args=exit_args) + changed = module.execute_ipa_commands(commands, result_handler, + exception_handler, + exit_args=exit_args, + one_name=len(names)==1) - if len(names) == 1: - ansible_module.exit_json(changed=changed, - user=exit_args[names[0]]) - else: - ansible_module.exit_json(changed=changed, user=exit_args) + ansible_module.exit_json(changed=changed, user=exit_args) """ + # Fail on given handlers_user_args without result or exception + # handler + if result_handler is None and exception_handler is None and \ + len(handlers_user_args) > 0: + self.fail_json(msg="Args without result and exception hander: " + "%s" % repr(handlers_user_args)) + + # Fail on given result_handler and fail_on_member_errors + if result_handler is not None and fail_on_member_errors: + self.fail_json( + msg="result_handler given and fail_on_member_errors set") + # No commands, report no changes if commands is None: return False @@ -759,6 +799,24 @@ else: if self.check_mode: return len(commands) > 0 + # Error list for result_handler and error_handler + _errors = [] + + # Handle fail_on_member_errors, set result_handler to + # member_error_handler + # Add internal _errors for result_hendler if the module is not + # adding it. This also activates the final fail_json if + # errors are found. + if fail_on_member_errors: + result_handler = IPAAnsibleModule.member_error_handler + handlers_user_args["errors"] = _errors + elif result_handler is not None: + if "errors" not in handlers_user_args: + # pylint: disable=deprecated-method + argspec = inspect.getargspec(result_handler) + if "errors" in argspec.args: + handlers_user_args["errors"] = _errors + changed = False for name, command, args in commands: try: @@ -773,13 +831,22 @@ else: else: changed = True - if handle_result is not None: - handle_result(self, result, command, name, args, - **handle_result_user_args) + # If result_handler is not None, call it with user args + # defined in **handlers_user_args + if result_handler is not None: + result_handler(self, result, command, name, args, + **handlers_user_args) except Exception as e: + if exception_handler is not None and \ + exception_handler(self, e, **handlers_user_args): + continue self.fail_json(msg="%s: %s: %s" % (command, name, str(e))) + # Fail on errors from result_handler and exception_handler + if len(_errors) > 0: + self.fail_json(msg=", ".join(_errors)) + return changed class FreeIPABaseModule(IPAAnsibleModule): diff --git a/plugins/modules/ipaautomember.py b/plugins/modules/ipaautomember.py index 49c8d9a28170db8360296645740c1bef4056eca6..9a93cd23c1d8b662daa79d615b010ef35fad5fc0 100644 --- a/plugins/modules/ipaautomember.py +++ b/plugins/modules/ipaautomember.py @@ -390,32 +390,16 @@ def main(): commands.append([None, 'automember_rebuild', {"hosts": rebuild_hosts}]) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - - for name, command, args in commands: - try: - if name is None: - result = ansible_module.ipa_command_no_name(command, args) - else: - result = ansible_module.ipa_command(command, name, args) + # Execute commands - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as ex: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(ex))) - - # result["failed"] is used only for INCLUDE_RE, EXCLUDE_RE - # if entries could not be added that are already there and - # it entries could not be removed that are not there. - # All other issues like invalid attributes etc. are handled - # as exceptions. Therefore the error section is not here as - # in other modules. + changed = ansible_module.execute_ipa_commands(commands) + + # result["failed"] is used only for INCLUDE_RE, EXCLUDE_RE + # if entries could not be added that are already there and + # if entries could not be removed that are not there. + # All other issues like invalid attributes etc. are handled + # as exceptions. Therefore the error section is not here as + # in other modules. # Done ansible_module.exit_json(changed=changed, **exit_args) diff --git a/plugins/modules/ipadelegation.py b/plugins/modules/ipadelegation.py index 846e1277ecc92742c888e3379fe4085f7f38bfbf..3ebbe88c01d31458a80afb2127e1479c37842f6f 100644 --- a/plugins/modules/ipadelegation.py +++ b/plugins/modules/ipadelegation.py @@ -289,23 +289,9 @@ def main(): else: ansible_module.fail_json(msg="Unkown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) + changed = ansible_module.execute_ipa_commands(commands) # Done diff --git a/plugins/modules/ipadnsrecord.py b/plugins/modules/ipadnsrecord.py index 3950b31395fe00328e2a99f9472953824b283654..69b9212ab03f9577ed3b3bc441902dfe25b3de58 100644 --- a/plugins/modules/ipadnsrecord.py +++ b/plugins/modules/ipadnsrecord.py @@ -1241,7 +1241,7 @@ def create_reverse_ip_record(module, zone_name, name, ips): 'idnsname': to_text(reverse_host), "ptrrecord": "%s.%s" % (name, zone_name) } - _cmds.append([reverse_zone, 'dnsrecord_add', rev_args]) + _cmds.append([to_text(reverse_zone), 'dnsrecord_add', rev_args]) return _cmds @@ -1408,6 +1408,14 @@ def define_commands_for_absent_state(module, zone_name, entry, res_find): return _commands +# pylint: disable=unused-argument +def exception_handler(module, ex): + if isinstance(ex, (ipalib_errors.EmptyModlist, + ipalib_errors.DuplicateEntry)): + return True + return False + + def main(): """Execute DNS record playbook.""" ansible_module = configure_module() @@ -1468,30 +1476,10 @@ def main(): if cmds: commands.extend(cmds) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - for name, command, args in commands: - try: - result = ansible_module.ipa_command( - command, to_text(name), args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - - except ipalib_errors.EmptyModlist: - continue - except ipalib_errors.DuplicateEntry: - continue - except Exception as e: - error_message = str(e) - ansible_module.fail_json( - msg="%s: %s: %s" % (command, name, error_message)) + changed = ansible_module.execute_ipa_commands( + commands, exception_handler=exception_handler) # Done ansible_module.exit_json(changed=changed, host=exit_args) diff --git a/plugins/modules/ipagroup.py b/plugins/modules/ipagroup.py index c19644c2b2df4cce147187cfb6ade5edbad06fdd..bbc8e9739957a99a36c4c72cad93f06cc942848f 100644 --- a/plugins/modules/ipagroup.py +++ b/plugins/modules/ipagroup.py @@ -658,34 +658,10 @@ def main(): else: ansible_module.fail_json(msg="Unkown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) - # Get all errors - # result are ignored. All others are reported. - errors = [] - for failed_item in result.get("failed", []): - failed = result["failed"][failed_item] - for member_type in failed: - for member, failure in failed[member_type]: - errors.append("%s: %s %s: %s" % ( - command, member_type, member, failure)) - if len(errors) > 0: - ansible_module.fail_json(msg=", ".join(errors)) + changed = ansible_module.execute_ipa_commands( + commands, fail_on_member_errors=True) # Done diff --git a/plugins/modules/ipahbacrule.py b/plugins/modules/ipahbacrule.py index ea8fd73aca656484ee6479d541da16f005e9e510..1d6a3b2fe4e881b883b9e66f015734e7fefef866 100644 --- a/plugins/modules/ipahbacrule.py +++ b/plugins/modules/ipahbacrule.py @@ -595,35 +595,10 @@ def main(): else: ansible_module.fail_json(msg="Unkown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - errors = [] - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) - # Get all errors - # result are ignored. All others are reported. - if "failed" in result and len(result["failed"]) > 0: - for item in result["failed"]: - failed_item = result["failed"][item] - for member_type in failed_item: - for member, failure in failed_item[member_type]: - errors.append("%s: %s %s: %s" % ( - command, member_type, member, failure)) - if len(errors) > 0: - ansible_module.fail_json(msg=", ".join(errors)) + changed = ansible_module.execute_ipa_commands( + commands, fail_on_member_errors=True) # Done diff --git a/plugins/modules/ipahbacsvc.py b/plugins/modules/ipahbacsvc.py index c6e31d47b7c99192e85833f9a136426e816825f8..12c8476d76b84a93d2fbbc23229e656ba0d5ff01 100644 --- a/plugins/modules/ipahbacsvc.py +++ b/plugins/modules/ipahbacsvc.py @@ -180,19 +180,9 @@ def main(): else: ansible_module.fail_json(msg="Unkown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - for name, command, args in commands: - try: - ansible_module.ipa_command(command, name, args) - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) + changed = ansible_module.execute_ipa_commands(commands) # Done diff --git a/plugins/modules/ipahbacsvcgroup.py b/plugins/modules/ipahbacsvcgroup.py index 5e301d6a318b6edcaa8a930623874c971154bf21..1e6e3439b846f65933326125a5b405b28da6471d 100644 --- a/plugins/modules/ipahbacsvcgroup.py +++ b/plugins/modules/ipahbacsvcgroup.py @@ -136,6 +136,21 @@ def gen_member_args(hbacsvc): return _args +# pylint: disable=unused-argument +def result_handler(module, result, command, name, args, errors): + # Get all errors + # All "already a member" and "not a member" failures in the + # result are ignored. All others are reported. + if "failed" in result and "member" in result["failed"]: + failed = result["failed"]["member"] + for member_type in failed: + for member, failure in failed[member_type]: + if "already a member" not in failure \ + and "not a member" not in failure: + errors.append("%s: %s %s: %s" % ( + command, member_type, member, failure)) + + def main(): ansible_module = IPAAnsibleModule( argument_spec=dict( @@ -278,36 +293,9 @@ def main(): else: ansible_module.fail_json(msg="Unkown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - errors = [] - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) - # Get all errors - # All "already a member" and "not a member" failures in the - # result are ignored. All others are reported. - if "failed" in result and "member" in result["failed"]: - failed = result["failed"]["member"] - for member_type in failed: - for member, failure in failed[member_type]: - if "already a member" not in failure \ - and "not a member" not in failure: - errors.append("%s: %s %s: %s" % ( - command, member_type, member, failure)) - if len(errors) > 0: - ansible_module.fail_json(msg=", ".join(errors)) + + changed = ansible_module.execute_ipa_commands(commands, result_handler) # Done diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py index 86453a775abd6203c581f8f9f16e7873a191def4..934030014a34c485b8a084e33ee1cc7dd0bee824 100644 --- a/plugins/modules/ipahost.py +++ b/plugins/modules/ipahost.py @@ -572,6 +572,54 @@ def check_parameters( # pylint: disable=unused-argument "'member' for state '%s'" % (x, state)) +# pylint: disable=unused-argument +def result_handler(module, result, command, name, args, errors, exit_args, + one_name): + if "random" in args and command in ["host_add", "host_mod"] \ + and "randompassword" in result["result"]: + if one_name: + exit_args["randompassword"] = \ + result["result"]["randompassword"] + else: + exit_args.setdefault(name, {})["randompassword"] = \ + result["result"]["randompassword"] + + # All "already a member" and "not a member" failures in the + # result are ignored. All others are reported. + if "failed" in result and len(result["failed"]) > 0: + for item in result["failed"]: + failed_item = result["failed"][item] + for member_type in failed_item: + for member, failure in failed_item[member_type]: + if "already a member" in failure \ + or "not a member" in failure: + continue + errors.append("%s: %s %s: %s" % ( + command, member_type, member, failure)) + + +# pylint: disable=unused-argument +def exception_handler(module, ex, errors, exit_args, one_name): + msg = str(ex) + if "already contains" in msg \ + or "does not contain" in msg: + return True + + # The canonical principal name may not be removed + if "equal to the canonical principal name must" in msg: + return True + + # Host is already disabled, ignore error + if "This entry is already disabled" in msg: + return True + + # Ignore no modification error. + if "no modifications to be performed" in msg: + return True + + return False + + def main(): host_spec = dict( # present @@ -1343,68 +1391,11 @@ def main(): del host_set - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - errors = [] - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - - if "random" in args and command in ["host_add", "host_mod"] \ - and "randompassword" in result["result"]: - if len(names) == 1: - exit_args["randompassword"] = \ - result["result"]["randompassword"] - else: - exit_args.setdefault(name, {})["randompassword"] = \ - result["result"]["randompassword"] - - except Exception as e: - msg = str(e) - if "already contains" in msg \ - or "does not contain" in msg: - continue - - # The canonical principal name may not be removed - if "equal to the canonical principal name must" in msg: - continue - - # Host is already disabled, ignore error - if "This entry is already disabled" in msg: - continue - - # Ignore no modification error. - if "no modifications to be performed" in msg: - continue - - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - msg)) - - # Get all errors - # All "already a member" and "not a member" failures in the - # result are ignored. All others are reported. - if "failed" in result and len(result["failed"]) > 0: - for item in result["failed"]: - failed_item = result["failed"][item] - for member_type in failed_item: - for member, failure in failed_item[member_type]: - if "already a member" in failure \ - or "not a member" in failure: - continue - errors.append("%s: %s %s: %s" % ( - command, member_type, member, failure)) - - if len(errors) > 0: - ansible_module.fail_json(msg=", ".join(errors)) + changed = ansible_module.execute_ipa_commands( + commands, result_handler, exception_handler, + exit_args=exit_args, one_name=len(names) == 1) # Done diff --git a/plugins/modules/ipahostgroup.py b/plugins/modules/ipahostgroup.py index b0f7857b171a871f7d56e4347ea1760a88628e90..b2f553f730fa27e0c5cfc13ee9406f5745af63ca 100644 --- a/plugins/modules/ipahostgroup.py +++ b/plugins/modules/ipahostgroup.py @@ -490,34 +490,10 @@ def main(): else: ansible_module.fail_json(msg="Unkown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) - # Get all errors - # All "already a member" and "not a member" failures in the - # result are ignored. All others are reported. - errors = [] - for failed_item in result.get("failed", []): - failed = result["failed"][failed_item] - for member_type in failed: - for member, failure in failed[member_type]: - errors.append("%s: %s %s: %s" % ( - command, member_type, member, failure)) - if len(errors) > 0: - ansible_module.fail_json(msg=", ".join(errors)) + + changed = ansible_module.execute_ipa_commands( + commands, fail_on_member_errors=True) # Done diff --git a/plugins/modules/ipalocation.py b/plugins/modules/ipalocation.py index 48d5b4876f5e110cbfccae05e9c11f558165a727..7f10b94459fa0d0171eaf669fc1a2e37f6ac6d4e 100644 --- a/plugins/modules/ipalocation.py +++ b/plugins/modules/ipalocation.py @@ -168,23 +168,8 @@ def main(): else: ansible_module.fail_json(msg="Unkown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) + changed = ansible_module.execute_ipa_commands(commands) # Done diff --git a/plugins/modules/ipapermission.py b/plugins/modules/ipapermission.py index 5921675f53757fbc18134fc04164ea141a1c1a00..2dc6ab1cea590e791aec8669ddb63e6b818da73c 100644 --- a/plugins/modules/ipapermission.py +++ b/plugins/modules/ipapermission.py @@ -180,6 +180,22 @@ def gen_args(right, attrs, bindtype, subtree, return _args +# pylint: disable=unused-argument +def result_handler(module, result, command, name, args, errors): + # Get all errors + # All "already a member" and "not a member" failures in the + # result are ignored. All others are reported. + for failed_item in result.get("failed", []): + failed = result["failed"][failed_item] + for member_type in failed: + for member, failure in failed[member_type]: + if "already a member" in failure \ + or "not a member" in failure: + continue + errors.append("%s: %s %s: %s" % ( + command, member_type, member, failure)) + + def main(): ansible_module = IPAAnsibleModule( argument_spec=dict( @@ -425,38 +441,9 @@ def main(): else: ansible_module.fail_json(msg="Unknown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) - # Get all errors - # All "already a member" and "not a member" failures in the - # result are ignored. All others are reported. - errors = [] - for failed_item in result.get("failed", []): - failed = result["failed"][failed_item] - for member_type in failed: - for member, failure in failed[member_type]: - if "already a member" in failure \ - or "not a member" in failure: - continue - errors.append("%s: %s %s: %s" % ( - command, member_type, member, failure)) - if len(errors) > 0: - ansible_module.fail_json(msg=", ".join(errors)) + changed = ansible_module.execute_ipa_commands(commands, result_handler) # Done diff --git a/plugins/modules/ipaprivilege.py b/plugins/modules/ipaprivilege.py index 3256eba97f3633a399cfb77c555b57b7d40df0fa..7b32468fd8af5c5ce1f271ea93d96835d07b41c0 100644 --- a/plugins/modules/ipaprivilege.py +++ b/plugins/modules/ipaprivilege.py @@ -126,6 +126,22 @@ def find_privilege(module, name): return _result["result"] +# pylint: disable=unused-argument +def result_handler(module, result, command, name, args, errors): + # Get all errors + # All "already a member" and "not a member" failures in the + # result are ignored. All others are reported. + for failed_item in result.get("failed", []): + failed = result["failed"][failed_item] + for member_type in failed: + for member, failure in failed[member_type]: + if "already a member" in failure \ + or "not a member" in failure: + continue + errors.append("%s: %s %s: %s" % ( + command, member_type, member, failure)) + + def main(): ansible_module = IPAAnsibleModule( argument_spec=dict( @@ -304,38 +320,9 @@ def main(): else: ansible_module.fail_json(msg="Unkown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as e: - ansible_module.fail_json( - msg="%s: %s: %s" % (command, name, str(e))) - # Get all errors - # All "already a member" and "not a member" failures in the - # result are ignored. All others are reported. - errors = [] - for failed_item in result.get("failed", []): - failed = result["failed"][failed_item] - for member_type in failed: - for member, failure in failed[member_type]: - if "already a member" in failure \ - or "not a member" in failure: - continue - errors.append("%s: %s %s: %s" % ( - command, member_type, member, failure)) - if len(errors) > 0: - ansible_module.fail_json(msg=", ".join(errors)) + changed = ansible_module.execute_ipa_commands(commands, result_handler) # Done diff --git a/plugins/modules/ipapwpolicy.py b/plugins/modules/ipapwpolicy.py index 758ee6dbe8654702e48a7e357da594bfb0643d34..55bedd072d648a59666b5671f906005b6060daa5 100644 --- a/plugins/modules/ipapwpolicy.py +++ b/plugins/modules/ipapwpolicy.py @@ -272,19 +272,9 @@ def main(): else: ansible_module.fail_json(msg="Unkown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - for name, command, args in commands: - try: - ansible_module.ipa_command(command, name, args) - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) + changed = ansible_module.execute_ipa_commands(commands) # Done diff --git a/plugins/modules/iparole.py b/plugins/modules/iparole.py index 4a073e6da9bdda77a75b294afe0edd2ea7502394..55b1e1e32bee742a0940c6edc56546c0167afef4 100644 --- a/plugins/modules/iparole.py +++ b/plugins/modules/iparole.py @@ -314,12 +314,12 @@ def ensure_members_are_present(module, name, res_find): return commands -def process_command_failures(command, result): +# pylint: disable=unused-argument +def result_handler(module, result, command, name, args, errors): """Process the result of a command, looking for errors.""" # Get all errors # All "already a member" and "not a member" failures in the # result are ignored. All others are reported. - errors = [] if "failed" in result and len(result["failed"]) > 0: for item in result["failed"]: failed_item = result["failed"][item] @@ -330,37 +330,6 @@ def process_command_failures(command, result): continue errors.append("%s: %s %s: %s" % ( command, member_type, member, failure)) - return errors - - -def process_commands(module, commands): - """Process the list of IPA API commands.""" - errors = [] - exit_args = {} - changed = False - - # Check mode exit - if module.check_mode: - return len(commands) > 0, exit_args - - for name, command, args in commands: - try: - result = module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - - errors = process_command_failures(command, result) - except Exception as exception: # pylint: disable=broad-except - module.fail_json( - msg="%s: %s: %s" % (command, name, str(exception))) - - if errors: - module.fail_json(msg=", ".join(errors)) - - return changed, exit_args def role_commands_for_name(module, state, action, name): @@ -454,7 +423,11 @@ def main(): cmds = role_commands_for_name(ansible_module, state, action, name) commands.extend(cmds) - changed, exit_args = process_commands(ansible_module, commands) + exit_args = {} + + # Execute commands + + changed = ansible_module.execute_ipa_commands(commands, result_handler) # Done ansible_module.exit_json(changed=changed, **exit_args) diff --git a/plugins/modules/ipaselfservice.py b/plugins/modules/ipaselfservice.py index 81b4461ce87ef6f627fc13defa42eef8280c68c3..53bd5b3b6a626763f183c173cc7945395decce41 100644 --- a/plugins/modules/ipaselfservice.py +++ b/plugins/modules/ipaselfservice.py @@ -278,17 +278,7 @@ def main(): # Execute commands - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) + changed = ansible_module.execute_ipa_commands(commands) # Done diff --git a/plugins/modules/ipaserver.py b/plugins/modules/ipaserver.py index c1bfe119af8dcbe382aa9b27678c3db9edf6d525..509e3ca16185f92da26018c0aa407e6cbff788bd 100644 --- a/plugins/modules/ipaserver.py +++ b/plugins/modules/ipaserver.py @@ -391,17 +391,7 @@ def main(): # Execute commands - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) + changed = ansible_module.execute_ipa_commands(commands) # Done diff --git a/plugins/modules/ipaservice.py b/plugins/modules/ipaservice.py index b72e09150d36f226121002d83ab7aed36f2e8185..29ef992bb808ccc9283b6e0e42ec3575ebf4dc7b 100644 --- a/plugins/modules/ipaservice.py +++ b/plugins/modules/ipaservice.py @@ -409,6 +409,23 @@ def init_ansible_module(): return ansible_module +# pylint: disable=unused-argument +def result_handler(module, result, command, name, args, errors): + # Get all errors + # All "already a member" and "not a member" failures in the + # result are ignored. All others are reported. + if "failed" in result and len(result["failed"]) > 0: + for item in result["failed"]: + failed_item = result["failed"][item] + for member_type in failed_item: + for member, failure in failed_item[member_type]: + if "already a member" in failure \ + or "not a member" in failure: + continue + errors.append("%s: %s %s: %s" % ( + command, member_type, member, failure)) + + def main(): ansible_module = init_ansible_module() @@ -831,34 +848,8 @@ def main(): ansible_module.exit_json(changed=len(commands) > 0, **exit_args) # Execute commands - errors = [] - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as ex: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(ex))) - # Get all errors - # All "already a member" and "not a member" failures in the - # result are ignored. All others are reported. - if "failed" in result and len(result["failed"]) > 0: - for item in result["failed"]: - failed_item = result["failed"][item] - for member_type in failed_item: - for member, failure in failed_item[member_type]: - if "already a member" in failure \ - or "not a member" in failure: - continue - errors.append("%s: %s %s: %s" % ( - command, member_type, member, failure)) - if len(errors) > 0: - ansible_module.fail_json(msg=", ".join(errors)) + + changed = ansible_module.execute_ipa_commands(commands, result_handler) # Done ansible_module.exit_json(changed=changed, **exit_args) diff --git a/plugins/modules/ipasudorule.py b/plugins/modules/ipasudorule.py index ca60d090aa9d670e9e58f6618e74e38ff56d80c8..a149c75ceb12eb1db2d9b254e766033550a0373a 100644 --- a/plugins/modules/ipasudorule.py +++ b/plugins/modules/ipasudorule.py @@ -824,36 +824,10 @@ def main(): else: ansible_module.fail_json(msg="Unkown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - errors = [] - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as ex: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(ex))) - # Get all errors - # result are ignored. All others are reported. - if "failed" in result and len(result["failed"]) > 0: - for item in result["failed"]: - failed_item = result["failed"][item] - for member_type in failed_item: - for member, failure in failed_item[member_type]: - errors.append("%s: %s %s: %s" % ( - command, member_type, member, failure)) - if len(errors) > 0: - ansible_module.fail_json(msg=", ".join(errors)) + changed = ansible_module.execute_ipa_commands( + commands, fail_on_member_errors=True) # Done diff --git a/plugins/modules/ipauser.py b/plugins/modules/ipauser.py index 7e44a3f3c90f2e8452d454efd48b23f80987ff38..1ffee44806bee7ea14bb962323dfeea7812955f4 100644 --- a/plugins/modules/ipauser.py +++ b/plugins/modules/ipauser.py @@ -716,6 +716,46 @@ def gen_certmapdata_args(certmapdata): return {"ipacertmapdata": to_text(certmapdata)} +# pylint: disable=unused-argument +def result_handler(module, result, command, name, args, errors, exit_args, + one_name): + + if "random" in args and command in ["user_add", "user_mod"] \ + and "randompassword" in result["result"]: + if one_name: + exit_args["randompassword"] = \ + result["result"]["randompassword"] + else: + exit_args.setdefault(name, {})["randompassword"] = \ + result["result"]["randompassword"] + + # Get all errors + # All "already a member" and "not a member" failures in the + # result are ignored. All others are reported. + if "failed" in result and len(result["failed"]) > 0: + for item in result["failed"]: + failed_item = result["failed"][item] + for member_type in failed_item: + for member, failure in failed_item[member_type]: + if "already a member" in failure \ + or "not a member" in failure: + continue + errors.append("%s: %s %s: %s" % ( + command, member_type, member, failure)) + + +# pylint: disable=unused-argument +def exception_handler(module, ex, errors, exit_args, one_name): + msg = str(ex) + if "already contains" in msg \ + or "does not contain" in msg: + return True + # The canonical principal name may not be removed + if "equal to the canonical principal name must" in msg: + return True + return False + + def main(): user_spec = dict( # present @@ -1359,58 +1399,11 @@ def main(): del user_set - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - errors = [] - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - - if "random" in args and command in ["user_add", "user_mod"] \ - and "randompassword" in result["result"]: - if len(names) == 1: - exit_args["randompassword"] = \ - result["result"]["randompassword"] - else: - exit_args.setdefault(name, {})["randompassword"] = \ - result["result"]["randompassword"] - - except Exception as e: - msg = str(e) - if "already contains" in msg \ - or "does not contain" in msg: - continue - # The canonical principal name may not be removed - if "equal to the canonical principal name must" in msg: - continue - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - msg)) - - # Get all errors - # All "already a member" and "not a member" failures in the - # result are ignored. All others are reported. - if "failed" in result and len(result["failed"]) > 0: - for item in result["failed"]: - failed_item = result["failed"][item] - for member_type in failed_item: - for member, failure in failed_item[member_type]: - if "already a member" in failure \ - or "not a member" in failure: - continue - errors.append("%s: %s %s: %s" % ( - command, member_type, member, failure)) - - if len(errors) > 0: - ansible_module.fail_json(msg=", ".join(errors)) + changed = ansible_module.execute_ipa_commands( + commands, result_handler, exception_handler, + exit_args=exit_args, one_name=len(names) == 1) # Done ansible_module.exit_json(changed=changed, user=exit_args) diff --git a/utils/templates/ipamodule+member.py.in b/utils/templates/ipamodule+member.py.in index c3e37727b5a189ee6d30b78e3d38f8a86f09c16d..7e7ad8ea18b1bc90cc1d49e0d3834881870364a2 100644 --- a/utils/templates/ipamodule+member.py.in +++ b/utils/templates/ipamodule+member.py.in @@ -286,38 +286,34 @@ def main(): else: ansible_module.fail_json(msg="Unkown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) # Execute commands - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) - # Get all errors - # All "already a member" and "not a member" failures in the - # result are ignored. All others are reported. - errors = [] - for failed_item in result.get("failed", []): - failed = result["failed"][failed_item] - for member_type in failed: - for member, failure in failed[member_type]: - if "already a member" in failure \ - or "not a member" in failure: - continue - errors.append("%s: %s %s: %s" % ( - command, member_type, member, failure)) - if len(errors) > 0: - ansible_module.fail_json(msg=", ".join(errors)) + # + # To handle default member errors there is a static method + # IPAAnsibleModule.handle_member_errors. It can be enabled with + # fail_on_member_failures=True for execute_ipa_commands. + # There might be cases in which this needs to be either done + # manually or extended. + # + # Example: + # + # pylint: disable=unused-argument + # def result_handler(module, result, command, name, args, errors): + # # Get all errors + # IPAAnsibleModule.handle_member_errors(module, result, command, + # name, args, errors) + # if "MY ERROR" in result.get("failed",[]): + # errors.append("My error") + # + # # Execute commands + # + # changed = ansible_module.execute_ipa_commands(commands, + # result_handler) + # + + changed = ansible_module.execute_ipa_commands( + commands, fail_on_member_failures=True) # Done diff --git a/utils/templates/ipamodule.py.in b/utils/templates/ipamodule.py.in index f7d1e538190d0ba3c46f80c80102a864a2020c97..b179a0b8f66ac8fb78a5cbd5a814b90b3e91c757 100644 --- a/utils/templates/ipamodule.py.in +++ b/utils/templates/ipamodule.py.in @@ -194,23 +194,9 @@ def main(): else: ansible_module.fail_json(msg="Unkown state '%s'" % state) - # Check mode exit - if ansible_module.check_mode: - ansible_module.exit_json(changed=len(commands) > 0, **exit_args) - # Execute commands - for name, command, args in commands: - try: - result = ansible_module.ipa_command(command, name, args) - if "completed" in result: - if result["completed"] > 0: - changed = True - else: - changed = True - except Exception as e: - ansible_module.fail_json(msg="%s: %s: %s" % (command, name, - str(e))) + changed = ansible_module.execute_ipa_commands(commands) # Done