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
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'])
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)))
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})
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)
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'])