Skip to content

Commit

Permalink
fix: 🐛 Correct CFs to not use dashes and use underscores for keys.
Browse files Browse the repository at this point in the history
This should fix issue #274.
  • Loading branch information
jdrew82 committed Nov 15, 2023
1 parent 3580394 commit 5a35b23
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 35 deletions.
4 changes: 2 additions & 2 deletions docs/user/integrations/ipfabric.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ There are several options available.

- **Debug**: Enables more verbose logging that can be useful for troubleshooting synchronization issues.
- **Safe Delete Mode**: Delete operations changes the object status to a predefined value (configurable via settings) and tags the object with `ssot-safe-delete` tag.
- **Sync Tagged Only**: Only load Nautobot data into DiffSync adapters that's been tagged with `ssot-synced-from-ipfabric` tag.
- **Sync Tagged Only**: Only load Nautobot data into DiffSync adapters that's been tagged with `ssot_last_synchronized` tag.
- **Dry run**: This will only report the difference between the source and destination without synchronization.
- **Site Filter**: Filter the data loaded into DiffSync by a top level location of a specified Site.

Expand Down Expand Up @@ -118,7 +118,7 @@ If you would like to change the default status change value, ensure you provide

![Safe Delete](../../images/ipfabric-safe-delete.png)

An example object that's been modified by SSoT App and tagged as `ssot-safe-delete` and `ssot-synced-from-ipfabric`. Notice the Status and child object, IPAddress has also changed to Deprecated and, it's status changed and tagged as well.
An example object that's been modified by SSoT App and tagged as `ssot-safe-delete` and `ssot_last_synchronized`. Notice the Status and child object, IPAddress has also changed to Deprecated and, it's status changed and tagged as well.

![Safe Delete Address](../../images/ipfabric-safe-delete-ipaddress.png)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def load_data(self):
location = self.location(
diffsync=self,
name=location_record.name,
site_id=location_record.custom_field_data.get("ipfabric-site-id"),
site_id=location_record.custom_field_data.get("ipfabric_site_id"),
status=location_record.status.name,
)
except AttributeError:
Expand Down
14 changes: 7 additions & 7 deletions nautobot_ssot/integrations/ipfabric/diffsync/diffsync_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def safe_delete(self, nautobot_object: Any, safe_delete_status: Optional[str] =
logger.warning(f"Tagging {nautobot_object} with `ssot-safe-delete`.")
update = True
if update:
tonb_nbutils.tag_object(nautobot_object=nautobot_object, custom_field="ssot-synced-from-ipfabric")
tonb_nbutils.tag_object(nautobot_object=nautobot_object, custom_field="ssot_last_synchronized")
else:
logger.warning(f"{nautobot_object} has previously been tagged with `ssot-safe-delete`. Skipping...")

Expand Down Expand Up @@ -120,7 +120,7 @@ def update(self, attrs):
"""Update Location Object in Nautobot."""
location = NautobotLocation.objects.get(name=self.name)
if attrs.get("site_id"):
location.custom_field_data["ipfabric-site-id"] = attrs.get("site_id")
location.custom_field_data["ipfabric_site_id"] = attrs.get("site_id")
location.validated_save()
if attrs.get("status") == "Active":
safe_delete_tag, _ = Tag.objects.get_or_create(name="SSoT Safe Delete")
Expand All @@ -129,7 +129,7 @@ def update(self, attrs):
device_tags = location.tags.filter(pk=safe_delete_tag.pk)
if device_tags.exists():
location.tags.remove(safe_delete_tag)
tonb_nbutils.tag_object(nautobot_object=location, custom_field="ssot-synced-from-ipfabric")
tonb_nbutils.tag_object(nautobot_object=location, custom_field="ssot_last_synchronized")
return super().update(attrs)


Expand Down Expand Up @@ -198,7 +198,7 @@ def create(cls, diffsync, ids, attrs):
)
try:
# Validated save happens inside of tag_objet
tonb_nbutils.tag_object(nautobot_object=new_device, custom_field="ssot-synced-from-ipfabric")
tonb_nbutils.tag_object(nautobot_object=new_device, custom_field="ssot_last_synchronized")
except ValidationError as error:
message = f"Unable to create device: {ids['name']}. A validation error occured. Enable debug for more information."
if diffsync.job.debug:
Expand Down Expand Up @@ -246,7 +246,7 @@ def update(self, attrs):
role_name=attrs.get("role", DEFAULT_DEVICE_ROLE), role_color=DEFAULT_DEVICE_ROLE_COLOR
)
_device.role = device_role_object
tonb_nbutils.tag_object(nautobot_object=_device, custom_field="ssot-synced-from-ipfabric")
tonb_nbutils.tag_object(nautobot_object=_device, custom_field="ssot_last_synchronized")
# Call the super().update() method to update the in-memory DiffSyncModel instance
return super().update(attrs)
except NautobotDevice.DoesNotExist:
Expand Down Expand Up @@ -384,7 +384,7 @@ def update(self, attrs): # pylint: disable=too-many-branches
device.primary_ip6 = interface_obj
device.save()
interface.save()
tonb_nbutils.tag_object(nautobot_object=interface, custom_field="ssot-synced-from-ipfabric")
tonb_nbutils.tag_object(nautobot_object=interface, custom_field="ssot_last_synchronized")
return super().update(attrs)

except NautobotDevice.DoesNotExist:
Expand Down Expand Up @@ -447,7 +447,7 @@ def update(self, attrs):
if attrs.get("description"):
vlan.description = vlan.description

tonb_nbutils.tag_object(nautobot_object=vlan, custom_field="ssot-synced-from-ipfabric")
tonb_nbutils.tag_object(nautobot_object=vlan, custom_field="ssot_last_synchronized")


Location.update_forward_refs()
Expand Down
2 changes: 1 addition & 1 deletion nautobot_ssot/integrations/ipfabric/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class IpFabricDataSource(DataSource):
sync_ipfabric_tagged_only = BooleanVar(
default=True,
label="Sync Tagged Only",
description="Only sync objects that have the 'ssot-synced-from-ipfabric' tag.",
description="Only sync objects that have the 'ssot_last_synchronized' tag.",
)
location_filter = OptionalObjectVar(
description="Only sync Nautobot records belonging to a single Location. This does not filter IPFabric data.",
Expand Down
7 changes: 4 additions & 3 deletions nautobot_ssot/integrations/ipfabric/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def create_custom_field(key: str, label: str, models: List, apps, cf_type: Optio
)
for model in models:
custom_field.content_types.add(ContentType.objects.get_for_model(model))
custom_field.save()
custom_field.validated_save()


def nautobot_database_ready_callback(sender, *, apps, **kwargs): # pylint: disable=unused-argument
Expand Down Expand Up @@ -76,6 +76,7 @@ def nautobot_database_ready_callback(sender, *, apps, **kwargs): # pylint: disa
loc_type.content_types.add(ContentType.objects.get_for_model(apps.get_model("ipam", "Prefix")))
loc_type.content_types.add(ContentType.objects.get_for_model(VLAN))
synced_from_models = [Device, DeviceType, Interface, Manufacturer, Location, VLAN, Role, IPAddress]
create_custom_field("ssot-synced-from-ipfabric", "Last synced from IPFabric on", synced_from_models, apps=apps)
create_custom_field("ipfabric-site-id", "IPFabric Location ID", [Location], apps=apps, cf_type="type_text")
create_custom_field("system_of_record", "System of Record", synced_from_models, apps=apps, cf_type="type_text")
create_custom_field("ssot_last_synchronized", "Last sync from System of Record", synced_from_models, apps=apps)
create_custom_field("ipfabric_site_id", "IPFabric Location ID", [Location], apps=apps, cf_type="type_text")
create_custom_field("ipfabric_type", "IPFabric Type", [Role], apps=apps, cf_type="type_text")
29 changes: 15 additions & 14 deletions nautobot_ssot/integrations/ipfabric/utilities/nbutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,20 @@ def create_location(location_name, location_id=None):
# Ensure custom field is available
custom_field_obj, _ = CustomField.objects.get_or_create(
type=CustomFieldTypeChoices.TYPE_TEXT,
label="ipfabric-site-id",
label="ipfabric_site_id",
defaults={"label": "IPFabric Location ID"},
)
custom_field_obj.content_types.add(ContentType.objects.get_for_model(Location))
location_obj.cf["ipfabric-site-id"] = location_id
location_obj.cf["ipfabric_site_id"] = location_id
location_obj.validated_save()
tag_object(nautobot_object=location_obj, custom_field="ssot-synced-from-ipfabric")
tag_object(nautobot_object=location_obj, custom_field="ssot_last_synchronized")
return location_obj


def create_manufacturer(vendor_name):
"""Create specified manufacturer in Nautobot."""
mf_name, _ = Manufacturer.objects.get_or_create(name=vendor_name)
tag_object(nautobot_object=mf_name, custom_field="ssot-synced-from-ipfabric")
tag_object(nautobot_object=mf_name, custom_field="ssot_last_synchronized")
return mf_name


Expand All @@ -65,7 +65,7 @@ def create_device_type_object(device_type, vendor_name):
"""
mf_name = create_manufacturer(vendor_name)
device_type_obj, _ = DeviceType.objects.get_or_create(manufacturer=mf_name, model=device_type)
tag_object(nautobot_object=device_type_obj, custom_field="ssot-synced-from-ipfabric")
tag_object(nautobot_object=device_type_obj, custom_field="ssot_last_synchronized")
return device_type_obj


Expand All @@ -84,7 +84,7 @@ def get_or_create_device_role_object(role_name, role_color):
role_obj.cf["ipfabric_type"] = role_name
role_obj.validated_save()
role_obj.content_types.set([ContentType.objects.get_for_model(Device)])
tag_object(nautobot_object=role_obj, custom_field="ssot-synced-from-ipfabric")
tag_object(nautobot_object=role_obj, custom_field="ssot_last_synchronized")
return role_obj


Expand Down Expand Up @@ -141,10 +141,10 @@ def create_ip(ip_address, subnet_mask, status="Active", object_pk=None):
assign_ip = IPAddressToInterface(ip_address=ip_obj, interface_id=object_pk.pk)
assign_ip.validated_save()
# Tag Interface (object_pk)
tag_object(nautobot_object=object_pk, custom_field="ssot-synced-from-ipfabric")
tag_object(nautobot_object=object_pk, custom_field="ssot_last_synchronized")

# Tag IP Addr
tag_object(nautobot_object=ip_obj, custom_field="ssot-synced-from-ipfabric")
tag_object(nautobot_object=ip_obj, custom_field="ssot_last_synchronized")
return ip_obj


Expand Down Expand Up @@ -179,7 +179,7 @@ def create_interface(device_obj, interface_details):
interface_obj.mgmt_only = fields.get("mgmt_only", False)
interface_obj.status = Status.objects.get_for_model(Interface).get(name=fields.get("status", "Active"))
interface_obj.validated_save()
tag_object(nautobot_object=interface_obj, custom_field="ssot-synced-from-ipfabric")
tag_object(nautobot_object=interface_obj, custom_field="ssot_last_synchronized")
return interface_obj


Expand All @@ -199,7 +199,7 @@ def create_vlan(vlan_name: str, vlan_id: int, vlan_status: str, location_obj: Lo
vlan_obj, _ = location_obj.vlans.get_or_create(
name=vlan_name, vid=vlan_id, status=Status.objects.get(name=vlan_status), description=description
)
tag_object(nautobot_object=vlan_obj, custom_field="ssot-synced-from-ipfabric")
tag_object(nautobot_object=vlan_obj, custom_field="ssot_last_synchronized")
return vlan_obj


Expand Down Expand Up @@ -229,10 +229,10 @@ def _tag_object(nautobot_object):
if hasattr(nautobot_object, "tags"):
nautobot_object.tags.add(tag)
if hasattr(nautobot_object, "cf"):
# Ensure that the "ssot-synced-from-ipfabric" custom field is present
if not any(cfield for cfield in CustomField.objects.all() if cfield.key == "ssot-synced-from-ipfabric"):
custom_field_obj, _ = CustomField.objects.get(
key="ssot-synced-from-ipfabric",
# Ensure that the "ssot_last_synchronized" custom field is present
if not any(cfield for cfield in CustomField.objects.all() if cfield.key == "ssot_last_synchronized"):
custom_field_obj = CustomField.objects.get(
key="ssot_last_synchronized",
)
synced_from_models = [
Device,
Expand All @@ -249,6 +249,7 @@ def _tag_object(nautobot_object):
custom_field_obj.validated_save()

# Update custom field date stamp
nautobot_object.cf["system_of_record"] = "IPFabric"
nautobot_object.cf[custom_field] = today
nautobot_object.validated_save()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def load(self):

def tag_involved_objects(self, target):
"""Tag all objects that were successfully synced to the target."""
# The ssot-synced-to-servicenow tag *should* have been created automatically during plugin installation
# The servicenow_last_synchronized tag *should* have been created automatically during plugin installation
# (see nautobot_ssot/integrations/servicenow/signals.py) but maybe a user deleted it inadvertently, so be safe:
tag, _ = Tag.objects.get_or_create(
name="SSoT Synced to ServiceNow",
Expand All @@ -137,12 +137,12 @@ def tag_involved_objects(self, target):
"color": ColorChoices.COLOR_LIGHT_GREEN,
},
)
# Ensure that the "ssot-synced-to-servicenow" custom field is present; as above, it *should* already exist.
# Ensure that the "servicenow_last_synchronized" custom field is present; as above, it *should* already exist.
custom_field, _ = CustomField.objects.get_or_create(
type=CustomFieldTypeChoices.TYPE_DATE,
key="ssot-synced-to-servicenow",
key="servicenow_last_synchronized",
defaults={
"label": "Last synced to ServiceNow on",
"label": "Last synced to ServiceNow",
},
)
for model in [Device, DeviceType, Interface, Manufacturer, Location]:
Expand Down
6 changes: 3 additions & 3 deletions nautobot_ssot/integrations/servicenow/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@


def register_signals(sender):
"""Register signals for Infoblox integration."""
"""Register signals for ServiceNow integration."""
nautobot_database_ready.connect(nautobot_database_ready_callback, sender=sender)


Expand All @@ -33,9 +33,9 @@ def nautobot_database_ready_callback(sender, *, apps, **kwargs): # pylint: disa
)
custom_field, _ = CustomField.objects.get_or_create(
type=CustomFieldTypeChoices.TYPE_DATE,
key="ssot-synced-to-servicenow",
key="servicenow_last_synchronized",
defaults={
"label": "Last synced to ServiceNow on",
"label": "Last synced to ServiceNow",
},
)
for content_type in [
Expand Down

0 comments on commit 5a35b23

Please sign in to comment.