Ejemplo n.º 1
0
def _create_or_update_port(neutron_network_id, endpoint_id, interface_cidrv4,
                           interface_cidrv6, interface_mac):
    response_interface = {}
    subnets = []
    fixed_ips = []

    subnetsv4 = subnetsv6 = []
    if interface_cidrv4:
        subnetsv4 = _get_subnets_by_interface_cidr(neutron_network_id,
                                                   interface_cidrv4)
    if interface_cidrv6:
        subnetsv6 = _get_subnets_by_interface_cidr(neutron_network_id,
                                                   interface_cidrv6)
    subnets = subnetsv4 + subnetsv6
    if not len(subnets):
        raise exceptions.NoResourceException(
            "No subnet exist for the cidrs {0} and {1} ".format(
                interface_cidrv4, interface_cidrv6))
    if len(subnets) > 2:
        raise exceptions.DuplicatedResourceException(
            "Multiple subnets exist for the cidrs {0} and {1}".format(
                interface_cidrv4, interface_cidrv6))

    _get_fixed_ips_by_interface_cidr(subnets, interface_cidrv4,
                                     interface_cidrv6, fixed_ips)
    filtered_ports = app.neutron.list_ports(fixed_ips=fixed_ips)
    num_port = len(filtered_ports.get('ports', []))
    if not num_port:
        fixed_ips = utils.get_dict_format_fixed_ips_from_kv_format(fixed_ips)
        response_port = _create_port(endpoint_id, neutron_network_id,
                                     interface_mac, fixed_ips)
    elif num_port == 1:
        port = filtered_ports['ports'][0]
        response_port = _update_port(port, endpoint_id)
    else:
        raise n_exceptions.DuplicatedResourceException(
            "Multiple ports exist for the cidrs {0} and {1}".format(
                interface_cidrv4, interface_cidrv6))

    created_fixed_ips = response_port['fixed_ips']
    subnets_dict_by_id = {subnet['id']: subnet for subnet in subnets}
    if not interface_mac:
        response_interface['MacAddress'] = response_port['mac_address']

    if not (interface_cidrv4 or interface_cidrv6):
        if 'ip_address' in response_port:
            _process_interface_address(response_port, subnets_dict_by_id,
                                       response_interface)
        for fixed_ip in created_fixed_ips:
            _process_interface_address(fixed_ip, subnets_dict_by_id,
                                       response_interface)

    return response_interface
Ejemplo n.º 2
0
def network_driver_leave():
    """Unbinds a Neutron Port to a network interface attached to a container.

    This function takes the following JSON data and delete the veth pair
    corresponding to the given info. ::

        {
            "NetworkID": string,
            "EndpointID": string
        }
    """
    json_data = flask.request.get_json(force=True)
    app.logger.debug(
        "Received JSON data {0} for /NetworkDriver.DeleteEndpoint".format(
            json_data))
    jsonschema.validate(json_data, schemata.LEAVE_SCHEMA)
    neutron_network_name = json_data['NetworkID']
    endpoint_id = json_data['EndpointID']

    filtered_networks = _get_networks_by_attrs(name=neutron_network_name)

    if not filtered_networks:
        return flask.jsonify({
            'Err':
            "Neutron network associated with ID {0} doesn't exit.".format(
                neutron_network_name)
        })
    else:
        neutron_port_name = utils.get_neutron_port_name(endpoint_id)
        filtered_ports = _get_ports_by_attrs(name=neutron_port_name)
        if not filtered_ports:
            raise exceptions.NoResourceException(
                "The port doesn't exist for the name {0}".format(
                    neutron_port_name))
        neutron_port = filtered_ports[0]
        try:
            stdout, stderr = binding.port_unbind(endpoint_id, neutron_port)
            app.logger.debug(stdout)
            if stderr:
                app.logger.error(stderr)
        except processutils.ProcessExecutionError:
            with excutils.save_and_reraise_exception():
                app.logger.error(
                    'Could not unbind the Neutron port from the veth '
                    'endpoint.')
        except exceptions.VethDeletionFailure:
            with excutils.save_and_reraise_exception():
                app.logger.error('Cleaning the veth pair up was failed.')

    return flask.jsonify(constants.SCHEMA['SUCCESS'])
Ejemplo n.º 3
0
def _get_or_create_subnet_by_pools(subnetpool_names, neutron_network_id,
                                   endpoint_id, new_subnets, existing_subnets):
    for subnetpool_name in subnetpool_names:
        pools = _get_subnetpools_by_attrs(name=subnetpool_name)
        if pools:
            pool = pools[0]
            prefixes = pool['prefixes']
            for prefix in prefixes:
                _process_subnet(neutron_network_id, endpoint_id, prefix,
                                new_subnets, existing_subnets,
                                pool_id=pool['id'])
    if not (new_subnets or existing_subnets):
        raise exceptions.NoResourceException(
            "No subnetpools with name {0} is found."
            .format(', '.join(subnetpool_names)))
Ejemplo n.º 4
0
def ipam_request_address():
    """Allocates the IP address in the given request.

    This function takes the following JSON data and add the given IP address in
    the allocation_pools attribute of the subnet. ::

        {
            "PoolID":  string
            "Address": string
            "Options": map[string]string
        }

    Then the following response is returned. ::

        {
            "Address": string
            "Data":    map[string]string
        }

    See the following link for more details about the spec:

    https://github.com/docker/libnetwork/blob/master/docs/ipam.md#requestaddress  # noqa
    """
    json_data = flask.request.get_json(force=True)
    app.logger.debug(
        "Received JSON data {0} for /IpamDriver.RequestAddress".format(
            json_data))
    jsonschema.validate(json_data, schemata.REQUEST_ADDRESS_SCHEMA)
    pool_id = json_data['PoolID']
    req_address = json_data['Address']
    allocated_address = ''
    subnet_cidr = ''
    pool_prefix_len = ''
    pools = _get_subnetpools_by_attrs(id=pool_id)
    if pools:
        pool = pools[0]
        prefixes = pool['prefixes']
        if len(prefixes) > 1:
            app.logger.warning(
                _LW("More than one prefixes present. Picking "
                    "first one."))

        for prefix in prefixes:
            cidr = netaddr.IPNetwork(prefix)
            pool_prefix_len = str(cidr.prefixlen)
            subnet_network = str(cidr.network)
            subnet_cidr = '/'.join([subnet_network, pool_prefix_len])
            break
    else:
        raise exceptions.NoResourceException(
            "No subnetpools with id {0} is found.".format(pool_id))
    # check if any subnet with matching cidr is present
    subnets = _get_subnets_by_attrs(cidr=subnet_cidr)
    if subnets:
        subnet = subnets[0]
        # allocating address for container port
        neutron_network_id = subnet['network_id']
        try:
            port = {
                'name': 'kuryr-unbound-port',
                'admin_state_up': True,
                'network_id': neutron_network_id,
                'binding:host_id': utils.get_hostname(),
            }
            fixed_ips = port['fixed_ips'] = []
            fixed_ip = {'subnet_id': subnet['id']}
            if req_address:
                fixed_ip['ip_address'] = req_address
            fixed_ips.append(fixed_ip)
            created_port_resp = app.neutron.create_port({'port': port})
            created_port = created_port_resp['port']
            allocated_address = created_port['fixed_ips'][0]['ip_address']
            allocated_address = '/'.join(
                [allocated_address, str(cidr.prefixlen)])
        except n_exceptions.NeutronClientException as ex:
            app.logger.error(
                _LE("Error happend during ip allocation on"
                    "Neutron side: {0}").format(ex))
            raise
    else:
        # Auxiliary address or gw_address is received at network creation time.
        # This address cannot be reserved with neutron at this time as subnet
        # is not created yet. In /NetworkDriver.CreateNetwork this address will
        # be reserved with neutron.
        if req_address:
            allocated_address = '/'.join([req_address, pool_prefix_len])

    return flask.jsonify({'Address': allocated_address})
Ejemplo n.º 5
0
def network_driver_join():
    """Binds a Neutron Port to a network interface attached to a container.

    This function takes the following JSON data, creates a veth pair, put one
    end inside of the container and binds another end to the Neutron Port
    specified in the request. ::

        {
            "NetworkID": string,
            "EndpointID": string,
            "SandboxKey": string,
            "Options": {
                ...
            }
        }

    If the binding is succeeded, the following JSON response is returned.::

        {
            "InterfaceName": {
                SrcName: string,
                DstPrefix: string
            },
            "Gateway": string,
            "GatewayIPv6": string,
            "StaticRoutes": [{
                "Destination": string,
                "RouteType": int,
                "NextHop": string,
            }, ...]
        }

    See the following link for more details about the spec:

      https://github.com/docker/libnetwork/blob/master/docs/remote.md#join  # noqa
    """
    json_data = flask.request.get_json(force=True)
    app.logger.debug(
        "Received JSON data {0} for /NetworkDriver.Join".format(json_data))
    jsonschema.validate(json_data, schemata.JOIN_SCHEMA)

    neutron_network_tags = utils.make_net_tags(json_data['NetworkID'])
    endpoint_id = json_data['EndpointID']
    filtered_networks = _get_networks_by_attrs(tags=neutron_network_tags)

    if not filtered_networks:
        return flask.jsonify({
            'Err':
            "Neutron network associated with tags {0} doesn't exit.".format(
                neutron_network_tags)
        })
    else:
        neutron_network_id = filtered_networks[0]['id']

        neutron_port_name = utils.get_neutron_port_name(endpoint_id)
        filtered_ports = _get_ports_by_attrs(name=neutron_port_name)
        if not filtered_ports:
            raise exceptions.NoResourceException(
                "The port doesn't exist for the name {0}".format(
                    neutron_port_name))
        neutron_port = filtered_ports[0]
        all_subnets = _get_subnets_by_attrs(network_id=neutron_network_id)

        try:
            ifname, peer_name, (stdout, stderr) = binding.port_bind(
                endpoint_id, neutron_port, all_subnets)
            app.logger.debug(stdout)
            if stderr:
                app.logger.error(stderr)
        except exceptions.VethCreationFailure as ex:
            with excutils.save_and_reraise_exception():
                app.logger.error(
                    _LE('Preparing the veth '
                        'pair was failed: {0}.').format(ex))
        except processutils.ProcessExecutionError:
            with excutils.save_and_reraise_exception():
                app.logger.error(
                    _LE('Could not bind the Neutron port to the veth endpoint.'
                        ))

        join_response = {
            "InterfaceName": {
                "SrcName": peer_name,
                "DstPrefix": config.CONF.binding.veth_dst_prefix
            },
            "StaticRoutes": []
        }

        for subnet in all_subnets:
            if subnet['ip_version'] == 4:
                join_response['Gateway'] = subnet.get('gateway_ip', '')
            else:
                join_response['GatewayIPv6'] = subnet.get('gateway_ip', '')
            host_routes = subnet.get('host_routes', [])

            for host_route in host_routes:
                static_route = {'Destination': host_route['destination']}
                if host_route.get('nexthop', None):
                    static_route['RouteType'] = const.TYPES['NEXTHOP']
                    static_route['NextHop'] = host_route['nexthop']
                else:
                    static_route['RouteType'] = const.TYPES['CONNECTED']
                join_response['StaticRoutes'].append(static_route)

        return flask.jsonify(join_response)
Ejemplo n.º 6
0
def ipam_release_address():
    """Deallocates the IP address in the given request.

    This function takes the following JSON data and remove the given IP address
    from the allocation_pool attribute of the subnet. ::

        {
            "PoolID": string
            "Address": string
        }

    Then the following response is returned. ::

        {}

    See the following link for more details about the spec:

      https://github.com/docker/libnetwork/blob/master/docs/ipam.md#releaseaddress  # noqa
    """
    json_data = flask.request.get_json(force=True)
    app.logger.debug(
        "Received JSON data {0} for /IpamDriver.ReleaseAddress".format(
            json_data))
    jsonschema.validate(json_data, schemata.RELEASE_ADDRESS_SCHEMA)
    pool_id = json_data['PoolID']
    rel_address = json_data['Address']
    pools = _get_subnetpools_by_attrs(id=pool_id)
    if pools:
        pool = pools[0]
        prefixes = pool['prefixes']
        for prefix in prefixes:
            cidr = netaddr.IPNetwork(prefix)
            subnet_network = str(cidr.network)
            subnet_cidr = '/'.join([subnet_network, str(cidr.prefixlen)])
    else:
        raise exceptions.NoResourceException(
            "No subnetpools with id {0} is found.".format(pool_id))
    # check if any subnet with matching cidr is present
    subnets = _get_subnets_by_attrs(cidr=subnet_cidr)
    if not len(subnets):
        raise exceptions.NoResourceException(
            "No subnet is found using pool {0} "
            "and pool_cidr {1}".format(pool_id, cidr))
    subnet = subnets[0]
    cidr_address = netaddr.IPNetwork(rel_address)
    rcvd_fixed_ips = []
    fixed_ip = {'subnet_id': subnet['id']}
    fixed_ip['ip_address'] = str(cidr_address.ip)
    rcvd_fixed_ips.append(fixed_ip)

    try:
        filtered_ports = []
        all_ports = app.neutron.list_ports()
        for port in all_ports['ports']:
            if port['fixed_ips'] == rcvd_fixed_ips:
                filtered_ports.append(port)
        for port in filtered_ports:
            app.neutron.delete_port(port['id'])
    except n_exceptions.NeutronClientException as ex:
        app.logger.error(
            _LE("Error happend while fetching and deleting port, "
                "{0}").format(ex))
        raise

    return flask.jsonify(const.SCHEMA['SUCCESS'])