Skip to content

Commit 797c383

Browse files
authored
Fixes #943: Partial update of custom fields is not idempotent (#944)
It is important that the object's custom fields dictionary contains only those keys that were given by the user. Otherwise the following dictionary comparison does not work and leads to the result, that there is a difference in state even when the entries already have the desired state. The issue is caused, because the comparison takes also those entries into account that were not given by the user. Signed-off-by: Christoph Fiehe <c.fiehe@eurodata.de>
1 parent c8bbd54 commit 797c383

File tree

2 files changed

+32
-14
lines changed

2 files changed

+32
-14
lines changed

plugins/module_utils/netbox_utils.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,22 +1270,16 @@ def _update_netbox_object(self, data):
12701270
NetBox object and the Ansible diff.
12711271
"""
12721272
serialized_nb_obj = self.nb_object.serialize()
1273-
updated_obj = serialized_nb_obj.copy()
1274-
1275-
if serialized_nb_obj.get("custom_fields"):
1273+
if "custom_fields" in serialized_nb_obj:
1274+
custom_fields = serialized_nb_obj.get("custom_fields", {})
1275+
shared_keys = custom_fields.keys() & data.get("custom_fields", {}).keys()
12761276
serialized_nb_obj["custom_fields"] = {
1277-
key: value
1278-
for key, value in serialized_nb_obj["custom_fields"].items()
1279-
if value is not None
1280-
}
1281-
1282-
if updated_obj.get("custom_fields"):
1283-
updated_obj["custom_fields"] = {
1284-
key: value
1285-
for key, value in updated_obj["custom_fields"].items()
1286-
if value is not None
1277+
key: custom_fields[key]
1278+
for key in shared_keys
1279+
if custom_fields[key] is not None
12871280
}
12881281

1282+
updated_obj = serialized_nb_obj.copy()
12891283
updated_obj.update(data)
12901284

12911285
if serialized_nb_obj.get("tags") and data.get("tags"):

tests/unit/module_utils/test_netbox_base_class.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ def fixture_arg_spec():
5454
"manufacturer": "Cisco",
5555
"site": "Test Site",
5656
"asset_tag": "1001",
57+
"custom_fields": {
58+
"Key1": "Value1",
59+
"Key2": "Value2",
60+
"Key3": "Value3",
61+
},
5762
},
5863
"state": "present",
5964
"validate_certs": False,
@@ -70,6 +75,11 @@ def normalized_data():
7075
"manufacturer": "cisco",
7176
"site": "test-site",
7277
"asset_tag": "1001",
78+
"custom_fields": {
79+
"Key1": "Value1",
80+
"Key2": "Value2",
81+
"Key3": "Value3",
82+
},
7383
}
7484

7585

@@ -142,14 +152,28 @@ def mock_netbox_module(mocker, mock_ansible_module, find_ids_return):
142152
def changed_serialized_obj(nb_obj_mock):
143153
changed_serialized_obj = nb_obj_mock.serialize().copy()
144154
changed_serialized_obj["name"] += " (modified)"
155+
changed_serialized_obj["custom_fields"] = {
156+
"Key1": "NewValue1",
157+
}
145158

146159
return changed_serialized_obj
147160

148161

149162
@pytest.fixture
150163
def on_update_diff(mock_netbox_module, nb_obj_mock, changed_serialized_obj):
151164
return mock_netbox_module._build_diff(
152-
before={"name": "Test Device1"}, after={"name": "Test Device1 (modified)"}
165+
before={
166+
"name": "Test Device1",
167+
"custom_fields": {
168+
"Key1": "Value1",
169+
},
170+
},
171+
after={
172+
"name": "Test Device1 (modified)",
173+
"custom_fields": {
174+
"Key1": "NewValue1",
175+
},
176+
},
153177
)
154178

155179

0 commit comments

Comments
 (0)