def ipam_release_pool(): """Deletes a new Neutron subnetpool from the given reuest. This function takes the following JSON data and delegates the subnetpool deletion to the Neutron client. :: { "PoolID": string } Then the following JSON response is returned. :: {} See the following link for more details about the spec: https://github.com/docker/libnetwork/blob/master/docs/ipam.md#releasepool # noqa """ json_data = flask.request.get_json(force=True) app.logger.debug("Received JSON data {0} for /IpamDriver.ReleasePool" .format(json_data)) jsonschema.validate(json_data, schemata.RELEASE_POOL_SCHEMA) pool_id = json_data['PoolID'] try: app.neutron.delete_subnetpool(pool_id) except n_exceptions.Conflict as ex: app.logger.info(_LI("The subnetpool with ID {0} is still in use." " It can't be deleted for now.").format(pool_id)) except n_exceptions.NeutronClientException as ex: app.logger.error(_LE("Error happend during deleting a " "Neutron subnetpool: {0}").format(ex)) raise return flask.jsonify(const.SCHEMA['SUCCESS'])
def ipam_release_pool(): """Deletes a new Neutron subnetpool from the given reuest. This function takes the following JSON data and delegates the subnetpool deletion to the Neutron client. :: { "PoolID": string } Then the following JSON response is returned. :: {} See the following link for more details about the spec: https://github.com/docker/libnetwork/blob/master/docs/ipam.md#releasepool # noqa """ json_data = flask.request.get_json(force=True) app.logger.debug( "Received JSON data {0} for /IpamDriver.ReleasePool".format(json_data)) jsonschema.validate(json_data, schemata.RELEASE_POOL_SCHEMA) pool_id = json_data['PoolID'] try: app.neutron.delete_subnetpool(pool_id) except n_exceptions.Conflict as ex: app.logger.info( _LI("The subnetpool with ID {0} is still in use." " It can't be deleted for now.").format(pool_id)) except n_exceptions.NeutronClientException as ex: app.logger.error( _LE("Error happend during deleting a " "Neutron subnetpool: {0}").format(ex)) raise 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_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 network_driver_create_network(): """Creates a new Neutron Network which name is the given NetworkID. This function takes the following JSON data and delegates the actual network creation to the Neutron client. libnetwork's NetworkID is used as the name of Network in Neutron. :: { "NetworkID": string, "IPv4Data" : [{ "AddressSpace": string, "Pool": ipv4-cidr-string, "Gateway" : ipv4-address, "AuxAddresses": { "<identifier1>" : "<ipv4-address1>", "<identifier2>" : "<ipv4-address2>", ... } }, ...], "IPv6Data" : [{ "AddressSpace": string, "Pool": ipv6-cidr-string, "Gateway" : ipv6-address, "AuxAddresses": { "<identifier1>" : "<ipv6-address1>", "<identifier2>" : "<ipv6-address2>", ... } }, ...], "Options": { ... } } See the following link for more details about the spec: https://github.com/docker/libnetwork/blob/master/docs/remote.md#create-network # noqa """ json_data = flask.request.get_json(force=True) app.logger.debug("Received JSON data {0} for" " /NetworkDriver.CreateNetwork".format(json_data)) jsonschema.validate(json_data, schemata.NETWORK_CREATE_SCHEMA) container_net_id = json_data['NetworkID'] neutron_network_name = utils.make_net_name(container_net_id) pool_cidr = json_data['IPv4Data'][0]['Pool'] gateway_ip = '' if 'Gateway' in json_data['IPv4Data'][0]: gateway_cidr = json_data['IPv4Data'][0]['Gateway'] gateway_ip = gateway_cidr.split('/')[0] app.logger.debug("gateway_cidr {0}, gateway_ip {1}".format( gateway_cidr, gateway_ip)) neutron_uuid = None neutron_name = None options = json_data.get('Options') if options: generic_options = options.get(const.NETWORK_GENERIC_OPTIONS) if generic_options: neutron_uuid = generic_options.get(const.NEUTRON_UUID_OPTION) neutron_name = generic_options.get(const.NEUTRON_NAME_OPTION) if not neutron_uuid and not neutron_name: network = app.neutron.create_network({ 'network': { 'name': neutron_network_name, "admin_state_up": True } }) network_id = network['network']['id'] _neutron_net_add_tags(network['network']['id'], container_net_id) app.logger.info( _LI("Created a new network with name {0}" " successfully: {1}").format(neutron_network_name, network)) else: try: if neutron_uuid: networks = _get_networks_by_attrs(id=neutron_uuid) else: networks = _get_networks_by_attrs(name=neutron_name) network_id = networks[0]['id'] except n_exceptions.NeutronClientException as ex: app.logger.error( _LE("Error happened during listing " "Neutron networks: {0}").format(ex)) raise _neutron_net_add_tags(network_id, container_net_id) _neutron_net_add_tag(network_id, const.KURYR_EXISTING_NEUTRON_NET) app.logger.info( _LI("Using existing network {0} successfully").format( neutron_uuid)) cidr = netaddr.IPNetwork(pool_cidr) subnet_network = str(cidr.network) subnet_cidr = '/'.join([subnet_network, str(cidr.prefixlen)]) subnets = _get_subnets_by_attrs(network_id=network_id, cidr=subnet_cidr) if not subnets: new_subnets = [{ 'name': pool_cidr, 'network_id': network_id, 'ip_version': cidr.version, 'cidr': subnet_cidr, 'enable_dhcp': app.enable_dhcp, }] if gateway_ip: new_subnets[0]['gateway_ip'] = gateway_ip app.neutron.create_subnet({'subnets': new_subnets}) 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 network_driver_create_network(): """Creates a new Neutron Network which name is the given NetworkID. This function takes the following JSON data and delegates the actual network creation to the Neutron client. libnetwork's NetworkID is used as the name of Network in Neutron. :: { "NetworkID": string, "IPv4Data" : [{ "AddressSpace": string, "Pool": ipv4-cidr-string, "Gateway" : ipv4-address, "AuxAddresses": { "<identifier1>" : "<ipv4-address1>", "<identifier2>" : "<ipv4-address2>", ... } }, ...], "IPv6Data" : [{ "AddressSpace": string, "Pool": ipv6-cidr-string, "Gateway" : ipv6-address, "AuxAddresses": { "<identifier1>" : "<ipv6-address1>", "<identifier2>" : "<ipv6-address2>", ... } }, ...], "Options": { ... } } See the following link for more details about the spec: https://github.com/docker/libnetwork/blob/master/docs/remote.md#create-network # noqa """ json_data = flask.request.get_json(force=True) app.logger.debug("Received JSON data {0} for" " /NetworkDriver.CreateNetwork".format(json_data)) jsonschema.validate(json_data, schemata.NETWORK_CREATE_SCHEMA) container_net_id = json_data['NetworkID'] neutron_network_name = utils.make_net_name(container_net_id, tags=app.tag) pool_cidr = json_data['IPv4Data'][0]['Pool'] gateway_ip = '' if 'Gateway' in json_data['IPv4Data'][0]: gateway_cidr = json_data['IPv4Data'][0]['Gateway'] gateway_ip = gateway_cidr.split('/')[0] app.logger.debug("gateway_cidr {0}, gateway_ip {1}" .format(gateway_cidr, gateway_ip)) neutron_uuid = None neutron_name = None options = json_data.get('Options') if options: generic_options = options.get(const.NETWORK_GENERIC_OPTIONS) if generic_options: neutron_uuid = generic_options.get(const.NEUTRON_UUID_OPTION) neutron_name = generic_options.get(const.NEUTRON_NAME_OPTION) if not neutron_uuid and not neutron_name: network = app.neutron.create_network( {'network': {'name': neutron_network_name, "admin_state_up": True}}) network_id = network['network']['id'] _neutron_net_add_tags(network['network']['id'], container_net_id, tags=app.tag) app.logger.info(_LI("Created a new network with name {0}" " successfully: {1}") .format(neutron_network_name, network)) else: try: if neutron_uuid: networks = _get_networks_by_attrs(id=neutron_uuid) else: networks = _get_networks_by_attrs(name=neutron_name) network_id = networks[0]['id'] except n_exceptions.NeutronClientException as ex: app.logger.error(_LE("Error happened during listing " "Neutron networks: {0}").format(ex)) raise if app.tag: _neutron_net_add_tags(network_id, container_net_id, tags=app.tag) _neutron_net_add_tag(network_id, const.KURYR_EXISTING_NEUTRON_NET) else: network = app.neutron.update_network( neutron_uuid, {'network': {'name': neutron_network_name}}) app.logger.info(_LI("Updated the network with new name {0}" " successfully: {1}") .format(neutron_network_name, network)) app.logger.info(_LI("Using existing network {0} successfully") .format(neutron_uuid)) cidr = netaddr.IPNetwork(pool_cidr) subnet_network = str(cidr.network) subnet_cidr = '/'.join([subnet_network, str(cidr.prefixlen)]) subnets = _get_subnets_by_attrs( network_id=network_id, cidr=subnet_cidr) if not subnets: new_subnets = [{ 'name': pool_cidr, 'network_id': network_id, 'ip_version': cidr.version, 'cidr': subnet_cidr, 'enable_dhcp': app.enable_dhcp, }] if gateway_ip: new_subnets[0]['gateway_ip'] = gateway_ip app.neutron.create_subnet({'subnets': new_subnets}) return flask.jsonify(const.SCHEMA['SUCCESS'])
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) neutron_network_name = json_data['NetworkID'] try: filtered_networks = _get_networks_by_attrs(name=neutron_network_name) except n_exceptions.NeutronClientException as ex: app.logger.error(_LE("Error happened during listing " "Neutron networks: {0}").format(ex)) raise # We assume Neutron's Network names are not conflicted in Kuryr because # they are Docker IDs, 256 bits hashed values, which are rarely conflicted. # However, if there're multiple networks associated with the single # NetworkID, it raises DuplicatedResourceException and stops processes. # See the following doc for more details about Docker's IDs: # https://github.com/docker/docker/blob/master/docs/terms/container.md#container-ids # noqa if not filtered_networks: app.logger.warn("Network with name {0} cannot be found" .format(neutron_network_name)) 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(constants.SCHEMA['SUCCESS'])
def network_driver_create_network(): """Creates a new Neutron Network which name is the given NetworkID. This function takes the following JSON data and delegates the actual network creation to the Neutron client. libnetwork's NetworkID is used as the name of Network in Neutron. :: { "NetworkID": string, "IPv4Data" : [{ "AddressSpace": string, "Pool": ipv4-cidr-string, "Gateway" : ipv4-address, "AuxAddresses": { "<identifier1>" : "<ipv4-address1>", "<identifier2>" : "<ipv4-address2>", ... } }, ...], "IPv6Data" : [{ "AddressSpace": string, "Pool": ipv6-cidr-string, "Gateway" : ipv6-address, "AuxAddresses": { "<identifier1>" : "<ipv6-address1>", "<identifier2>" : "<ipv6-address2>", ... } }, ...], "Options": { ... } } See the following link for more details about the spec: https://github.com/docker/libnetwork/blob/master/docs/remote.md#create-network # noqa """ json_data = flask.request.get_json(force=True) app.logger.debug("Received JSON data {0} for" " /NetworkDriver.CreateNetwork".format(json_data)) jsonschema.validate(json_data, schemata.NETWORK_CREATE_SCHEMA) neutron_network_name = json_data['NetworkID'] pool_cidr = json_data['IPv4Data'][0]['Pool'] gateway_ip = '' if 'Gateway' in json_data['IPv4Data'][0]: gateway_cidr = json_data['IPv4Data'][0]['Gateway'] gateway_ip = gateway_cidr.split('/')[0] app.logger.debug("gateway_cidr {0}, gateway_ip {1}" .format(gateway_cidr, gateway_ip)) network = app.neutron.create_network( {'network': {'name': neutron_network_name, "admin_state_up": True}}) app.logger.info(_LI("Created a new network with name {0}" " successfully: {1}") .format(neutron_network_name, network)) cidr = netaddr.IPNetwork(pool_cidr) subnet_network = str(cidr.network) subnet_cidr = '/'.join([subnet_network, str(cidr.prefixlen)]) subnets = _get_subnets_by_attrs( network_id=network['network']['id'], cidr=subnet_cidr) if not subnets: new_subnets = [{ 'name': pool_cidr, 'network_id': network['network']['id'], 'ip_version': cidr.version, 'cidr': subnet_cidr, 'enable_dhcp': app.enable_dhcp, }] if gateway_ip: new_subnets[0]['gateway_ip'] = gateway_ip app.neutron.create_subnet({'subnets': new_subnets}) return flask.jsonify(constants.SCHEMA['SUCCESS'])