Skip to content

Commit ab2f370

Browse files
committed
Merge branch 'wip/freeipa_server_modules'
2 parents cd384ff + b868d8b commit ab2f370

14 files changed

Lines changed: 7756 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818

1919
### Added
2020

21+
* **role:freeipa_server**: Add `--diff` support for all FreeIPA modules and add `freeipa_server:configure` tag
2122
* **role:mariadb_server**: Add `mariadb_server__cnf_wsrep_log_conflicts` and `mariadb_server__cnf_wsrep_retry_autocommit` variables
2223
* **role:mariadb_server**: Add `mariadb_server__cnf_wsrep_gtid_mode` variable to configure `wsrep_gtid_mode` for Galera
2324
* **role:openvpn_server**: Add `openvpn_server:crl` tag to allow deploying the certificate revocation list independently

plugins/module_utils/ipa_diff.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Temporary diff helpers for ansible-freeipa modules.
2+
# Remove once https://github.com/freeipa/ansible-freeipa/pull/1415
3+
# is merged and released.
4+
5+
from __future__ import (absolute_import, division, print_function)
6+
7+
__metaclass__ = type
8+
9+
from ansible.module_utils._text import to_text
10+
11+
12+
def _compare_key(arg, ipa_arg):
13+
"""Compare a single key's value using compare_args_ipa logic."""
14+
if isinstance(ipa_arg, (list, tuple)):
15+
if not isinstance(arg, list):
16+
arg = [arg]
17+
if len(ipa_arg) != len(arg):
18+
return False
19+
if ipa_arg and arg and not (
20+
isinstance(ipa_arg[0], type(arg[0]))
21+
or isinstance(arg[0], type(ipa_arg[0]))
22+
):
23+
arg = [to_text(_a) for _a in arg]
24+
try:
25+
return set(arg) == set(ipa_arg)
26+
except TypeError:
27+
return arg == ipa_arg
28+
return arg == ipa_arg
29+
30+
31+
class IPADiffTracker:
32+
"""Track before/after state for Ansible --diff output."""
33+
34+
def __init__(self):
35+
self._diffs = []
36+
37+
def build_diff(self):
38+
"""Return kwargs for exit_json (empty dict if no changes)."""
39+
if not self._diffs:
40+
return {}
41+
return {"diff": self._diffs}
42+
43+
def add_entry_diff(self, name, before, after):
44+
"""Record a diff entry for one IPA object."""
45+
if before == after:
46+
return
47+
self._diffs.append({
48+
"before_header": name,
49+
"after_header": name,
50+
"before": before,
51+
"after": after,
52+
})
53+
54+
55+
def gen_args_diff(args, res_find, ignore=None):
56+
"""Extract only changed keys from args vs res_find for diff output.
57+
58+
Returns (before_dict, after_dict) containing only keys that differ.
59+
Uses the same comparison logic as compare_args_ipa for consistency.
60+
Single-element IPA lists are normalized to scalars for readability.
61+
"""
62+
if not args:
63+
return {}, {}
64+
before = {}
65+
after = {}
66+
if ignore is None:
67+
ignore = []
68+
for key in args:
69+
if key in ignore:
70+
continue
71+
arg = args[key]
72+
ipa_arg = res_find.get(key, [""])
73+
if not _compare_key(arg, ipa_arg):
74+
# Normalize for display
75+
_ipa = ipa_arg[0] if isinstance(ipa_arg, (list, tuple)) \
76+
and len(ipa_arg) == 1 else ipa_arg
77+
_arg = arg[0] if isinstance(arg, (list, tuple)) \
78+
and len(arg) == 1 else arg
79+
before[key] = _ipa
80+
after[key] = _arg
81+
return before, after
82+
83+
84+
def gen_member_diff(member_key, add_list, del_list, current_list):
85+
"""Compute before/after for one member category.
86+
87+
Returns (before_dict, after_dict) with member_key as key and sorted
88+
lists as values. Returns ({}, {}) if no changes.
89+
"""
90+
if not add_list and not del_list:
91+
return {}, {}
92+
current = sorted(current_list or [])
93+
desired = sorted(
94+
[x for x in current if x not in (del_list or [])]
95+
+ (add_list or [])
96+
)
97+
return {member_key: current}, {member_key: desired}
98+
99+
100+
def merge_diffs(*diff_pairs):
101+
"""Merge multiple (before, after) tuples into a single pair."""
102+
merged_before = {}
103+
merged_after = {}
104+
for _before, _after in diff_pairs:
105+
merged_before.update(_before)
106+
merged_after.update(_after)
107+
return merged_before, merged_after

0 commit comments

Comments
 (0)