Example #1
0
def check_for_neutron_ext_tag():
    """Validates for mandatory extension support availability in neutron."""
    app.tag = True
    try:
        app.neutron.show_extension(TAG_NEUTRON_EXTENSION)
    except n_exceptions.NeutronClientException as e:
        app.tag = False
        if e.status_code == n_exceptions.NotFound.status_code:
            app.logger.warn(_LW("Neutron tags not supported. "
                                "Continue without using them."))
Example #2
0
def check_for_neutron_ext_tag():
    """Validates for mandatory extension support availability in neutron."""
    app.tag = True
    try:
        app.neutron.show_extension(TAG_NEUTRON_EXTENSION)
    except n_exceptions.NeutronClientException as e:
        app.tag = False
        if e.status_code == n_exceptions.NotFound.status_code:
            app.logger.warn(
                _LW("Neutron tags not supported. "
                    "Continue without using them."))
Example #3
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})
Example #4
0
def ipam_request_pool():
    """Creates a new Neutron subnetpool from the given request.

    This funciton takes the following JSON data and delegates the subnetpool
    creation to the Neutron client. ::

        {
            "AddressSpace": string
            "Pool":         string
            "SubPool":      string
            "Options":      map[string]string
            "V6":           bool
        }

    Then the following JSON response is returned. ::

        {
            "PoolID": string
            "Pool":   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#requestpool  # noqa
    """
    json_data = flask.request.get_json(force=True)
    app.logger.debug(
        "Received JSON data {0} for /IpamDriver.RequestPool".format(json_data))
    jsonschema.validate(json_data, schemata.REQUEST_POOL_SCHEMA)
    requested_pool = json_data['Pool']
    requested_subpool = json_data['SubPool']
    v6 = json_data['V6']
    pool_id = ''
    subnet_cidr = ''
    if requested_pool:
        app.logger.info(_LI("Creating subnetpool with the given pool CIDR"))
        if requested_subpool:
            cidr = netaddr.IPNetwork(requested_subpool)
        else:
            cidr = netaddr.IPNetwork(requested_pool)
        subnet_cidr = _get_subnet_cidr_using_cidr(cidr)
        pool_name = utils.get_neutron_subnetpool_name(subnet_cidr)
        # Check if requested pool already exist
        pools = _get_subnetpools_by_attrs(name=pool_name)
        if pools:
            pool_id = pools[0]['id']
        if not pools:
            new_subnetpool = {
                'name': pool_name,
                'default_prefixlen': cidr.prefixlen,
                'prefixes': [subnet_cidr]
            }
            created_subnetpool_response = app.neutron.create_subnetpool(
                {'subnetpool': new_subnetpool})
            pool = created_subnetpool_response['subnetpool']
            pool_id = pool['id']
    else:
        if v6:
            default_pool_list = SUBNET_POOLS_V6
        else:
            default_pool_list = SUBNET_POOLS_V4
        pool_name = default_pool_list[0]
        pools = _get_subnetpools_by_attrs(name=pool_name)
        if pools:
            pool = pools[0]
            pool_id = pool['id']
            prefixes = pool['prefixes']
            if len(prefixes) > 1:
                app.logger.warning(
                    _LW("More than one prefixes present. "
                        "Picking first one."))
            cidr = netaddr.IPNetwork(prefixes[0])
            subnet_cidr = _get_subnet_cidr_using_cidr(cidr)
        else:
            app.logger.error(_LE("Default neutron pools not found."))
    req_pool_res = {'PoolID': pool_id, 'Pool': subnet_cidr}
    return flask.jsonify(req_pool_res)
Example #5
0
def network_driver_delete_network():
    """Delete the Neutron Network with name as the given NetworkID.

    This function takes the following JSON data and delegates the actual
    network deletion to the Neutron client. ::

        {
            "NetworkID": string
        }

    See the following link for more details about the spec:

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

    container_net_id = json_data['NetworkID']
    neutron_network_tags = utils.make_net_tags(container_net_id)
    existing_network_tags = neutron_network_tags + ','
    existing_network_tags += const.KURYR_EXISTING_NEUTRON_NET
    try:
        existing_networks = _get_networks_by_attrs(tags=existing_network_tags)
    except n_exceptions.NeutronClientException as ex:
        app.logger.error(
            _LE("Error happened during listing "
                "Neutron networks: {0}").format(ex))
        raise

    if existing_networks:
        app.logger.warn(
            _LW("Network is a pre existing Neutron network, "
                "not deleting in Neutron. removing tags: {0}").format(
                    existing_network_tags))
        neutron_net_id = existing_networks[0]['id']
        _neutron_net_remove_tags(neutron_net_id, container_net_id)
        _neutron_net_remove_tag(neutron_net_id,
                                const.KURYR_EXISTING_NEUTRON_NET)
        return flask.jsonify(const.SCHEMA['SUCCESS'])

    try:
        filtered_networks = _get_networks_by_attrs(tags=neutron_network_tags)
    except n_exceptions.NeutronClientException as ex:
        app.logger.error(
            _LE("Error happened during listing "
                "Neutron networks: {0}").format(ex))
        raise

    if not filtered_networks:
        app.logger.warn(
            _LW("Network with tags {0} cannot be found").format(
                neutron_network_tags))
    else:
        neutron_network_id = filtered_networks[0]['id']
        filtered_subnets = _get_subnets_by_attrs(network_id=neutron_network_id)
        for subnet in filtered_subnets:
            try:
                subnetpool_id = subnet.get('subnetpool_id', None)

                _cache_default_subnetpool_ids(app)

                if subnetpool_id not in app.DEFAULT_POOL_IDS:
                    # If the subnet to be deleted has any port, when some ports
                    # are referring to the subnets in other words,
                    # delete_subnet throws an exception, SubnetInUse that
                    # extends Conflict. This can happen when the multiple
                    # Docker endpoints are created with the same subnet CIDR
                    # and it's totally the normal case. So we'd just log that
                    # and continue to proceed.
                    app.neutron.delete_subnet(subnet['id'])
            except n_exceptions.Conflict as ex:
                app.logger.error(
                    _LE("Subnet, {0}, is in use. Network cant be deleted.").
                    format(subnet['id']))
                raise
            except n_exceptions.NeutronClientException as ex:
                app.logger.error(
                    _LE("Error happened during deleting a "
                        "Neutron subnets: {0}").format(ex))
                raise

        try:
            app.neutron.delete_network(neutron_network_id)
        except n_exceptions.NeutronClientException as ex:
            app.logger.error(
                _LE("Error happened during deleting a "
                    "Neutron network: {0}").format(ex))
            raise
        app.logger.info(
            _LI("Deleted the network with ID {0} successfully").format(
                neutron_network_id))
    return flask.jsonify(const.SCHEMA['SUCCESS'])
Example #6
0
def ipam_request_pool():
    """Creates a new Neutron subnetpool from the given request.

    This funciton takes the following JSON data and delegates the subnetpool
    creation to the Neutron client. ::

        {
            "AddressSpace": string
            "Pool":         string
            "SubPool":      string
            "Options":      map[string]string
            "V6":           bool
        }

    Then the following JSON response is returned. ::

        {
            "PoolID": string
            "Pool":   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#requestpool  # noqa
    """
    json_data = flask.request.get_json(force=True)
    app.logger.debug("Received JSON data {0} for /IpamDriver.RequestPool"
                     .format(json_data))
    jsonschema.validate(json_data, schemata.REQUEST_POOL_SCHEMA)
    requested_pool = json_data['Pool']
    requested_subpool = json_data['SubPool']
    v6 = json_data['V6']
    pool_id = ''
    subnet_cidr = ''
    if requested_pool:
        app.logger.info(_LI("Creating subnetpool with the given pool CIDR"))
        if requested_subpool:
            cidr = netaddr.IPNetwork(requested_subpool)
        else:
            cidr = netaddr.IPNetwork(requested_pool)
        subnet_cidr = _get_subnet_cidr_using_cidr(cidr)
        pool_name = utils.get_neutron_subnetpool_name(subnet_cidr)
        # Check if requested pool already exist
        pools = _get_subnetpools_by_attrs(name=pool_name)
        if pools:
            pool_id = pools[0]['id']
        if not pools:
            new_subnetpool = {
                'name': pool_name,
                'default_prefixlen': cidr.prefixlen,
                'prefixes': [subnet_cidr]}
            created_subnetpool_response = app.neutron.create_subnetpool(
                {'subnetpool': new_subnetpool})
            pool = created_subnetpool_response['subnetpool']
            pool_id = pool['id']
    else:
        if v6:
            default_pool_list = SUBNET_POOLS_V6
        else:
            default_pool_list = SUBNET_POOLS_V4
        pool_name = default_pool_list[0]
        pools = _get_subnetpools_by_attrs(name=pool_name)
        if pools:
            pool = pools[0]
            pool_id = pool['id']
            prefixes = pool['prefixes']
            if len(prefixes) > 1:
                app.logger.warning(_LW("More than one prefixes present. "
                                     "Picking first one."))
            cidr = netaddr.IPNetwork(prefixes[0])
            subnet_cidr = _get_subnet_cidr_using_cidr(cidr)
        else:
            app.logger.error(_LE("Default neutron pools not found."))
    req_pool_res = {'PoolID': pool_id,
                    'Pool': subnet_cidr}
    return flask.jsonify(req_pool_res)
Example #7
0
def network_driver_delete_network():
    """Delete the Neutron Network with name as the given NetworkID.

    This function takes the following JSON data and delegates the actual
    network deletion to the Neutron client. ::

        {
            "NetworkID": string
        }

    See the following link for more details about the spec:

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

    container_net_id = json_data['NetworkID']
    neutron_network_identifier = _make_net_identifier(container_net_id,
                                                      tags=app.tag)
    if app.tag:
        existing_network_identifier = neutron_network_identifier + ','
        existing_network_identifier += const.KURYR_EXISTING_NEUTRON_NET
        try:
            existing_networks = _get_networks_by_identifier(
                existing_network_identifier)
        except n_exceptions.NeutronClientException as ex:
            app.logger.error(_LE("Error happened during listing "
                                 "Neutron networks: {0}").format(ex))
            raise

        if existing_networks:
            app.logger.warn(_LW("Network is a pre existing Neutron network, "
                                "not deleting in Neutron. removing tags: {0}")
                            .format(existing_network_identifier))
            neutron_net_id = existing_networks[0]['id']
            _neutron_net_remove_tags(neutron_net_id, container_net_id)
            _neutron_net_remove_tag(neutron_net_id,
                                    const.KURYR_EXISTING_NEUTRON_NET)
            return flask.jsonify(const.SCHEMA['SUCCESS'])

    try:
        filtered_networks = _get_networks_by_identifier(
            neutron_network_identifier)
    except n_exceptions.NeutronClientException as ex:
        app.logger.error(_LE("Error happened during listing "
                             "Neutron networks: {0}").format(ex))
        raise

    if not filtered_networks:
        app.logger.warn(_LW("Network with identifier {0} cannot be found")
                        .format(neutron_network_identifier))
    else:
        neutron_network_id = filtered_networks[0]['id']
        filtered_subnets = _get_subnets_by_attrs(
            network_id=neutron_network_id)
        for subnet in filtered_subnets:
            try:
                subnetpool_id = subnet.get('subnetpool_id', None)

                _cache_default_subnetpool_ids(app)

                if subnetpool_id not in app.DEFAULT_POOL_IDS:
                    # If the subnet to be deleted has any port, when some ports
                    # are referring to the subnets in other words,
                    # delete_subnet throws an exception, SubnetInUse that
                    # extends Conflict. This can happen when the multiple
                    # Docker endpoints are created with the same subnet CIDR
                    # and it's totally the normal case. So we'd just log that
                    # and continue to proceed.
                    app.neutron.delete_subnet(subnet['id'])
            except n_exceptions.Conflict as ex:
                app.logger.error(_LE(
                    "Subnet, {0}, is in use. Network cant be deleted.").format(
                        subnet['id']))
                raise
            except n_exceptions.NeutronClientException as ex:
                app.logger.error(_LE("Error happened during deleting a "
                                     "Neutron subnets: {0}").format(ex))
                raise

        try:
            app.neutron.delete_network(neutron_network_id)
        except n_exceptions.NeutronClientException as ex:
            app.logger.error(_LE("Error happened during deleting a "
                                 "Neutron network: {0}").format(ex))
            raise
        app.logger.info(_LI("Deleted the network with ID {0} successfully")
                        .format(neutron_network_id))
    return flask.jsonify(const.SCHEMA['SUCCESS'])
Example #8
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})