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.") # Reduce add lists for member_user, member_group, # member_service and member_external to new entries # only that are not in res_find. if user is not None and "member_user" in res_find: user = gen_add_list(user, res_find["member_user"]) if group is not None and "member_group" in res_find: group = gen_add_list(group, res_find["member_group"]) if service is not None and "member_service" in res_find: service = gen_add_list(service, res_find["member_service"]) if externalmember is not None \ and "member_external" in res_find: externalmember = gen_add_list( externalmember, res_find["member_external"]) if any([user, group, service, externalmember]): commands.append( [name, "group_add_member", add_member_args]) 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, "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.") # Reduce del lists of member_user, member_group, # member_service and member_external to the entries only # that are in res_find. if user is not None: user = gen_intersection_list( user, res_find.get("member_user")) if group is not None: group = gen_intersection_list( group, res_find.get("member_group")) if service is not None: service = gen_intersection_list( service, res_find.get("member_service")) if externalmember is not None: externalmember = gen_intersection_list( externalmember, res_find.get("member_external")) if any([user, group, service, externalmember]): commands.append( [name, "group_remove_member", del_member_args]) 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, "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 # 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)) 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 = IPAAnsibleModule( argument_spec=dict( # general name=dict(type="list", aliases=["cn"], default=None, required=True), # present description=dict(type="str", default=None), usercategory=dict(type="str", default=None, aliases=["usercat"], choices=["all", ""]), hostcategory=dict(type="str", default=None, aliases=["hostcat"], choices=["all", ""]), servicecategory=dict(type="str", default=None, aliases=["servicecat"], choices=["all", ""]), nomembers=dict(required=False, type='bool', default=None), host=dict(required=False, type='list', default=None), hostgroup=dict(required=False, type='list', default=None), hbacsvc=dict(required=False, type='list', default=None), hbacsvcgroup=dict(required=False, type='list', default=None), user=dict(required=False, type='list', default=None), group=dict(required=False, type='list', default=None), action=dict(type="str", default="hbacrule", choices=["member", "hbacrule"]), # state state=dict(type="str", default="present", choices=["present", "absent", "enabled", "disabled"]), ), 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") usercategory = ansible_module.params_get("usercategory") hostcategory = ansible_module.params_get("hostcategory") servicecategory = ansible_module.params_get("servicecategory") nomembers = ansible_module.params_get("nomembers") host = ansible_module.params_get_lowercase("host") hostgroup = ansible_module.params_get_lowercase("hostgroup") hbacsvc = ansible_module.params_get_lowercase("hbacsvc") hbacsvcgroup = ansible_module.params_get_lowercase("hbacsvcgroup") user = ansible_module.params_get_lowercase("user") group = ansible_module.params_get_lowercase("group") 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 hbacrule can be added at a time.") if action == "member": invalid = [ "description", "usercategory", "hostcategory", "servicecategory", "nomembers" ] else: if hostcategory == 'all' and any([host, hostgroup]): ansible_module.fail_json( msg="Hosts cannot be added when host category='all'") if usercategory == 'all' and any([user, group]): ansible_module.fail_json( msg="Users cannot be added when user category='all'") if servicecategory == 'all' and any([hbacsvc, hbacsvcgroup]): ansible_module.fail_json( msg="Services cannot be added when service category='all'") elif state == "absent": if len(names) < 1: ansible_module.fail_json(msg="No name given.") invalid = [ "description", "usercategory", "hostcategory", "servicecategory", "nomembers" ] if action == "hbacrule": invalid.extend([ "host", "hostgroup", "hbacsvc", "hbacsvcgroup", "user", "group" ]) elif state in ["enabled", "disabled"]: if len(names) < 1: ansible_module.fail_json(msg="No name given.") if action == "member": ansible_module.fail_json( msg="Action member can not be used with states enabled and " "disabled") invalid = [ "description", "usercategory", "hostcategory", "servicecategory", "nomembers", "host", "hostgroup", "hbacsvc", "hbacsvcgroup", "user", "group" ] else: ansible_module.fail_json(msg="Invalid state '%s'" % state) ansible_module.params_fail_used_invalid(invalid, state, action) # Init changed = False exit_args = {} # Connect to IPA API with ansible_module.ipa_connect(): # Get default domain default_domain = ansible_module.ipa_get_domain() # Ensure fqdn host names, use default domain for simple names if host is not None: _host = [ensure_fqdn(x, default_domain).lower() for x in host] host = _host commands = [] for name in names: # Make sure hbacrule exists res_find = find_hbacrule(ansible_module, name) host_add, host_del = [], [] hostgroup_add, hostgroup_del = [], [] hbacsvc_add, hbacsvc_del = [], [] hbacsvcgroup_add, hbacsvcgroup_del = [], [] user_add, user_del = [], [] group_add, group_del = [], [] # Create command if state == "present": # Generate args args = gen_args(description, usercategory, hostcategory, servicecategory, nomembers) if action == "hbacrule": # Found the hbacrule if res_find is not None: # Remove usercategory, hostcategory and # servicecategory from args if "" and category # not in res_find (needed for idempotency) if "usercategory" in args and \ args["usercategory"] == "" and \ "usercategory" not in res_find: del args["usercategory"] if "hostcategory" in args and \ args["hostcategory"] == "" and \ "hostcategory" not in res_find: del args["hostcategory"] if "servicecategory" in args and \ args["servicecategory"] == "" and \ "servicecategory" not in res_find: del args["servicecategory"] # 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, "hbacrule_mod", args]) else: commands.append([name, "hbacrule_add", args]) # Set res_find to empty dict for next step res_find = {} # Generate addition and removal lists if host is not None: host_add, host_del = gen_add_del_lists( host, res_find.get("memberhost_host")) if hostgroup is not None: hostgroup_add, hostgroup_del = gen_add_del_lists( hostgroup, res_find.get("memberhost_hostgroup")) if hbacsvc is not None: hbacsvc_add, hbacsvc_del = gen_add_del_lists( hbacsvc, res_find.get("memberservice_hbacsvc")) if hbacsvcgroup is not None: hbacsvcgroup_add, hbacsvcgroup_del = gen_add_del_lists( hbacsvcgroup, res_find.get("memberservice_hbacsvcgroup")) if user is not None: user_add, user_del = gen_add_del_lists( user, res_find.get("memberuser_user")) if group is not None: group_add, group_del = gen_add_del_lists( group, res_find.get("memberuser_group")) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No hbacrule '%s'" % name) # Generate add lists for host, hostgroup and # res_find to only try to add hosts and hostgroups # that not in hbacrule already if host: host_add = gen_add_list( host, res_find.get("memberhost_host")) if hostgroup: hostgroup_add = gen_add_list( hostgroup, res_find.get("memberhost_hostgroup")) # Generate add lists for hbacsvc, hbacsvcgroup and # res_find to only try to add hbacsvcs and hbacsvcgroups # that not in hbacrule already if hbacsvc: hbacsvc_add = gen_add_list( hbacsvc, res_find.get("memberservice_hbacsvc")) if hbacsvcgroup: hbacsvcgroup_add = gen_add_list( hbacsvcgroup, res_find.get("memberservice_hbacsvcgroup")) # Generate add lists for user, group and # res_find to only try to add users and groups # that not in hbacrule already if user: user_add = gen_add_list( user, res_find.get("memberuser_user")) if group: group_add = gen_add_list( group, res_find.get("memberuser_group")) elif state == "absent": if action == "hbacrule": if res_find is not None: commands.append([name, "hbacrule_del", {}]) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No hbacrule '%s'" % name) # Generate intersection lists for host, hostgroup and # res_find to only try to remove hosts and hostgroups # that are in hbacrule if host: if "memberhost_host" in res_find: host_del = gen_intersection_list( host, res_find["memberhost_host"]) if hostgroup: if "memberhost_hostgroup" in res_find: hostgroup_del = gen_intersection_list( hostgroup, res_find["memberhost_hostgroup"]) # Generate intersection lists for hbacsvc, hbacsvcgroup # and res_find to only try to remove hbacsvcs and # hbacsvcgroups that are in hbacrule if hbacsvc: if "memberservice_hbacsvc" in res_find: hbacsvc_del = gen_intersection_list( hbacsvc, res_find["memberservice_hbacsvc"]) if hbacsvcgroup: if "memberservice_hbacsvcgroup" in res_find: hbacsvcgroup_del = gen_intersection_list( hbacsvcgroup, res_find["memberservice_hbacsvcgroup"]) # Generate intersection lists for user, group and # res_find to only try to remove users and groups # that are in hbacrule if user: if "memberuser_user" in res_find: user_del = gen_intersection_list( user, res_find["memberuser_user"]) if group: if "memberuser_group" in res_find: group_del = gen_intersection_list( group, res_find["memberuser_group"]) elif state == "enabled": if res_find is None: ansible_module.fail_json(msg="No hbacrule '%s'" % name) # hbacrule_enable is not failing on an enabled hbacrule # Therefore it is needed to have a look at the ipaenabledflag # in res_find. if "ipaenabledflag" not in res_find or \ res_find["ipaenabledflag"][0] != "TRUE": commands.append([name, "hbacrule_enable", {}]) elif state == "disabled": if res_find is None: ansible_module.fail_json(msg="No hbacrule '%s'" % name) # hbacrule_disable is not failing on an disabled hbacrule # Therefore it is needed to have a look at the ipaenabledflag # in res_find. if "ipaenabledflag" not in res_find or \ res_find["ipaenabledflag"][0] != "FALSE": commands.append([name, "hbacrule_disable", {}]) else: ansible_module.fail_json(msg="Unkown state '%s'" % state) # Manage HBAC rule members. # Add hosts and hostgroups if len(host_add) > 0 or len(hostgroup_add) > 0: commands.append([ name, "hbacrule_add_host", { "host": host_add, "hostgroup": hostgroup_add, } ]) # Remove hosts and hostgroups if len(host_del) > 0 or len(hostgroup_del) > 0: commands.append([ name, "hbacrule_remove_host", { "host": host_del, "hostgroup": hostgroup_del, } ]) # Add hbacsvcs and hbacsvcgroups if len(hbacsvc_add) > 0 or len(hbacsvcgroup_add) > 0: commands.append([ name, "hbacrule_add_service", { "hbacsvc": hbacsvc_add, "hbacsvcgroup": hbacsvcgroup_add, } ]) # Remove hbacsvcs and hbacsvcgroups if len(hbacsvc_del) > 0 or len(hbacsvcgroup_del) > 0: commands.append([ name, "hbacrule_remove_service", { "hbacsvc": hbacsvc_del, "hbacsvcgroup": hbacsvcgroup_del, } ]) # Add users and groups if len(user_add) > 0 or len(group_add) > 0: commands.append([ name, "hbacrule_add_user", { "user": user_add, "group": group_add, } ]) # Remove users and groups if len(user_del) > 0 or len(group_del) > 0: commands.append([ name, "hbacrule_remove_user", { "user": user_del, "group": 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)
def main(): ansible_module = IPAAnsibleModule( argument_spec=dict( # general name=dict(type="list", aliases=["cn"], default=None, required=True), # present description=dict(required=False, type="str", default=None), usercategory=dict(required=False, type="str", default=None, choices=["all", ""], aliases=['usercat']), hostcategory=dict(required=False, type="str", default=None, choices=["all", ""], aliases=['hostcat']), nomembers=dict(required=False, type='bool', default=None), host=dict(required=False, type='list', default=None), hostgroup=dict(required=False, type='list', default=None), user=dict(required=False, type='list', default=None), group=dict(required=False, type='list', default=None), allow_sudocmd=dict(required=False, type="list", default=None), deny_sudocmd=dict(required=False, type="list", default=None), allow_sudocmdgroup=dict(required=False, type="list", default=None), deny_sudocmdgroup=dict(required=False, type="list", default=None), cmdcategory=dict(required=False, type="str", default=None, choices=["all", ""], aliases=['cmdcat']), runasusercategory=dict(required=False, type="str", default=None, choices=["all", ""], aliases=['runasusercat']), runasgroupcategory=dict(required=False, type="str", default=None, choices=["all", ""], aliases=['runasgroupcat']), runasuser=dict(required=False, type="list", default=None), runasgroup=dict(required=False, type="list", default=None), order=dict(type="int", required=False, aliases=['sudoorder']), sudooption=dict(required=False, type='list', default=None, aliases=["options"]), action=dict(type="str", default="sudorule", choices=["member", "sudorule"]), # state state=dict(type="str", default="present", choices=["present", "absent", "enabled", "disabled"]), ), supports_check_mode=True, ) ansible_module._ansible_debug = True # Get parameters # general names = ansible_module.params_get("name") # present # The 'noqa' variables are not used here, but required for vars(). # The use of 'noqa' ensures flake8 does not complain about them. description = ansible_module.params_get("description") # noqa cmdcategory = ansible_module.params_get('cmdcategory') # noqa usercategory = ansible_module.params_get("usercategory") # noqa hostcategory = ansible_module.params_get("hostcategory") # noqa runasusercategory = ansible_module.params_get( # noqa "runasusercategory") runasgroupcategory = ansible_module.params_get( # noqa "runasgroupcategory") hostcategory = ansible_module.params_get("hostcategory") # noqa nomembers = ansible_module.params_get("nomembers") # noqa host = ansible_module.params_get("host") hostgroup = ansible_module.params_get("hostgroup") user = ansible_module.params_get("user") group = ansible_module.params_get("group") allow_sudocmd = ansible_module.params_get('allow_sudocmd') allow_sudocmdgroup = ansible_module.params_get('allow_sudocmdgroup') deny_sudocmd = ansible_module.params_get('deny_sudocmd') deny_sudocmdgroup = ansible_module.params_get('deny_sudocmdgroup') sudooption = ansible_module.params_get("sudooption") order = ansible_module.params_get("order") runasuser = ansible_module.params_get("runasuser") runasgroup = ansible_module.params_get("runasgroup") action = ansible_module.params_get("action") # state state = ansible_module.params_get("state") # Check parameters if state == "present": if len(names) != 1: ansible_module.fail_json( msg="Only one sudorule can be added at a time.") if action == "member": invalid = ["description", "usercategory", "hostcategory", "cmdcategory", "runasusercategory", "runasgroupcategory", "order", "nomembers"] for arg in invalid: if arg in vars() and vars()[arg] is not None: ansible_module.fail_json( msg="Argument '%s' can not be used with action " "'%s'" % (arg, action)) else: if hostcategory == 'all' and any([host, hostgroup]): ansible_module.fail_json( msg="Hosts cannot be added when host category='all'") if usercategory == 'all' and any([user, group]): ansible_module.fail_json( msg="Users cannot be added when user category='all'") if cmdcategory == 'all' \ and any([allow_sudocmd, allow_sudocmdgroup]): ansible_module.fail_json( msg="Commands cannot be added when command category='all'") elif state == "absent": if len(names) < 1: ansible_module.fail_json(msg="No name given.") invalid = ["description", "usercategory", "hostcategory", "cmdcategory", "runasusercategory", "runasgroupcategory", "nomembers", "order"] if action == "sudorule": invalid.extend(["host", "hostgroup", "user", "group", "runasuser", "runasgroup", "allow_sudocmd", "allow_sudocmdgroup", "deny_sudocmd", "deny_sudocmdgroup", "sudooption"]) for arg in invalid: if vars()[arg] is not None: ansible_module.fail_json( msg="Argument '%s' can not be used with state '%s'" % (arg, state)) elif state in ["enabled", "disabled"]: if len(names) < 1: ansible_module.fail_json(msg="No name given.") if action == "member": ansible_module.fail_json( msg="Action member can not be used with states enabled and " "disabled") invalid = ["description", "usercategory", "hostcategory", "cmdcategory", "runasusercategory", "runasgroupcategory", "nomembers", "nomembers", "host", "hostgroup", "user", "group", "allow_sudocmd", "allow_sudocmdgroup", "deny_sudocmd", "deny_sudocmdgroup", "runasuser", "runasgroup", "order", "sudooption"] for arg in invalid: if vars()[arg] is not None: ansible_module.fail_json( msg="Argument '%s' can not be used with state '%s'" % (arg, state)) else: ansible_module.fail_json(msg="Invalid state '%s'" % state) # Init changed = False exit_args = {} # Connect to IPA API with ansible_module.ipa_connect(): commands = [] for name in names: # Make sure sudorule exists res_find = find_sudorule(ansible_module, name) # Create command if state == "present": # Generate args args = gen_args(description, usercategory, hostcategory, cmdcategory, runasusercategory, runasgroupcategory, order, nomembers) if action == "sudorule": # Found the sudorule if res_find is not None: # Remove empty usercategory, hostcategory, # cmdcaterory, runasusercategory and hostcategory # from args if "" and if the category is not in the # sudorule. The empty string is used to reset the # category. if "usercategory" in args \ and args["usercategory"] == "" \ and "usercategory" not in res_find: del args["usercategory"] if "hostcategory" in args \ and args["hostcategory"] == "" \ and "hostcategory" not in res_find: del args["hostcategory"] if "cmdcategory" in args \ and args["cmdcategory"] == "" \ and "cmdcategory" not in res_find: del args["cmdcategory"] if "ipasudorunasusercategory" in args \ and args["ipasudorunasusercategory"] == "" \ and "ipasudorunasusercategory" not in res_find: del args["ipasudorunasusercategory"] if "ipasudorunasgroupcategory" in args \ and args["ipasudorunasgroupcategory"] == "" \ and "ipasudorunasgroupcategory" not in res_find: del args["ipasudorunasgroupcategory"] # 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, "sudorule_mod", args]) else: commands.append([name, "sudorule_add", args]) # Set res_find to empty dict for next step res_find = {} # Generate addition and removal lists host_add, host_del = gen_add_del_lists( host, res_find.get('memberhost_host', [])) hostgroup_add, hostgroup_del = gen_add_del_lists( hostgroup, res_find.get('memberhost_hostgroup', [])) user_add, user_del = gen_add_del_lists( user, res_find.get('memberuser_user', [])) group_add, group_del = gen_add_del_lists( group, res_find.get('memberuser_group', [])) allow_cmd_add, allow_cmd_del = gen_add_del_lists( allow_sudocmd, res_find.get('memberallowcmd_sudocmd', [])) allow_cmdgroup_add, allow_cmdgroup_del = gen_add_del_lists( allow_sudocmdgroup, res_find.get('memberallowcmd_sudocmdgroup', [])) deny_cmd_add, deny_cmd_del = gen_add_del_lists( deny_sudocmd, res_find.get('memberdenycmd_sudocmd', [])) deny_cmdgroup_add, deny_cmdgroup_del = gen_add_del_lists( deny_sudocmdgroup, res_find.get('memberdenycmd_sudocmdgroup', [])) sudooption_add, sudooption_del = gen_add_del_lists( sudooption, res_find.get('ipasudoopt', [])) runasuser_add, runasuser_del = gen_add_del_lists( runasuser, res_find.get('ipasudorunas_user', [])) runasgroup_add, runasgroup_del = gen_add_del_lists( runasgroup, res_find.get('ipasudorunas_group', [])) # Add hosts and hostgroups if len(host_add) > 0 or len(hostgroup_add) > 0: commands.append([name, "sudorule_add_host", { "host": host_add, "hostgroup": hostgroup_add, }]) # Remove hosts and hostgroups if len(host_del) > 0 or len(hostgroup_del) > 0: commands.append([name, "sudorule_remove_host", { "host": host_del, "hostgroup": hostgroup_del, }]) # Add users and groups if len(user_add) > 0 or len(group_add) > 0: commands.append([name, "sudorule_add_user", { "user": user_add, "group": group_add, }]) # Remove users and groups if len(user_del) > 0 or len(group_del) > 0: commands.append([name, "sudorule_remove_user", { "user": user_del, "group": group_del, }]) # Add commands allowed if len(allow_cmd_add) > 0 or len(allow_cmdgroup_add) > 0: commands.append([name, "sudorule_add_allow_command", {"sudocmd": allow_cmd_add, "sudocmdgroup": allow_cmdgroup_add, }]) if len(allow_cmd_del) > 0 or len(allow_cmdgroup_del) > 0: commands.append([name, "sudorule_remove_allow_command", {"sudocmd": allow_cmd_del, "sudocmdgroup": allow_cmdgroup_del }]) # Add commands denied if len(deny_cmd_add) > 0 or len(deny_cmdgroup_add) > 0: commands.append([name, "sudorule_add_deny_command", {"sudocmd": deny_cmd_add, "sudocmdgroup": deny_cmdgroup_add, }]) if len(deny_cmd_del) > 0 or len(deny_cmdgroup_del) > 0: commands.append([name, "sudorule_remove_deny_command", {"sudocmd": deny_cmd_del, "sudocmdgroup": deny_cmdgroup_del }]) # Add RunAS Users if len(runasuser_add) > 0: commands.append([name, "sudorule_add_runasuser", {"user": runasuser_add}]) # Remove RunAS Users if len(runasuser_del) > 0: commands.append([name, "sudorule_remove_runasuser", {"user": runasuser_del}]) # Add RunAS Groups if len(runasgroup_add) > 0: commands.append([name, "sudorule_add_runasgroup", {"group": runasgroup_add}]) # Remove RunAS Groups if len(runasgroup_del) > 0: commands.append([name, "sudorule_remove_runasgroup", {"group": runasgroup_del}]) # Add sudo options for sudoopt in sudooption_add: commands.append([name, "sudorule_add_option", {"ipasudoopt": sudoopt}]) # Remove sudo options for sudoopt in sudooption_del: commands.append([name, "sudorule_remove_option", {"ipasudoopt": sudoopt}]) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No sudorule '%s'" % name) # Generate add lists for host, hostgroup, user, group, # allow_sudocmd, allow_sudocmdgroup, deny_sudocmd, # deny_sudocmdgroup, sudooption, runasuser, runasgroup # and res_find to only try to add the items that not in # the sudorule already if host is not None and \ "memberhost_host" in res_find: host = gen_add_list( host, res_find["memberhost_host"]) if hostgroup is not None and \ "memberhost_hostgroup" in res_find: hostgroup = gen_add_list( hostgroup, res_find["memberhost_hostgroup"]) if user is not None and \ "memberuser_user" in res_find: user = gen_add_list( user, res_find["memberuser_user"]) if group is not None and \ "memberuser_group" in res_find: group = gen_add_list( group, res_find["memberuser_group"]) if allow_sudocmd is not None and \ "memberallowcmd_sudocmd" in res_find: allow_sudocmd = gen_add_list( allow_sudocmd, res_find["memberallowcmd_sudocmd"]) if allow_sudocmdgroup is not None and \ "memberallowcmd_sudocmdgroup" in res_find: allow_sudocmdgroup = gen_add_list( allow_sudocmdgroup, res_find["memberallowcmd_sudocmdgroup"]) if deny_sudocmd is not None and \ "memberdenycmd_sudocmd" in res_find: deny_sudocmd = gen_add_list( deny_sudocmd, res_find["memberdenycmd_sudocmd"]) if deny_sudocmdgroup is not None and \ "memberdenycmd_sudocmdgroup" in res_find: deny_sudocmdgroup = gen_add_list( deny_sudocmdgroup, res_find["memberdenycmd_sudocmdgroup"]) if sudooption is not None and \ "ipasudoopt" in res_find: sudooption = gen_add_list( sudooption, res_find["ipasudoopt"]) if runasuser is not None and \ "ipasudorunas_user" in res_find: runasuser = gen_add_list( runasuser, res_find["ipasudorunas_user"]) if runasgroup is not None and \ "ipasudorunasgroup_group" in res_find: runasgroup = gen_add_list( runasgroup, res_find["ipasudorunasgroup_group"]) # Add hosts and hostgroups if host is not None or hostgroup is not None: commands.append([name, "sudorule_add_host", { "host": host, "hostgroup": hostgroup, }]) # Add users and groups if user is not None or group is not None: commands.append([name, "sudorule_add_user", { "user": user, "group": group, }]) # Add commands if allow_sudocmd is not None \ or allow_sudocmdgroup is not None: commands.append([name, "sudorule_add_allow_command", {"sudocmd": allow_sudocmd, "sudocmdgroup": allow_sudocmdgroup, }]) # Add commands if deny_sudocmd is not None \ or deny_sudocmdgroup is not None: commands.append([name, "sudorule_add_deny_command", {"sudocmd": deny_sudocmd, "sudocmdgroup": deny_sudocmdgroup, }]) # Add RunAS Users if runasuser is not None and len(runasuser) > 0: commands.append([name, "sudorule_add_runasuser", {"user": runasuser}]) # Add RunAS Groups if runasgroup is not None and len(runasgroup) > 0: commands.append([name, "sudorule_add_runasgroup", {"group": runasgroup}]) # Add options if sudooption is not None: existing_opts = res_find.get('ipasudoopt', []) for sudoopt in sudooption: if sudoopt not in existing_opts: commands.append([name, "sudorule_add_option", {"ipasudoopt": sudoopt}]) elif state == "absent": if action == "sudorule": if res_find is not None: commands.append([name, "sudorule_del", {}]) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No sudorule '%s'" % name) # Generate intersection lists for host, hostgroup, user, # group, allow_sudocmd, allow_sudocmdgroup, deny_sudocmd # deny_sudocmdgroup, sudooption, runasuser, runasgroup # and res_find to only try to remove the items that are # in sudorule if host is not None: if "memberhost_host" in res_find: host = gen_intersection_list( host, res_find["memberhost_host"]) else: host = None if hostgroup is not None: if "memberhost_hostgroup" in res_find: hostgroup = gen_intersection_list( hostgroup, res_find["memberhost_hostgroup"]) else: hostgroup = None if user is not None: if "memberuser_user" in res_find: user = gen_intersection_list( user, res_find["memberuser_user"]) else: user = None if group is not None: if "memberuser_group" in res_find: group = gen_intersection_list( group, res_find["memberuser_group"]) else: group = None if allow_sudocmd is not None: if "memberallowcmd_sudocmd" in res_find: allow_sudocmd = gen_intersection_list( allow_sudocmd, res_find["memberallowcmd_sudocmd"]) else: allow_sudocmd = None if allow_sudocmdgroup is not None: if "memberallowcmd_sudocmdgroup" in res_find: allow_sudocmdgroup = gen_intersection_list( allow_sudocmdgroup, res_find["memberallowcmd_sudocmdgroup"]) else: allow_sudocmdgroup = None if deny_sudocmd is not None: if "memberdenycmd_sudocmd" in res_find: deny_sudocmd = gen_intersection_list( deny_sudocmd, res_find["memberdenycmd_sudocmd"]) else: deny_sudocmd = None if deny_sudocmdgroup is not None: if "memberdenycmd_sudocmdgroup" in res_find: deny_sudocmdgroup = gen_intersection_list( deny_sudocmdgroup, res_find["memberdenycmd_sudocmdgroup"]) else: deny_sudocmdgroup = None if sudooption is not None: if "ipasudoopt" in res_find: sudooption = gen_intersection_list( sudooption, res_find["ipasudoopt"]) else: sudooption = None if runasuser is not None: if "ipasudorunas_user" in res_find: runasuser = gen_intersection_list( runasuser, res_find["ipasudorunas_user"]) else: runasuser = None if runasgroup is not None: if "ipasudorunasgroup_group" in res_find: runasgroup = gen_intersection_list( runasgroup, res_find["ipasudorunasgroup_group"]) else: runasgroup = None # Remove hosts and hostgroups if host is not None or hostgroup is not None: commands.append([name, "sudorule_remove_host", { "host": host, "hostgroup": hostgroup, }]) # Remove users and groups if user is not None or group is not None: commands.append([name, "sudorule_remove_user", { "user": user, "group": group, }]) # Remove allow commands if allow_sudocmd is not None \ or allow_sudocmdgroup is not None: commands.append([name, "sudorule_remove_allow_command", {"sudocmd": allow_sudocmd, "sudocmdgroup": allow_sudocmdgroup }]) # Remove deny commands if deny_sudocmd is not None \ or deny_sudocmdgroup is not None: commands.append([name, "sudorule_remove_deny_command", {"sudocmd": deny_sudocmd, "sudocmdgroup": deny_sudocmdgroup }]) # Remove RunAS Users if runasuser is not None: commands.append([name, "sudorule_remove_runasuser", {"user": runasuser}]) # Remove RunAS Groups if runasgroup is not None: commands.append([name, "sudorule_remove_runasgroup", {"group": runasgroup}]) # Remove options if sudooption is not None: existing_opts = res_find.get('ipasudoopt', []) for sudoopt in sudooption: if sudoopt in existing_opts: commands.append([name, "sudorule_remove_option", {"ipasudoopt": sudoopt}]) elif state == "enabled": if res_find is None: ansible_module.fail_json(msg="No sudorule '%s'" % name) # sudorule_enable is not failing on an enabled sudorule # Therefore it is needed to have a look at the ipaenabledflag # in res_find. if "ipaenabledflag" not in res_find or \ res_find["ipaenabledflag"][0] != "TRUE": commands.append([name, "sudorule_enable", {}]) elif state == "disabled": if res_find is None: ansible_module.fail_json(msg="No sudorule '%s'" % name) # sudorule_disable is not failing on an disabled sudorule # Therefore it is needed to have a look at the ipaenabledflag # in res_find. if "ipaenabledflag" not in res_find or \ res_find["ipaenabledflag"][0] != "FALSE": commands.append([name, "sudorule_disable", {}]) 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), 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), nomembers=dict(required=False, type='bool', default=None), hbacsvc=dict(required=False, type='list', default=None), action=dict(type="str", default="hbacsvcgroup", choices=["member", "hbacsvcgroup"]), # state state=dict(type="str", default="present", choices=["present", "absent"]), ), 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") hbacsvc = ansible_module.params_get_lowercase("hbacsvc") 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 hbacsvcgroup can be added at a time.") if action == "member": invalid = ["description", "nomembers"] if state == "absent": if len(names) < 1: ansible_module.fail_json(msg="No name given.") invalid = ["description", "nomembers"] if action == "hbacsvcgroup": invalid.extend(["hbacsvc"]) ansible_module.params_fail_used_invalid(invalid, state, action) # Init changed = False exit_args = {} # Connect to IPA API with ansible_module.ipa_connect(): commands = [] for name in names: # Make sure hbacsvcgroup exists res_find = find_hbacsvcgroup(ansible_module, name) hbacsvc_add, hbacsvc_del = [], [] # Create command if state == "present": # Generate args args = gen_args(description, nomembers) if action == "hbacsvcgroup": # Found the hbacsvcgroup 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, "hbacsvcgroup_mod", args]) else: commands.append([name, "hbacsvcgroup_add", args]) # Set res_find to empty dict for next step res_find = {} member_args = gen_member_args(hbacsvc) if not compare_args_ipa(ansible_module, member_args, res_find): # Generate addition and removal lists if hbacsvc is not None: hbacsvc_add, hbacsvc_del = gen_add_del_lists( hbacsvc, res_find.get("member_hbacsvc")) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No hbacsvcgroup '%s'" % name) # Ensure members are present if hbacsvc: hbacsvc_add = gen_add_list( hbacsvc, res_find.get("member_hbacsvc")) elif state == "absent": if action == "hbacsvcgroup": if res_find is not None: commands.append([name, "hbacsvcgroup_del", {}]) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No hbacsvcgroup '%s'" % name) # Ensure members are absent if hbacsvc: hbacsvc_del = gen_intersection_list( hbacsvc, res_find.get("member_hbacsvc")) else: ansible_module.fail_json(msg="Unkown state '%s'" % state) # Manage members if len(hbacsvc_add) > 0: commands.append([ name, "hbacsvcgroup_add_member", { "hbacsvc": hbacsvc_add } ]) # Remove members if len(hbacsvc_del) > 0: commands.append([ name, "hbacsvcgroup_remove_member", { "hbacsvc": hbacsvc_del } ]) # Execute commands changed = ansible_module.execute_ipa_commands(commands, result_handler) # 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), usercategory=dict(type="str", default=None, aliases=["usercat"], choices=["all", ""]), hostcategory=dict(type="str", default=None, aliases=["hostcat"], choices=["all", ""]), servicecategory=dict(type="str", default=None, aliases=["servicecat"], choices=["all", ""]), nomembers=dict(required=False, type='bool', default=None), host=dict(required=False, type='list', default=None), hostgroup=dict(required=False, type='list', default=None), hbacsvc=dict(required=False, type='list', default=None), hbacsvcgroup=dict(required=False, type='list', default=None), user=dict(required=False, type='list', default=None), group=dict(required=False, type='list', default=None), action=dict(type="str", default="hbacrule", choices=["member", "hbacrule"]), # state state=dict(type="str", default="present", choices=["present", "absent", "enabled", "disabled"]), ), 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") usercategory = module_params_get(ansible_module, "usercategory") hostcategory = module_params_get(ansible_module, "hostcategory") servicecategory = module_params_get(ansible_module, "servicecategory") nomembers = module_params_get(ansible_module, "nomembers") host = module_params_get(ansible_module, "host") hostgroup = module_params_get(ansible_module, "hostgroup") hbacsvc = module_params_get(ansible_module, "hbacsvc") hbacsvcgroup = module_params_get(ansible_module, "hbacsvcgroup") user = module_params_get(ansible_module, "user") group = module_params_get(ansible_module, "group") 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 hbacrule can be added at a time.") if action == "member": invalid = ["description", "usercategory", "hostcategory", "servicecategory", "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)) else: if hostcategory == 'all' and any([host, hostgroup]): ansible_module.fail_json( msg="Hosts cannot be added when host category='all'") if usercategory == 'all' and any([user, group]): ansible_module.fail_json( msg="Users cannot be added when user category='all'") if servicecategory == 'all' and any([hbacsvc, hbacsvcgroup]): ansible_module.fail_json( msg="Services cannot be added when service category='all'") elif state == "absent": if len(names) < 1: ansible_module.fail_json(msg="No name given.") invalid = ["description", "usercategory", "hostcategory", "servicecategory", "nomembers"] if action == "hbacrule": invalid.extend(["host", "hostgroup", "hbacsvc", "hbacsvcgroup", "user", "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)) elif state in ["enabled", "disabled"]: if len(names) < 1: ansible_module.fail_json(msg="No name given.") if action == "member": ansible_module.fail_json( msg="Action member can not be used with states enabled and " "disabled") invalid = ["description", "usercategory", "hostcategory", "servicecategory", "nomembers", "host", "hostgroup", "hbacsvc", "hbacsvcgroup", "user", "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)) else: ansible_module.fail_json(msg="Invalid state '%s'" % 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() # Get default domain default_domain = api_get_domain() # Ensure fqdn host names, use default domain for simple names if host is not None: _host = [ensure_fqdn(x, default_domain) for x in host] host = _host commands = [] for name in names: # Make sure hbacrule exists res_find = find_hbacrule(ansible_module, name) # Create command if state == "present": # Generate args args = gen_args(description, usercategory, hostcategory, servicecategory, nomembers) if action == "hbacrule": # Found the hbacrule if res_find is not None: # Remove usercategory, hostcategory and # servicecategory from args if "" and category # not in res_find (needed for idempotency) if "usercategory" in args and \ args["usercategory"] == "" and \ "usercategory" not in res_find: del args["usercategory"] if "hostcategory" in args and \ args["hostcategory"] == "" and \ "hostcategory" not in res_find: del args["hostcategory"] if "servicecategory" in args and \ args["servicecategory"] == "" and \ "servicecategory" not in res_find: del args["servicecategory"] # 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, "hbacrule_mod", args]) else: commands.append([name, "hbacrule_add", args]) # Set res_find to empty dict for next step res_find = {} # Generate addition and removal lists host_add, host_del = gen_add_del_lists( host, res_find.get("memberhost_host")) hostgroup_add, hostgroup_del = gen_add_del_lists( hostgroup, res_find.get("memberhost_hostgroup")) hbacsvc_add, hbacsvc_del = gen_add_del_lists( hbacsvc, res_find.get("memberservice_hbacsvc")) hbacsvcgroup_add, hbacsvcgroup_del = gen_add_del_lists( hbacsvcgroup, res_find.get("memberservice_hbacsvcgroup")) user_add, user_del = gen_add_del_lists( user, res_find.get("memberuser_user")) group_add, group_del = gen_add_del_lists( group, res_find.get("memberuser_group")) # Add hosts and hostgroups if len(host_add) > 0 or len(hostgroup_add) > 0: commands.append([name, "hbacrule_add_host", { "host": host_add, "hostgroup": hostgroup_add, }]) # Remove hosts and hostgroups if len(host_del) > 0 or len(hostgroup_del) > 0: commands.append([name, "hbacrule_remove_host", { "host": host_del, "hostgroup": hostgroup_del, }]) # Add hbacsvcs and hbacsvcgroups if len(hbacsvc_add) > 0 or len(hbacsvcgroup_add) > 0: commands.append([name, "hbacrule_add_service", { "hbacsvc": hbacsvc_add, "hbacsvcgroup": hbacsvcgroup_add, }]) # Remove hbacsvcs and hbacsvcgroups if len(hbacsvc_del) > 0 or len(hbacsvcgroup_del) > 0: commands.append([name, "hbacrule_remove_service", { "hbacsvc": hbacsvc_del, "hbacsvcgroup": hbacsvcgroup_del, }]) # Add users and groups if len(user_add) > 0 or len(group_add) > 0: commands.append([name, "hbacrule_add_user", { "user": user_add, "group": group_add, }]) # Remove users and groups if len(user_del) > 0 or len(group_del) > 0: commands.append([name, "hbacrule_remove_user", { "user": user_del, "group": group_del, }]) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No hbacrule '%s'" % name) # Generate add lists for host, hostgroup and # res_find to only try to add hosts and hostgroups # that not in hbacrule already if host is not None and \ "memberhost_host" in res_find: host = gen_add_list( host, res_find["memberhost_host"]) if hostgroup is not None and \ "memberhost_hostgroup" in res_find: hostgroup = gen_add_list( hostgroup, res_find["memberhost_hostgroup"]) # Add hosts and hostgroups if host is not None or hostgroup is not None: commands.append([name, "hbacrule_add_host", { "host": host, "hostgroup": hostgroup, }]) # Generate add lists for hbacsvc, hbacsvcgroup and # res_find to only try to add hbacsvcs and hbacsvcgroups # that not in hbacrule already if hbacsvc is not None and \ "memberservice_hbacsvc" in res_find: hbacsvc = gen_add_list( hbacsvc, res_find["memberservice_hbacsvc"]) if hbacsvcgroup is not None and \ "memberservice_hbacsvcgroup" in res_find: hbacsvcgroup = gen_add_list( hbacsvcgroup, res_find["memberservice_hbacsvcgroup"]) # Add hbacsvcs and hbacsvcgroups if hbacsvc is not None or hbacsvcgroup is not None: commands.append([name, "hbacrule_add_service", { "hbacsvc": hbacsvc, "hbacsvcgroup": hbacsvcgroup, }]) # Generate add lists for user, group and # res_find to only try to add users and groups # that not in hbacrule already if user is not None and \ "memberuser_user" in res_find: user = gen_add_list( user, res_find["memberuser_user"]) if group is not None and \ "memberuser_group" in res_find: group = gen_add_list( group, res_find["memberuser_group"]) # Add users and groups if user is not None or group is not None: commands.append([name, "hbacrule_add_user", { "user": user, "group": group, }]) elif state == "absent": if action == "hbacrule": if res_find is not None: commands.append([name, "hbacrule_del", {}]) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No hbacrule '%s'" % name) # Generate intersection lists for host, hostgroup and # res_find to only try to remove hosts and hostgroups # that are in hbacrule if host is not None: if "memberhost_host" in res_find: host = gen_intersection_list( host, res_find["memberhost_host"]) else: host = None if hostgroup is not None: if "memberhost_hostgroup" in res_find: hostgroup = gen_intersection_list( hostgroup, res_find["memberhost_hostgroup"]) else: hostgroup = None # Remove hosts and hostgroups if host is not None or hostgroup is not None: commands.append([name, "hbacrule_remove_host", { "host": host, "hostgroup": hostgroup, }]) # Generate intersection lists for hbacsvc, hbacsvcgroup # and res_find to only try to remove hbacsvcs and # hbacsvcgroups that are in hbacrule if hbacsvc is not None: if "memberservice_hbacsvc" in res_find: hbacsvc = gen_intersection_list( hbacsvc, res_find["memberservice_hbacsvc"]) else: hbacsvc = None if hbacsvcgroup is not None: if "memberservice_hbacsvcgroup" in res_find: hbacsvcgroup = gen_intersection_list( hbacsvcgroup, res_find["memberservice_hbacsvcgroup"]) else: hbacsvcgroup = None # Remove hbacsvcs and hbacsvcgroups if hbacsvc is not None or hbacsvcgroup is not None: commands.append([name, "hbacrule_remove_service", { "hbacsvc": hbacsvc, "hbacsvcgroup": hbacsvcgroup, }]) # Generate intersection lists for user, group and # res_find to only try to remove users and groups # that are in hbacrule if user is not None: if "memberuser_user" in res_find: user = gen_intersection_list( user, res_find["memberuser_user"]) else: user = None if group is not None: if "memberuser_group" in res_find: group = gen_intersection_list( group, res_find["memberuser_group"]) else: group = None # Remove users and groups if user is not None or group is not None: commands.append([name, "hbacrule_remove_user", { "user": user, "group": group, }]) elif state == "enabled": if res_find is None: ansible_module.fail_json(msg="No hbacrule '%s'" % name) # hbacrule_enable is not failing on an enabled hbacrule # Therefore it is needed to have a look at the ipaenabledflag # in res_find. if "ipaenabledflag" not in res_find or \ res_find["ipaenabledflag"][0] != "TRUE": commands.append([name, "hbacrule_enable", {}]) elif state == "disabled": if res_find is None: ansible_module.fail_json(msg="No hbacrule '%s'" % name) # hbacrule_disable is not failing on an disabled hbacrule # Therefore it is needed to have a look at the ipaenabledflag # in res_find. if "ipaenabledflag" not in res_find or \ res_find["ipaenabledflag"][0] != "FALSE": commands.append([name, "hbacrule_disable", {}]) 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 = 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 # 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)) 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 = IPAAnsibleModule( argument_spec=dict( # general name=dict(type="list", aliases=["cn"], default=None, required=True), # present principal=dict(required=False, type='list', default=None), target=dict(required=False, type='list', aliases=["servicedelegationtarget"], default=None), action=dict(type="str", default="servicedelegationrule", choices=["member", "servicedelegationrule"]), # state state=dict(type="str", default="present", choices=["present", "absent"]), ), supports_check_mode=True, ) ansible_module._ansible_debug = True # Get parameters # general names = ansible_module.params_get("name") # present principal = ansible_module.params_get("principal") target = ansible_module.params_get("target") 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 servicedelegationrule can be added at a time.") if state == "absent": if len(names) < 1: ansible_module.fail_json(msg="No name given.") if action == "servicedelegationrule": invalid = ["principal", "target"] ansible_module.params_fail_used_invalid(invalid, state, action) # Init membertarget = "ipaallowedtarget_servicedelegationtarget" changed = False exit_args = {} # Connect to IPA API with ansible_module.ipa_connect(): # Normalize principals if principal: principal = servicedelegation_normalize_principals( ansible_module, principal, state == "present") if target and state == "present": check_targets(ansible_module, target) commands = [] principal_add = principal_del = [] target_add = target_del = [] for name in names: # Make sure servicedelegationrule exists res_find = find_servicedelegationrule(ansible_module, name) # Create command if state == "present": if action == "servicedelegationrule": # A servicedelegationrule does not have normal options. # There is no servicedelegationtarget-mod command. # Principal members are handled with the _add_member and # _remove_member commands further down. if res_find is None: commands.append([name, "servicedelegationrule_add", {}]) res_find = {} # Generate addition and removal lists for principal principal_add, principal_del = gen_add_del_lists( principal, res_find.get("memberprincipal")) # Generate addition and removal lists for target target_add, target_del = gen_add_del_lists( target, res_find.get(membertarget)) elif action == "member": if res_find is None: ansible_module.fail_json( msg="No servicedelegationrule '%s'" % name) # Reduce add lists for principal # to new entries only that are not in res_find. if principal is not None and \ "memberprincipal" in res_find: principal_add = gen_add_list( principal, res_find["memberprincipal"]) else: principal_add = principal # Reduce add lists for target # to new entries only that are not in res_find. if target is not None and membertarget in res_find: target_add = gen_add_list( target, res_find[membertarget]) else: target_add = target elif state == "absent": if action == "servicedelegationrule": if res_find is not None: commands.append([name, "servicedelegationrule_del", {}]) elif action == "member": if res_find is None: ansible_module.fail_json( msg="No servicedelegationrule '%s'" % name) # Reduce del lists of principals to the entries only # that are in res_find. if principal is not None: principal_del = gen_intersection_list( principal, res_find.get("memberprincipal")) else: principal_del = principal # Reduce del lists of targets to the entries only # that are in res_find. if target is not None: target_del = gen_intersection_list( target, res_find.get(membertarget)) else: target_del = target else: ansible_module.fail_json(msg="Unkown state '%s'" % state) # Handle members # Add principal members if principal_add is not None and len(principal_add) > 0: commands.append( [name, "servicedelegationtarget_add_member", { "principal": principal_add, }]) # Remove principal members if principal_del is not None and len(principal_del) > 0: commands.append( [name, "servicedelegationtarget_remove_member", { "principal": principal_del, }]) # Add target members if target_add is not None and len(target_add) > 0: commands.append( [name, "servicedelegationrule_add_target", { "servicedelegationtarget": target_add, }]) # Remove target members if target_del is not None and len(target_del) > 0: commands.append( [name, "servicedelegationrule_remove_target", { "servicedelegationtarget": target_del, }]) # 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)
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) # 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) # 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]: 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 = init_ansible_module() # Get parameters # general names = ansible_module.params_get("name") # service attributes principal = ansible_module.params_get("principal") certificate = ansible_module.params_get("certificate") pac_type = ansible_module.params_get("pac_type", allow_empty_string=True) auth_ind = ansible_module.params_get("auth_ind", allow_empty_string=True) skip_host_check = ansible_module.params_get("skip_host_check") force = ansible_module.params_get("force") requires_pre_auth = ansible_module.params_get("requires_pre_auth") ok_as_delegate = ansible_module.params_get("ok_as_delegate") ok_to_auth_as_delegate = ansible_module.params_get( "ok_to_auth_as_delegate") smb = ansible_module.params_get("smb") netbiosname = ansible_module.params_get("netbiosname") host = ansible_module.params_get("host") delete_continue = ansible_module.params_get("delete_continue") # action action = ansible_module.params_get("action") # state state = ansible_module.params_get("state") # check parameters check_parameters(ansible_module, state, action, names) # Init changed = False exit_args = {} # Connect to IPA API with ansible_module.ipa_connect(): has_skip_host_check = ansible_module.ipa_command_param_exists( "service_add", "skip_host_check") if skip_host_check and not has_skip_host_check: ansible_module.fail_json( msg="Skipping host check is not supported by your IPA version") commands = [] keytab_members = ["user", "group", "host", "hostgroup"] for name in names: res_find = find_service(ansible_module, name) res_principals = [] keytab = { "retrieve": { "allow": {k: [] for k in keytab_members}, "disallow": {k: [] for k in keytab_members}, }, "create": { "allow": {k: [] for k in keytab_members}, "disallow": {k: [] for k in keytab_members}, }, } certificate_add, certificate_del = [], [] host_add, host_del = [], [] principal_add, principal_del = [], [] if principal and res_find: # When comparing principals to the existing ones, # the REALM is needded, and are added here for those # that do not have it. principal = [ p if "@" in p else "%s@%s" % (p, api_get_realm()) for p in principal ] principal = list(set(principal)) # Create list of existing principal aliases as strings # to compare with provided ones. canonicalname = { to_text(p) for p in res_find.get("krbcanonicalname", []) } res_principals = [ to_text(elem) for elem in res_find.get("krbprincipalname", []) ] res_principals = list(set(res_principals) - canonicalname) if state == "present": if action == "service": args = gen_args(pac_type, auth_ind, skip_host_check, force, requires_pre_auth, ok_as_delegate, ok_to_auth_as_delegate) if not has_skip_host_check and 'skip_host_check' in args: del args['skip_host_check'] if smb: if res_find is None: _name = "cifs/" + name res_find = find_service(ansible_module, _name) if res_find is None: _args = gen_args_smb(netbiosname, ok_as_delegate, ok_to_auth_as_delegate) commands.append( [name, 'service_add_smb', _args]) res_find = {} # service_add_smb will prefix 'name' with # "cifs/", so we will need to change it here, # so that service_mod, if called later, works. name = _name if res_find is None: commands.append([name, 'service_add', args]) # Use an empty res_find to manage members res_find = {} else: for remove in ['skip_host_check', 'force']: if remove in args: del args[remove] if ("ipakrbauthzdata" in args and (args.get("ipakrbauthzdata", [""]) == res_find.get( "ipakrbauthzdata", [""]))): del args["ipakrbauthzdata"] if ("krbprincipalauthind" in args and (args.get("krbprincipalauthind", [""]) == res_find.get("krbprincipalauthind", [""]))): del args["krbprincipalauthind"] if not compare_args_ipa(ansible_module, args, res_find): commands.append([name, "service_mod", args]) # Manage members certificate_add, certificate_del = gen_add_del_lists( certificate, res_find.get("usercertificate")) host_add, host_del = gen_add_del_lists( host, res_find.get('managedby_host')) principal_add, principal_del = gen_add_del_lists( principal, res_principals) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No service '%s'" % name) certificate_add = gen_add_list( certificate, res_find.get("usercertificate")) host_add = gen_add_list(host, res_find.get('managedby_host')) principal_add = gen_add_list(principal, res_principals) # get keytab management lists for any 'action'. for perm in ["create", "retrieve"]: oper = "write" if perm == "create" else "read" for key in ["user", "group", "host", "hostgroup"]: add_list, del_list = (gen_add_del_lists( ansible_module.params_get("allow_%s_keytab_%s" % (perm, key)), res_find.get('ipaallowedtoperform_%s_keys_%s' % (oper, key)))) keytab[perm]["allow"][key] = add_list # Only remove members if action is 'service' if action == "service": keytab[perm]["disallow"][key] = del_list elif state == "absent": if action == "service": if res_find is not None: args = {'continue': delete_continue} commands.append([name, 'service_del', args]) elif action == "member": if res_find is None: ansible_module.fail_json(msg="No service '%s'" % name) principal_del = gen_intersection_list( principal, res_principals) certificate_del = gen_intersection_list( certificate, res_find.get("usercertificate")) host_del = gen_intersection_list( host, res_find.get("managedby_host")) for perm in ["create", "retrieve"]: oper = "write" if perm == "create" else "read" for key in ["user", "group", "host", "hostgroup"]: res_param = ('ipaallowedtoperform_%s_keys_%s' % (oper, key)) module_params = ansible_module.params_get( "allow_%s_keytab_%s" % (perm, key)) existing = res_find.get(res_param) del_list = (gen_intersection_list( module_params, existing)) keytab[perm]["disallow"][key] = del_list elif state == "disabled": if action == "service": if res_find is not None: has_cert = bool(res_find.get('usercertificate')) has_keytab = res_find.get('has_keytab', False) if has_cert or has_keytab: commands.append([name, 'service_disable', {}]) else: ansible_module.fail_json( msg="Invalid action '%s' for state '%s'" % (action, state)) # Members are not managed when disabling service. # Continue with next 'name'. continue else: ansible_module.fail_json(msg="Unkown state '%s'" % state) # Manage members if principal_add: commands.append([ name, "service_add_principal", { "krbprincipalname": principal_add } ]) if principal_del: commands.append([ name, "service_remove_principal", { "krbprincipalname": principal_del } ]) if certificate_add: commands.append([ name, "service_add_cert", { "usercertificate": certificate_add } ]) if certificate_del: commands.append([ name, "service_remove_cert", { "usercertificate": certificate_del } ]) if host_add: commands.append([name, "service_add_host", {"host": host_add}]) if host_del: commands.append( [name, "service_remove_host", { "host": host_del }]) # manage keytab permissions. for perm in ["create", "retrieve"]: for mode in ["allow", "disallow"]: for key in ["user", "group", "host", "hostgroup"]: if keytab[perm][mode][key]: commands.append([ name, "service_%s_%s_keytab" % (mode, perm), keytab[perm][mode] ]) break # Check mode exit if ansible_module.check_mode: ansible_module.exit_json(changed=len(commands) > 0, **exit_args) # Execute commands changed = ansible_module.execute_ipa_commands( commands, fail_on_member_errors=True) # Done ansible_module.exit_json(changed=changed, **exit_args)