ipfabric_netbox 3.1.2__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.

Potentially problematic release.


This version of ipfabric_netbox might be problematic. Click here for more details.

Files changed (59) hide show
  1. ipfabric_netbox/__init__.py +42 -0
  2. ipfabric_netbox/api/__init__.py +2 -0
  3. ipfabric_netbox/api/nested_serializers.py +99 -0
  4. ipfabric_netbox/api/serializers.py +160 -0
  5. ipfabric_netbox/api/urls.py +21 -0
  6. ipfabric_netbox/api/views.py +111 -0
  7. ipfabric_netbox/choices.py +226 -0
  8. ipfabric_netbox/filtersets.py +125 -0
  9. ipfabric_netbox/forms.py +1063 -0
  10. ipfabric_netbox/jobs.py +95 -0
  11. ipfabric_netbox/migrations/0001_initial.py +342 -0
  12. ipfabric_netbox/migrations/0002_ipfabricsnapshot_status.py +17 -0
  13. ipfabric_netbox/migrations/0003_ipfabricsource_type_and_more.py +49 -0
  14. ipfabric_netbox/migrations/0004_ipfabricsync_auto_merge.py +17 -0
  15. ipfabric_netbox/migrations/0005_alter_ipfabricrelationshipfield_source_model_and_more.py +64 -0
  16. ipfabric_netbox/migrations/0006_alter_ipfabrictransformmap_target_model.py +48 -0
  17. ipfabric_netbox/migrations/__init__.py +0 -0
  18. ipfabric_netbox/models.py +874 -0
  19. ipfabric_netbox/navigation.py +62 -0
  20. ipfabric_netbox/signals.py +68 -0
  21. ipfabric_netbox/tables.py +208 -0
  22. ipfabric_netbox/template_content.py +13 -0
  23. ipfabric_netbox/templates/ipfabric_netbox/inc/diff.html +72 -0
  24. ipfabric_netbox/templates/ipfabric_netbox/inc/json.html +20 -0
  25. ipfabric_netbox/templates/ipfabric_netbox/inc/logs_pending.html +6 -0
  26. ipfabric_netbox/templates/ipfabric_netbox/inc/merge_form.html +22 -0
  27. ipfabric_netbox/templates/ipfabric_netbox/inc/site_topology_button.html +70 -0
  28. ipfabric_netbox/templates/ipfabric_netbox/inc/site_topology_modal.html +61 -0
  29. ipfabric_netbox/templates/ipfabric_netbox/inc/snapshotdata.html +60 -0
  30. ipfabric_netbox/templates/ipfabric_netbox/inc/sync_delete.html +19 -0
  31. ipfabric_netbox/templates/ipfabric_netbox/inc/transform_map_field_map.html +11 -0
  32. ipfabric_netbox/templates/ipfabric_netbox/inc/transform_map_relationship_map.html +11 -0
  33. ipfabric_netbox/templates/ipfabric_netbox/ipfabric_table.html +55 -0
  34. ipfabric_netbox/templates/ipfabric_netbox/ipfabricbranch.html +141 -0
  35. ipfabric_netbox/templates/ipfabric_netbox/ipfabricsnapshot.html +105 -0
  36. ipfabric_netbox/templates/ipfabric_netbox/ipfabricsource.html +111 -0
  37. ipfabric_netbox/templates/ipfabric_netbox/ipfabricsync.html +103 -0
  38. ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap.html +41 -0
  39. ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap_list.html +17 -0
  40. ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap_restore.html +59 -0
  41. ipfabric_netbox/templates/ipfabric_netbox/partials/branch_all.html +10 -0
  42. ipfabric_netbox/templates/ipfabric_netbox/partials/branch_progress.html +19 -0
  43. ipfabric_netbox/templates/ipfabric_netbox/partials/branch_status.html +1 -0
  44. ipfabric_netbox/templates/ipfabric_netbox/partials/job_logs.html +53 -0
  45. ipfabric_netbox/templates/ipfabric_netbox/partials/sync_last_branch.html +1 -0
  46. ipfabric_netbox/templates/ipfabric_netbox/sync_list.html +126 -0
  47. ipfabric_netbox/templates/static/ipfabric_netbox/css/rack.css +9 -0
  48. ipfabric_netbox/tests/__init__.py +0 -0
  49. ipfabric_netbox/tests/test_models.py +1340 -0
  50. ipfabric_netbox/urls.py +141 -0
  51. ipfabric_netbox/utilities/__init__.py +0 -0
  52. ipfabric_netbox/utilities/ipfutils.py +591 -0
  53. ipfabric_netbox/utilities/logging.py +93 -0
  54. ipfabric_netbox/utilities/nbutils.py +105 -0
  55. ipfabric_netbox/utilities/transform_map.py +35 -0
  56. ipfabric_netbox/views.py +845 -0
  57. ipfabric_netbox-3.1.2.dist-info/METADATA +88 -0
  58. ipfabric_netbox-3.1.2.dist-info/RECORD +59 -0
  59. ipfabric_netbox-3.1.2.dist-info/WHEEL +4 -0
@@ -0,0 +1,1063 @@
1
+ import copy
2
+
3
+ from core.choices import DataSourceStatusChoices
4
+ from django import forms
5
+ from django.conf import settings
6
+ from django.contrib.contenttypes.models import ContentType
7
+ from django.core.exceptions import ValidationError
8
+ from django.utils import timezone
9
+ from django.utils.translation import gettext_lazy as _
10
+ from extras.choices import DurationChoices
11
+ from netbox.forms import NetBoxModelFilterSetForm
12
+ from netbox.forms import NetBoxModelForm
13
+ from packaging import version
14
+ from utilities.datetime import local_now
15
+ from utilities.forms import add_blank_choice
16
+ from utilities.forms import FilterForm
17
+ from utilities.forms import get_field_value
18
+ from utilities.forms.fields import CommentField
19
+ from utilities.forms.fields import DynamicModelChoiceField
20
+ from utilities.forms.fields import DynamicModelMultipleChoiceField
21
+ from utilities.forms.rendering import FieldSet
22
+ from utilities.forms.widgets import APISelectMultiple
23
+ from utilities.forms.widgets import DateTimePicker
24
+ from utilities.forms.widgets import HTMXSelect
25
+ from utilities.forms.widgets import NumberWithOptions
26
+
27
+ from .choices import IPFabricSnapshotStatusModelChoices
28
+ from .choices import transform_field_source_columns
29
+ from .models import IPFabricBranch
30
+ from .models import IPFabricRelationshipField
31
+ from .models import IPFabricSnapshot
32
+ from .models import IPFabricSource
33
+ from .models import IPFabricSync
34
+ from .models import IPFabricTransformField
35
+ from .models import IPFabricTransformMap
36
+
37
+ NETBOX_CURRENT_VERSION = version.parse(settings.VERSION)
38
+
39
+ if NETBOX_CURRENT_VERSION >= version.parse("3.7.0"):
40
+ from netbox.forms.mixins import SavedFiltersMixin
41
+ else:
42
+ from extras.forms.mixins import SavedFiltersMixin
43
+
44
+ exclude_fields = [
45
+ "id",
46
+ "created",
47
+ "last_updated",
48
+ "custom_field_data",
49
+ "_name",
50
+ "status",
51
+ ]
52
+
53
+
54
+ class IPFSiteChoiceField(forms.MultipleChoiceField):
55
+ def valid_value(self, value):
56
+ """Check to see if the provided value is a valid choice."""
57
+ text_value = str(value)
58
+ for k, v in self.choices:
59
+ if isinstance(v, (list, tuple)):
60
+ for k2, v2 in v:
61
+ if value == k2 or text_value == str(k2):
62
+ return True
63
+ else:
64
+ if value == k or text_value == str(k):
65
+ return True
66
+ return False
67
+
68
+
69
+ dcim_parameters = {
70
+ "site": forms.BooleanField(required=False, label=_("Sites"), initial=True),
71
+ "manufacturer": forms.BooleanField(
72
+ required=False, label=_("Manufacturers"), initial=True
73
+ ),
74
+ "devicetype": forms.BooleanField(
75
+ required=False, label=_("Device Types"), initial=True
76
+ ),
77
+ "devicerole": forms.BooleanField(
78
+ required=False, label=_("Device Roles"), initial=True
79
+ ),
80
+ "platform": forms.BooleanField(required=False, label=_("Platforms"), initial=True),
81
+ "device": forms.BooleanField(required=False, label=_("Devices"), initial=True),
82
+ "virtualchassis": forms.BooleanField(
83
+ required=False, label=_("Virtual Chassis"), initial=True
84
+ ),
85
+ "interface": forms.BooleanField(required=False, label=_("Interfaces")),
86
+ "inventoryitem": forms.BooleanField(required=False, label=_("Part Numbers")),
87
+ }
88
+ ipam_parameters = {
89
+ "vlan": forms.BooleanField(required=False, label=_("VLANs")),
90
+ "vrf": forms.BooleanField(required=False, label=_("VRFs")),
91
+ "prefix": forms.BooleanField(required=False, label=_("Prefixes")),
92
+ "ipaddress": forms.BooleanField(required=False, label=_("IP Addresses")),
93
+ }
94
+ sync_parameters = {"dcim": dcim_parameters, "ipam": ipam_parameters}
95
+
96
+
97
+ def source_column_choices(model):
98
+ columns = transform_field_source_columns.get(model, None)
99
+ if columns:
100
+ choices = [(f, f) for f in transform_field_source_columns.get(model)]
101
+ else:
102
+ choices = []
103
+ return choices
104
+
105
+
106
+ def add_all_sites(choices):
107
+ """
108
+ Add a blank choice to the beginning of a choices list.
109
+ """
110
+ return ((None, "All Sites"),) + tuple(choices)
111
+
112
+
113
+ def str_to_list(str):
114
+ if not isinstance(str, list):
115
+ return [str]
116
+ else:
117
+ return str
118
+
119
+
120
+ def list_to_choices(choices):
121
+ new_choices = ()
122
+ for choice in choices:
123
+ new_choices = new_choices + ((choice, choice),)
124
+ return new_choices
125
+
126
+
127
+ class IPFabricRelationshipFieldForm(NetBoxModelForm):
128
+ coalesce = forms.BooleanField(required=False, initial=False)
129
+ target_field = forms.CharField(
130
+ label="Target Field",
131
+ required=True,
132
+ help_text="Select target model field.",
133
+ widget=forms.Select(),
134
+ )
135
+
136
+ fieldsets = (
137
+ FieldSet(
138
+ "transform_map",
139
+ "source_model",
140
+ "target_field",
141
+ "coalesce",
142
+ name=_("Transform Map"),
143
+ ),
144
+ FieldSet("template", name=_("Extras")),
145
+ )
146
+
147
+ class Meta:
148
+ model = IPFabricRelationshipField
149
+ fields = (
150
+ "transform_map",
151
+ "source_model",
152
+ "target_field",
153
+ "coalesce",
154
+ "template",
155
+ )
156
+ widgets = {
157
+ "transform_map": HTMXSelect(),
158
+ }
159
+ help_texts = {
160
+ "link_text": _(
161
+ "Jinja2 template code for the source field. Reference the object as <code>{{ object }}</code>. "
162
+ "templates which render as empty text will not be displayed."
163
+ ),
164
+ }
165
+
166
+ def __init__(self, *args, **kwargs):
167
+ super().__init__(*args, **kwargs)
168
+ if not self.data:
169
+ if self.instance and self.instance.pk is not None:
170
+ fields = (
171
+ self.instance.transform_map.target_model.model_class()._meta.fields
172
+ )
173
+ self.fields["target_field"].widget.choices = add_blank_choice(
174
+ [
175
+ (f.name, f.verbose_name)
176
+ for f in fields
177
+ if f.is_relation and f.name not in exclude_fields
178
+ ]
179
+ )
180
+ self.fields["target_field"].widget.initial = self.instance.target_field
181
+ else:
182
+ if kwargs["initial"].get("transform_map", None):
183
+ transform_map_id = kwargs["initial"]["transform_map"]
184
+ transform_map = IPFabricTransformMap.objects.get(
185
+ pk=transform_map_id
186
+ )
187
+ fields = transform_map.target_model.model_class()._meta.fields
188
+ choices = [
189
+ (f.name, f.verbose_name)
190
+ for f in fields
191
+ if f.is_relation and f.name not in exclude_fields
192
+ ]
193
+ self.fields["target_field"].widget.choices = add_blank_choice(
194
+ choices
195
+ )
196
+
197
+
198
+ class IPFabricTransformFieldForm(NetBoxModelForm):
199
+ coalesce = forms.BooleanField(required=False, initial=False)
200
+ source_field = forms.CharField(
201
+ label="Source Field",
202
+ required=True,
203
+ help_text="Select column from IP Fabric.",
204
+ widget=forms.Select(),
205
+ )
206
+ target_field = forms.CharField(
207
+ label="Target Field",
208
+ required=True,
209
+ help_text="Select target model field.",
210
+ widget=forms.Select(),
211
+ )
212
+
213
+ fieldsets = (
214
+ FieldSet(
215
+ "transform_map",
216
+ "source_field",
217
+ "target_field",
218
+ "coalesce",
219
+ name=_("Transform Map"),
220
+ ),
221
+ FieldSet("template", name=_("Extras")),
222
+ )
223
+
224
+ class Meta:
225
+ model = IPFabricTransformField
226
+ fields = (
227
+ "transform_map",
228
+ "source_field",
229
+ "target_field",
230
+ "coalesce",
231
+ "template",
232
+ )
233
+ widgets = {
234
+ "template": forms.Textarea(attrs={"class": "font-monospace"}),
235
+ "transform_map": HTMXSelect(),
236
+ }
237
+ help_texts = {
238
+ "link_text": _(
239
+ "Jinja2 template code for the source field. Reference the object as <code>{{ object }}</code>. "
240
+ "templates which render as empty text will not be displayed."
241
+ ),
242
+ }
243
+
244
+ def __init__(self, *args, **kwargs):
245
+ super().__init__(*args, **kwargs)
246
+ if not self.data:
247
+ if self.instance and self.instance.pk is not None:
248
+ fields = (
249
+ self.instance.transform_map.target_model.model_class()._meta.fields
250
+ )
251
+ source_fields = self.instance.transform_map.source_model
252
+ self.fields["target_field"].widget.choices = add_blank_choice(
253
+ [
254
+ (f.name, f.verbose_name)
255
+ for f in fields
256
+ if not f.is_relation and f.name not in exclude_fields
257
+ ]
258
+ )
259
+ self.fields["target_field"].widget.initial = self.instance.target_field
260
+ self.fields["source_field"].widget.choices = add_blank_choice(
261
+ source_column_choices(source_fields)
262
+ )
263
+ else:
264
+ if kwargs["initial"].get("transform_map", None):
265
+ transform_map_id = kwargs["initial"]["transform_map"]
266
+ transform_map = IPFabricTransformMap.objects.get(
267
+ pk=transform_map_id
268
+ )
269
+ fields = transform_map.target_model.model_class()._meta.fields
270
+ choices = [
271
+ (f.name, f.verbose_name)
272
+ for f in fields
273
+ if not f.is_relation and f.name not in exclude_fields
274
+ ]
275
+ self.fields["target_field"].widget.choices = add_blank_choice(
276
+ choices
277
+ )
278
+ self.fields["source_field"].widget.choices = add_blank_choice(
279
+ source_column_choices(transform_map.source_model)
280
+ )
281
+
282
+
283
+ class IPFabricTransformMapForm(forms.ModelForm):
284
+ status = forms.CharField(
285
+ required=False,
286
+ label=_("Status"),
287
+ widget=forms.Select(),
288
+ )
289
+
290
+ class Meta:
291
+ model = IPFabricTransformMap
292
+ fields = ("name", "source_model", "target_model", "status")
293
+ widgets = {
294
+ "target_model": HTMXSelect(hx_url="/plugins/ipfabric/transform-map/add"),
295
+ }
296
+
297
+ def __init__(self, *args, **kwargs):
298
+ super().__init__(*args, **kwargs)
299
+ if not self.data:
300
+ if kwargs["initial"].get("target_model"):
301
+ target_model = ContentType.objects.get(
302
+ pk=kwargs["initial"].get("target_model")
303
+ )
304
+ try:
305
+ status = target_model.model_class()._meta.get_field("status")
306
+ self.fields["status"].widget.choices = add_blank_choice(
307
+ status.choices
308
+ )
309
+ self.fields["status"].widget.initial = get_field_value(
310
+ self, "status"
311
+ )
312
+ except Exception as e: # noqa: F841
313
+ self.fields["status"].widget.attrs["disabled"] = "disabled"
314
+ else:
315
+ if self.instance and self.instance.pk is not None:
316
+ transform_map = self.instance.target_model.model_class()
317
+ try:
318
+ status = transform_map._meta.get_field("status")
319
+ self.fields["status"].widget.choices = add_blank_choice(
320
+ status.choices
321
+ )
322
+ self.fields["status"].widget.initial = get_field_value(
323
+ self, "status"
324
+ )
325
+ except Exception as e: # noqa: F841
326
+ self.fields["status"].widget.attrs["disabled"] = "disabled"
327
+
328
+
329
+ class IPFabricSnapshotFilterForm(NetBoxModelFilterSetForm):
330
+ model = IPFabricSnapshot
331
+ fieldsets = (
332
+ FieldSet("q", "filter_id"),
333
+ FieldSet("name", "source_id", "status", "snapshot_id", name=_("Source")),
334
+ )
335
+ name = forms.CharField(required=False, label=_("Name"))
336
+ status = forms.CharField(required=False, label=_("Status"))
337
+ source_id = DynamicModelMultipleChoiceField(
338
+ queryset=IPFabricSource.objects.all(), required=False, label=_("Source")
339
+ )
340
+ snapshot_id = forms.CharField(required=False, label=_("Snapshot ID"))
341
+
342
+
343
+ class IPFabricSourceFilterForm(NetBoxModelFilterSetForm):
344
+ model = IPFabricSource
345
+ fieldsets = (
346
+ FieldSet("q", "filter_id"),
347
+ FieldSet("status", name=_("Source")),
348
+ )
349
+ status = forms.MultipleChoiceField(choices=DataSourceStatusChoices, required=False)
350
+
351
+
352
+ class IPFabricBranchFilterForm(SavedFiltersMixin, FilterForm):
353
+ fieldsets = (
354
+ FieldSet("q", "filter_id"),
355
+ FieldSet("sync_id", name=_("Source")),
356
+ )
357
+ model = IPFabricBranch
358
+ sync_id = DynamicModelMultipleChoiceField(
359
+ queryset=IPFabricSync.objects.all(), required=False, label=_("Sync")
360
+ )
361
+
362
+
363
+ class IPFabricSourceForm(NetBoxModelForm):
364
+ comments = CommentField()
365
+
366
+ class Meta:
367
+ model = IPFabricSource
368
+ fields = [
369
+ "name",
370
+ "type",
371
+ "url",
372
+ "description",
373
+ "comments",
374
+ ]
375
+ widgets = {
376
+ "type": HTMXSelect(),
377
+ }
378
+
379
+ @property
380
+ def fieldsets(self):
381
+ fieldsets = [
382
+ FieldSet("name", "type", "url", name=_("Source")),
383
+ FieldSet("timeout", name=_("Parameters")),
384
+ ]
385
+
386
+ if self.source_type == "local":
387
+ fieldsets[1] = FieldSet("auth", "verify", "timeout", name=_("Parameters"))
388
+
389
+ return fieldsets
390
+
391
+ def __init__(self, *args, **kwargs):
392
+ super().__init__(*args, **kwargs)
393
+ self.source_type = get_field_value(self, "type")
394
+
395
+ self.fields["timeout"] = forms.IntegerField(
396
+ required=False,
397
+ label=_("Timeout"),
398
+ help_text=_("Timeout for the API request."),
399
+ widget=forms.NumberInput(attrs={"class": "form-control"}),
400
+ )
401
+
402
+ if self.source_type == "local":
403
+ self.fields["auth"] = forms.CharField(
404
+ required=True,
405
+ label=_("API Token"),
406
+ widget=forms.TextInput(attrs={"class": "form-control"}),
407
+ help_text=_("IP Fabric API Token."),
408
+ )
409
+ self.fields["verify"] = forms.BooleanField(
410
+ required=False,
411
+ initial=True,
412
+ help_text=_(
413
+ "Certificate validation. Uncheck if using self signed certificate."
414
+ ),
415
+ )
416
+ if self.instance.pk:
417
+ for name, form_field in self.instance.parameters.items():
418
+ self.fields[name].initial = self.instance.parameters.get(name)
419
+
420
+ def save(self, *args, **kwargs):
421
+ parameters = {}
422
+ for name in self.fields:
423
+ if name.startswith("auth"):
424
+ parameters["auth"] = self.cleaned_data[name]
425
+ if name.startswith("verify"):
426
+ parameters["verify"] = self.cleaned_data[name]
427
+ if name.startswith("timeout"):
428
+ parameters["timeout"] = self.cleaned_data[name]
429
+
430
+ self.instance.parameters = parameters
431
+ self.instance.status = DataSourceStatusChoices.NEW
432
+
433
+ instance = super().save(*args, **kwargs)
434
+
435
+ if instance.type == "remote":
436
+ if not IPFabricSnapshot.objects.filter(
437
+ source=instance, snapshot_id="$last"
438
+ ).exists():
439
+ IPFabricSnapshot.objects.create(
440
+ source=instance,
441
+ name="$last",
442
+ snapshot_id="$last",
443
+ status=IPFabricSnapshotStatusModelChoices.STATUS_LOADED,
444
+ last_updated=timezone.now(),
445
+ )
446
+
447
+ return instance
448
+
449
+
450
+ class IPFabricSyncForm(NetBoxModelForm):
451
+ source = forms.ModelChoiceField(
452
+ queryset=IPFabricSource.objects.all(),
453
+ required=True,
454
+ label=_("IP Fabric Source"),
455
+ widget=HTMXSelect(),
456
+ )
457
+ snapshot_data = DynamicModelChoiceField(
458
+ queryset=IPFabricSnapshot.objects.filter(status="loaded"),
459
+ required=True,
460
+ label=_("Snapshot"),
461
+ query_params={
462
+ "source_id": "$source",
463
+ "status": "loaded",
464
+ },
465
+ )
466
+
467
+ sites = forms.MultipleChoiceField(
468
+ required=False,
469
+ label=_("Sites"),
470
+ widget=APISelectMultiple(
471
+ api_url="/api/plugins/ipfabric/snapshot/{{snapshot_data}}/sites/",
472
+ ),
473
+ )
474
+
475
+ scheduled = forms.DateTimeField(
476
+ required=False,
477
+ widget=DateTimePicker(),
478
+ label=_("Schedule at"),
479
+ help_text=_("Schedule execution of sync to a set time"),
480
+ )
481
+ interval = forms.IntegerField(
482
+ required=False,
483
+ min_value=1,
484
+ label=_("Recurs every"),
485
+ widget=NumberWithOptions(options=DurationChoices),
486
+ help_text=_("Interval at which this sync is re-run (in minutes)"),
487
+ )
488
+ auto_merge = forms.BooleanField(
489
+ required=False,
490
+ label=_("Auto Merge"),
491
+ help_text=_("Automatically merge staged changes into NetBox"),
492
+ )
493
+
494
+ class Meta:
495
+ model = IPFabricSync
496
+ fields = (
497
+ "name",
498
+ "source",
499
+ "snapshot_data",
500
+ "auto_merge",
501
+ "sites",
502
+ "type",
503
+ "tags",
504
+ "scheduled",
505
+ "interval",
506
+ )
507
+ widgets = {
508
+ "source": HTMXSelect(),
509
+ "type": HTMXSelect(),
510
+ }
511
+
512
+ @property
513
+ def fieldsets(self):
514
+ fieldsets = [
515
+ FieldSet("name", "source", name=_("IP Fabric Source")),
516
+ ]
517
+ if self.source_type == "local":
518
+ fieldsets.append(
519
+ FieldSet("snapshot_data", "sites", name=_("Snapshot Information")),
520
+ )
521
+ else:
522
+ fieldsets.append(
523
+ FieldSet("snapshot_data", name=_("Snapshot Information")),
524
+ )
525
+ fieldsets.append(FieldSet("type", name=_("Ingestion Type")))
526
+ if self.backend_fields:
527
+ for k, v in self.backend_fields.items():
528
+ fieldsets.append(FieldSet(*v, name=f"{k.upper()} Parameters"))
529
+ fieldsets.append(
530
+ FieldSet("scheduled", "interval", name=_("Ingestion Execution Parameters"))
531
+ )
532
+ fieldsets.append(FieldSet("auto_merge", name=_("Extras")))
533
+ fieldsets.append(FieldSet("tags", name=_("Tags")))
534
+
535
+ return fieldsets
536
+
537
+ def __init__(self, *args, **kwargs):
538
+ super().__init__(*args, **kwargs)
539
+ self.source_type = None
540
+ ingestion_type = get_field_value(self, "source")
541
+
542
+ if not self.data:
543
+ if ingestion_type:
544
+ self.source_type = IPFabricSource.objects.get(pk=ingestion_type).type
545
+ if sites := get_field_value(self, "sites"):
546
+ sites = list_to_choices(str_to_list(sites))
547
+ self.fields["sites"].choices = sites
548
+ self.fields["sites"].initial = sites
549
+ else:
550
+ if snapshot_id := self.data.get("snapshot_data"):
551
+ snapshot_sites = IPFabricSnapshot.objects.get(pk=snapshot_id).sites
552
+ choices = list_to_choices(str_to_list(snapshot_sites))
553
+ self.fields["sites"].choices = choices
554
+
555
+ if self.instance and self.instance.pk:
556
+ if not kwargs.get("initial"):
557
+ self.source_type = self.instance.snapshot_data.source.type
558
+ self.initial["source"] = self.instance.snapshot_data.source
559
+ if not self.data:
560
+ self.fields["sites"].choices = list_to_choices(
561
+ self.instance.snapshot_data.sites
562
+ )
563
+
564
+ self.initial["sites"] = self.instance.parameters["sites"]
565
+
566
+ backend_type = get_field_value(self, "type")
567
+ backend = {}
568
+ if backend_type == "all":
569
+ backend = sync_parameters
570
+ else:
571
+ backend[backend_type] = sync_parameters.get(backend_type)
572
+
573
+ now = local_now().strftime("%Y-%m-%d %H:%M:%S")
574
+ self.fields["scheduled"].help_text += f" (current time: <strong>{now}</strong>)"
575
+
576
+ # Add backend-specific form fields
577
+ self.backend_fields = {}
578
+
579
+ for k, v in backend.items():
580
+ self.backend_fields[k] = []
581
+ for name, form_field in v.items():
582
+ field_name = f"ipf_{name}"
583
+ self.backend_fields[k].append(field_name)
584
+ self.fields[field_name] = copy.copy(form_field)
585
+ if self.instance and self.instance.parameters:
586
+ self.fields[field_name].initial = self.instance.parameters.get(name)
587
+
588
+ def clean(self):
589
+ super().clean()
590
+ snapshot = self.cleaned_data["snapshot_data"]
591
+
592
+ sites = self.data.get("sites")
593
+ choices = list_to_choices(str_to_list(sites))
594
+ self.fields["sites"].choices = choices
595
+
596
+ if sites:
597
+ if not any(y in x for x in snapshot.sites for y in sites):
598
+ raise ValidationError({"sites": f"{sites} not part of the snapshot."})
599
+
600
+ scheduled_time = self.cleaned_data.get("scheduled")
601
+ if scheduled_time and scheduled_time < local_now():
602
+ raise forms.ValidationError(_("Scheduled time must be in the future."))
603
+
604
+ # When interval is used without schedule at, schedule for the current time
605
+ if self.cleaned_data.get("interval") and not scheduled_time:
606
+ self.cleaned_data["scheduled"] = local_now()
607
+
608
+ return self.cleaned_data
609
+
610
+ def save(self, *args, **kwargs):
611
+ parameters = {}
612
+ for name in self.fields:
613
+ if name.startswith("ipf_"):
614
+ parameters[name[4:]] = self.cleaned_data[name]
615
+ if name == "sites":
616
+ parameters["sites"] = self.cleaned_data["sites"]
617
+ self.instance.parameters = parameters
618
+ self.instance.status = DataSourceStatusChoices.NEW
619
+
620
+ object = super().save(*args, **kwargs)
621
+ if object.scheduled:
622
+ object.enqueue_sync_job()
623
+ return object
624
+
625
+
626
+ # class SyncForm(forms.Form):
627
+ # def __init__(self, *args, **kwargs):
628
+ # self.snapshots = kwargs.pop("snapshot_choices", None)
629
+ # self.sites = kwargs.pop("site_choices", None)
630
+ # super(SyncForm, self).__init__(*args, **kwargs)
631
+ # if self.snapshots:
632
+ # snapshot_choices = [
633
+ # (snapshot_id, snapshot_name)
634
+ # for snapshot_name, snapshot_id in self.snapshots.values()
635
+ # ]
636
+ # self.fields["snapshot"] = forms.ChoiceField(
637
+ # label="Snapshot",
638
+ # required=True,
639
+ # choices=snapshot_choices,
640
+ # help_text="IPFabric snapshot to sync from. Defaults to $last",
641
+ # widget=forms.Select(
642
+ # attrs={
643
+ # "hx-get": reverse("plugins:ipfabric_netbox:ipfabricsync_add"),
644
+ # "hx-trigger": "change",
645
+ # "hx-target": "#modules",
646
+ # "class": "form-control",
647
+ # }
648
+ # ),
649
+ # )
650
+ # if self.sites:
651
+ # site_choices = [(site, site) for site in self.sites]
652
+ # self.fields["site"] = forms.ChoiceField(
653
+ # label="Site",
654
+ # required=False,
655
+ # choices=add_blank_choice(site_choices),
656
+ # help_text="Sites available within snapshot",
657
+ # widget=forms.Select(attrs={"class": "form-control"}),
658
+ # )
659
+ # else:
660
+ # self.fields["site"] = forms.ChoiceField(
661
+ # label="Site",
662
+ # required=False,
663
+ # choices=add_blank_choice([]),
664
+ # help_text="Sites available within snapshot",
665
+ # widget=forms.Select(
666
+ # attrs={"class": "form-control", "disabled": "disabled"}
667
+ # ),
668
+ # )
669
+
670
+ tableChoices = [
671
+ ("eol_details", "Inventory - EOL_DETAILS"),
672
+ ("fans", "Inventory - FANS"),
673
+ ("interfaces", "Inventory - INTERFACES"),
674
+ ("modules", "Inventory - MODULES"),
675
+ ("pn", "Inventory - PN"),
676
+ ("addressing.arp_table", "Addressing - ARP_TABLE"),
677
+ ("addressing.ipv6_neighbor_discovery", "Addressing - IPV6_NEIGHBOR_DISCOVERY"),
678
+ ("addressing.mac_table", "Addressing - MAC_TABLE"),
679
+ ("addressing.managed_ip_ipv4", "Addressing - MANAGED_IP_IPV4"),
680
+ ("addressing.managed_ip_ipv6", "Addressing - MANAGED_IP_IPV6"),
681
+ ("addressing.nat44", "Addressing - NAT44"),
682
+ ("cloud.virtual_interfaces", "Cloud - VIRTUAL_INTERFACES"),
683
+ ("cloud.virtual_machines", "Cloud - VIRTUAL_MACHINES"),
684
+ ("dhcp.relay_global_stats_received", "Dhcp - RELAY_GLOBAL_STATS_RECEIVED"),
685
+ ("dhcp.relay_global_stats_relayed", "Dhcp - RELAY_GLOBAL_STATS_RELAYED"),
686
+ ("dhcp.relay_global_stats_sent", "Dhcp - RELAY_GLOBAL_STATS_SENT"),
687
+ ("dhcp.relay_global_stats_summary", "Dhcp - RELAY_GLOBAL_STATS_SUMMARY"),
688
+ ("dhcp.relay_interfaces", "Dhcp - RELAY_INTERFACES"),
689
+ ("dhcp.relay_interfaces_stats_received", "Dhcp - RELAY_INTERFACES_STATS_RECEIVED"),
690
+ ("dhcp.relay_interfaces_stats_relayed", "Dhcp - RELAY_INTERFACES_STATS_RELAYED"),
691
+ ("dhcp.relay_interfaces_stats_sent", "Dhcp - RELAY_INTERFACES_STATS_SENT"),
692
+ ("dhcp.server_excluded_interfaces", "Dhcp - SERVER_EXCLUDED_INTERFACES"),
693
+ ("dhcp.server_excluded_ranges", "Dhcp - SERVER_EXCLUDED_RANGES"),
694
+ ("dhcp.server_leases", "Dhcp - SERVER_LEASES"),
695
+ ("dhcp.server_pools", "Dhcp - SERVER_POOLS"),
696
+ ("dhcp.server_summary", "Dhcp - SERVER_SUMMARY"),
697
+ ("fhrp.glbp_forwarders", "Fhrp - GLBP_FORWARDERS"),
698
+ ("fhrp.group_state", "Fhrp - GROUP_STATE"),
699
+ ("fhrp.stproot_alignment", "Fhrp - STPROOT_ALIGNMENT"),
700
+ ("fhrp.virtual_gateways", "Fhrp - VIRTUAL_GATEWAYS"),
701
+ (
702
+ "interfaces.average_rates_data_bidirectional",
703
+ "Interfaces - AVERAGE_RATES_DATA_BIDIRECTIONAL",
704
+ ),
705
+ (
706
+ "interfaces.average_rates_data_bidirectional_per_device",
707
+ "Interfaces - AVERAGE_RATES_DATA_BIDIRECTIONAL_PER_DEVICE",
708
+ ),
709
+ (
710
+ "interfaces.average_rates_data_inbound",
711
+ "Interfaces - AVERAGE_RATES_DATA_INBOUND",
712
+ ),
713
+ (
714
+ "interfaces.average_rates_data_inbound_per_device",
715
+ "Interfaces - AVERAGE_RATES_DATA_INBOUND_PER_DEVICE",
716
+ ),
717
+ (
718
+ "interfaces.average_rates_data_outbound",
719
+ "Interfaces - AVERAGE_RATES_DATA_OUTBOUND",
720
+ ),
721
+ (
722
+ "interfaces.average_rates_data_outbound_per_device",
723
+ "Interfaces - AVERAGE_RATES_DATA_OUTBOUND_PER_DEVICE",
724
+ ),
725
+ (
726
+ "interfaces.average_rates_drops_bidirectional",
727
+ "Interfaces - AVERAGE_RATES_DROPS_BIDIRECTIONAL",
728
+ ),
729
+ (
730
+ "interfaces.average_rates_drops_bidirectional_per_device",
731
+ "Interfaces - AVERAGE_RATES_DROPS_BIDIRECTIONAL_PER_DEVICE",
732
+ ),
733
+ (
734
+ "interfaces.average_rates_drops_inbound",
735
+ "Interfaces - AVERAGE_RATES_DROPS_INBOUND",
736
+ ),
737
+ (
738
+ "interfaces.average_rates_drops_inbound_per_device",
739
+ "Interfaces - AVERAGE_RATES_DROPS_INBOUND_PER_DEVICE",
740
+ ),
741
+ (
742
+ "interfaces.average_rates_drops_outbound",
743
+ "Interfaces - AVERAGE_RATES_DROPS_OUTBOUND",
744
+ ),
745
+ (
746
+ "interfaces.average_rates_drops_outbound_per_device",
747
+ "Interfaces - AVERAGE_RATES_DROPS_OUTBOUND_PER_DEVICE",
748
+ ),
749
+ (
750
+ "interfaces.average_rates_errors_bidirectional",
751
+ "Interfaces - AVERAGE_RATES_ERRORS_BIDIRECTIONAL",
752
+ ),
753
+ (
754
+ "interfaces.average_rates_errors_bidirectional_per_device",
755
+ "Interfaces - AVERAGE_RATES_ERRORS_BIDIRECTIONAL_PER_DEVICE",
756
+ ),
757
+ (
758
+ "interfaces.average_rates_errors_inbound",
759
+ "Interfaces - AVERAGE_RATES_ERRORS_INBOUND",
760
+ ),
761
+ (
762
+ "interfaces.average_rates_errors_inbound_per_device",
763
+ "Interfaces - AVERAGE_RATES_ERRORS_INBOUND_PER_DEVICE",
764
+ ),
765
+ (
766
+ "interfaces.average_rates_errors_outbound",
767
+ "Interfaces - AVERAGE_RATES_ERRORS_OUTBOUND",
768
+ ),
769
+ (
770
+ "interfaces.average_rates_errors_outbound_per_device",
771
+ "Interfaces - AVERAGE_RATES_ERRORS_OUTBOUND_PER_DEVICE",
772
+ ),
773
+ (
774
+ "interfaces.connectivity_matrix_unmanaged_neighbors_detail",
775
+ "Interfaces - CONNECTIVITY_MATRIX_UNMANAGED_NEIGHBORS_DETAIL",
776
+ ),
777
+ (
778
+ "interfaces.connectivity_matrix_unmanaged_neighbors_summary",
779
+ "Interfaces - CONNECTIVITY_MATRIX_UNMANAGED_NEIGHBORS_SUMMARY",
780
+ ),
781
+ ("interfaces.counters_inbound", "Interfaces - COUNTERS_INBOUND"),
782
+ ("interfaces.counters_outbound", "Interfaces - COUNTERS_OUTBOUND"),
783
+ (
784
+ "interfaces.current_rates_data_bidirectional",
785
+ "Interfaces - CURRENT_RATES_DATA_BIDIRECTIONAL",
786
+ ),
787
+ (
788
+ "interfaces.current_rates_data_inbound",
789
+ "Interfaces - CURRENT_RATES_DATA_INBOUND",
790
+ ),
791
+ (
792
+ "interfaces.current_rates_data_outbound",
793
+ "Interfaces - CURRENT_RATES_DATA_OUTBOUND",
794
+ ),
795
+ ("interfaces.err_disabled", "Interfaces - ERR_DISABLED"),
796
+ (
797
+ "interfaces.point_to_point_over_ethernet",
798
+ "Interfaces - POINT_TO_POINT_OVER_ETHERNET",
799
+ ),
800
+ (
801
+ "interfaces.point_to_point_over_ethernet_sessions",
802
+ "Interfaces - POINT_TO_POINT_OVER_ETHERNET_SESSIONS",
803
+ ),
804
+ ("interfaces.storm_control_all", "Interfaces - STORM_CONTROL_ALL"),
805
+ ("interfaces.storm_control_broadcast", "Interfaces - STORM_CONTROL_BROADCAST"),
806
+ ("interfaces.storm_control_multicast", "Interfaces - STORM_CONTROL_MULTICAST"),
807
+ ("interfaces.storm_control_unicast", "Interfaces - STORM_CONTROL_UNICAST"),
808
+ ("interfaces.switchport", "Interfaces - SWITCHPORT"),
809
+ ("interfaces.transceivers", "Interfaces - TRANSCEIVERS"),
810
+ ("interfaces.transceivers_errors", "Interfaces - TRANSCEIVERS_ERRORS"),
811
+ ("interfaces.transceivers_statistics", "Interfaces - TRANSCEIVERS_STATISTICS"),
812
+ (
813
+ "interfaces.transceivers_triggered_thresholds",
814
+ "Interfaces - TRANSCEIVERS_TRIGGERED_THRESHOLDS",
815
+ ),
816
+ ("interfaces.tunnels_ipv4", "Interfaces - TUNNELS_IPV4"),
817
+ ("interfaces.tunnels_ipv6", "Interfaces - TUNNELS_IPV6"),
818
+ ("load_balancing.virtual_servers", "Load_balancing - VIRTUAL_SERVERS"),
819
+ (
820
+ "load_balancing.virtual_servers_f5_partitions",
821
+ "Load_balancing - VIRTUAL_SERVERS_F5_PARTITIONS",
822
+ ),
823
+ (
824
+ "load_balancing.virtual_servers_pool_members",
825
+ "Load_balancing - VIRTUAL_SERVERS_POOL_MEMBERS",
826
+ ),
827
+ ("load_balancing.virtual_servers_pools", "Load_balancing - VIRTUAL_SERVERS_POOLS"),
828
+ ("management.aaa_accounting", "Management - AAA_ACCOUNTING"),
829
+ ("management.aaa_authentication", "Management - AAA_AUTHENTICATION"),
830
+ ("management.aaa_authorization", "Management - AAA_AUTHORIZATION"),
831
+ ("management.aaa_lines", "Management - AAA_LINES"),
832
+ ("management.aaa_password_strength", "Management - AAA_PASSWORD_STRENGTH"),
833
+ ("management.aaa_servers", "Management - AAA_SERVERS"),
834
+ ("management.aaa_users", "Management - AAA_USERS"),
835
+ (
836
+ "management.cisco_smart_licenses_authorization",
837
+ "Management - CISCO_SMART_LICENSES_AUTHORIZATION",
838
+ ),
839
+ (
840
+ "management.cisco_smart_licenses_registration",
841
+ "Management - CISCO_SMART_LICENSES_REGISTRATION",
842
+ ),
843
+ (
844
+ "management.cisco_smart_licenses_reservations",
845
+ "Management - CISCO_SMART_LICENSES_RESERVATIONS",
846
+ ),
847
+ ("management.dns_resolver_servers", "Management - DNS_RESOLVER_SERVERS"),
848
+ ("management.dns_resolver_settings", "Management - DNS_RESOLVER_SETTINGS"),
849
+ ("management.flow_overview", "Management - FLOW_OVERVIEW"),
850
+ ("management.license_summary", "Management - LICENSE_SUMMARY"),
851
+ ("management.licenses", "Management - LICENSES"),
852
+ ("management.licenses_detail", "Management - LICENSES_DETAIL"),
853
+ ("management.logging_local", "Management - LOGGING_LOCAL"),
854
+ ("management.logging_remote", "Management - LOGGING_REMOTE"),
855
+ ("management.logging_summary", "Management - LOGGING_SUMMARY"),
856
+ ("management.netflow_collectors", "Management - NETFLOW_COLLECTORS"),
857
+ ("management.netflow_devices", "Management - NETFLOW_DEVICES"),
858
+ ("management.netflow_interfaces", "Management - NETFLOW_INTERFACES"),
859
+ ("management.ntp_sources", "Management - NTP_SOURCES"),
860
+ ("management.ntp_summary", "Management - NTP_SUMMARY"),
861
+ ("management.port_mirroring", "Management - PORT_MIRRORING"),
862
+ ("management.ptp_interfaces", "Management - PTP_INTERFACES"),
863
+ ("management.ptp_local_clock", "Management - PTP_LOCAL_CLOCK"),
864
+ ("management.ptp_masters", "Management - PTP_MASTERS"),
865
+ ("management.saved_config_consistency", "Management - SAVED_CONFIG_CONSISTENCY"),
866
+ ("management.sflow_collectors", "Management - SFLOW_COLLECTORS"),
867
+ ("management.sflow_devices", "Management - SFLOW_DEVICES"),
868
+ ("management.sflow_sources", "Management - SFLOW_SOURCES"),
869
+ ("management.snmp_communities", "Management - SNMP_COMMUNITIES"),
870
+ ("management.snmp_summary", "Management - SNMP_SUMMARY"),
871
+ ("management.snmp_trap_hosts", "Management - SNMP_TRAP_HOSTS"),
872
+ ("management.snmp_users", "Management - SNMP_USERS"),
873
+ ("management.telnet_access", "Management - TELNET_ACCESS"),
874
+ ("mpls.forwarding", "Mpls - FORWARDING"),
875
+ ("mpls.l2vpn_circuit_cross_connect", "Mpls - L2VPN_CIRCUIT_CROSS_CONNECT"),
876
+ ("mpls.l2vpn_point_to_multipoint", "Mpls - L2VPN_POINT_TO_MULTIPOINT"),
877
+ ("mpls.l2vpn_point_to_point_vpws", "Mpls - L2VPN_POINT_TO_POINT_VPWS"),
878
+ ("mpls.l2vpn_pseudowires", "Mpls - L2VPN_PSEUDOWIRES"),
879
+ ("mpls.l3vpn_pe_routers", "Mpls - L3VPN_PE_ROUTERS"),
880
+ ("mpls.l3vpn_pe_vrfs", "Mpls - L3VPN_PE_VRFS"),
881
+ ("mpls.l3vpn_vrf_targets", "Mpls - L3VPN_VRF_TARGETS"),
882
+ ("mpls.ldp_interfaces", "Mpls - LDP_INTERFACES"),
883
+ ("mpls.ldp_neighbors", "Mpls - LDP_NEIGHBORS"),
884
+ ("mpls.rsvp_interfaces", "Mpls - RSVP_INTERFACES"),
885
+ ("mpls.rsvp_neighbors", "Mpls - RSVP_NEIGHBORS"),
886
+ ("multicast.igmp_groups", "Multicast - IGMP_GROUPS"),
887
+ ("multicast.igmp_interfaces", "Multicast - IGMP_INTERFACES"),
888
+ (
889
+ "multicast.igmp_snooping_global_config",
890
+ "Multicast - IGMP_SNOOPING_GLOBAL_CONFIG",
891
+ ),
892
+ ("multicast.igmp_snooping_groups", "Multicast - IGMP_SNOOPING_GROUPS"),
893
+ ("multicast.igmp_snooping_vlans", "Multicast - IGMP_SNOOPING_VLANS"),
894
+ ("multicast.mac_table", "Multicast - MAC_TABLE"),
895
+ ("multicast.mroute_counters", "Multicast - MROUTE_COUNTERS"),
896
+ ("multicast.mroute_first_hop_router", "Multicast - MROUTE_FIRST_HOP_ROUTER"),
897
+ ("multicast.mroute_oil_detail", "Multicast - MROUTE_OIL_DETAIL"),
898
+ ("multicast.mroute_overview", "Multicast - MROUTE_OVERVIEW"),
899
+ ("multicast.mroute_sources", "Multicast - MROUTE_SOURCES"),
900
+ ("multicast.mroute_table", "Multicast - MROUTE_TABLE"),
901
+ ("multicast.pim_interfaces", "Multicast - PIM_INTERFACES"),
902
+ ("multicast.pim_neighbors", "Multicast - PIM_NEIGHBORS"),
903
+ ("multicast.rp_bsr", "Multicast - RP_BSR"),
904
+ ("multicast.rp_mappings", "Multicast - RP_MAPPINGS"),
905
+ ("multicast.rp_mappings_groups", "Multicast - RP_MAPPINGS_GROUPS"),
906
+ (
907
+ "oam.unidirectional_link_detection_interfaces",
908
+ "Oam - UNIDIRECTIONAL_LINK_DETECTION_INTERFACES",
909
+ ),
910
+ (
911
+ "oam.unidirectional_link_detection_neighbors",
912
+ "Oam - UNIDIRECTIONAL_LINK_DETECTION_NEIGHBORS",
913
+ ),
914
+ (
915
+ "platforms.cisco_fabric_path_isis_neighbors",
916
+ "Platforms - CISCO_FABRIC_PATH_ISIS_NEIGHBORS",
917
+ ),
918
+ ("platforms.cisco_fabric_path_routes", "Platforms - CISCO_FABRIC_PATH_ROUTES"),
919
+ ("platforms.cisco_fabric_path_summary", "Platforms - CISCO_FABRIC_PATH_SUMMARY"),
920
+ ("platforms.cisco_fabric_path_switches", "Platforms - CISCO_FABRIC_PATH_SWITCHES"),
921
+ ("platforms.cisco_fex_interfaces", "Platforms - CISCO_FEX_INTERFACES"),
922
+ ("platforms.cisco_fex_modules", "Platforms - CISCO_FEX_MODULES"),
923
+ ("platforms.cisco_vdc_devices", "Platforms - CISCO_VDC_DEVICES"),
924
+ ("platforms.cisco_vss_chassis", "Platforms - CISCO_VSS_CHASSIS"),
925
+ ("platforms.cisco_vss_vsl", "Platforms - CISCO_VSS_VSL"),
926
+ ("platforms.environment_fans", "Platforms - ENVIRONMENT_FANS"),
927
+ ("platforms.environment_modules", "Platforms - ENVIRONMENT_MODULES"),
928
+ ("platforms.environment_power_supplies", "Platforms - ENVIRONMENT_POWER_SUPPLIES"),
929
+ (
930
+ "platforms.environment_power_supplies_fans",
931
+ "Platforms - ENVIRONMENT_POWER_SUPPLIES_FANS",
932
+ ),
933
+ (
934
+ "platforms.environment_temperature_sensors",
935
+ "Platforms - ENVIRONMENT_TEMPERATURE_SENSORS",
936
+ ),
937
+ ("platforms.juniper_cluster", "Platforms - JUNIPER_CLUSTER"),
938
+ ("platforms.logical_devices", "Platforms - LOGICAL_DEVICES"),
939
+ ("platforms.platform_cisco_vss", "Platforms - PLATFORM_CISCO_VSS"),
940
+ ("platforms.poe_devices", "Platforms - POE_DEVICES"),
941
+ ("platforms.poe_interfaces", "Platforms - POE_INTERFACES"),
942
+ ("platforms.poe_modules", "Platforms - POE_MODULES"),
943
+ ("platforms.stacks", "Platforms - STACKS"),
944
+ ("platforms.stacks_members", "Platforms - STACKS_MEMBERS"),
945
+ ("platforms.stacks_stack_ports", "Platforms - STACKS_STACK_PORTS"),
946
+ (
947
+ "port_channels.inbound_balancing_table",
948
+ "Port_channels - INBOUND_BALANCING_TABLE",
949
+ ),
950
+ ("port_channels.member_status_table", "Port_channels - MEMBER_STATUS_TABLE"),
951
+ ("port_channels.mlag_cisco_vpc", "Port_channels - MLAG_CISCO_VPC"),
952
+ ("port_channels.mlag_peers", "Port_channels - MLAG_PEERS"),
953
+ ("port_channels.mlag_switches", "Port_channels - MLAG_SWITCHES"),
954
+ (
955
+ "port_channels.outbound_balancing_table",
956
+ "Port_channels - OUTBOUND_BALANCING_TABLE",
957
+ ),
958
+ ("qos.marking", "Qos - MARKING"),
959
+ ("qos.policing", "Qos - POLICING"),
960
+ ("qos.policy_maps", "Qos - POLICY_MAPS"),
961
+ ("qos.priority_queuing", "Qos - PRIORITY_QUEUING"),
962
+ ("qos.queuing", "Qos - QUEUING"),
963
+ ("qos.random_drops", "Qos - RANDOM_DROPS"),
964
+ ("qos.shaping", "Qos - SHAPING"),
965
+ ("routing.bgp_address_families", "Routing - BGP_ADDRESS_FAMILIES"),
966
+ ("routing.bgp_neighbors", "Routing - BGP_NEIGHBORS"),
967
+ ("routing.eigrp_interfaces", "Routing - EIGRP_INTERFACES"),
968
+ ("routing.eigrp_neighbors", "Routing - EIGRP_NEIGHBORS"),
969
+ ("routing.isis_interfaces", "Routing - ISIS_INTERFACES"),
970
+ ("routing.isis_levels", "Routing - ISIS_LEVELS"),
971
+ ("routing.isis_neighbors", "Routing - ISIS_NEIGHBORS"),
972
+ ("routing.lisp_map_resolvers_ipv4", "Routing - LISP_MAP_RESOLVERS_IPV4"),
973
+ ("routing.lisp_map_resolvers_ipv6", "Routing - LISP_MAP_RESOLVERS_IPV6"),
974
+ ("routing.lisp_routes_ipv4", "Routing - LISP_ROUTES_IPV4"),
975
+ ("routing.lisp_routes_ipv6", "Routing - LISP_ROUTES_IPV6"),
976
+ ("routing.ospf_interfaces", "Routing - OSPF_INTERFACES"),
977
+ ("routing.ospf_neighbors", "Routing - OSPF_NEIGHBORS"),
978
+ ("routing.ospfv3_interfaces", "Routing - OSPFV3_INTERFACES"),
979
+ ("routing.ospfv3_neighbors", "Routing - OSPFV3_NEIGHBORS"),
980
+ ("routing.policies", "Routing - POLICIES"),
981
+ ("routing.policies_interfaces", "Routing - POLICIES_INTERFACES"),
982
+ ("routing.policies_pbr", "Routing - POLICIES_PBR"),
983
+ ("routing.policies_prefix_list", "Routing - POLICIES_PREFIX_LIST"),
984
+ ("routing.policies_prefix_list_ipv6", "Routing - POLICIES_PREFIX_LIST_IPV6"),
985
+ ("routing.rip_interfaces", "Routing - RIP_INTERFACES"),
986
+ ("routing.rip_neighbors", "Routing - RIP_NEIGHBORS"),
987
+ ("routing.routes_ipv4", "Routing - ROUTES_IPV4"),
988
+ ("routing.routes_ipv6", "Routing - ROUTES_IPV6"),
989
+ ("routing.summary_protocols", "Routing - SUMMARY_PROTOCOLS"),
990
+ ("routing.summary_protocols_bgp", "Routing - SUMMARY_PROTOCOLS_BGP"),
991
+ ("routing.summary_protocols_eigrp", "Routing - SUMMARY_PROTOCOLS_EIGRP"),
992
+ ("routing.summary_protocols_isis", "Routing - SUMMARY_PROTOCOLS_ISIS"),
993
+ ("routing.summary_protocols_ospf", "Routing - SUMMARY_PROTOCOLS_OSPF"),
994
+ ("routing.summary_protocols_ospfv3", "Routing - SUMMARY_PROTOCOLS_OSPFV3"),
995
+ ("routing.summary_protocols_rip", "Routing - SUMMARY_PROTOCOLS_RIP"),
996
+ ("routing.vrf_detail", "Routing - VRF_DETAIL"),
997
+ ("routing.vrf_interfaces", "Routing - VRF_INTERFACES"),
998
+ ("sdn.aci_dtep", "Sdn - ACI_DTEP"),
999
+ ("sdn.aci_endpoints", "Sdn - ACI_ENDPOINTS"),
1000
+ ("sdn.aci_vlan", "Sdn - ACI_VLAN"),
1001
+ ("sdn.aci_vrf", "Sdn - ACI_VRF"),
1002
+ ("sdn.apic_controllers", "Sdn - APIC_CONTROLLERS"),
1003
+ ("sdn.vxlan_interfaces", "Sdn - VXLAN_INTERFACES"),
1004
+ ("sdn.vxlan_peers", "Sdn - VXLAN_PEERS"),
1005
+ ("sdn.vxlan_vni", "Sdn - VXLAN_VNI"),
1006
+ ("sdn.vxlan_vtep", "Sdn - VXLAN_VTEP"),
1007
+ ("sdwan.links", "Sdwan - LINKS"),
1008
+ ("sdwan.sites", "Sdwan - SITES"),
1009
+ ("security.acl", "Security - ACL"),
1010
+ ("security.acl_global_policies", "Security - ACL_GLOBAL_POLICIES"),
1011
+ ("security.acl_interface", "Security - ACL_INTERFACE"),
1012
+ ("security.dhcp_snooping", "Security - DHCP_SNOOPING"),
1013
+ ("security.dhcp_snooping_bindings", "Security - DHCP_SNOOPING_BINDINGS"),
1014
+ ("security.dmvpn", "Security - DMVPN"),
1015
+ ("security.ipsec_gateways", "Security - IPSEC_GATEWAYS"),
1016
+ ("security.ipsec_tunnels", "Security - IPSEC_TUNNELS"),
1017
+ ("security.secure_ports_devices", "Security - SECURE_PORTS_DEVICES"),
1018
+ ("security.secure_ports_interfaces", "Security - SECURE_PORTS_INTERFACES"),
1019
+ ("security.secure_ports_users", "Security - SECURE_PORTS_USERS"),
1020
+ ("security.zone_firewall_interfaces", "Security - ZONE_FIREWALL_INTERFACES"),
1021
+ ("security.zone_firewall_policies", "Security - ZONE_FIREWALL_POLICIES"),
1022
+ ("technology.serial_ports", "Technology - SERIAL_PORTS"),
1023
+ ("stp.bridges", "Stp - BRIDGES"),
1024
+ ("stp.guards", "Stp - GUARDS"),
1025
+ ("stp.inconsistencies", "Stp - INCONSISTENCIES"),
1026
+ ("stp.inconsistencies_details", "Stp - INCONSISTENCIES_DETAILS"),
1027
+ (
1028
+ "stp.inconsistencies_stp_cdp_ports_mismatch",
1029
+ "Stp - INCONSISTENCIES_STP_CDP_PORTS_MISMATCH",
1030
+ ),
1031
+ ("stp.instances", "Stp - INSTANCES"),
1032
+ ("stp.neighbors", "Stp - NEIGHBORS"),
1033
+ ("stp.ports", "Stp - PORTS"),
1034
+ ("stp.vlans", "Stp - VLANS"),
1035
+ ("vlans.device_detail", "Vlans - DEVICE_DETAIL"),
1036
+ ("vlans.device_summary", "Vlans - DEVICE_SUMMARY"),
1037
+ ]
1038
+
1039
+
1040
+ class IPFabricTableForm(forms.Form):
1041
+ source = DynamicModelChoiceField(
1042
+ queryset=IPFabricSource.objects.all(),
1043
+ required=False,
1044
+ label=_("IP Fabric Source"),
1045
+ )
1046
+ snapshot_data = DynamicModelChoiceField(
1047
+ queryset=IPFabricSnapshot.objects.filter(status="loaded"),
1048
+ label=_("Snapshot"),
1049
+ required=False,
1050
+ query_params={
1051
+ "source_id": "$source",
1052
+ "status": "loaded",
1053
+ },
1054
+ help_text=_("IP Fabric snapshot to query. Defaults to $last if not specified."),
1055
+ )
1056
+ table = forms.ChoiceField(choices=tableChoices, required=True)
1057
+ cache_enable = forms.ChoiceField(
1058
+ choices=((True, "Yes"), (False, "No")),
1059
+ required=False,
1060
+ label=_("Cache"),
1061
+ initial=True,
1062
+ help_text=_("Cache results for 24 hours"),
1063
+ )