[2.1b2] Infinite recursion observed while toggling interface state

Bug #1622105 reported by Mike Pontillo on 2016-09-10
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
MAAS
High
Mike Pontillo
2.3
High
Mike Pontillo
2.4
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

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
Chris Gregan (cgregan) wrote :

escalated to field high as it is impacting a customer deploy

tags: added: cpe-onsite
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  Edit
Everyone can see this information.

Other bug subscribers