Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle data type or empty string in module_utils #1143

Merged
merged 5 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 77 additions & 13 deletions plugins/module_utils/ansible_freeipa_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,20 +470,19 @@ def _afm_convert(value):
return value


def module_params_get(module, name, allow_empty_string=False):
def module_params_get(module, name, allow_empty_list_item=False):
value = _afm_convert(module.params.get(name))

# Fail on empty strings in the list or if allow_empty_string is True
# if there is another entry in the list together with the empty
# string.
# Fail on empty strings in the list or if allow_empty_list_item is True
# if there is another entry in the list together with the empty string.
# Due to an issue in Ansible it is possible to use the empty string
# "" for lists with choices, even if the empty list is not part of
# the choices.
# Ansible issue https://github.com/ansible/ansible/issues/77108
if isinstance(value, list):
for val in value:
if isinstance(val, (str, unicode)) and not val:
if not allow_empty_string:
if not allow_empty_list_item:
module.fail_json(
msg="Parameter '%s' contains an empty string" %
name)
Expand All @@ -495,15 +494,57 @@ def module_params_get(module, name, allow_empty_string=False):
return value


def module_params_get_lowercase(module, name, allow_empty_string=False):
value = module_params_get(module, name, allow_empty_string)
def module_params_get_lowercase(module, name, allow_empty_list_item=False):
value = module_params_get(module, name, allow_empty_list_item)
if isinstance(value, list):
value = [v.lower() for v in value]
if isinstance(value, (str, unicode)):
value = value.lower()
return value


def module_params_get_with_type_cast(
module, name, datatype, allow_empty=False
):
"""
Retrieve value set for module parameter as a specific data type.

Parameters
----------
module: AnsibleModule
The module from where to get the parameter value from.
name: string
The name of the parameter to retrieve.
datatype: type
The type to convert the value to, if value is not empty.
allow_empty: bool
Allow an empty string for non list parameters or a list
containing (only) an empty string item. This is used for
resetting parameters to the default value.

"""
value = module_params_get(module, name, allow_empty)
if not allow_empty and value == "":
module.fail_json(
msg="Argument '%s' must not be an empty string" % (name,)
)
if value is not None and value != "":
try:
if datatype is bool:
# We let Ansible handle bool values
value = boolean(value)
else:
value = datatype(value)
except ValueError:
module.fail_json(
msg="Invalid value '%s' for argument '%s'" % (value, name)
)
except TypeError as terr:
# If Ansible fails to parse a boolean, it will raise TypeError
module.fail_json(msg="Param '%s': %s" % (name, str(terr)))
return value


def api_get_domain():
return api.env.domain

Expand Down Expand Up @@ -1051,33 +1092,56 @@ def ipa_connect(self, context=None):
finally:
temp_kdestroy(ccache_dir, ccache_name)

def params_get(self, name, allow_empty_string=False):
def params_get(self, name, allow_empty_list_item=False):
"""
Retrieve value set for module parameter.

Parameters
----------
name: string
The name of the parameter to retrieve.
allow_empty_string: bool
allow_empty_list_item: bool
The parameter allowes to have empty strings in a list

"""
return module_params_get(self, name, allow_empty_string)
return module_params_get(self, name, allow_empty_list_item)

def params_get_lowercase(self, name, allow_empty_string=False):
def params_get_lowercase(self, name, allow_empty_list_item=False):
"""
Retrieve value set for module parameter as lowercase, if not None.

Parameters
----------
name: string
The name of the parameter to retrieve.
allow_empty_string: bool
allow_empty_list_item: bool
The parameter allowes to have empty strings in a list

"""
return module_params_get_lowercase(self, name, allow_empty_string)
return module_params_get_lowercase(self, name, allow_empty_list_item)

def params_get_with_type_cast(
self, name, datatype, allow_empty=True
):
"""
Retrieve value set for module parameter as a specific data type.

Parameters
----------
name: string
The name of the parameter to retrieve.
datatype: type
The type to convert the value to, if not empty.
datatype: type
The type to convert the value to, if value is not empty.
allow_empty: bool
Allow an empty string for non list parameters or a list
containing (only) an empty string item. This is used for
resetting parameters to the default value.

"""
return module_params_get_with_type_cast(
self, name, datatype, allow_empty)

def params_fail_used_invalid(self, invalid_params, state, action=None):
"""
Expand Down
4 changes: 2 additions & 2 deletions plugins/modules/ipaconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,13 +470,13 @@ def main():
"netbios_name": "netbios_name",
"add_sids": "add_sids",
}
allow_empty_string = ["pac_type", "user_auth_type", "configstring"]
reverse_field_map = {v: k for k, v in field_map.items()}
allow_empty_list_item = ["pac_type", "user_auth_type", "configstring"]

params = {}
for x in field_map:
val = ansible_module.params_get(
x, allow_empty_string=x in allow_empty_string)
x, allow_empty_list_item=x in allow_empty_list_item)

if val is not None:
params[field_map.get(x, x)] = val
Expand Down
7 changes: 4 additions & 3 deletions plugins/modules/ipahost.py
Original file line number Diff line number Diff line change
Expand Up @@ -876,10 +876,11 @@ def main():
allow_retrieve_keytab_hostgroup = ansible_module.params_get(
"allow_retrieve_keytab_hostgroup")
mac_address = ansible_module.params_get("mac_address")
sshpubkey = ansible_module.params_get("sshpubkey",
allow_empty_string=True)
sshpubkey = ansible_module.params_get(
"sshpubkey", allow_empty_list_item=True)
userclass = ansible_module.params_get("userclass")
auth_ind = ansible_module.params_get("auth_ind", allow_empty_string=True)
auth_ind = ansible_module.params_get(
"auth_ind", allow_empty_list_item=True)
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(
Expand Down
15 changes: 1 addition & 14 deletions plugins/modules/ipaidoverridegroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def main():
# present
description = ansible_module.params_get("description")
name = ansible_module.params_get("name")
gid = ansible_module.params_get("gid")
gid = ansible_module.params_get_with_type_cast("gid", int)

# runtime flags
fallback_to_ldap = ansible_module.params_get("fallback_to_ldap")
Expand Down Expand Up @@ -271,19 +271,6 @@ def main():

ansible_module.params_fail_used_invalid(invalid, state)

# Ensure parameter values are valid and have proper type.
def int_or_empty_param(value, param):
if value is not None and value != "":
try:
value = int(value)
except ValueError:
ansible_module.fail_json(
msg="Invalid value '%s' for argument '%s'" % (value, param)
)
return value

gid = int_or_empty_param(gid, "gid")

# Init

changed = False
Expand Down
18 changes: 2 additions & 16 deletions plugins/modules/ipaidoverrideuser.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,9 +439,9 @@ def main():
# present
description = ansible_module.params_get("description")
name = ansible_module.params_get("name")
uid = ansible_module.params_get("uid")
uid = ansible_module.params_get_with_type_cast("uid", int)
gecos = ansible_module.params_get("gecos")
gidnumber = ansible_module.params_get("gidnumber")
gidnumber = ansible_module.params_get_with_type_cast("gidnumber", int)
homedir = ansible_module.params_get("homedir")
shell = ansible_module.params_get("shell")
sshpubkey = ansible_module.params_get("sshpubkey")
Expand Down Expand Up @@ -479,20 +479,6 @@ def main():

ansible_module.params_fail_used_invalid(invalid, state, action)

# Ensure parameter values are valid and have proper type.
def int_or_empty_param(value, param):
if value is not None and value != "":
try:
value = int(value)
except ValueError:
ansible_module.fail_json(
msg="Invalid value '%s' for argument '%s'" % (value, param)
)
return value

uid = int_or_empty_param(uid, "uid")
gidnumber = int_or_empty_param(gidnumber, "gidnumber")

if certificate is not None:
certificate = [cert.strip() for cert in certificate]

Expand Down
79 changes: 29 additions & 50 deletions plugins/modules/ipapwpolicy.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@
"""

from ansible.module_utils.ansible_freeipa_module import \
IPAAnsibleModule, compare_args_ipa, boolean
IPAAnsibleModule, compare_args_ipa


def find_pwpolicy(module, name):
Expand Down Expand Up @@ -294,20 +294,34 @@ def main():
names = ansible_module.params_get("name")

# present
maxlife = ansible_module.params_get("maxlife")
minlife = ansible_module.params_get("minlife")
history = ansible_module.params_get("history")
minclasses = ansible_module.params_get("minclasses")
minlength = ansible_module.params_get("minlength")
priority = ansible_module.params_get("priority")
maxfail = ansible_module.params_get("maxfail")
failinterval = ansible_module.params_get("failinterval")
lockouttime = ansible_module.params_get("lockouttime")
maxrepeat = ansible_module.params_get("maxrepeat")
maxsequence = ansible_module.params_get("maxsequence")
dictcheck = ansible_module.params_get("dictcheck")
usercheck = ansible_module.params_get("usercheck")
gracelimit = ansible_module.params_get("gracelimit")
maxlife = ansible_module.params_get_with_type_cast(
"maxlife", int, allow_empty=True)
minlife = ansible_module.params_get_with_type_cast(
"minlife", int, allow_empty=True)
history = ansible_module.params_get_with_type_cast(
"history", int, allow_empty=True)
minclasses = ansible_module.params_get_with_type_cast(
"minclasses", int, allow_empty=True)
minlength = ansible_module.params_get_with_type_cast(
"minlength", int, allow_empty=True)
priority = ansible_module.params_get_with_type_cast(
"priority", int, allow_empty=True)
maxfail = ansible_module.params_get_with_type_cast(
"maxfail", int, allow_empty=True)
failinterval = ansible_module.params_get_with_type_cast(
"failinterval", int, allow_empty=True)
lockouttime = ansible_module.params_get_with_type_cast(
"lockouttime", int, allow_empty=True)
maxrepeat = ansible_module.params_get_with_type_cast(
"maxrepeat", int, allow_empty=True)
maxsequence = ansible_module.params_get_with_type_cast(
"maxsequence", int, allow_empty=True)
dictcheck = ansible_module.params_get_with_type_cast(
"dictcheck", bool, allow_empty=True)
usercheck = ansible_module.params_get_with_type_cast(
"usercheck", bool, allow_empty=True)
gracelimit = ansible_module.params_get_with_type_cast(
"gracelimit", int, allow_empty=True)

# state
state = ansible_module.params_get("state")
Expand Down Expand Up @@ -336,41 +350,6 @@ def main():

ansible_module.params_fail_used_invalid(invalid, state)

# Ensure parameter values are valid and have proper type.
def int_or_empty_param(value, param):
if value is not None and value != "":
try:
value = int(value)
except ValueError:
ansible_module.fail_json(
msg="Invalid value '%s' for argument '%s'" % (value, param)
)
return value

maxlife = int_or_empty_param(maxlife, "maxlife")
minlife = int_or_empty_param(minlife, "minlife")
history = int_or_empty_param(history, "history")
minclasses = int_or_empty_param(minclasses, "minclasses")
minlength = int_or_empty_param(minlength, "minlength")
priority = int_or_empty_param(priority, "priority")
maxfail = int_or_empty_param(maxfail, "maxfail")
failinterval = int_or_empty_param(failinterval, "failinterval")
lockouttime = int_or_empty_param(lockouttime, "lockouttime")
maxrepeat = int_or_empty_param(maxrepeat, "maxrepeat")
maxsequence = int_or_empty_param(maxsequence, "maxsequence")
gracelimit = int_or_empty_param(gracelimit, "gracelimit")

def bool_or_empty_param(value, param): # pylint: disable=R1710
if value is None or value == "":
return value
try:
return boolean(value)
except TypeError as terr:
ansible_module.fail_json(msg="Param '%s': %s" % (param, str(terr)))

dictcheck = bool_or_empty_param(dictcheck, "dictcheck")
usercheck = bool_or_empty_param(usercheck, "usercheck")

# Ensure gracelimit has proper limit.
if gracelimit:
if gracelimit < -1:
Expand Down
6 changes: 4 additions & 2 deletions plugins/modules/ipaservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,8 +607,10 @@ def main():
# white space also.
if certificate is not None:
certificate = [cert.strip() for cert in 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)
pac_type = ansible_module.params_get(
"pac_type", allow_empty_list_item=True)
auth_ind = ansible_module.params_get(
"auth_ind", allow_empty_list_item=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")
Expand Down
4 changes: 2 additions & 2 deletions plugins/modules/ipauser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1185,9 +1185,9 @@ def main():
manager = ansible_module.params_get("manager")
carlicense = ansible_module.params_get("carlicense")
sshpubkey = ansible_module.params_get("sshpubkey",
allow_empty_string=True)
allow_empty_list_item=True)
userauthtype = ansible_module.params_get("userauthtype",
allow_empty_string=True)
allow_empty_list_item=True)
userclass = ansible_module.params_get("userclass")
radius = ansible_module.params_get("radius")
radiususer = ansible_module.params_get("radiususer")
Expand Down
Loading