nautobot / nautobot-app-ssot

Single Source of Truth for Nautobot
https://docs.nautobot.com/projects/ssot/en/latest/
Other
37 stars 39 forks source link

Invalid Handling of controller_managed_device_groups and Empty controller_group Causes Sync Errors in Nautobot SSOT #563

Closed TheHack42 closed 4 weeks ago

TheHack42 commented 1 month ago

Environment

Expected Behavior

The devices should be properly synchronized into Nautobot without exceptions. The controller_group should be set correctly, and the related ControllerManagedDeviceGroup should be retrieved based on the provided value or gracefully handled if empty.

Observed Behavior

There are two issues observed:

  1. In the following code: https://github.com/nautobot/nautobot-app-ssot/blob/develop/nautobot_ssot/integrations/aci/diffsync/models/nautobot.py#L182

    controller_group=(
        self.job.apic.controller_managed_device_groups.name
        if self.job.apic.controller_managed_device_groups
        else ""
    )

    The variable self.job.apic.controller_managed_device_groups is a ManyRelation, not an instance of ControllerManagedDeviceGroup. As a result:

    • Accessing the name attribute on a ManyRelation return a None value.
    • The condition if self.job.apic.controller_managed_device_groups will always evaluate to true, which makes the current logic invalid.
    • Additionally, None is not allowed, and since the Pydantic validation requires a valid string, it throws an error: "Input should be a valid string".
  2. In the following code: https://github.com/nautobot/nautobot-app-ssot/blob/develop/nautobot_ssot/integrations/aci/diffsync/adapters/aci.py#L438

    def create(cls, adapter, ids, attrs):
        """Create Device object in Nautobot."""
        _device = OrmDevice(
            name=ids["name"],
            role=Role.objects.get(name=attrs["device_role"]),
            device_type=OrmDeviceType.objects.get(model=attrs["device_type"]),
            serial=attrs["serial"],
            comments=attrs["comments"],
            controller_managed_device_group=ControllerManagedDeviceGroup.objects.get(name=attrs["controller_group"]),
            location=Location.objects.get(name=ids["site"], location_type=LocationType.objects.get(name="Site")),
            status=Status.objects.get(name="Active"),
        )

    The value of attrs["controller_group"] can be an empty string, and if so, the query for ControllerManagedDeviceGroup.objects.get(name=attrs["controller_group"]) will fail and raise a DoesNotExist exception.

Steps to Reproduce

  1. Run the Nautobot SSOT synchronization job.
  2. Ensure the synchronization involves a device with an empty or missing controller_group field.
  3. The Pydantic validation error or DoesNotExist exception will occur.

Potential Fix

For the first issue:

For the second issue:

Thanks

jdrew82 commented 1 month ago

@TheHack42 Thank you for opening this Issue. I've reviewed your comment and I think you might have some things flipped around. Specifically, it appears that the code examples you provide are flipped for the lines you cite. With that addressed, I wanted to respond to a few things:

jdrew82 commented 1 month ago

@TheHack42 I think I see the ManyRelation now. That's a bit odd as the code does show it should be an FK. I'll work on getting a fix in for that.

TheHack42 commented 4 weeks ago

Hello,

First of all, thank you @jdrew82 for your interest in my issue. Indeed, I mistakenly inverted the link citing the line of code in the examples I provided. My apologies for that.

I hope my explanations are clear.

Thanks in advance.

jdrew82 commented 4 weeks ago

@TheHack42 Thanks for the response. I've actually made the correction for the ManyField in #574 so the fix should be in the next release we cut. As for your second point, we should never actually have an empty string in that field though from the way the integration is designed.

jdrew82 commented 4 weeks ago

@TheHack42 This should be resolved now with 3.2.0. Please let me know if you're seeing instances where the CMDG get happens with a blank string. That shouldn't be possible with how things are structured but maybe there's something that's been missed.