예제 #1
0
    def notify_add_biport(self, node, biport):
        """
        Get notified that a new biport was added to this engine node.

        :param node: The specification node that spawn this engine node.
        :type node: pynml.nml.Node
        :param biport: The specification bidirectional port added.
        :type biport: pynml.nml.BidirectionalPort
        :rtype: str
        :return: The assigned interface name of the port.
        """

        network_config = self._get_network_config()

        category = biport.metadata.get('category',
                                       network_config['default_category'])
        category_config = network_config['mapping'][category]

        if category_config['managed_by'] is 'docker':
            netname = category_config.get(
                'connect_to', '{}_{}'.format(self._container_name, category))
            return get_iface_name(self, netname)
        else:
            return biport.metadata.get('label', biport.identifier)
예제 #2
0
def create_docker_network(enode, category, config):
    """
    Create a Docker managed network with given configuration (netns, prefix) to
    be used with Topology framework.

    :param enode: The platform (a.k.a "engine") node to configure.
    :param str category: Name of the panel category.
    :param dict config: Configuration for the network. A dictionary like:

     ::

        {
            'netns': 'mynetns',
            'managed_by': 'docker',
            'connect_to': 'somedockernetwork',
            'prefix': ''
        }

     This dictionary is taken from the ``node._get_network_config()`` result.
    """
    # Let's find out which networks exist already
    dockernets = enode._client.networks()

    # Let's figure out what docker network we should connect to
    netname = config.get(
        'connect_to',
        '{}_{}'.format(enode._container_name, category)
    )

    # Create docker network if it doesn't exist already
    if not any(d['Name'] == netname for d in dockernets):
        enode._client.create_network(
            name=netname,
            driver='bridge'
        )

    # Disconnect from 'none' to be able to connect to other
    # networks (https://github.com/docker/docker/issues/21132)
    networks = enode._client.inspect_container(
        enode.container_id
    )['NetworkSettings']['Networks']
    if 'none' in networks:
        enode._client.disconnect_container_from_network(
            container=enode._container_id,
            net_id='none'
        )

    # Connect container to the docker network
    enode._client.connect_container_to_network(
        container=enode._container_id,
        net_id=netname
    )

    # Check if this category has a defined netns
    netns = config.get('netns', None)
    if netns is None:
        return

    # Create this network's namespace inside the container
    # https://imgflip.com/i/16621d
    enode._docker_exec('ip netns add {}'.format(netns))

    netns_exec = 'ip netns exec {}'.format(netns)

    # lo should always be up
    enode._docker_exec('{} ip link set dev lo up'.format(netns_exec))

    # Find out the name Docker gave to this interface name
    iface = get_iface_name(enode, netname)

    # Prefix interface
    prefixed_iface = '{}{}'.format(config['prefix'], iface)

    # Move this network's interface to its netns
    enode._docker_exec(
        'ip link set dev {iface} netns {netns} name {prefixed_iface}'.format(
            **locals()
        )
    )

    # Reset the interface to original config
    # This is required because after moving the iface from netns it lost its
    # ip and other config.
    enode._docker_exec(
        '{netns_exec} '
        'ip address add {docker_netconf[IPAddress]}/'
        '{docker_netconf[IPPrefixLen]} '
        'dev {prefixed_iface}'.format(
            **locals()
        )
    )
    enode._docker_exec(
        '{netns_exec} ip link set dev {prefixed_iface} up'.format(
            **locals()
        )
    )