[2.1b2] Infinite recursion observed while toggling interface state

Bug #1622105 reported by Mike Pontillo
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
MAAS
Fix Released
High
Mike Pontillo
2.3
Fix Released
High
Mike Pontillo
2.4
Fix Released
High
Mike Pontillo

Bug Description

Looking at a snippet from the backtrace, it seems to occur during the post-save signal handler (interface_enabled_or_disabled -> resave_children_handler -> update_interface_parents) in a loop.

          File "/usr/lib/python3/dist-packages/maasserver/utils/signals.py", line 87, in post_save_callback
            callback(instance, original_values, deleted=False)
          File "/usr/lib/python3/dist-packages/maasserver/models/signals/interfaces.py", line 56, in interface_enabled_or_disabled
            instance.ensure_link_up()
          File "/usr/lib/python3/dist-packages/maasserver/models/interface.py", line 873, in ensure_link_up
            self.link_subnet(INTERFACE_LINK_TYPE.LINK_UP, subnet)
          File "/usr/lib/python3/dist-packages/maasserver/models/interface.py", line 824, in link_subnet
            return self._link_subnet_link_up(subnet)
          File "/usr/lib/python3/dist-packages/maasserver/models/interface.py", line 796, in _link_subnet_link_up
            self.save()
          File "/usr/lib/python3/dist-packages/maasserver/models/cleansave.py", line 29, in save
            return super(CleanSave, self).save(*args, **kwargs)
          File "/usr/lib/python3/dist-packages/maasserver/models/timestampedmodel.py", line 72, in save
            return super(TimestampedModel, self).save(*args, **kwargs)
          File "/usr/lib/python3/dist-packages/django/db/models/base.py", line 734, in save
            force_update=force_update, update_fields=update_fields)
          File "/usr/lib/python3/dist-packages/django/db/models/base.py", line 771, in save_base
            update_fields=update_fields, raw=raw, using=using)
          File "/usr/lib/python3/dist-packages/django/dispatch/dispatcher.py", line 189, in send
            response = receiver(signal=self, sender=sender, **named)
          File "/usr/lib/python3/dist-packages/maasserver/models/signals/interfaces.py", line 277, in resave_children_interface_handler
            rel.child.save()
          File "/usr/lib/python3/dist-packages/maasserver/models/interface.py", line 1387, in save
            super().save(*args, **kwargs)
          File "/usr/lib/python3/dist-packages/maasserver/models/cleansave.py", line 29, in save
            return super(CleanSave, self).save(*args, **kwargs)
          File "/usr/lib/python3/dist-packages/maasserver/models/timestampedmodel.py", line 72, in save
            return super(TimestampedModel, self).save(*args, **kwargs)
          File "/usr/lib/python3/dist-packages/django/db/models/base.py", line 734, in save
            force_update=force_update, update_fields=update_fields)
          File "/usr/lib/python3/dist-packages/django/db/models/base.py", line 771, in save_base
            update_fields=update_fields, raw=raw, using=using)
          File "/usr/lib/python3/dist-packages/django/dispatch/dispatcher.py", line 189, in send
            response = receiver(signal=self, sender=sender, **named)
          File "/usr/lib/python3/dist-packages/maasserver/models/signals/interfaces.py", line 160, in update_interface_parents
            parent.clear_all_links(clearing_config=True)
          File "/usr/lib/python3/dist-packages/maasserver/models/interface.py", line 971, in clear_all_links
            self.unlink_ip_address(ip_address, clearing_config=clearing_config)
          File "/usr/lib/python3/dist-packages/maasserver/models/interface.py", line 899, in unlink_ip_address
            ip_address.delete()
          File "/usr/lib/python3/dist-packages/django/db/models/base.py", line 896, in delete
            collector.delete()
          File "/usr/lib/python3/dist-packages/django/db/models/deletion.py", line 287, in delete
            sender=model, instance=obj, using=self.using
          File "/usr/lib/python3/dist-packages/django/dispatch/dispatcher.py", line 189, in send
            response = receiver(signal=self, sender=sender, **named)
          File "/usr/lib/python3/dist-packages/maasserver/models/signals/staticipaddress.py", line 35, in pre_delete_record_bmcs_on_delete
            instance.__previous_bmcs = set(instance.bmc_set.all())
          File "/usr/lib/python3/dist-packages/django/db/models/manager.py", line 228, in all
            return self.get_queryset()
          File "/usr/lib/python3/dist-packages/django/db/models/fields/related.py", line 715, in get_queryset
            qs = qs.filter(**self.core_filters)
          File "/usr/lib/python3/dist-packages/django/db/models/query.py", line 679, in filter
            return self._filter_or_exclude(False, *args, **kwargs)
          File "/usr/lib/python3/dist-packages/django/db/models/query.py", line 697, in _filter_or_exclude
            clone.query.add_q(Q(*args, **kwargs))
          File "/usr/lib/python3/dist-packages/django/db/models/sql/query.py", line 1310, in add_q
            clause, require_inner = self._add_q(where_part, self.used_aliases)
          File "/usr/lib/python3/dist-packages/django/db/models/sql/query.py", line 1338, in _add_q
            allow_joins=allow_joins, split_subq=split_subq,
          File "/usr/lib/python3/dist-packages/django/db/models/sql/query.py", line 1200, in build_filter
            lookups, value)
          File "/usr/lib/python3/dist-packages/django/db/models/fields/related.py", line 1761, in get_lookup_constraint
            lookup_class(target.get_col(alias, source), val), AND)
          File "/usr/lib/python3/dist-packages/django/db/models/lookups.py", line 101, in __init__
            self.rhs = self.get_prep_lookup()
          File "/usr/lib/python3/dist-packages/django/db/models/lookups.py", line 139, in get_prep_lookup
            return self.lhs.output_field.get_prep_lookup(self.lookup_name, self.rhs)
          File "/usr/lib/python3/dist-packages/django/utils/functional.py", line 59, in __get__
            res = instance.__dict__[self.name] = self.func(instance)
          File "/usr/lib/python3/dist-packages/django/db/models/expressions.py", line 221, in output_field
            if self._output_field_or_none is None:
          File "/usr/lib/python3/dist-packages/django/utils/functional.py", line 59, in __get__
            res = instance.__dict__[self.name] = self.func(instance)
        builtins.RecursionError: maximum recursion depth exceeded

Tags: cpe-onsite

Related branches

Changed in maas:
importance: Undecided → High
milestone: none → 2.1.0
Changed in maas:
milestone: 2.1.0 → 2.1.1
Changed in maas:
milestone: 2.1.1 → 2.1.2
Changed in maas:
milestone: 2.1.2 → 2.1.3
Revision history for this message
Chris Gregan (cgregan) wrote :

escalated to field high as it is impacting a customer deploy

tags: added: cpe-onsite
Revision history for this message
Mike Pontillo (mpontillo) wrote :

@cgregan, can you check if the patch in the linked merge proposal fixes the issue for the customer?

https://code.launchpad.net/~mpontillo/maas/interface-up-down-visited-recursion-prevent/+merge/305403

This proposal got lost when we transitioned to git, and I was planning to take another look shortly.

Changed in maas:
milestone: 2.1.3 → 2.5.0
Changed in maas:
status: In Progress → Fix Committed
Changed in maas:
milestone: 2.5.0 → 2.5.0alpha1
Changed in maas:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.