Esempio n. 1
0
 def test_circular_dependency_results_in_an_exception(self):
     self.assertRaises(CircularDependency, list, sorttop({1: {2}, 2: {1}}))
Esempio n. 2
0
def update_node_interfaces(node,
                           interfaces,
                           topology_hints=None,
                           create_fabrics=True):
    """Update the interfaces attached to the node

    :param interfaces: a dict with interface details.
    :param topology_hints: List of dictionaries representing hints
        about fabric/VLAN connectivity.
    :param create_fabrics: If True, creates fabrics associated with each
        VLAN. Otherwise, creates the interfaces but does not create any
        links or VLANs.
    """
    # Avoid circular imports
    from metadataserver.builtin_scripts.hooks import (
        parse_interfaces_details,
        update_interface_details,
    )

    # Get all of the current interfaces on this node.
    current_interfaces = {
        interface.id: interface
        for interface in node.interface_set.all().order_by("id")
    }

    # Update the interfaces in dependency order. This make sure that the
    # parent is created or updated before the child. The order inside
    # of the sorttop result is ordered so that the modification locks that
    # postgres grabs when updating interfaces is always in the same order.
    # The ensures that multiple threads can call this method at the
    # exact same time. Without this ordering it will deadlock because
    # multiple are trying to update the same items in the database in
    # a different order.
    process_order = sorttop(
        {name: config["parents"]
         for name, config in interfaces.items()})
    process_order = [sorted(list(items)) for items in process_order]
    # Cache the neighbour discovery settings, since they will be used for
    # every interface on this Controller.
    discovery_mode = Config.objects.get_network_discovery_config()
    interfaces_details = parse_interfaces_details(node)
    for name in flatten(process_order):
        settings = interfaces[name]
        # Note: the interface that comes back from this call may be None,
        # if we decided not to model an interface based on what the rack
        # sent.
        interface = update_interface(
            node,
            name,
            settings,
            create_fabrics=create_fabrics,
            hints=topology_hints,
        )
        if interface is not None:
            interface.update_discovery_state(discovery_mode, settings)
            if interface.type == INTERFACE_TYPE.PHYSICAL:
                update_interface_details(interface, interfaces_details)
            if interface.id in current_interfaces:
                del current_interfaces[interface.id]

    if not create_fabrics:
        # This could be an existing rack controller re-registering,
        # so don't delete interfaces during this phase.
        return

    # Remove all the interfaces that no longer exist. We do this in reverse
    # order so the child is deleted before the parent.
    deletion_order = {}
    for nic_id, nic in current_interfaces.items():
        deletion_order[nic_id] = [
            parent.id for parent in nic.parents.all()
            if parent.id in current_interfaces
        ]
    deletion_order = sorttop(deletion_order)
    deletion_order = [sorted(list(items)) for items in deletion_order]
    deletion_order = reversed(list(flatten(deletion_order)))
    for delete_id in deletion_order:
        if node.boot_interface_id == delete_id:
            node.boot_interface = None
        current_interfaces[delete_id].delete()
    node.save()
Esempio n. 3
0
 def assertSort(self, data, *batches):
     self.assertThat(tuple(sorttop(data)), Equals(batches))
Esempio n. 4
0
def update_node_interfaces(node, data):
    """Update the interfaces attached to the node

    :param data: a dict containing commissioning data
    """
    from metadataserver.builtin_scripts.hooks import (
        parse_interfaces,
        update_interface_details,
    )

    if "network-extra" in data:
        topology_hints = data["network-extra"]["hints"]
        monitored_interfaces = data["network-extra"]["monitored-interfaces"]
        address_extra = get_address_extra(data["network-extra"]["interfaces"])
    else:
        topology_hints = None
        monitored_interfaces = []
        address_extra = {}

    current_interfaces = {
        interface.id: interface
        for interface in node.interface_set.all()
    }

    # Update the interfaces in dependency order. This make sure that the
    # parent is created or updated before the child. The order inside
    # of the sorttop result is ordered so that the modification locks that
    # postgres grabs when updating interfaces is always in the same order.
    # The ensures that multiple threads can call this method at the
    # exact same time. Without this ordering it will deadlock because
    # multiple are trying to update the same items in the database in
    # a different order.
    process_order = sorttop(get_interface_dependencies(data))
    process_order = [sorted(list(items)) for items in process_order]
    # Cache the neighbour discovery settings, since they will be used for
    # every interface on this Controller.
    discovery_mode = Config.objects.get_network_discovery_config()
    interfaces_details = parse_interfaces(node, data)
    for name in flatten(process_order):
        # Note: the interface that comes back from this call may be None,
        # if we decided not to model an interface based on what the rack
        # sent.
        interface = update_interface(
            node,
            name,
            data,
            address_extra,
            hints=topology_hints,
        )
        if interface is None:
            continue
        interface.update_discovery_state(discovery_mode, name
                                         in monitored_interfaces)
        if interface.type == INTERFACE_TYPE.PHYSICAL:
            update_interface_details(interface, interfaces_details)
        if interface.id in current_interfaces:
            del current_interfaces[interface.id]

    # Remove all the interfaces that no longer exist. We do this in reverse
    # order so the child is deleted before the parent.
    deletion_order = {}
    for nic_id, nic in current_interfaces.items():
        deletion_order[nic_id] = [
            parent.id for parent in nic.parents.all()
            if parent.id in current_interfaces
        ]
    deletion_order = sorttop(deletion_order)
    deletion_order = [sorted(list(items)) for items in deletion_order]
    deletion_order = reversed(list(flatten(deletion_order)))
    for delete_id in deletion_order:
        if node.boot_interface_id == delete_id:
            node.boot_interface = None
        current_interfaces[delete_id].delete()
    node.save()