Skip to content

Commit c06c974

Browse files
author
Simon Kowallik
committed
version 1.1.0
- avoid mutation of desired_config in dict_diff function - documentation - repo updates
1 parent 920a002 commit c06c974

22 files changed

+2403
-258
lines changed

Makefile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,13 @@ isort:
4646

4747
code-format: isort black ruff # more is MORE!
4848

49-
test:
50-
PYTHONPATH=$PWD cd ansible_collections/f5_ps_ansible/f5os && pytest tests/unit/plugins/module_utils/test_utils.py
49+
doc: docs ## alias for docs
50+
51+
docs:
52+
python3 docs/f5os/ansible_module_autodoc.py
53+
54+
pytests:
55+
cd ansible_collections/f5_ps_ansible/f5os && PYTHONPATH=$(BASE_DIR) pytest tests/unit/plugins/module_utils/test_utils.py
5156

5257
tests: test
5358

ansible_collections/f5_ps_ansible/f5os/galaxy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
namespace: f5_ps_ansible
33
name: f5os
4-
version: 1.0.0
4+
version: 1.1.0
55
readme: README.md
66
authors:
77
- Simon Kowallik <[email protected]>

ansible_collections/f5_ps_ansible/f5os/plugins/module_utils/utils.py

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
# Copyright: Simon Kowallik for the F5 DevCentral Community
44
# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
55

6+
from copy import deepcopy
7+
68
from ansible.module_utils.connection import Connection
79

810

@@ -101,7 +103,7 @@ def dicts_equal(d1, d2, remove_keys=[]) -> bool:
101103
Values with integers and floats are compared as strings, hence the type is ignored.
102104
"""
103105

104-
def _process_lists(d1, d2):
106+
def _process_lists(_d1, _d2):
105107
def _sort_key(element):
106108
if isinstance(element, dict):
107109
return (3, str(element)) # Assign a higher priority to dicts
@@ -114,68 +116,64 @@ def _sort_key(element):
114116
else:
115117
return (4, str(element)) # Catch-all for other types
116118

117-
if len(d1) != len(d2):
119+
if len(_d1) != len(_d2):
118120
return False
119121

120122
# sort lists by type and value
121-
_l1 = sorted(d1, key=_sort_key)
122-
_l2 = sorted(d2, key=_sort_key)
123+
_l1 = sorted(_d1, key=_sort_key)
124+
_l2 = sorted(_d2, key=_sort_key)
123125

124-
for i in range(len(_l1)):
125-
if isinstance(_l1[i], dict):
126-
print(f"_l1[{i}] is dict")
127-
if not dicts_equal(_l1[i], _l2[i]):
126+
for i, item in enumerate(_l1):
127+
if isinstance(item, dict):
128+
if not dicts_equal(item, _l2[i]):
128129
return False
129-
elif isinstance(_l1[i], list):
130-
print(f"_l1[{i}] is list")
131-
if not _process_lists(_l1[i], _l2[i]):
130+
elif isinstance(item, list):
131+
if not _process_lists(item, _l2[i]):
132132
return False
133133
else:
134-
print(f"_l1[{i}] is other")
135-
if str(_l1[i]) not in [
134+
if str(item) not in [
136135
str(entry) for entry in _l2 if not isinstance(entry, (list, dict))
137136
]:
138137
return False
139138
return True
140139

140+
_d1 = deepcopy(d1)
141+
_d2 = deepcopy(d2)
142+
141143
if remove_keys:
142-
d1 = recurse_remove_keys(d1, remove_keys)
143-
d2 = recurse_remove_keys(d2, remove_keys)
144+
_d1 = recurse_remove_keys(_d1, remove_keys)
145+
_d2 = recurse_remove_keys(_d2, remove_keys)
144146

145147
# simplest case: if the dictionaries are the same object, they are the same
146-
if d1 == d2:
148+
if _d1 == _d2:
147149
return True
148150

149151
# If the types are different, the dictionaries are different
150-
if type(d1) != type(d2):
152+
if type(_d1) != type(_d2):
151153
return False
152154

153155
# If the dictionaries are not the same length, they are different
154-
if len(d1) != len(d2):
156+
if len(_d1) != len(_d2):
155157
return False
156158

157159
# If the dictionaries are empty, they are the same
158-
if len(d1) == 0:
160+
if len(_d1) == 0:
159161
return False
160162

161163
# If the dictionaries are not empty, compare the keys
162-
if set(d1) != set(d2):
164+
if set(_d1) != set(_d2):
163165
return False
164166

165167
# If the keys are the same, compare the values
166-
for key in d1.keys():
167-
print(f"key: {key}")
168-
if isinstance(d1[key], dict):
169-
print(f"{key} is dict")
170-
if not dicts_equal(d1[key], d2[key]):
168+
for key in _d1.keys():
169+
if isinstance(_d1[key], dict):
170+
if not dicts_equal(_d1[key], _d2[key]):
171171
return False
172-
elif isinstance(d1[key], list):
173-
print(f"{key} is list")
174-
if not _process_lists(d1[key], d2[key]):
172+
elif isinstance(_d1[key], list):
173+
if not _process_lists(_d1[key], _d2[key]):
175174
return False
176175
else:
177-
print(f"{key} is other")
178-
if not str(d1[key]) == str(d2[key]):
176+
if str(_d1[key]) != str(_d2[key]):
179177
return False
180178

181179
return True

ansible_collections/f5_ps_ansible/f5os/plugins/modules/f5os_restconf_config.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@
6161
notes:
6262
- This module requires the f5networks.f5os collection to be installed on the ansible controller.
6363
- This module uses the httpapi of the f5networks.f5os collection.
64-
- When using config_query the jmespath module is required.
64+
- When using config_query jmespath module is required.
65+
- For better diff support, deepdiff module is recommended.
6566
"""
6667

6768
EXAMPLES = r"""
@@ -94,11 +95,13 @@
9495
method: PATCH # Use PATCH to partially update the configuration
9596
config:
9697
openconfig-lldp:config:
98+
# the PATCH method will only update these keys:
9799
enabled: 'true'
98100
f5-lldp:max-neighbors-per-port: 50
99-
# all missing keys of this entity need to be in keys_ignore,
100-
# otherwise change detection will fail and ansible will always report a change
101101
keys_ignore:
102+
# keys_ignore has all remaining keys of this API endpoint.
103+
# The ansible module will therefore ignore the values in the
104+
# below keys when comparing the desired and current configuration.
102105
- f5-lldp:reinit-delay
103106
- f5-lldp:tx-delay
104107
- f5-lldp:tx-hold

ansible_collections/f5_ps_ansible/f5os/tests/unit/plugins/module_utils/test_utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,17 @@ def test_types(self, d1, d2, result):
183183
{ "one": [ {"t": "1", "k": "a", "1": True}, [1, 3, 2, True, False], {"t": "2", "l": ["XXXX", 2, "c"]}, ], "list": [2, 1, 3,] },
184184
False),
185185
])
186+
186187
def test_deep(self, d1, d2, result):
187188
assert dicts_equal(d1, d2) == result
188189

190+
def test_mutation(self):
191+
'''must not mutate input dictionaries'''
192+
d1 = {"list": [{"key1": 1, "key2": 2}]}
193+
d2 = {"list": [{"key2": 2}]}
189194

195+
assert dicts_equal(d1, d2, remove_keys=['key1']) == True
196+
assert d1 == {"list": [{"key1": 1, "key2": 2}]}
190197

191198
class Test_remove_state_property:
192199
TEST_NTP = [

0 commit comments

Comments
 (0)