nautobot / nautobot-app-golden-config

Golden Configuration App for Nautobot.
https://docs.nautobot.com/projects/golden-config/en/latest/
Other
101 stars 57 forks source link

`MultipleObjectsReturned` Error in Signal If Job Class Name is not Unique #766

Open bryanculver opened 6 months ago

bryanculver commented 6 months ago

Offending line of code here: https://github.com/nautobot/nautobot-app-golden-config/blob/ab33c8c89ebc2deff1aa6bd1f0226e9009cfad1c/nautobot_golden_config/signals.py#L60

Should a user duplicate the class name of a Job in their code (for example cribbing it and not knowing the class name should be unique) can result in Nautobot failing to run post migrate, with the resulting output:

│   File "/usr/local/lib/python3.11/site-packages/nautobot/core/apps/__init__.py", line 795, in post_migrate_send_nautobot_database_ready                                                                         │
│     nautobot_database_ready.send(sender=app_conf, app_config=app_conf, **kwargs)                                                                                                                                │
│   File "/usr/local/lib/python3.11/site-packages/django/dispatch/dispatcher.py", line 180, in send                                                                                                               │
│     return [                                                                                                                                                                                                    │
│            ^                                                                                                                                                                                                    │
│   File "/usr/local/lib/python3.11/site-packages/django/dispatch/dispatcher.py", line 181, in <listcomp>                                                                                                         │
│     (receiver, receiver(signal=self, sender=sender, **named))                                                                                                                                                   │
│                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                                                                    │
│   File "/usr/local/lib/python3.11/site-packages/nautobot_golden_config/signals.py", line 60, in post_migrate_create_job_button                                                                                  │
│     deploy_job_button = Job.objects.get(job_class_name="DeployConfigPlanJobButtonReceiver")                                                                                                                     │
│                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                                     │
│   File "/usr/local/lib/python3.11/site-packages/django/db/models/manager.py", line 85, in manager_method                                                                                                        │
│     return getattr(self.get_queryset(), name)(*args, **kwargs)                                                                                                                                                  │
│            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                                                                  │
│   File "/usr/local/lib/python3.11/site-packages/django/db/models/query.py", line 439, in get                                                                                                                    │
│     raise self.model.MultipleObjectsReturned(                                                                                                                                                                   │
│ __fake__.Job.MultipleObjectsReturned: get() returned more than one Job -- it returned 2!                                                                                                                        │
│ ❌ Waited 30s or more for the DB to become ready.

The Job lookup should include the full path:

>>> Job.objects.get(job_class_name="DeployConfigPlanJobButtonReceiver", module_name="nautobot_golden_config.jobs")
<Job: Deploy Config Plan (Job Button Receiver)>
bryanculver commented 6 months ago

Another option:

Job.objects.get_for_class_path(class_path="nautobot_golden_config.jobs.DeployConfigPlanJobButtonReceiver")