Skip to content

Commit 0b4a6a0

Browse files
committed
ipahost: Fix idempotence issues with update_dns and multiple objects
When using ipahost with the 'hosts' parameters several parameter conversion routines were not being performed causing the module to try to execute tasks it was not suposed to. This issues were fixed by adapting the module to use EntryFactory. Another issue was happening when 'update_dns: true' is used with some parameters, like 'description', 'location' or 'mac_address', where, even if no change was to be performed the plugin would evaluate that the arguments were different, and tried to modify the object. The fix for this issue is to ignore 'updatedns' when comparing the parameters provided with the existing IPA object. This modification also fix the case where duplicate entries used with the 'name' parameter in case 'state: absent' would fail without indicating the use of duplicate entries. Fixes: #1296 Fixes: https://issues.redhat.com/browse/RHEL-111063 Signed-off-by: Rafael Guterres Jeffman <rjeffman@redhat.com>
1 parent f62e8fd commit 0b4a6a0

4 files changed

Lines changed: 337 additions & 350 deletions

File tree

plugins/module_utils/ansible_freeipa_module.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,14 @@ def convert_param_value_to_lowercase(value):
537537
return value
538538

539539

540+
def convert_param_value_to_uppercase(value):
541+
if isinstance(value, list):
542+
value = [v.upper() for v in value]
543+
if isinstance(value, (str, unicode)):
544+
value = value.upper()
545+
return value
546+
547+
540548
def module_params_get_with_type_cast(
541549
module, name, datatype, allow_empty=False
542550
):
@@ -1656,6 +1664,10 @@ class EntryFactory:
16561664
not valid, 'fail_json' should be called. The function must return
16571665
the entry, modified or not. The funcion signature is
16581666
'def fn(module:IPAAnsibleModule, entry: Entry) -> Entry:'
1667+
unique_key: A string or list of strings representing parameter names
1668+
that uniquely identify an object. When set, the objects are checked
1669+
for duplicates and a EntryFactory.DuplicateKeyError is raised, when
1670+
instantiating the EntryFactory object if any duplicate is found.
16591671
**user_vars: any other keyword argument is passed to the
16601672
validate_entry callback as user data.
16611673
@@ -1693,13 +1705,21 @@ def main():
16931705
16941706
"""
16951707

1708+
class DuplicateKeyError(Exception):
1709+
"""An exeption for duplicate keys in EntryFactory."""
1710+
1711+
def __init__(self, dups):
1712+
dups = [k if len(k) > 1 else k[0] for k in dups]
1713+
super().__init__(", ".join(repr(k) for k in dups))
1714+
16961715
def __init__(
16971716
self,
16981717
ansible_module,
16991718
invalid_params,
17001719
multiname,
17011720
params,
17021721
validate_entry=None,
1722+
unique_key=None,
17031723
**user_vars
17041724
):
17051725
"""Initialize the Entry Factory."""
@@ -1714,6 +1734,26 @@ def __init__(
17141734
self.validate_entry = validate_entry
17151735
self.user_vars = user_vars
17161736
self.__entries = self._get_entries()
1737+
_dups = self.get_duplicate_keys(unique_key)
1738+
if _dups:
1739+
raise EntryFactory.DuplicateKeyError(_dups)
1740+
1741+
def get_duplicate_keys(self, unique_key):
1742+
"""Get a set of duplicate keys based on the given parameter name(s)."""
1743+
_dups = set()
1744+
if unique_key is not None:
1745+
if isinstance(unique_key, (str, unicode)): # pylint: disable=all
1746+
unique_key = [unique_key]
1747+
_keys = set()
1748+
for _entry in self.__entries:
1749+
_key_set = tuple(set(_entry[k] for k in unique_key))
1750+
if _key_set in _keys:
1751+
_dups.add(_key_set)
1752+
_keys.add(_key_set)
1753+
return _dups
1754+
1755+
def __len__(self):
1756+
return len(self.__entries)
17171757

17181758
def __iter__(self):
17191759
"""Initialize factory iterator."""

0 commit comments

Comments
 (0)