Closed peteeckel closed 1 month ago
also for consideration - #56. (may/may not be related)
That's possible, although here the error occurs in post_save()
, while #56 affects merging.
I ran in to this problem too. I think it boils down to signal_receivers.py:L93
setting ChangeDiff.original = None in some cases:
diff = ChangeDiff(
branch=branch,
object=instance.changed_object,
action=instance.action,
original=instance.prechange_data_clean or None,
modified=instance.postchange_data_clean or None,
current=current_data or None,
last_updated=timezone.now(),
)
None gets saved and then _update_conflicts()
tries to call items() on None.
Here's one way to quickly re-produce the issue:
from netbox_branching.models import Branch, ChangeDiff
from dcim.models import Interface
from netbox_branching.utilities import activate_branch
from django.utils import timezone
branch = Branch(name='Test 1')
branch.schema_id = 'test1'
branch.save(provision=False)
branch.provision(user=None)
with activate_branch(branch):
interface, success = Interface.objects.get_or_create(name='Ethernet1')
interface.description = "foobar"
diff = ChangeDiff(
branch=branch,
object=interface,
action="update",
original=None,
modified=None,
current=None,
last_updated=timezone.now(),
)
interface.save()
diff.save()
Output:
(venv) unit@5788bbbb9a0c:/opt/netbox/netbox$ /opt/netbox/netbox/manage.py shell
🧬 loaded config '/etc/netbox/config/configuration.py'
🧬 loaded config '/etc/netbox/config/extra.py'
🧬 loaded config '/etc/netbox/config/logging.py'
🧬 loaded config '/etc/netbox/config/plugins.py'
Python 3.12.3 (main, Jul 31 2024, 17:43:48) [GCC 13.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from netbox_branching.models import Branch, ChangeDiff
>>> from dcim.models import Interface
>>> from netbox_branching.utilities import activate_branch
>>> from django.utils import timezone
>>> branch = Branch(name='Test 1')
>>> branch.schema_id = 'test1'
>>> branch.save(provision=False)
>>> branch.provision(user=None)
>>> with activate_branch(branch):
... interface, success = Interface.objects.get_or_create(name='Ethernet1')
... interface.description = "foobar"
... diff = ChangeDiff(
... branch=branch,
... object=interface,
... action="update",
... original=None,
... modified=None,
... current=None,
... last_updated=timezone.now(),
... )
... interface.save()
...
>>> diff.save()
Traceback (most recent call last):
File "/usr/lib/python3.12/code.py", line 90, in runcode
exec(code, self.locals)
File "<console>", line 1, in <module>
File "/opt/netbox/venv/lib/python3.12/site-packages/netbox_branching/models/changes.py", line 160, in save
self._update_conflicts()
File "/opt/netbox/venv/lib/python3.12/site-packages/netbox_branching/models/changes.py", line 175, in _update_conflicts
k for k, v in self.original.items()
^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'items'
I'm not able to reproduce this using either netbox-branching v0.4.0 or the current develop
branch: The new zone is created within the branch as expected. @peteeckel could you provide more detailed reproduction steps please?
Just tried with a fresh database, and now I can't reproduce it either - what about the minimised reproduction code that @stiltzkin10 contributed? The error is exactly the same.
Arbitrary code does not prove a bug. The behavior must be reproducible in NetBox itself.
I created a new plugin with this model:
from django.db import models
from django.urls import reverse
from netbox.models import NetBoxModel
from dcim.models import Site
class Branchingbug(NetBoxModel):
name = models.CharField(max_length=100)
class Meta:
ordering = ("name",)
def save(self, **kwargs):
"""Save."""
site = Site.objects.get(name='MySite')
site.description = "foobar"
site.save()
super().save(**kwargs)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("plugins:branchingbug:branchingbug", args=[self.pk])
It works fine if I'm in the "Main" branch, but if I create a new branch and try to create a new instance of this plugin it crashes.
If I change the get()
call to get_or_create()
and let it create a new site it doesn't fail.
This looks like the same root issue as #56: The model is making branch-agnostic queries.
Generally speaking, it's best to avoid making database queries (especially mutating queries) inside save()
. If that's unavoidable, you'll need to ensure that the method's using
keyword argument is passed through to ensure the correct database connection is used.
I'm going to close this out as it substantially overlaps with #56; let's continue any further relevant discussion under that issue.
Plugin Version
0.4.0
NetBox Version
4.1.0
Python Version
3.12.1
Steps to Reproduce
Expected Behavior
The zone is cloned in the branch.
Observed Behavior
After reloading it seems that the new zone has been created anyway.