ipfabric_netbox 4.2.0b5__py3-none-any.whl → 4.2.0b6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ipfabric_netbox/__init__.py +1 -1
- ipfabric_netbox/forms.py +10 -1
- ipfabric_netbox/migrations/0017_ipfabricsync_update_custom_fields.py +17 -0
- ipfabric_netbox/models.py +1 -0
- ipfabric_netbox/tests/test_models.py +47 -10
- ipfabric_netbox/utilities/ipfutils.py +43 -23
- {ipfabric_netbox-4.2.0b5.dist-info → ipfabric_netbox-4.2.0b6.dist-info}/METADATA +1 -1
- {ipfabric_netbox-4.2.0b5.dist-info → ipfabric_netbox-4.2.0b6.dist-info}/RECORD +9 -8
- {ipfabric_netbox-4.2.0b5.dist-info → ipfabric_netbox-4.2.0b6.dist-info}/WHEEL +0 -0
ipfabric_netbox/__init__.py
CHANGED
ipfabric_netbox/forms.py
CHANGED
|
@@ -493,6 +493,12 @@ class IPFabricSyncForm(NetBoxModelForm):
|
|
|
493
493
|
),
|
|
494
494
|
)
|
|
495
495
|
|
|
496
|
+
update_custom_fields = forms.BooleanField(
|
|
497
|
+
required=False,
|
|
498
|
+
label=_("Custom Fields Updating"),
|
|
499
|
+
help_text=_("Update object custom fields where applicable."),
|
|
500
|
+
)
|
|
501
|
+
|
|
496
502
|
scheduled = forms.DateTimeField(
|
|
497
503
|
required=False,
|
|
498
504
|
widget=DateTimePicker(),
|
|
@@ -519,6 +525,7 @@ class IPFabricSyncForm(NetBoxModelForm):
|
|
|
519
525
|
"source",
|
|
520
526
|
"snapshot_data",
|
|
521
527
|
"auto_merge",
|
|
528
|
+
"update_custom_fields",
|
|
522
529
|
"sites",
|
|
523
530
|
"type",
|
|
524
531
|
"tags",
|
|
@@ -550,7 +557,9 @@ class IPFabricSyncForm(NetBoxModelForm):
|
|
|
550
557
|
fieldsets.append(
|
|
551
558
|
FieldSet("scheduled", "interval", name=_("Ingestion Execution Parameters"))
|
|
552
559
|
)
|
|
553
|
-
fieldsets.append(
|
|
560
|
+
fieldsets.append(
|
|
561
|
+
FieldSet("auto_merge", "update_custom_fields", name=_("Extras"))
|
|
562
|
+
)
|
|
554
563
|
fieldsets.append(FieldSet("tags", name=_("Tags")))
|
|
555
564
|
|
|
556
565
|
return fieldsets
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Generated by Django 5.2.5 on 2025-08-22 12:32
|
|
2
|
+
from django.db import migrations
|
|
3
|
+
from django.db import models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("ipfabric_netbox", "0016_tags_and_changelog_for_snapshots"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AddField(
|
|
13
|
+
model_name="ipfabricsync",
|
|
14
|
+
name="update_custom_fields",
|
|
15
|
+
field=models.BooleanField(default=True),
|
|
16
|
+
),
|
|
17
|
+
]
|
ipfabric_netbox/models.py
CHANGED
|
@@ -611,6 +611,7 @@ class IPFabricSync(IPFabricClient, JobsMixin, TagsMixin, ChangeLoggedModel):
|
|
|
611
611
|
)
|
|
612
612
|
parameters = models.JSONField(blank=True, null=True)
|
|
613
613
|
auto_merge = models.BooleanField(default=False)
|
|
614
|
+
update_custom_fields = models.BooleanField(default=True)
|
|
614
615
|
last_synced = models.DateTimeField(blank=True, null=True, editable=False)
|
|
615
616
|
scheduled = models.DateTimeField(null=True, blank=True)
|
|
616
617
|
interval = models.PositiveIntegerField(
|
|
@@ -8,6 +8,7 @@ from django.test import TestCase
|
|
|
8
8
|
from django.utils import timezone
|
|
9
9
|
|
|
10
10
|
from ipfabric_netbox.choices import IPFabricSnapshotStatusModelChoices
|
|
11
|
+
from ipfabric_netbox.models import IPFabricIngestion
|
|
11
12
|
from ipfabric_netbox.models import IPFabricSnapshot
|
|
12
13
|
from ipfabric_netbox.models import IPFabricSource
|
|
13
14
|
from ipfabric_netbox.models import IPFabricSync
|
|
@@ -121,6 +122,7 @@ class IPFabricTransformMapModelTestCase(TestCase):
|
|
|
121
122
|
type="dcim",
|
|
122
123
|
status="new",
|
|
123
124
|
snapshot_data=snapshot,
|
|
125
|
+
update_custom_fields=True,
|
|
124
126
|
parameters={
|
|
125
127
|
"vrf": False,
|
|
126
128
|
"site": True,
|
|
@@ -138,6 +140,8 @@ class IPFabricTransformMapModelTestCase(TestCase):
|
|
|
138
140
|
},
|
|
139
141
|
)
|
|
140
142
|
|
|
143
|
+
ingestion = IPFabricIngestion.objects.create(sync=sync)
|
|
144
|
+
|
|
141
145
|
runner = IPFabricSyncRunner(
|
|
142
146
|
settings={
|
|
143
147
|
"site": True,
|
|
@@ -152,7 +156,11 @@ class IPFabricTransformMapModelTestCase(TestCase):
|
|
|
152
156
|
"snapshot_id": "12dd8c61-129c-431a-b98b-4c9211571f89",
|
|
153
157
|
},
|
|
154
158
|
sync=sync,
|
|
159
|
+
ingestion=ingestion,
|
|
155
160
|
)
|
|
161
|
+
# Need to monkeypatch since we are not in active Branch (different schema)
|
|
162
|
+
# Using default schema "default" here since we are in "test_netbox" DB
|
|
163
|
+
runner.get_db_connection_name = lambda: "default"
|
|
156
164
|
|
|
157
165
|
site_data = {
|
|
158
166
|
"siteName": "MPLS",
|
|
@@ -166,7 +174,9 @@ class IPFabricTransformMapModelTestCase(TestCase):
|
|
|
166
174
|
"networksCount": 6,
|
|
167
175
|
}
|
|
168
176
|
|
|
169
|
-
self.site = runner.
|
|
177
|
+
self.site = runner.sync_item(
|
|
178
|
+
item=site_data, app_label="dcim", model="site", cf=sync.update_custom_fields
|
|
179
|
+
)
|
|
170
180
|
|
|
171
181
|
device_data = {
|
|
172
182
|
"id": "961251111",
|
|
@@ -204,14 +214,36 @@ class IPFabricTransformMapModelTestCase(TestCase):
|
|
|
204
214
|
"slug": None,
|
|
205
215
|
}
|
|
206
216
|
|
|
207
|
-
self.mf_obj = runner.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
217
|
+
self.mf_obj = runner.sync_item(
|
|
218
|
+
item=device_data,
|
|
219
|
+
app_label="dcim",
|
|
220
|
+
model="manufacturer",
|
|
221
|
+
cf=sync.update_custom_fields,
|
|
222
|
+
)
|
|
223
|
+
self.dt_obj = runner.sync_item(
|
|
224
|
+
item=device_data,
|
|
225
|
+
app_label="dcim",
|
|
226
|
+
model="devicetype",
|
|
227
|
+
cf=sync.update_custom_fields,
|
|
228
|
+
)
|
|
229
|
+
self.platform = runner.sync_item(
|
|
230
|
+
item=device_data,
|
|
231
|
+
app_label="dcim",
|
|
232
|
+
model="platform",
|
|
233
|
+
cf=sync.update_custom_fields,
|
|
234
|
+
)
|
|
235
|
+
self.role = runner.sync_item(
|
|
236
|
+
item=device_data,
|
|
237
|
+
app_label="dcim",
|
|
238
|
+
model="devicerole",
|
|
239
|
+
cf=sync.update_custom_fields,
|
|
240
|
+
)
|
|
241
|
+
self.device_object = runner.sync_item(
|
|
242
|
+
item=device_data,
|
|
243
|
+
app_label="dcim",
|
|
244
|
+
model="device",
|
|
245
|
+
cf=sync.update_custom_fields,
|
|
246
|
+
)
|
|
215
247
|
|
|
216
248
|
def test_transform_map(self):
|
|
217
249
|
site_transform_map = IPFabricTransformMap.objects.get(name="Site Transform Map")
|
|
@@ -383,5 +415,10 @@ class IPFabricTransformMapModelTestCase(TestCase):
|
|
|
383
415
|
)
|
|
384
416
|
transform_field.template = "{{ object.hostname }} - test"
|
|
385
417
|
transform_field.save()
|
|
386
|
-
device_object = runner.
|
|
418
|
+
device_object = runner.sync_item(
|
|
419
|
+
item=device_data,
|
|
420
|
+
app_label="dcim",
|
|
421
|
+
model="device",
|
|
422
|
+
cf=sync.update_custom_fields,
|
|
423
|
+
)
|
|
387
424
|
self.assertEqual(device_object.name, "L21PE152 - test")
|
|
@@ -589,6 +589,35 @@ class IPFabricSyncRunner(object):
|
|
|
589
589
|
|
|
590
590
|
return instance
|
|
591
591
|
|
|
592
|
+
def sync_item(
|
|
593
|
+
self,
|
|
594
|
+
item,
|
|
595
|
+
app_label: str,
|
|
596
|
+
model: str,
|
|
597
|
+
cf: bool = False,
|
|
598
|
+
ingestion: "IPFabricIngestion" = None,
|
|
599
|
+
) -> ModelTypeVar | None:
|
|
600
|
+
"""Sync a single item to NetBox."""
|
|
601
|
+
synced_object = self.sync_model(
|
|
602
|
+
app_label=app_label,
|
|
603
|
+
model=model,
|
|
604
|
+
data=item,
|
|
605
|
+
sync=self.settings.get(model),
|
|
606
|
+
)
|
|
607
|
+
if synced_object is None:
|
|
608
|
+
return None
|
|
609
|
+
|
|
610
|
+
if cf:
|
|
611
|
+
synced_object.snapshot()
|
|
612
|
+
synced_object.custom_field_data[
|
|
613
|
+
"ipfabric_source"
|
|
614
|
+
] = self.sync.snapshot_data.source.pk
|
|
615
|
+
if ingestion:
|
|
616
|
+
synced_object.custom_field_data["ipfabric_ingestion"] = ingestion.pk
|
|
617
|
+
synced_object.save()
|
|
618
|
+
|
|
619
|
+
return synced_object
|
|
620
|
+
|
|
592
621
|
def sync_items(
|
|
593
622
|
self,
|
|
594
623
|
items,
|
|
@@ -605,23 +634,7 @@ class IPFabricSyncRunner(object):
|
|
|
605
634
|
return
|
|
606
635
|
|
|
607
636
|
for item in items:
|
|
608
|
-
|
|
609
|
-
app_label=app_label,
|
|
610
|
-
model=model,
|
|
611
|
-
data=item,
|
|
612
|
-
sync=self.settings.get(model),
|
|
613
|
-
)
|
|
614
|
-
if synced_object is None:
|
|
615
|
-
continue
|
|
616
|
-
|
|
617
|
-
if cf:
|
|
618
|
-
synced_object.snapshot()
|
|
619
|
-
synced_object.custom_field_data[
|
|
620
|
-
"ipfabric_source"
|
|
621
|
-
] = self.sync.snapshot_data.source.pk
|
|
622
|
-
if ingestion:
|
|
623
|
-
synced_object.custom_field_data["ipfabric_ingestion"] = ingestion.pk
|
|
624
|
-
synced_object.save()
|
|
637
|
+
self.sync_item(item, app_label, model, cf, ingestion)
|
|
625
638
|
|
|
626
639
|
@handle_errors
|
|
627
640
|
def sync_devices(
|
|
@@ -684,11 +697,14 @@ class IPFabricSyncRunner(object):
|
|
|
684
697
|
|
|
685
698
|
if device_object and self.settings.get("device"):
|
|
686
699
|
device_object.snapshot()
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
700
|
+
if self.sync.update_custom_fields:
|
|
701
|
+
device_object.custom_field_data[
|
|
702
|
+
"ipfabric_source"
|
|
703
|
+
] = self.sync.snapshot_data.source.pk
|
|
704
|
+
if ingestion:
|
|
705
|
+
device_object.custom_field_data[
|
|
706
|
+
"ipfabric_ingestion"
|
|
707
|
+
] = ingestion.pk
|
|
692
708
|
device_object.save()
|
|
693
709
|
|
|
694
710
|
self.logger.increment_statistics(model="device")
|
|
@@ -829,7 +845,11 @@ class IPFabricSyncRunner(object):
|
|
|
829
845
|
) = self.collect_data()
|
|
830
846
|
|
|
831
847
|
self.sync_items(
|
|
832
|
-
app_label="dcim",
|
|
848
|
+
app_label="dcim",
|
|
849
|
+
model="site",
|
|
850
|
+
items=sites,
|
|
851
|
+
cf=self.sync.update_custom_fields,
|
|
852
|
+
ingestion=ingestion,
|
|
833
853
|
)
|
|
834
854
|
self.sync_devices(
|
|
835
855
|
ingestion,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
ipfabric_netbox/__init__.py,sha256=
|
|
1
|
+
ipfabric_netbox/__init__.py,sha256=E5BKH5-wfz4YUPlNookiC6kVSmlN7ZR5mc7rN9YeHCY,674
|
|
2
2
|
ipfabric_netbox/api/__init__.py,sha256=XRclTGWVR0ZhAAwgYul5Wm_loug5_hUjEumbLQEwKYM,47
|
|
3
3
|
ipfabric_netbox/api/serializers.py,sha256=RV1tmkbRF_Est3x1w_bfk63qwgEQc97Bm4mk89tv2FU,6502
|
|
4
4
|
ipfabric_netbox/api/urls.py,sha256=1fXXVTxNY5E64Nfz6b7zXD9bZI3FcefuxAWKMe0w_QU,1240
|
|
@@ -7,7 +7,7 @@ ipfabric_netbox/choices.py,sha256=tQ5RHwmuArQ7dCLcE3A_Bnw2ctGHgw67z--AawyyPPg,52
|
|
|
7
7
|
ipfabric_netbox/data/transform_map.json,sha256=4PsucgMHcLW3SPoKEptQCd0gA5tCF4hjrR4bGQFCWy8,21744
|
|
8
8
|
ipfabric_netbox/exceptions.py,sha256=DT4dpbakvqoROtBR_F0LzvQCMNWpGhufFcUbZTx0OLY,2655
|
|
9
9
|
ipfabric_netbox/filtersets.py,sha256=FrlHkLWf_mNMTaT_Zm2wl1wYkHXMX7hXxMLYAkC6_Gg,7922
|
|
10
|
-
ipfabric_netbox/forms.py,sha256=
|
|
10
|
+
ipfabric_netbox/forms.py,sha256=PLAoSJGqwHWPVO5F8Sf2iJv-L5xjYzv-wseiasaxdlg,44767
|
|
11
11
|
ipfabric_netbox/graphql/__init__.py,sha256=-a5w_VY7pc-RVt8MvThkTzeAqCC3xCan4Ue6iMefmjI,754
|
|
12
12
|
ipfabric_netbox/graphql/enums.py,sha256=4jtB2gKsmPXu9is5jd38hUbfrt1V5Wm1Ff-2JCDI3EU,1518
|
|
13
13
|
ipfabric_netbox/graphql/filters.py,sha256=NGIxHIQhmya-aEsgzQgkRjwMxV1jaGOPxLzRzlrJPPg,12587
|
|
@@ -31,8 +31,9 @@ ipfabric_netbox/migrations/0013_switch_to_branching_plugin.py,sha256=JfdTNerjuFy
|
|
|
31
31
|
ipfabric_netbox/migrations/0014_ipfabrictransformmapgroup_ipfabrictransformmap_group.py,sha256=RCfgKyqQhTkfSPhf0IukI3fjeAEBUs5pKWIpsLxgzp0,2272
|
|
32
32
|
ipfabric_netbox/migrations/0015_ipfabricingestionissue.py,sha256=AjAkyboa4BSXsN53BqzO1k_U6QHu4rlA2IhzhubocJw,1732
|
|
33
33
|
ipfabric_netbox/migrations/0016_tags_and_changelog_for_snapshots.py,sha256=XqftTQ4GFnoCoGSHPa2WL_bjSVCGxdP2MFXCUa6LN1k,929
|
|
34
|
+
ipfabric_netbox/migrations/0017_ipfabricsync_update_custom_fields.py,sha256=IVbAL2WdigYT40sXN0A8K3HweJ_O4QqyzjB06TbkG5E,447
|
|
34
35
|
ipfabric_netbox/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
-
ipfabric_netbox/models.py,sha256=
|
|
36
|
+
ipfabric_netbox/models.py,sha256=U9_ooh8juhtXwwcj0ay_6KZ-FlBt2SYrR7YCScAYa9k,36168
|
|
36
37
|
ipfabric_netbox/navigation.py,sha256=2dEJ_wKHb52Tl0FOV1TH3JbxRe8YZ56ewrTsBFGKpCg,2210
|
|
37
38
|
ipfabric_netbox/signals.py,sha256=cGa5PVD2i24pGXiVNfbu6ruIDqPVdwKQHTSWe9Ura84,1838
|
|
38
39
|
ipfabric_netbox/tables.py,sha256=pHKv6Bosjnc-7aApak3nLhzxqBiA30olPdaMO8F1PQg,8262
|
|
@@ -70,14 +71,14 @@ ipfabric_netbox/templatetags/ipfabric_netbox_helpers.py,sha256=STw4pAd2qG7hgf-O6
|
|
|
70
71
|
ipfabric_netbox/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
72
|
ipfabric_netbox/tests/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
72
73
|
ipfabric_netbox/tests/api/test_api.py,sha256=DVMnhtleWJdpmVHafqCh9fgN6PZhWMEBXBL_rfm3ly8,30615
|
|
73
|
-
ipfabric_netbox/tests/test_models.py,sha256=
|
|
74
|
+
ipfabric_netbox/tests/test_models.py,sha256=rPwdVs127vU78yOcmlC44f7dZw12oLVzTSJf1nH0jus,16068
|
|
74
75
|
ipfabric_netbox/urls.py,sha256=ok66LP09rYi01qJmwdGGlBzV9wrGWVwVAIngPcreJxg,5449
|
|
75
76
|
ipfabric_netbox/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
|
-
ipfabric_netbox/utilities/ipfutils.py,sha256=
|
|
77
|
+
ipfabric_netbox/utilities/ipfutils.py,sha256=wFmL5oriuF-is1ZlrIcLmoeYUY5ih-CA9weRQrx5AiA,31885
|
|
77
78
|
ipfabric_netbox/utilities/logging.py,sha256=GYknjocMN6LQ2873_az3y0RKm29TCXaWviUIIneH-x0,3445
|
|
78
79
|
ipfabric_netbox/utilities/nbutils.py,sha256=kFBEiJOGvr_49hJWCS2duXojx2-A9kVk0Xp_vj0ohfs,2641
|
|
79
80
|
ipfabric_netbox/utilities/transform_map.py,sha256=QotbGc2TksINJrb62STgAigpC5Nsgi5umYHu_0rZd8k,2204
|
|
80
81
|
ipfabric_netbox/views.py,sha256=nGWO-PlTyKviBzGEdmE3C_1I-xFjZMldqOWGx12wdbg,36855
|
|
81
|
-
ipfabric_netbox-4.2.
|
|
82
|
-
ipfabric_netbox-4.2.
|
|
83
|
-
ipfabric_netbox-4.2.
|
|
82
|
+
ipfabric_netbox-4.2.0b6.dist-info/METADATA,sha256=UKZI463uPse64h8bR0yCQQvkYUbqTuWwZlDMtG5fpFY,4638
|
|
83
|
+
ipfabric_netbox-4.2.0b6.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
84
|
+
ipfabric_netbox-4.2.0b6.dist-info/RECORD,,
|
|
File without changes
|