=== modified file 'src/maasserver/models/signals/interfaces.py' --- src/maasserver/models/signals/interfaces.py 2016-07-30 01:17:54 +0000 +++ src/maasserver/models/signals/interfaces.py 2016-09-10 07:09:35 +0000 @@ -45,6 +45,28 @@ signals = SignalsManager() +class InterfaceVisitingThreadLocal(threading.local): + """Since infinite recursion could occur in an arbitrary interface + hierarchy, use thread-local storage to ensure that each interface is only + visited once. + """ + def __init__(self): + super().__init__() + self.visiting = set() + +enabled_or_disabled_thread_local = InterfaceVisitingThreadLocal() + + +def ensure_link_up(interface): + visiting = enabled_or_disabled_thread_local.visiting + if interface.id not in visiting: + try: + visiting.add(interface.id) + interface.ensure_link_up() + finally: + visiting.discard(interface.id) + + def interface_enabled_or_disabled(instance, old_values, **kwargs): """When an interface is enabled be sure at minimum a LINK_UP is created. When an interface is disabled make sure that all its links are removed, @@ -53,9 +75,10 @@ return if instance.is_enabled(): # Make sure it has a LINK_UP link, and for its children. - instance.ensure_link_up() + ensure_link_up(instance) for rel in instance.children_relationships.all(): - rel.child.ensure_link_up() + ensure_link_up(rel.child) + else: # Was disabled. Remove the links. for ip_address in instance.ip_addresses.exclude( @@ -140,16 +163,7 @@ klass, ['params'], delete=False) -class InterfaceUpdateParentsThreadLocal(threading.local): - """Since infinite recursion could occur in an arbitrary interface - hierarchy, use thread-local stroage to ensure that each interface is only - visited once. - """ - def __init__(self): - super().__init__() - self.visiting = set() - -update_parents_thread_local = InterfaceUpdateParentsThreadLocal() +update_parents_thread_local = InterfaceVisitingThreadLocal() def update_interface_parents(sender, instance, created, **kwargs):