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(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)