ipfabric_netbox 4.3.2b7__tar.gz → 4.3.2b8__tar.gz

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 (88) hide show
  1. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/PKG-INFO +1 -1
  2. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/__init__.py +1 -1
  3. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/exceptions.py +5 -0
  4. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/utilities/ipfutils.py +94 -66
  5. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/pyproject.toml +1 -1
  6. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/README.md +0 -0
  7. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/api/__init__.py +0 -0
  8. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/api/serializers.py +0 -0
  9. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/api/urls.py +0 -0
  10. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/api/views.py +0 -0
  11. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/choices.py +0 -0
  12. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/data/transform_map.json +0 -0
  13. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/filtersets.py +0 -0
  14. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/forms.py +0 -0
  15. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/graphql/__init__.py +0 -0
  16. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/graphql/enums.py +0 -0
  17. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/graphql/filters.py +0 -0
  18. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/graphql/schema.py +0 -0
  19. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/graphql/types.py +0 -0
  20. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/jobs.py +0 -0
  21. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0001_initial.py +0 -0
  22. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0001_initial_squashed_0013_switch_to_branching_plugin.py +0 -0
  23. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0002_ipfabricsnapshot_status.py +0 -0
  24. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0003_ipfabricsource_type_and_more.py +0 -0
  25. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0004_ipfabricsync_auto_merge.py +0 -0
  26. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0005_alter_ipfabricrelationshipfield_source_model_and_more.py +0 -0
  27. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0006_alter_ipfabrictransformmap_target_model.py +0 -0
  28. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0007_prepare_custom_fields.py +0 -0
  29. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0008_prepare_transform_maps.py +0 -0
  30. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0009_transformmap_changes_for_netbox_v4_2.py +0 -0
  31. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0010_remove_uuid_from_get_or_create.py +0 -0
  32. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0011_update_part_number_DCIM_inventory_item_template.py +0 -0
  33. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0012_remove_status_field.py +0 -0
  34. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0013_switch_to_branching_plugin.py +0 -0
  35. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0014_ipfabrictransformmapgroup_ipfabrictransformmap_group.py +0 -0
  36. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0015_ipfabricingestionissue.py +0 -0
  37. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0016_tags_and_changelog_for_snapshots.py +0 -0
  38. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0017_ipfabricsync_update_custom_fields.py +0 -0
  39. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0018_remove_type_field.py +0 -0
  40. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0019_alter_ipfabrictransformmap_options_and_more.py +0 -0
  41. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0020_clean_scheduled_jobs.py +0 -0
  42. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/0021_update_transform_maps.py +0 -0
  43. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/migrations/__init__.py +0 -0
  44. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/models.py +0 -0
  45. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/navigation.py +0 -0
  46. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/signals.py +0 -0
  47. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/tables.py +0 -0
  48. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/template_content.py +0 -0
  49. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/inc/clone_form.html +0 -0
  50. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/inc/diff.html +0 -0
  51. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/inc/json.html +0 -0
  52. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/inc/logs_pending.html +0 -0
  53. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/inc/merge_form.html +0 -0
  54. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/inc/site_topology_button.html +0 -0
  55. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/inc/site_topology_modal.html +0 -0
  56. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/inc/snapshotdata.html +0 -0
  57. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/inc/transform_map_field_map.html +0 -0
  58. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/inc/transform_map_relationship_map.html +0 -0
  59. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/ipfabric_table.html +0 -0
  60. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/ipfabricingestion.html +0 -0
  61. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/ipfabricsnapshot.html +0 -0
  62. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/ipfabricsource.html +0 -0
  63. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/ipfabricsync.html +0 -0
  64. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap.html +0 -0
  65. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap_list.html +0 -0
  66. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap_restore.html +0 -0
  67. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmapgroup.html +0 -0
  68. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/partials/ingestion_all.html +0 -0
  69. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/partials/ingestion_progress.html +0 -0
  70. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/partials/ingestion_statistics.html +0 -0
  71. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/partials/ingestion_status.html +0 -0
  72. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/partials/job_logs.html +0 -0
  73. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/partials/object_tabs.html +0 -0
  74. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/ipfabric_netbox/partials/sync_last_ingestion.html +0 -0
  75. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templates/static/ipfabric_netbox/css/rack.css +0 -0
  76. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templatetags/__init__.py +0 -0
  77. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/templatetags/ipfabric_netbox_helpers.py +0 -0
  78. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/tests/__init__.py +0 -0
  79. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/tests/api/__init__.py +0 -0
  80. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/tests/api/test_api.py +0 -0
  81. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/tests/test_forms.py +0 -0
  82. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/tests/test_models.py +0 -0
  83. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/tests/test_views.py +0 -0
  84. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/urls.py +0 -0
  85. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/utilities/__init__.py +0 -0
  86. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/utilities/logging.py +0 -0
  87. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/utilities/transform_map.py +0 -0
  88. {ipfabric_netbox-4.3.2b7 → ipfabric_netbox-4.3.2b8}/ipfabric_netbox/views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipfabric_netbox
3
- Version: 4.3.2b7
3
+ Version: 4.3.2b8
4
4
  Summary: NetBox plugin to sync IP Fabric data into NetBox
5
5
  License: MIT
6
6
  Keywords: netbox,ipfabric,plugin,sync
@@ -6,7 +6,7 @@ class NetboxIPFabricConfig(PluginConfig):
6
6
  name = "ipfabric_netbox"
7
7
  verbose_name = "NetBox IP Fabric SoT Plugin"
8
8
  description = "Sync IP Fabric into NetBox"
9
- version = "4.3.2b7"
9
+ version = "4.3.2b8"
10
10
  base_url = "ipfabric"
11
11
  min_version = "4.4.0"
12
12
 
@@ -46,5 +46,10 @@ class IPAddressPrimaryRemovalError(IngestionIssue, SyncError):
46
46
  return "Error removing primary IP from other device."
47
47
 
48
48
 
49
+ class IPAddressPrimaryAssignmentError(IngestionIssue, SyncError):
50
+ def __str__(self):
51
+ return "Error assigning primary IP to device."
52
+
53
+
49
54
  class RequiredDependencyFailedSkip(SearchError):
50
55
  """Raised when a required dependency failed, causing this item to be skipped."""
@@ -14,10 +14,13 @@ from typing import TypeVar
14
14
  from core.exceptions import SyncError
15
15
  from core.signals import clear_events
16
16
  from dcim.models import Device
17
+ from dcim.models import VirtualChassis
18
+ from dcim.signals import assign_virtualchassis_master
17
19
  from django.conf import settings
18
20
  from django.core.exceptions import MultipleObjectsReturned
19
21
  from django.core.exceptions import ObjectDoesNotExist
20
22
  from django.db.models import Model
23
+ from django.db.models import signals
21
24
  from django.utils.text import slugify
22
25
  from django_tables2 import Column
23
26
  from extras.events import flush_events
@@ -30,6 +33,7 @@ from netutils.utils import jinja2_convenience_function
30
33
  from ..choices import IPFabricSourceTypeChoices
31
34
  from ..choices import IPFabricSyncStatusChoices
32
35
  from ..exceptions import IPAddressDuplicateError
36
+ from ..exceptions import IPAddressPrimaryAssignmentError
33
37
  from ..exceptions import IPAddressPrimaryRemovalError
34
38
  from ..exceptions import RequiredDependencyFailedSkip
35
39
  from ..exceptions import SearchError
@@ -997,84 +1001,99 @@ class IPFabricSyncRunner(object):
997
1001
  self.events_clearer.increment()
998
1002
 
999
1003
  @handle_errors
1000
- def sync_ip_addresses(self, ip_addresses: set[DataRecord]) -> None:
1001
- """
1002
- We cannot assign primary IP in signals since IPAddress does not
1003
- contain information whether it is primary or not. And it must be done
1004
- on Device object, so cannot be done via Transform Maps yet since that
1005
- would require another Transform Map for Device.
1006
- So we need to do it manually here.
1004
+ def sync_ipaddress(self, ip_address: DataRecord) -> "IPAddress | None":
1005
+ """Sync a single IP Address to NetBox, separated to use @handle_errors."""
1006
+ connection_name = self.get_db_connection_name()
1007
1007
 
1008
- Cleaning events queue happens during each cycle to make sure all required
1009
- operations (primary IP assignment) happen during the same batch.
1010
- """
1011
- if not self.settings.get("ipaddress"):
1012
- self.logger.log_info(
1013
- "Did not ask to sync ipaddresses, skipping.", obj=self.sync
1008
+ # First remove primary IP from the target object.
1009
+ # It cannot be done using hooks since there is no pre_clean at it fails on full_clean()
1010
+ try:
1011
+ ipv4_address = render_jinja2(
1012
+ ip_address.transform_map.field_maps.get(
1013
+ target_field="address"
1014
+ ).template,
1015
+ {"object": ip_address.data},
1014
1016
  )
1017
+ other_device = (
1018
+ Device.objects.using(connection_name)
1019
+ .exclude(serial=serial(ip_address.data))
1020
+ .get(primary_ip4__address=ipv4_address)
1021
+ )
1022
+ other_device.snapshot()
1023
+ other_device.primary_ip4 = None
1024
+ other_device.save(using=connection_name)
1025
+ except Device.DoesNotExist:
1026
+ # There is no other device with this IP as primary, all good
1027
+ pass
1028
+ except Exception as err:
1029
+ # The transform maps might be changed, and we fail to resolve the template
1030
+ # Make sure this does not crash the sync and is handled gracefully
1031
+ _, issue = self.create_or_get_sync_issue(
1032
+ exception=err,
1033
+ ingestion=self.ingestion,
1034
+ message="Error removing primary IP from other device.",
1035
+ model=ip_address.model,
1036
+ data=ip_address.data,
1037
+ )
1038
+ self.events_clearer.increment()
1039
+ raise IPAddressPrimaryRemovalError(
1040
+ data=ip_address.data,
1041
+ model=ip_address.model,
1042
+ issue_id=issue.pk,
1043
+ ) from err
1044
+
1045
+ ip_address_obj: "IPAddress | None" = self.sync_item(record=ip_address)
1046
+ if ip_address_obj is None or ip_address_obj.assigned_object is None:
1047
+ self.events_clearer.increment()
1015
1048
  return
1016
1049
 
1017
- for ip_address in ip_addresses:
1018
- connection_name = self.get_db_connection_name()
1050
+ parent_device = ip_address_obj.assigned_object.parent_object
1019
1051
 
1020
- # First remove primary IP from the target object.
1021
- # It cannot be done using hooks since there is no pre_clean at it fails on full_clean()
1052
+ # Now assign this IP as primary to the parent device, if not assigned yet or assigned to different IP
1053
+ if ip_address.data.get("is_primary") and (
1054
+ not parent_device.primary_ip4
1055
+ or parent_device.primary_ip4.pk != ip_address_obj.pk
1056
+ ):
1022
1057
  try:
1023
- ipv4_address = render_jinja2(
1024
- ip_address.transform_map.field_maps.get(
1025
- target_field="address"
1026
- ).template,
1027
- {"object": ip_address.data},
1028
- )
1029
- other_device = (
1030
- Device.objects.using(connection_name)
1031
- .exclude(serial=serial(ip_address.data))
1032
- .get(primary_ip4__address=ipv4_address)
1033
- )
1034
- other_device.snapshot()
1035
- other_device.primary_ip4 = None
1036
- other_device.save(using=connection_name)
1037
- except Device.DoesNotExist:
1038
- # There is no other device with this IP as primary, all good
1039
- pass
1058
+ parent_device.snapshot()
1059
+ parent_device.primary_ip4 = ip_address_obj
1060
+ parent_device.save(using=connection_name)
1040
1061
  except Exception as err:
1041
- # The transform maps might be changed, and we fail to resolve the template
1042
- # Make sure this does not crash the sync and is handled gracefully
1043
1062
  _, issue = self.create_or_get_sync_issue(
1044
1063
  exception=err,
1045
1064
  ingestion=self.ingestion,
1046
- message="Error removing primary IP from other device.",
1065
+ message="Error assigning primary IP to device.",
1047
1066
  model=ip_address.model,
1048
1067
  data=ip_address.data,
1049
1068
  )
1050
1069
  self.events_clearer.increment()
1051
- raise IPAddressPrimaryRemovalError(
1070
+ raise IPAddressPrimaryAssignmentError(
1052
1071
  data=ip_address.data,
1053
1072
  model=ip_address.model,
1054
1073
  issue_id=issue.pk,
1055
1074
  ) from err
1075
+ self.events_clearer.increment()
1056
1076
 
1057
- ip_address_obj: "IPAddress | None" = self.sync_item(record=ip_address)
1058
- if ip_address_obj is None or ip_address_obj.assigned_object is None:
1059
- self.events_clearer.increment()
1060
- continue
1077
+ @handle_errors
1078
+ def sync_ip_addresses(self, ip_addresses: set[DataRecord]) -> None:
1079
+ """
1080
+ We cannot assign primary IP in signals since IPAddress does not
1081
+ contain information whether it is primary or not. And it must be done
1082
+ on Device object, so cannot be done via Transform Maps yet since that
1083
+ would require another Transform Map for Device.
1084
+ So we need to do it manually here.
1061
1085
 
1062
- parent_device = ip_address_obj.assigned_object.parent_object
1086
+ Cleaning events queue happens during each cycle to make sure all required
1087
+ operations (primary IP assignment) happen during the same batch.
1088
+ """
1089
+ if not self.settings.get("ipaddress"):
1090
+ self.logger.log_info(
1091
+ "Did not ask to sync ipaddresses, skipping.", obj=self.sync
1092
+ )
1093
+ return
1063
1094
 
1064
- # Now assign this IP as primary to the parent device, if not assigned yet or assigned to different IP
1065
- if ip_address.data.get("is_primary") and (
1066
- not parent_device.primary_ip4
1067
- or parent_device.primary_ip4.pk != ip_address_obj.pk
1068
- ):
1069
- try:
1070
- parent_device.snapshot()
1071
- parent_device.primary_ip4 = ip_address_obj
1072
- parent_device.save(using=connection_name)
1073
- except (ValueError, AttributeError) as err:
1074
- self.logger.log_failure(
1075
- f"Error assigning primary IP to device: {err}", obj=self.sync
1076
- )
1077
- self.events_clearer.increment()
1095
+ for ip_address in ip_addresses:
1096
+ self.sync_ipaddress(ip_address)
1078
1097
 
1079
1098
  def collect_and_sync(self, ingestion=None) -> None:
1080
1099
  self.logger.log_info("Starting data collection.", obj=self.sync)
@@ -1092,15 +1111,24 @@ class IPFabricSyncRunner(object):
1092
1111
  self.sync_items(items=records["devicetype"])
1093
1112
  self.sync_items(items=records["platform"])
1094
1113
  self.sync_items(items=records["devicerole"])
1095
- self.sync_items(items=records["virtualchassis"])
1096
- self.sync_devices(
1097
- devices=records["device"],
1098
- cf=self.sync.update_custom_fields,
1099
- ingestion=ingestion,
1100
- )
1101
- # The Device exists now, so we can update the master of the VC.
1102
- # The logic is handled in transform maps.
1103
- self.sync_items(items=records["virtualchassis"], stats=False)
1114
+ try:
1115
+ # This signal does not call for snapshot(), causing issue with branching plugin
1116
+ signals.post_save.disconnect(
1117
+ assign_virtualchassis_master, sender=VirtualChassis
1118
+ )
1119
+ self.sync_items(items=records["virtualchassis"])
1120
+ self.sync_devices(
1121
+ devices=records["device"],
1122
+ cf=self.sync.update_custom_fields,
1123
+ ingestion=ingestion,
1124
+ )
1125
+ # The Device exists now, so we can update the master of the VC.
1126
+ # The logic is handled in transform maps.
1127
+ self.sync_items(items=records["virtualchassis"], stats=False)
1128
+ finally:
1129
+ signals.post_save.connect(
1130
+ assign_virtualchassis_master, sender=VirtualChassis
1131
+ )
1104
1132
  self.sync_items(items=records["interface"])
1105
1133
  self.sync_items(items=records["macaddress"])
1106
1134
  self.sync_items(items=records["inventoryitem"])
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "ipfabric_netbox"
3
- version = "4.3.2b7"
3
+ version = "4.3.2b8"
4
4
  description = "NetBox plugin to sync IP Fabric data into NetBox"
5
5
  authors = ["Solution Architecture <solution.architecture@ipfabric.io>"]
6
6
  license = "MIT"