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