Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: 🐛 Several fixes in the ACI integration #213

Merged
12 changes: 10 additions & 2 deletions nautobot_ssot/integrations/aci/diffsync/adapters/aci.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def load_ipaddresses(self):
node_dict = self.conn.get_nodes()
# Leaf/Spine management IP addresses
for node in node_dict.values():
if node["oob_ip"] and not node["oob_ip"] == "0.0.0.0": # nosec
if "oob_ip" in node and node["oob_ip"] and not node["oob_ip"] == "0.0.0.0": # nosec
new_ipaddress = self.ip_address(
address=f"{node['oob_ip']}/32",
device=node["name"],
Expand Down Expand Up @@ -342,6 +342,7 @@ def load_devices(self):
"""Load devices from ACI device data."""
devicetype_file_path = os.path.join(os.path.dirname(__file__), "..", "device-types")
for key, value in self.devices.items():
model = ""
if f"{value['model']}.yaml" in os.listdir(devicetype_file_path):
device_specs = load_yamlfile(
os.path.join(
Expand All @@ -350,8 +351,15 @@ def load_devices(self):
)
)
model = device_specs["model"]
else:

if not model:
self.get_or_instantiate(
"device_type",
ids={"model": value["model"], "part_nbr": ""},
attrs={"manufacturer": "Cisco", "u_height": 1, "comments": ""},
)
model = value["model"]

new_device = self.device(
name=value["name"],
device_type=model,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
from collections import defaultdict
from diffsync import DiffSync
from diffsync.enum import DiffSyncModelFlags
from django.db.models import ProtectedError
from django.utils.text import slugify
from nautobot.tenancy.models import Tenant
Expand Down Expand Up @@ -161,11 +162,12 @@ def load_interfaces(self):

def load_deviceroles(self):
"""Method to load Device Roles from Nautobot."""
for nbdevicerole in DeviceRole.objects.filter(slug__contains="-ssot-aci"):
for nbdevicerole in DeviceRole.objects.all():
_devicerole = self.device_role(
name=nbdevicerole.name,
description=nbdevicerole.description,
)
_devicerole.model_flags = DiffSyncModelFlags.SKIP_UNMATCHED_DST
self.add(_devicerole)

def load_devices(self):
Expand Down Expand Up @@ -238,7 +240,7 @@ def load_prefixes(self):
status=nbprefix.status.name,
site=self.site,
description=nbprefix.description,
tenant=nbprefix.tenant.name,
tenant=nbprefix.tenant.name if nbprefix.tenant else None,
vrf=vrf,
vrf_tenant=vrf_tenant,
site_tag=self.site,
Expand Down
55 changes: 43 additions & 12 deletions nautobot_ssot/integrations/aci/diffsync/models/nautobot.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ class NautobotDeviceRole(DeviceRole):
def create(cls, diffsync, ids, attrs):
"""Create DeviceRole object in Nautobot."""
_ids_name = ids["name"]
_devicerole = OrmDeviceRole(name=_ids_name, slug=f"{_ids_name}-ssot-aci", description=attrs["description"])
_devicerole = OrmDeviceRole(name=_ids_name, slug=slugify(_ids_name), description=attrs["description"])
_devicerole.validated_save()
return super().create(ids=ids, diffsync=diffsync, attrs=attrs)

Expand Down Expand Up @@ -268,6 +268,7 @@ def create(cls, diffsync, ids, attrs):
device=OrmDevice.objects.get(name=ids["device"], site=Site.objects.get(name=ids["site"])),
description=attrs["description"],
type=attrs["type"],
status=Status.objects.get(name="Active"),
)
_interface.custom_field_data["gbic_vendor"] = attrs["gbic_vendor"]
_interface.custom_field_data["gbic_sn"] = attrs["gbic_sn"]
Expand Down Expand Up @@ -348,10 +349,12 @@ def create(cls, diffsync, ids, attrs):
else:
obj_type = None
obj_id = None
if ids["tenant"]:
tenant_name = OrmTenant.objects.get(name=ids["tenant"])
else:
tenant_name = None

try:
tenant = OrmTenant.objects.get(name=ids["tenant"])
except OrmTenant.DoesNotExist:
tenant = None

try:
vrf_tenant = OrmTenant.objects.get(name=attrs["vrf_tenant"])
except OrmTenant.DoesNotExist:
Expand All @@ -372,7 +375,7 @@ def create(cls, diffsync, ids, attrs):
address=ids["address"],
status=Status.objects.get(name=attrs["status"]),
description=attrs["description"],
tenant=tenant_name,
tenant=tenant,
assigned_object_type=obj_type,
assigned_object_id=obj_id,
vrf=vrf_name,
Expand Down Expand Up @@ -417,10 +420,21 @@ def delete(self):
"""Delete IPAddress object in Nautobot."""
self.diffsync.job.log_warning(f"IP Address {self.address} will be deleted.")
super().delete()

try:
tenant = OrmTenant.objects.get(name=self.tenant)
except OrmTenant.DoesNotExist:
tenant = None

try:
vrf_tenant = OrmTenant.objects.get(name=self.vrf_tenant)
except OrmTenant.DoesNotExist:
vrf_tenant = None

_ipaddress = OrmIPAddress.objects.get(
address=self.get_identifiers()["address"],
tenant=OrmTenant.objects.get(name=self.tenant),
vrf=OrmVrf.objects.get(name=self.vrf, tenant=OrmTenant.objects.get(name=self.vrf_tenant)),
tenant=tenant,
vrf=OrmVrf.objects.get(name=self.vrf, tenant=vrf_tenant),
)
self.diffsync.objects_to_delete["ipaddress"].append(_ipaddress) # pylint: disable=protected-access
return self
Expand All @@ -435,7 +449,7 @@ def create(cls, diffsync, ids, attrs):
try:
vrf_tenant = OrmTenant.objects.get(name=attrs["vrf_tenant"])
except OrmTenant.DoesNotExist:
diffsync.job.log_warning(message=f"Tenant {attrs['vrf_tenant']} not found for VRF {attrs['vrf']}")
diffsync.job.log_warning(message=f"Tenant {attrs['vrf_tenant']} not found for VRF {ids['vrf']}")
vrf_tenant = None

if ids["vrf"] and vrf_tenant:
Expand All @@ -446,11 +460,17 @@ def create(cls, diffsync, ids, attrs):
vrf = None
else:
vrf = None

try:
prefix_tenant = OrmTenant.objects.get(name=ids["tenant"])
except OrmTenant.DoesNotExist:
prefix_tenant = None

_prefix = OrmPrefix(
prefix=ids["prefix"],
status=Status.objects.get(name=attrs["status"]),
description=attrs["description"],
tenant=OrmTenant.objects.get(name=ids["tenant"]),
tenant=prefix_tenant,
site=Site.objects.get(name=ids["site"]),
vrf=vrf,
)
Expand Down Expand Up @@ -481,10 +501,21 @@ def delete(self):
"""Delete Prefix object in Nautobot."""
self.diffsync.job.log_warning(f"Prefix {self.prefix} will be deleted.")
super().delete()

try:
tenant = OrmTenant.objects.get(name=self.tenant)
except OrmTenant.DoesNotExist:
tenant = None

try:
vrf_tenant = OrmTenant.objects.get(name=self.vrf_tenant)
except OrmTenant.DoesNotExist:
vrf_tenant = None

_prefix = OrmPrefix.objects.get(
prefix=self.get_identifiers()["prefix"],
tenant=OrmTenant.objects.get(name=self.tenant),
vrf=OrmVrf.objects.get(name=self.vrf, tenant=OrmTenant.objects.get(name=self.vrf_tenant)),
tenant=tenant,
vrf=OrmVrf.objects.get(name=self.vrf, tenant=vrf_tenant),
)
self.diffsync.objects_to_delete["prefix"].append(_prefix) # pylint: disable=protected-access
return self
Expand Down
8 changes: 8 additions & 0 deletions nautobot_ssot/integrations/aci/jobs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Jobs for ACI SSoT plugin."""
from django.templatetags.static import static
from django.urls import reverse
from diffsync import DiffSyncFlags
from nautobot.core.settings_funcs import is_truthy
from nautobot.extras.jobs import BooleanVar, ChoiceVar, Job
from nautobot_ssot.jobs.base import DataMapping, DataSource
Expand Down Expand Up @@ -47,6 +48,13 @@ class Meta: # pylint: disable=too-few-public-methods
data_source_icon = static("nautobot_ssot_aci/aci.png")
description = "Sync information from ACI to Nautobot"

def __init__(self):
"""Initialize ExampleYAMLDataSource."""
super().__init__()
self.diffsync_flags = (
self.diffsync_flags | DiffSyncFlags.SKIP_UNMATCHED_DST # pylint: disable=unsupported-binary-operation
)

@classmethod
def data_mappings(cls):
"""Shows mapping of models between ACI and Nautobot."""
Expand Down