Skip to content

Commit d018675

Browse files
committed
[minor_change] Created nd_backup_schedule module using Ansible Network Resource Modules Approach
1 parent 3cab814 commit d018675

File tree

5 files changed

+816
-391
lines changed

5 files changed

+816
-391
lines changed

plugins/module_utils/constants.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,11 @@
156156
"disable",
157157
"restart",
158158
"delete",
159+
"deleted",
159160
"update",
161+
"merged",
162+
"replaced",
163+
"overridden",
160164
)
161165

162166
INTERFACE_FLOW_RULES_TYPES_MAPPING = {"port_channel": "PORTCHANNEL", "physical": "PHYSICAL", "l3out_sub_interface": "L3_SUBIF", "l3out_svi": "SVI"}

plugins/module_utils/nd.py

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -73,53 +73,27 @@ def cmp(a, b):
7373

7474

7575
def issubset(subset, superset):
76-
"""Recurse through nested dictionary and compare entries"""
76+
"""Recurse through a nested dictionary and check if it is a subset of another."""
7777

78-
# Both objects are the same object
79-
if subset is superset:
80-
return True
81-
82-
# Both objects are identical
83-
if subset == superset:
84-
return True
85-
86-
# Both objects have a different type
87-
if isinstance(subset) is not isinstance(superset):
78+
if type(subset) is not type(superset):
8879
return False
8980

81+
if not isinstance(subset, dict):
82+
if isinstance(subset, list):
83+
return all(item in superset for item in subset)
84+
return subset == superset
85+
9086
for key, value in subset.items():
91-
# Ignore empty values
9287
if value is None:
93-
return True
88+
continue
9489

95-
# Item from subset is missing from superset
9690
if key not in superset:
9791
return False
9892

99-
# Item has different types in subset and superset
100-
if isinstance(superset.get(key)) is not isinstance(value):
101-
return False
93+
superset_value = superset.get(key)
10294

103-
# Compare if item values are subset
104-
if isinstance(value, dict):
105-
if not issubset(superset.get(key), value):
106-
return False
107-
elif isinstance(value, list):
108-
try:
109-
# NOTE: Fails for lists of dicts
110-
if not set(value) <= set(superset.get(key)):
111-
return False
112-
except TypeError:
113-
# Fall back to exact comparison for lists of dicts
114-
diff = list(filterfalse(lambda i: i in value, superset.get(key))) + list(filterfalse(lambda j: j in superset.get(key), value))
115-
if diff:
116-
return False
117-
elif isinstance(value, set):
118-
if not value <= superset.get(key):
119-
return False
120-
else:
121-
if not value == superset.get(key):
122-
return False
95+
if not issubset(value, superset_value):
96+
return False
12397

12498
return True
12599

@@ -210,6 +184,9 @@ def __init__(self, module):
210184

211185
# info output
212186
self.previous = dict()
187+
self.before = []
188+
self.commands = []
189+
self.after = []
213190
self.proposed = dict()
214191
self.sent = dict()
215192
self.stdout = None
@@ -433,6 +410,7 @@ def exit_json(self, **kwargs):
433410
if self.params.get("state") in ALLOWED_STATES_TO_APPEND_SENT_AND_PROPOSED:
434411
if self.params.get("output_level") in ("debug", "info"):
435412
self.result["previous"] = self.previous
413+
self.result["before"] = self.before
436414
# FIXME: Modified header only works for PATCH
437415
if not self.has_modified and self.previous != self.existing:
438416
self.result["changed"] = True
@@ -450,8 +428,10 @@ def exit_json(self, **kwargs):
450428
if self.params.get("state") in ALLOWED_STATES_TO_APPEND_SENT_AND_PROPOSED:
451429
self.result["sent"] = self.sent
452430
self.result["proposed"] = self.proposed
431+
self.result["commands"] = self.commands
453432

454433
self.result["current"] = self.existing
434+
self.result["after"] = self.after
455435

456436
if self.module._diff and self.result.get("changed") is True:
457437
self.result["diff"] = dict(
@@ -468,6 +448,7 @@ def fail_json(self, msg, **kwargs):
468448
if self.params.get("state") in ALLOWED_STATES_TO_APPEND_SENT_AND_PROPOSED:
469449
if self.params.get("output_level") in ("debug", "info"):
470450
self.result["previous"] = self.previous
451+
self.result["before"] = self.before
471452
# FIXME: Modified header only works for PATCH
472453
if not self.has_modified and self.previous != self.existing:
473454
self.result["changed"] = True
@@ -486,8 +467,10 @@ def fail_json(self, msg, **kwargs):
486467
if self.params.get("state") in ALLOWED_STATES_TO_APPEND_SENT_AND_PROPOSED:
487468
self.result["sent"] = self.sent
488469
self.result["proposed"] = self.proposed
470+
self.result["commands"] = self.commands
489471

490472
self.result["current"] = self.existing
473+
self.result["after"] = self.after
491474

492475
self.result.update(**kwargs)
493476
self.module.fail_json(msg=msg, **self.result)
@@ -499,23 +482,30 @@ def check_changed(self):
499482
existing["password"] = self.sent.get("password")
500483
return not issubset(self.sent, existing)
501484

502-
def get_diff(self, unwanted=None):
485+
def get_diff(self, unwanted=None, previous=None, payload=None):
503486
"""Check if existing payload and sent payload and removing keys that are not required"""
504487
if unwanted is None:
505488
unwanted = []
506-
if not self.existing and self.sent:
507-
return True
489+
490+
if previous is None and payload is None:
491+
if not self.existing and self.sent:
492+
return True
508493

509494
existing = self.existing
510495
sent = self.sent
511496

497+
if previous and payload:
498+
existing = previous
499+
sent = payload
500+
512501
for key in unwanted:
513502
if isinstance(key, str):
514503
if key in existing:
515504
try:
516505
del existing[key]
517506
except KeyError:
518507
pass
508+
if key in sent:
519509
try:
520510
del sent[key]
521511
except KeyError:
@@ -524,12 +514,14 @@ def get_diff(self, unwanted=None):
524514
key_path, last = key[:-1], key[-1]
525515
try:
526516
existing_parent = reduce(dict.get, key_path, existing)
527-
del existing_parent[last]
517+
if existing_parent is not None:
518+
del existing_parent[last]
528519
except KeyError:
529520
pass
530521
try:
531522
sent_parent = reduce(dict.get, key_path, sent)
532-
del sent_parent[last]
523+
if sent_parent is not None:
524+
del sent_parent[last]
533525
except KeyError:
534526
pass
535527
return not issubset(sent, existing)
@@ -567,3 +559,8 @@ def get_object_by_nested_key_value(self, path, nested_key_path, value, data_key=
567559
return obj
568560

569561
return None
562+
563+
def delete(self, check_mode, path):
564+
if not check_mode:
565+
self.request(path, method="DELETE")
566+
return {"path": path, "method": "DELETE"}

plugins/module_utils/utils.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,44 @@ def snake_to_camel(snake_str, upper_case_components=None):
2424
return camel_case_str
2525
else:
2626
return snake_str
27+
28+
29+
def compare_config_and_remote_objects(remote_objects, config_objects, key="name"):
30+
remote_object_names = {obj[key] for obj in remote_objects}
31+
config_object_names = {obj[key] for obj in config_objects}
32+
33+
# Common objects from Config (name in both remote and config data)
34+
update = [obj for obj in config_objects if obj[key] in remote_object_names]
35+
36+
# Unmatched objects from Remote (name not in Config)
37+
delete = [obj for obj in remote_objects if obj[key] not in config_object_names]
38+
39+
# Unmatched objects from Config (name not in Remote)
40+
create = [obj for obj in config_objects if obj[key] not in remote_object_names]
41+
42+
return {
43+
"config_data_update": update,
44+
"remote_data_delete": delete, # Only when state is overridden
45+
"config_data_create": create,
46+
}
47+
48+
49+
def compare_unordered_list_of_dicts(list1, list2):
50+
if (not isinstance(list1, list) or not isinstance(list2, list)) or (len(list1) != len(list2)):
51+
return False
52+
53+
for dict1 in list1:
54+
found_match = False
55+
for i, dict2 in enumerate(list2):
56+
if dict1 == dict2:
57+
list2.pop(i)
58+
found_match = True
59+
break
60+
if not found_match:
61+
return False
62+
63+
return True
64+
65+
66+
def wrap_objects_by_key(object_list, key="name"):
67+
return {obj.get(key): obj for obj in object_list}

0 commit comments

Comments
 (0)