def main(): ansible_module = AnsibleModule( argument_spec=dict( # general ipaadmin_principal=dict(type="str", default="admin"), ipaadmin_password=dict(type="str", required=False, no_log=True), name=dict(type="list", aliases=["cn"], default=None, required=True), # present description=dict(type="str", default=None), nomembers=dict(required=False, type='bool', default=None), host=dict(required=False, type='list', default=None), hostgroup=dict(required=False, type='list', default=None), membermanager_user=dict(required=False, type='list', default=None), membermanager_group=dict(required=False, type='list', default=None), rename=dict(required=False, type='str', default=None, aliases=["new_name"]), action=dict(type="str", default="hostgroup", choices=["member", "hostgroup"]), # state state=dict(type="str", default="present", choices=["present", "absent", "renamed"]), ), supports_check_mode=True, ) ansible_module._ansible_debug = True # Get parameters # general ipaadmin_principal = module_params_get(ansible_module, "ipaadmin_principal") ipaadmin_password = module_params_get(ansible_module, "ipaadmin_password") names = module_params_get(ansible_module, "name") # present description = module_params_get(ansible_module, "description") nomembers = module_params_get(ansible_module, "nomembers") host = module_params_get(ansible_module, "host") hostgroup = module_params_get(ansible_module, "hostgroup") membermanager_user = module_params_get(ansible_module, "membermanager_user") membermanager_group = module_params_get(ansible_module, "membermanager_group") rename = module_params_get(ansible_module, "rename") action = module_params_get(ansible_module, "action") # state state = module_params_get(ansible_module, "state") # Check parameters if state == "present": if len(names) != 1: ansible_module.fail_json( msg="Only one hostgroup can be added at a time.") invalid = ["rename"] if action == "member": invalid.extend(["description", "nomembers"]) for x in invalid: if vars()[x] is not None: ansible_module.fail_json( msg="Argument '%s' can not be used with action " "'%s'" % (x, action)) if state == "renamed": if len(names) != 1: ansible_module.fail_json( msg="Only one hostgroup can be added at a time.") if action == "member": ansible_module.fail_json( msg="Action '%s' can not be used with state '%s'" % (action, state)) invalid = [ "description", "nomembers", "host", "hostgroup", "membermanager_user", "membermanager_group" ] for x in invalid: if vars()[x] is not None: ansible_module.fail_json( msg="Argument '%s' can not be used with state '%s'" % (x, state)) if state == "absent": if len(names) < 1: ansible_module.fail_json(msg="No name given.") invalid = ["description", "nomembers", "rename"] if action == "hostgroup": invalid.extend(["host", "hostgroup"]) for x in invalid: if vars()[x] is not None: ansible_module.fail_json( msg="Argument '%s' can not be used with state '%s'" % (x, state)) # Init changed = False exit_args = {} ccache_dir = None ccache_name = None try: if not valid_creds(ansible_module, ipaadmin_principal): ccache_dir, ccache_name = temp_kinit(ipaadmin_principal, ipaadmin_password) api_connect() has_add_membermanager = api_check_command( "hostgroup_add_member_manager") if ((membermanager_user is not None or membermanager_group is not None) and not has_add_membermanager): ansible_module.fail_json( msg="Managing a membermanager user or group is not supported " "by your IPA version") has_mod_rename = api_check_param("hostgroup_mod", "rename") if not has_mod_rename and rename is not None: ansible_module.fail_json( msg="Renaming hostgroups is not supported by your IPA version") commands = [] for name in names: # Make sure hostgroup exists res_find = find_hostgroup(ansible_module, name) # Create command if state == "present": # Generate args args = gen_args(description, nomembers, rename) if action == "hostgroup": # Found the hostgroup if res_find is not None: # For all settings is args, check if there are # different settings in the find result. # If yes: modify if not compare_args_ipa(ansible_module, args, res_find): commands.append([name, "hostgroup_mod", args]) else: commands.append([name, "hostgroup_add", args]) # Set res_find to empty dict for next step res_find = {} member_args = gen_member_args(host, hostgroup) if not compare_args_ipa(ansible_module, member_args, res_find): # Generate addition and removal lists host_add, host_del = gen_add_del_lists( host, res_find.get("member_host")) hostgroup_add, hostgroup_del = gen_add_del_lists( hostgroup, res_find.get("member_hostgroup")) # Add members if len(host_add) > 0 or len(hostgroup_add) > 0: commands.append([ name, "hostgroup_add_member", { "host": host_add, "hostgroup": hostgroup_add, } ]) # Remove members if len(host_del) > 0 or len(hostgroup_del) > 0: commands.append([ name, "hostgroup_remove_member", { "host": host_del, "hostgroup": hostgroup_del, } ]) membermanager_user_add, membermanager_user_del = \ gen_add_del_lists( membermanager_user, res_find.get("membermanager_user") ) membermanager_group_add, membermanager_group_del = \ gen_add_del_lists( membermanager_group, res_find.get("membermanager_group") ) if has_add_membermanager: # Add membermanager users and groups if len(membermanager_user_add) > 0 or \ len(membermanager_group_add) > 0: commands.append([ name, "hostgroup_add_member_manager", { "user": membermanager_user_add, "group": membermanager_group_add, } ]) # Remove member manager if len(membermanager_user_del) > 0 or \ len(membermanager_group_del) > 0: commands.append([ name, "hostgroup_remove_member_manager", { "user": membermanager_user_del, "group": membermanager_group_del, } ]) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No hostgroup '%s'" % name) # Ensure members are present commands.append([ name, "hostgroup_add_member", { "host": host, "hostgroup": hostgroup, } ]) if has_add_membermanager: # Add membermanager users and groups if membermanager_user is not None or \ membermanager_group is not None: commands.append([ name, "hostgroup_add_member_manager", { "user": membermanager_user, "group": membermanager_group, } ]) elif state == "renamed": if res_find is not None: if rename != name: commands.append( [name, "hostgroup_mod", { "rename": rename }]) else: # If a hostgroup with the desired name exists, do nothing. new_find = find_hostgroup(ansible_module, rename) if new_find is None: # Fail only if the either hostsgroups do not exist. ansible_module.fail_json( msg="Attribute `rename` can not be used, unless " "hostgroup exists.") elif state == "absent": if action == "hostgroup": if res_find is not None: commands.append([name, "hostgroup_del", {}]) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No hostgroup '%s'" % name) # Ensure members are absent commands.append([ name, "hostgroup_remove_member", { "host": host, "hostgroup": hostgroup, } ]) if has_add_membermanager: # Remove membermanager users and groups if membermanager_user is not None or \ membermanager_group is not None: commands.append([ name, "hostgroup_remove_member_manager", { "user": membermanager_user, "group": membermanager_group, } ]) 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 = api_command(ansible_module, 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)) except Exception as e: ansible_module.fail_json(msg=str(e)) finally: temp_kdestroy(ccache_dir, ccache_name) # Done ansible_module.exit_json(changed=changed, **exit_args)
def main(): ansible_module = AnsibleModule( argument_spec=dict( # general ipaadmin_principal=dict(type="str", default="admin"), ipaadmin_password=dict(type="str", required=False, no_log=True), name=dict(type="list", aliases=["cn"], default=None, required=True), # present description=dict(type="str", default=None), gid=dict(type="int", aliases=["gidnumber"], default=None), nonposix=dict(required=False, type='bool', default=None), external=dict(required=False, type='bool', default=None), posix=dict(required=False, type='bool', default=None), nomembers=dict(required=False, type='bool', default=None), user=dict(required=False, type='list', default=None), group=dict(required=False, type='list', default=None), service=dict(required=False, type='list', default=None), membermanager_user=dict(required=False, type='list', default=None), membermanager_group=dict(required=False, type='list', default=None), externalmember=dict( required=False, type='list', default=None, aliases=["ipaexternalmember", "external_member"]), action=dict(type="str", default="group", choices=["member", "group"]), # state state=dict(type="str", default="present", choices=["present", "absent"]), ), mutually_exclusive=[['posix', 'nonposix']], supports_check_mode=True, ) ansible_module._ansible_debug = True # Get parameters # general ipaadmin_principal = module_params_get( ansible_module, "ipaadmin_principal", ) ipaadmin_password = module_params_get(ansible_module, "ipaadmin_password") names = module_params_get(ansible_module, "name") # present description = module_params_get(ansible_module, "description") gid = module_params_get(ansible_module, "gid") nonposix = module_params_get(ansible_module, "nonposix") external = module_params_get(ansible_module, "external") posix = module_params_get(ansible_module, "posix") nomembers = module_params_get(ansible_module, "nomembers") user = module_params_get(ansible_module, "user") group = module_params_get(ansible_module, "group") service = module_params_get(ansible_module, "service") membermanager_user = module_params_get(ansible_module, "membermanager_user") membermanager_group = module_params_get(ansible_module, "membermanager_group") externalmember = module_params_get(ansible_module, "externalmember") action = module_params_get(ansible_module, "action") # state state = module_params_get(ansible_module, "state") # Check parameters if state == "present": if len(names) != 1: ansible_module.fail_json( msg="Only one group can be added at a time.") if action == "member": invalid = [ "description", "gid", "posix", "nonposix", "external", "nomembers" ] for x in invalid: if vars()[x] is not None: ansible_module.fail_json( msg="Argument '%s' can not be used with action " "'%s'" % (x, action)) if state == "absent": if len(names) < 1: ansible_module.fail_json(msg="No name given.") invalid = [ "description", "gid", "posix", "nonposix", "external", "nomembers" ] if action == "group": invalid.extend(["user", "group", "service", "externalmember"]) for x in invalid: if vars()[x] is not None: ansible_module.fail_json( msg="Argument '%s' can not be used with state '%s'" % (x, state)) # Init changed = False exit_args = {} ccache_dir = None ccache_name = None try: if not valid_creds(ansible_module, ipaadmin_principal): ccache_dir, ccache_name = temp_kinit(ipaadmin_principal, ipaadmin_password) api_connect() has_add_member_service = api_check_param("group_add_member", "service") if service is not None and not has_add_member_service: ansible_module.fail_json( msg="Managing a service as part of a group is not supported " "by your IPA version") has_add_membermanager = api_check_command("group_add_member_manager") if ((membermanager_user is not None or membermanager_group is not None) and not has_add_membermanager): ansible_module.fail_json( msg="Managing a membermanager user or group is not supported " "by your IPA version") commands = [] for name in names: # Make sure group exists res_find = find_group(ansible_module, name) # Create command if state == "present": # Can't change an existing posix group check_objectclass_args(ansible_module, res_find, nonposix, posix, external) # Generate args args = gen_args(description, gid, nomembers) if action == "group": # Found the group if res_find is not None: # For all settings is args, check if there are # different settings in the find result. # If yes: modify if should_modify_group(ansible_module, res_find, args, nonposix, posix, external): if (posix or (nonposix is not None and not nonposix)): args['posix'] = True if external: args['external'] = True commands.append([name, "group_mod", args]) else: if nonposix or (posix is not None and not posix): args['nonposix'] = True if external: args['external'] = True commands.append([name, "group_add", args]) # Set res_find dict for next step res_find = {} # if we just created/modified the group, update res_find res_find.setdefault("objectclass", []) if external and not is_external_group(res_find): res_find["objectclass"].append("ipaexternalgroup") if posix and not is_posix_group(res_find): res_find["objectclass"].append("posixgroup") member_args = gen_member_args(user, group, service, externalmember) if not compare_args_ipa(ansible_module, member_args, res_find): # Generate addition and removal lists user_add, user_del = gen_add_del_lists( user, res_find.get("member_user")) group_add, group_del = gen_add_del_lists( group, res_find.get("member_group")) service_add, service_del = gen_add_del_lists( service, res_find.get("member_service")) (externalmember_add, externalmember_del) = gen_add_del_lists( externalmember, res_find.get("member_external")) # setup member args for add/remove members. add_member_args = { "user": user_add, "group": group_add, } del_member_args = { "user": user_del, "group": group_del, } if has_add_member_service: add_member_args["service"] = service_add del_member_args["service"] = service_del if is_external_group(res_find): add_member_args["ipaexternalmember"] = \ externalmember_add del_member_args["ipaexternalmember"] = \ externalmember_del elif externalmember or external: ansible_module.fail_json( msg="Cannot add external members to a " "non-external group.") # Add members add_members = any([ user_add, group_add, service_add, externalmember_add ]) if add_members: commands.append( [name, "group_add_member", add_member_args]) # Remove members remove_members = any([ user_del, group_del, service_del, externalmember_del ]) if remove_members: commands.append( [name, "group_remove_member", del_member_args]) membermanager_user_add, membermanager_user_del = \ gen_add_del_lists( membermanager_user, res_find.get("membermanager_user") ) membermanager_group_add, membermanager_group_del = \ gen_add_del_lists( membermanager_group, res_find.get("membermanager_group") ) if has_add_membermanager: # Add membermanager users and groups if len(membermanager_user_add) > 0 or \ len(membermanager_group_add) > 0: commands.append([ name, "group_add_member_manager", { "user": membermanager_user_add, "group": membermanager_group_add, } ]) # Remove member manager if len(membermanager_user_del) > 0 or \ len(membermanager_group_del) > 0: commands.append([ name, "group_remove_member_manager", { "user": membermanager_user_del, "group": membermanager_group_del, } ]) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No group '%s'" % name) add_member_args = { "user": user, "group": group, } if has_add_member_service: add_member_args["service"] = service if is_external_group(res_find): add_member_args["ipaexternalmember"] = externalmember elif externalmember: ansible_module.fail_json( msg="Cannot add external members to a " "non-external group.") if any([user, group, service, externalmember]): commands.append( [name, "group_add_member", add_member_args]) if has_add_membermanager: # Add membermanager users and groups if membermanager_user is not None or \ membermanager_group is not None: commands.append([ name, "group_add_member_manager", { "user": membermanager_user, "group": membermanager_group, } ]) elif state == "absent": if action == "group": if res_find is not None: commands.append([name, "group_del", {}]) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No group '%s'" % name) del_member_args = { "user": user, "group": group, } if has_add_member_service: del_member_args["service"] = service if is_external_group(res_find): del_member_args["ipaexternalmember"] = externalmember elif externalmember: ansible_module.fail_json( msg="Cannot add external members to a " "non-external group.") if any([user, group, service, externalmember]): commands.append( [name, "group_remove_member", del_member_args]) if has_add_membermanager: # Remove membermanager users and groups if membermanager_user is not None or \ membermanager_group is not None: commands.append([ name, "group_remove_member_manager", { "user": membermanager_user, "group": membermanager_group, } ]) 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 = api_command(ansible_module, 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)) except Exception as e: ansible_module.fail_json(msg=str(e)) finally: temp_kdestroy(ccache_dir, ccache_name) # Done ansible_module.exit_json(changed=changed, **exit_args)