def main(): ansible_module = IPAAnsibleModule( argument_spec=dict( # general 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 names = ansible_module.params_get("name") # present description = ansible_module.params_get("description") nomembers = ansible_module.params_get("nomembers") host = ansible_module.params_get("host") hostgroup = ansible_module.params_get("hostgroup") membermanager_user = ansible_module.params_get("membermanager_user") membermanager_group = ansible_module.params_get("membermanager_group") rename = ansible_module.params_get("rename") action = ansible_module.params_get("action") # state state = ansible_module.params_get("state") # Check parameters invalid = [] 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"]) 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" ] 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"]) ansible_module.params_fail_used_invalid(invalid, state, action) # Init changed = False exit_args = {} # Connect to IPA API with ansible_module.ipa_connect(): has_add_membermanager = ansible_module.ipa_command_exists( "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 = ansible_module.ipa_command_param_exists( "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") # If hosts are given, ensure that the hosts are FQDN and also # lowercase to be able to do a proper comparison to exising hosts # in the hostgroup. # Fixes #666 (ipahostgroup not idempotent and with error) if host is not None: default_domain = ansible_module.ipa_get_domain() host = [ensure_fqdn(_host, default_domain).lower() for _host in host] 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) # Reduce add lists for member_host and member_hostgroup, # to new entries only that are not in res_find. if host is not None and "member_host" in res_find: host = gen_add_list(host, res_find["member_host"]) if hostgroup is not None \ and "member_hostgroup" in res_find: hostgroup = gen_add_list( hostgroup, res_find["member_hostgroup"]) # Ensure members are present commands.append([name, "hostgroup_add_member", { "host": host, "hostgroup": hostgroup, }]) if has_add_membermanager: # Reduce add list for membermanager_user and # membermanager_group to new entries only that are # not in res_find. if membermanager_user is not None \ and "membermanager_user" in res_find: membermanager_user = gen_add_list( membermanager_user, res_find["membermanager_user"]) if membermanager_group is not None \ and "membermanager_group" in res_find: membermanager_group = gen_add_list( membermanager_group, res_find["membermanager_group"]) # 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) # Reduce del lists of member_host and member_hostgroup, # to the entries only that are in res_find. if host is not None: host = gen_intersection_list( host, res_find.get("member_host")) if hostgroup is not None: hostgroup = gen_intersection_list( hostgroup, res_find.get("member_hostgroup")) # Ensure members are absent commands.append([name, "hostgroup_remove_member", { "host": host, "hostgroup": hostgroup, }]) if has_add_membermanager: # Reduce del lists of membermanager_user and # membermanager_group to the entries only that are # in res_find. if membermanager_user is not None: membermanager_user = gen_intersection_list( membermanager_user, res_find.get("membermanager_user")) if membermanager_group is not None: membermanager_group = gen_intersection_list( membermanager_group, res_find.get("membermanager_group")) # 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) # Execute commands changed = ansible_module.execute_ipa_commands( commands, fail_on_member_errors=True) # Done ansible_module.exit_json(changed=changed, **exit_args)
def main(): ansible_module = IPAAnsibleModule( argument_spec=dict( # general 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"]), ), # It does not make sense to set posix, nonposix or external at the # same time mutually_exclusive=[['posix', 'nonposix', 'external']], supports_check_mode=True, ) ansible_module._ansible_debug = True # Get parameters # general names = ansible_module.params_get("name") # present description = ansible_module.params_get("description") gid = ansible_module.params_get("gid") nonposix = ansible_module.params_get("nonposix") external = ansible_module.params_get("external") posix = ansible_module.params_get("posix") nomembers = ansible_module.params_get("nomembers") user = ansible_module.params_get("user") group = ansible_module.params_get("group") # Services are not case sensitive service = ansible_module.params_get_lowercase("service") membermanager_user = ansible_module.params_get("membermanager_user") membermanager_group = ansible_module.params_get("membermanager_group") externalmember = ansible_module.params_get("externalmember") action = ansible_module.params_get("action") # state state = ansible_module.params_get("state") # Check parameters invalid = [] 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" ] 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"]) ansible_module.params_fail_used_invalid(invalid, state, action) if external is False: ansible_module.fail_json(msg="group can not be non-external") # Init changed = False exit_args = {} # If nonposix is used, set posix as not nonposix if nonposix is not None: posix = not nonposix # Connect to IPA API with ansible_module.ipa_connect(): has_add_member_service = ansible_module.ipa_command_param_exists( "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 = ansible_module.ipa_command_exists( "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) user_add, user_del = [], [] group_add, group_del = [], [] service_add, service_del = [], [] externalmember_add, externalmember_del = [], [] membermanager_user_add, membermanager_user_del = [], [] membermanager_group_add, membermanager_group_del = [], [] # Create command if state == "present": # Can't change an existing posix group check_objectclass_args(ansible_module, res_find, 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 in args, check if there are # different settings in the find result. # If yes: modify # Also if it is a modification from nonposix to posix # or nonposix to external. if not compare_args_ipa( ansible_module, args, res_find) or ( not is_posix_group(res_find) and not is_external_group(res_find) and (posix or external)): if posix: args['posix'] = True if external: args['external'] = True commands.append([name, "group_mod", args]) else: if 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")) 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") ) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No group '%s'" % name) # Reduce add lists for member_user, member_group, # member_service and member_external to new entries # only that are not in res_find. user_add = gen_add_list(user, res_find.get("member_user")) group_add = gen_add_list(group, res_find.get("member_group")) service_add = gen_add_list(service, res_find.get("member_service")) externalmember_add = gen_add_list( externalmember, res_find.get("member_external")) membermanager_user_add = gen_add_list( membermanager_user, res_find.get("membermanager_user")) membermanager_group_add = gen_add_list( membermanager_group, res_find.get("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) if not is_external_group(res_find) and externalmember: ansible_module.fail_json( msg="Cannot add external members to a " "non-external group.") user_del = gen_intersection_list( user, res_find.get("member_user")) group_del = gen_intersection_list( group, res_find.get("member_group")) service_del = gen_intersection_list( service, res_find.get("member_service")) externalmember_del = gen_intersection_list( externalmember, res_find.get("member_external")) membermanager_user_del = gen_intersection_list( membermanager_user, res_find.get("membermanager_user")) membermanager_group_del = gen_intersection_list( membermanager_group, res_find.get("membermanager_group")) else: ansible_module.fail_json(msg="Unkown state '%s'" % state) # manage members # 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]) # manage membermanager members if has_add_membermanager: # Add membermanager users and groups if any([membermanager_user_add, membermanager_group_add]): commands.append([ name, "group_add_member_manager", { "user": membermanager_user_add, "group": membermanager_group_add, } ]) # Remove member manager if any([membermanager_user_del, membermanager_group_del]): commands.append([ name, "group_remove_member_manager", { "user": membermanager_user_del, "group": membermanager_group_del, } ]) # Execute commands changed = ansible_module.execute_ipa_commands( commands, fail_on_member_errors=True) # Done ansible_module.exit_json(changed=changed, **exit_args)