From 47490acec93a04574b2336920b95f6d20cf7b385 Mon Sep 17 00:00:00 2001 From: vikaschoudhary16 Date: Sat, 2 Jul 2016 15:56:45 +0530 Subject: [PATCH] Refactoring: Drop all the code except common one Related patchset in kuryr-libnetwork: https://review.openstack.org/#/c/337350/ Implements blueprint code-refactoring Change-Id: I91a402a159817462535e77296217a9dd7eb0fd08 --- etc/kuryr.json | 4 - etc/kuryr.spec | 1 - kuryr/__init__.py | 16 - kuryr/controllers.py | 1356 ----------------- kuryr/{common => lib}/__init__.py | 0 kuryr/{ => lib}/_i18n.py | 0 kuryr/{ => lib}/binding.py | 6 +- kuryr/{common => lib}/config.py | 4 +- kuryr/{common => lib}/constants.py | 0 kuryr/{common => lib}/exceptions.py | 0 kuryr/{ => lib}/opts.py | 2 +- kuryr/{ => lib}/utils.py | 99 +- kuryr/{ => lib}/version.py | 0 kuryr/schemata/__init__.py | 35 - kuryr/schemata/commons.py | 249 --- kuryr/schemata/endpoint_create.py | 48 - kuryr/schemata/endpoint_delete.py | 40 - kuryr/schemata/join.py | 52 - kuryr/schemata/leave.py | 24 - kuryr/schemata/network_create.py | 55 - kuryr/schemata/network_delete.py | 36 - kuryr/schemata/release_address.py | 41 - kuryr/schemata/release_pool.py | 36 - kuryr/schemata/request_address.py | 47 - kuryr/schemata/request_pool.py | 58 - kuryr/server.py | 36 - kuryr/tests/contrib/gate_hook.sh | 4 +- kuryr/tests/contrib/post_test_hook.sh | 4 +- kuryr/tests/fullstack/__init__.py | 0 kuryr/tests/fullstack/kuryr_base.py | 31 - kuryr/tests/fullstack/test_container.py | 88 -- kuryr/tests/fullstack/test_network.py | 125 -- kuryr/tests/unit/base.py | 267 +--- kuryr/tests/unit/test_config.py | 21 +- kuryr/tests/unit/test_ipam_pool.py | 94 -- kuryr/tests/unit/test_join.py | 127 -- kuryr/tests/unit/test_kuryr.py | 872 ----------- kuryr/tests/unit/test_kuryr_endpoint.py | 252 --- .../tests/unit/test_kuryr_existing_network.py | 181 --- kuryr/tests/unit/test_kuryr_ipam.py | 485 ------ kuryr/tests/unit/test_kuryr_network.py | 256 ---- kuryr/tests/unit/test_leave.py | 104 -- kuryr/tests/unit/test_utils.py | 35 +- setup.cfg | 6 +- 44 files changed, 23 insertions(+), 5174 deletions(-) delete mode 100644 etc/kuryr.json delete mode 100644 etc/kuryr.spec delete mode 100755 kuryr/controllers.py rename kuryr/{common => lib}/__init__.py (100%) rename kuryr/{ => lib}/_i18n.py (100%) rename kuryr/{ => lib}/binding.py (98%) rename kuryr/{common => lib}/config.py (98%) rename kuryr/{common => lib}/constants.py (100%) rename kuryr/{common => lib}/exceptions.py (100%) rename kuryr/{ => lib}/opts.py (98%) rename kuryr/{ => lib}/utils.py (52%) rename kuryr/{ => lib}/version.py (100%) delete mode 100644 kuryr/schemata/__init__.py delete mode 100755 kuryr/schemata/commons.py delete mode 100644 kuryr/schemata/endpoint_create.py delete mode 100644 kuryr/schemata/endpoint_delete.py delete mode 100644 kuryr/schemata/join.py delete mode 100644 kuryr/schemata/leave.py delete mode 100644 kuryr/schemata/network_create.py delete mode 100644 kuryr/schemata/network_delete.py delete mode 100644 kuryr/schemata/release_address.py delete mode 100644 kuryr/schemata/release_pool.py delete mode 100755 kuryr/schemata/request_address.py delete mode 100644 kuryr/schemata/request_pool.py delete mode 100644 kuryr/server.py delete mode 100644 kuryr/tests/fullstack/__init__.py delete mode 100644 kuryr/tests/fullstack/kuryr_base.py delete mode 100644 kuryr/tests/fullstack/test_container.py delete mode 100644 kuryr/tests/fullstack/test_network.py delete mode 100644 kuryr/tests/unit/test_ipam_pool.py delete mode 100644 kuryr/tests/unit/test_join.py delete mode 100644 kuryr/tests/unit/test_kuryr.py delete mode 100644 kuryr/tests/unit/test_kuryr_endpoint.py delete mode 100644 kuryr/tests/unit/test_kuryr_existing_network.py delete mode 100644 kuryr/tests/unit/test_kuryr_ipam.py delete mode 100644 kuryr/tests/unit/test_kuryr_network.py delete mode 100644 kuryr/tests/unit/test_leave.py diff --git a/etc/kuryr.json b/etc/kuryr.json deleted file mode 100644 index f2fc2f53..00000000 --- a/etc/kuryr.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "Name": "kuryr", - "Addr": "http://127.0.0.1:2377" -} diff --git a/etc/kuryr.spec b/etc/kuryr.spec deleted file mode 100644 index 81fd123b..00000000 --- a/etc/kuryr.spec +++ /dev/null @@ -1 +0,0 @@ -http://127.0.0.1:2377 diff --git a/kuryr/__init__.py b/kuryr/__init__.py index c577b9cb..e69de29b 100644 --- a/kuryr/__init__.py +++ b/kuryr/__init__.py @@ -1,16 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr import utils - - -app = utils.make_json_app(__name__) diff --git a/kuryr/controllers.py b/kuryr/controllers.py deleted file mode 100755 index 1cd59695..00000000 --- a/kuryr/controllers.py +++ /dev/null @@ -1,1356 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os_client_config - -import flask -import jsonschema -import netaddr -import time - -from neutronclient.common import exceptions as n_exceptions -from neutronclient.neutron import client -from oslo_concurrency import processutils -from oslo_config import cfg -from oslo_log import log -from oslo_utils import excutils - -from kuryr import app -from kuryr import binding -from kuryr.common import config -from kuryr.common import constants as const -from kuryr.common import exceptions -from kuryr._i18n import _LE, _LI, _LW -from kuryr import schemata -from kuryr import utils - -LOG = log.getLogger(__name__) - - -MANDATORY_NEUTRON_EXTENSION = "subnet_allocation" -TAG_NEUTRON_EXTENSION = "tag" -SUBNET_POOLS_V4 = [cfg.CONF.neutron_client.default_subnetpool_v4] -SUBNET_POOLS_V6 = [cfg.CONF.neutron_client.default_subnetpool_v6] - - -def _get_cloud_config(cloud='devstack-admin'): - return os_client_config.OpenStackConfig().get_one_cloud(cloud=cloud) - - -def _credentials(cloud='devstack-admin'): - """Retrieves credentials to run functional tests - - Credentials are either read via os-client-config from the environment - or from a config file ('clouds.yaml'). Environment variables override - those from the config file. - - devstack produces a clouds.yaml with two named clouds - one named - 'devstack' which has user privs and one named 'devstack-admin' which - has admin privs. This function will default to getting the devstack-admin - cloud as that is the current expected behavior. - """ - return _get_cloud_config(cloud=cloud).get_auth_args() - - -def _get_neutron_client_from_creds(): - creds = _credentials() - username = creds['username'] - tenant_name = creds['project_name'] - password = creds['password'] - auth_url = creds['auth_url'] + "/v2.0" - neutron_client = client.Client('2.0', username=username, - tenant_name=tenant_name, - password=password, - auth_url=auth_url) - return neutron_client - - -def get_neutron_client(): - """Creates the Neutron client for communicating with Neutron.""" - try: - # First try to retrieve neutron client from a working OS deployment - # This is used for gate testing. - # Since this always use admin credentials, next patch will introduce - # a config parameter that disable this for production environments - neutron_client = _get_neutron_client_from_creds() - return neutron_client - except Exception: - pass - cfg.CONF.import_group('neutron_client', 'kuryr.common.config') - cfg.CONF.import_group('keystone_client', 'kuryr.common.config') - - keystone_conf = cfg.CONF.keystone_client - username = keystone_conf.admin_user - tenant_name = keystone_conf.admin_tenant_name - password = keystone_conf.admin_password - auth_token = keystone_conf.admin_token - auth_uri = keystone_conf.auth_uri.rstrip('/') - ca_cert = keystone_conf.auth_ca_cert - insecure = keystone_conf.auth_insecure - - neutron_uri = cfg.CONF.neutron_client.neutron_uri - if username and password: - # Authenticate with password crentials - neutron_client = utils.get_neutron_client( - url=neutron_uri, username=username, tenant_name=tenant_name, - password=password, auth_url=auth_uri, - ca_cert=ca_cert, insecure=insecure) - else: - neutron_client = utils.get_neutron_client_simple( - url=neutron_uri, auth_url=auth_uri, token=auth_token) - return neutron_client - - -def neutron_client(): - if not hasattr(app, 'neutron'): - app.neutron = get_neutron_client() - app.enable_dhcp = cfg.CONF.neutron_client.enable_dhcp - app.vif_plug_is_fatal = cfg.CONF.neutron_client.vif_plugging_is_fatal - app.vif_plug_timeout = cfg.CONF.neutron_client.vif_plugging_timeout - app.neutron.format = 'json' - - -def check_for_neutron_ext_support(): - """Validates for mandatory extension support availability in neutron.""" - try: - app.neutron.show_extension(MANDATORY_NEUTRON_EXTENSION) - except n_exceptions.NeutronClientException as e: - if e.status_code == n_exceptions.NotFound.status_code: - raise exceptions.MandatoryApiMissing( - "Neutron extension with alias '{0}' not found" - .format(MANDATORY_NEUTRON_EXTENSION)) - - -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.warning(_LW("Neutron tags not supported. " - "Continue without using them.")) - - -def _cache_default_subnetpool_ids(app): - """Caches IDs of the default subnetpools as app.DEFAULT_POOL_IDS.""" - if not hasattr(app, 'DEFAULT_POOL_IDS'): - default_subnetpool_id_set = set() - try: - subnetpool_names = SUBNET_POOLS_V4 + SUBNET_POOLS_V6 - for subnetpool_name in subnetpool_names: - subnetpools = app.neutron.list_subnetpools( - name=subnetpool_name) - for subnetpool in subnetpools['subnetpools']: - default_subnetpool_id_set.add(subnetpool['id']) - except n_exceptions.NeutronClientException as ex: - app.logger.error(_LE("Error happened during retrieving the default" - " subnet pools: %s"), ex) - app.DEFAULT_POOL_IDS = frozenset(default_subnetpool_id_set) - - -def _get_networks_by_attrs(**attrs): - networks = app.neutron.list_networks(**attrs) - if len(networks.get('networks', [])) > 1: - raise exceptions.DuplicatedResourceException( - "Multiple Neutron networks exist for the params {0}" - .format(', '.join(['{0}={1}'.format(k, v) - for k, v in attrs.items()]))) - return networks['networks'] - - -def _get_subnets_by_attrs(**attrs): - subnets = app.neutron.list_subnets(**attrs) - return subnets['subnets'] - - -def _get_ports_by_attrs(**attrs): - ports = app.neutron.list_ports(**attrs) - if len(ports.get('ports', [])) > 1: - raise exceptions.DuplicatedResourceException( - "Multiple Neutron ports exist for the params {0} " - .format(', '.join(['{0}={1}'.format(k, v) - for k, v in attrs.items()]))) - return ports['ports'] - - -def _get_subnetpools_by_attrs(**attrs): - subnetpools = app.neutron.list_subnetpools(**attrs) - if len(subnetpools.get('subnetpools', [])) > 1: - raise exceptions.DuplicatedResourceException( - "Multiple Neutron subnetspool exist for the params {0} " - .format(', '.join(['{0}={1}'.format(k, v) - for k, v in attrs.items()]))) - return subnetpools['subnetpools'] - - -def _get_subnet_cidr_using_cidr(cidr): - subnet_network = str(cidr.network) - subnet_cidr = '/'.join([subnet_network, - str(cidr.prefixlen)]) - return subnet_cidr - - -def _get_subnets_by_interface_cidr(neutron_network_id, - interface_cidr): - cidr = netaddr.IPNetwork(interface_cidr) - subnet_network = cidr.network - subnet_cidr = '/'.join([str(subnet_network), - str(cidr.prefixlen)]) - subnets = _get_subnets_by_attrs( - network_id=neutron_network_id, cidr=subnet_cidr) - if len(subnets) > 2: - raise exceptions.DuplicatedResourceException( - "Multiple Neutron subnets exist for the network_id={0}" - "and cidr={1}" - .format(neutron_network_id, cidr)) - return subnets - - -def _process_interface_address(port_dict, subnets_dict_by_id, - response_interface): - assigned_address = port_dict['ip_address'] - subnet_id = port_dict['subnet_id'] - subnet = subnets_dict_by_id[subnet_id] - cidr = netaddr.IPNetwork(subnet['cidr']) - assigned_address += '/' + str(cidr.prefixlen) - if cidr.version == 4: - response_interface['Address'] = assigned_address - else: - response_interface['AddressIPv6'] = assigned_address - - -def _create_port(endpoint_id, neutron_network_id, interface_mac, fixed_ips): - port = { - 'name': utils.get_neutron_port_name(endpoint_id), - 'admin_state_up': True, - 'network_id': neutron_network_id, - 'device_owner': const.DEVICE_OWNER, - 'device_id': endpoint_id, - 'binding:host_id': utils.get_hostname(), - 'fixed_ips': fixed_ips - } - if interface_mac: - port['mac_address'] = interface_mac - try: - rcvd_port = app.neutron.create_port({'port': port}) - except n_exceptions.NeutronClientException as ex: - app.logger.error(_LE("Error happened during creating a" - " Neutron port: %s"), ex) - raise - return rcvd_port['port'] - - -def _update_port(port, endpoint_id): - port['name'] = utils.get_neutron_port_name(endpoint_id) - try: - response_port = app.neutron.update_port( - port['id'], - {'port': { - 'name': port['name'], - 'device_owner': const.DEVICE_OWNER, - 'device_id': endpoint_id}}) - except n_exceptions.NeutronClientException as ex: - app.logger.error(_LE("Error happened during creating a " - "Neutron port: %s"), ex) - raise - return response_port['port'] - - -def _get_fixed_ips_by_interface_cidr(subnets, interface_cidrv4, - interface_cidrv6, fixed_ips): - for subnet in subnets: - fixed_ip = [('subnet_id=%s' % subnet['id'])] - if interface_cidrv4 or interface_cidrv6: - if subnet['ip_version'] == 4 and interface_cidrv4: - cidr = netaddr.IPNetwork(interface_cidrv4) - elif subnet['ip_version'] == 6 and interface_cidrv6: - cidr = netaddr.IPNetwork(interface_cidrv6) - subnet_cidr = '/'.join([str(cidr.network), - str(cidr.prefixlen)]) - if subnet['cidr'] != subnet_cidr: - continue - fixed_ip.append('ip_address=%s' % str(cidr.ip)) - fixed_ips.extend(fixed_ip) - - -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 _neutron_net_add_tag(netid, tag): - app.neutron.add_tag('networks', netid, tag) - - -def _neutron_net_add_tags(netid, tag, tags=True): - if tags: - tags = utils.create_net_tags(tag) - for tag in tags: - _neutron_net_add_tag(netid, tag) - - -def _neutron_net_remove_tag(netid, tag): - app.neutron.remove_tag('networks', netid, tag) - - -def _neutron_net_remove_tags(netid, tag): - tags = utils.create_net_tags(tag) - for tag in tags: - _neutron_net_remove_tag(netid, tag) - - -def _make_net_identifier(network_id, tags=True): - if tags: - return utils.make_net_tags(network_id) - return network_id - - -def _get_networks_by_identifier(identifier): - if app.tag: - return _get_networks_by_attrs(tags=identifier) - return _get_networks_by_attrs(name=identifier) - - -def _port_active(neutron_port_id, vif_plug_timeout): - port_active = False - tries = 0 - while True: - try: - port = app.neutron.show_port(neutron_port_id) - except n_exceptions.NeutronClientException as ex: - app.logger.error(_LE('Could not get the port %s to check ' - 'its status'), ex) - else: - if port['port']['status'] == const.PORT_STATUS_ACTIVE: - port_active = True - if port_active or (tries >= vif_plug_timeout): - break - LOG.debug('Waiting for port %s to become ACTIVE', neutron_port_id) - tries += 1 - time.sleep(1) - - return port_active - - -@app.route('/Plugin.Activate', methods=['POST']) -def plugin_activate(): - """Returns the list of the implemented drivers. - - This function returns the list of the implemented drivers defaults to - ``[NetworkDriver, IpamDriver]`` in the handshake of the remote driver, - which happens right before the first request against Kuryr. - - See the following link for more details about the spec: - - https://github.com/docker/libnetwork/blob/master/docs/remote.md#handshake # noqa - """ - return flask.jsonify(const.SCHEMA['PLUGIN_ACTIVATE']) - - -@app.route('/NetworkDriver.GetCapabilities', methods=['POST']) -def plugin_scope(): - """Returns the capability as the remote network driver. - - This function returns the capability of the remote network driver, which is - ``global`` or ``local`` and defaults to ``local``. With ``global`` - capability, the network information is shared among multipe Docker daemons - if the distributed store is appropriately configured. - - See the following link for more details about the spec: - - https://github.com/docker/libnetwork/blob/master/docs/remote.md#set-capability # noqa - """ - capabilities = {'Scope': cfg.CONF.capability_scope} - return flask.jsonify(capabilities) - - -@app.route('/NetworkDriver.DiscoverNew', methods=['POST']) -def network_driver_discover_new(): - """The callback function for the DiscoverNew notification. - - The DiscoverNew notification includes the type of the - resource that has been newly discovered and possibly other - information associated with the resource. - - See the following link for more details about the spec: - - https://github.com/docker/libnetwork/blob/master/docs/remote.md#discovernew-notification # noqa - """ - return flask.jsonify(const.SCHEMA['SUCCESS']) - - -@app.route('/NetworkDriver.DiscoverDelete', methods=['POST']) -def network_driver_discover_delete(): - """The callback function for the DiscoverDelete notification. - - The DiscoverDelete notification includes the type of the - resource that has been deleted and possibly other - information associated with the resource. - - See the following link for more details about the spec: - - https://github.com/docker/libnetwork/blob/master/docs/remote.md#discoverdelete-notification # noqa - """ - return flask.jsonify(const.SCHEMA['SUCCESS']) - - -@app.route('/NetworkDriver.CreateNetwork', methods=['POST']) -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": { - "" : "", - "" : "", - ... - } - }, ...], - "IPv6Data" : [{ - "AddressSpace": string, - "Pool": ipv6-cidr-string, - "Gateway" : ipv6-address, - "AuxAddresses": { - "" : "", - "" : "", - ... - } - }, ...], - "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 %s for" - " /NetworkDriver.CreateNetwork", 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 %(gateway_cidr)s, " - "gateway_ip %(gateway_ip)s", - {'gateway_cidr': gateway_cidr, 'gateway_ip': gateway_ip}) - - neutron_uuid = None - neutron_name = None - pool_name = '' - pool_id = '' - 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) - pool_name = generic_options.get(const.NEUTRON_POOL_NAME_OPTION) - - if pool_name: - pools = _get_subnetpools_by_attrs(name=pool_name) - if pools: - pool_id = pools[0]['id'] - else: - raise exceptions.KuryrException( - ("Specified pool name({0}) does not " - "exist.").format(pool_name)) - - 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 " - "%(neutron_network_name)s successfully: %(network)s"), - {'neutron_network_name': neutron_network_name, 'network': network}) - else: - try: - if neutron_uuid: - networks = _get_networks_by_attrs(id=neutron_uuid) - specified_network = neutron_uuid - else: - networks = _get_networks_by_attrs(name=neutron_name) - specified_network = neutron_name - if not networks: - raise exceptions.KuryrException( - ("Specified network id/name({0}) does not " - "exist.").format(specified_network)) - network_id = networks[0]['id'] - except n_exceptions.NeutronClientException as ex: - app.logger.error(_LE("Error happened during listing " - "Neutron networks: %s"), 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 " - "%(neutron_network_name)s successfully: %(network)s"), - {'neutron_network_name': neutron_network_name, - 'network': network}) - app.logger.info(_LI("Using existing network %s " - "successfully"), 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 len(subnets) > 1: - raise exceptions.DuplicatedResourceException( - "Multiple Neutron subnets exist for the network_id={0}" - "and cidr={1}".format(network_id, 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 pool_id: - new_subnets[0]['subnetpool_id'] = pool_id - if gateway_ip: - new_subnets[0]['gateway_ip'] = gateway_ip - - app.neutron.create_subnet({'subnets': new_subnets}) - - return flask.jsonify(const.SCHEMA['SUCCESS']) - - -@app.route('/NetworkDriver.DeleteNetwork', methods=['POST']) -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 %s for" - " /NetworkDriver.DeleteNetwork", 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: %s"), ex) - raise - - if existing_networks: - app.logger.warning(_LW("Network is a pre existing Neutron " - "network, not deleting in Neutron. " - "removing tags: %s"), - 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: %s"), ex) - raise - - if not filtered_networks: - app.logger.warning(_LW("Network with identifier %s cannot be " - "found"), - neutron_network_identifier) - else: - neutron_network_id = filtered_networks[0]['id'] - filtered_subnets = _get_subnets_by_attrs( - network_id=neutron_network_id) - if len(filtered_subnets) > 2: # subnets for IPv4 and/or IPv6 - raise exceptions.DuplicatedResourceException( - "Multiple Neutron subnets exist for the network_id={0} " - .format(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, %s, is in use. Network cant be deleted."), - subnet['id']) - raise - except n_exceptions.NeutronClientException as ex: - app.logger.error(_LE("Error happened during deleting a " - "Neutron subnets: %s"), 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: %s"), ex) - raise - app.logger.info(_LI("Deleted the network with ID %s " - "successfully"), neutron_network_id) - return flask.jsonify(const.SCHEMA['SUCCESS']) - - -@app.route('/NetworkDriver.CreateEndpoint', methods=['POST']) -def network_driver_create_endpoint(): - """Creates new Neutron Subnets and a Port with the given EndpointID. - - This function takes the following JSON data and delegates the actual - endpoint creation to the Neutron client mapping it into Subnet and Port. :: - - { - "NetworkID": string, - "EndpointID": string, - "Options": { - ... - }, - "Interface": { - "Address": string, - "AddressIPv6": string, - "MacAddress": string - } - } - - Then the following JSON response is returned. :: - - { - "Interface": { - "Address": string, - "AddressIPv6": string, - "MacAddress": string - } - } - - See the following link for more details about the spec: - - https://github.com/docker/libnetwork/blob/master/docs/remote.md#create-endpoint # noqa - """ - json_data = flask.request.get_json(force=True) - app.logger.debug("Received JSON data %s for " - "/NetworkDriver.CreateEndpoint", json_data) - jsonschema.validate(json_data, schemata.ENDPOINT_CREATE_SCHEMA) - - neutron_network_identifier = _make_net_identifier(json_data['NetworkID'], - tags=app.tag) - endpoint_id = json_data['EndpointID'] - filtered_networks = _get_networks_by_identifier(neutron_network_identifier) - - if not filtered_networks: - return flask.jsonify({ - 'Err': "Neutron net associated with identifier {0} doesn't exist." - .format(neutron_network_identifier) - }) - else: - neutron_network_id = filtered_networks[0]['id'] - interface = json_data['Interface'] or {} # Workaround for null - interface_cidrv4 = interface.get('Address', '') - interface_cidrv6 = interface.get('AddressIPv6', '') - interface_mac = interface.get('MacAddress', '') - if not interface_cidrv4 and not interface_cidrv6: - return flask.jsonify({ - 'Err': "Interface address v4 or v6 not provided." - }) - response_interface = _create_or_update_port( - neutron_network_id, endpoint_id, interface_cidrv4, - interface_cidrv6, interface_mac) - - return flask.jsonify({'Interface': response_interface}) - - -@app.route('/NetworkDriver.EndpointOperInfo', methods=['POST']) -def network_driver_endpoint_operational_info(): - return flask.jsonify(const.SCHEMA['ENDPOINT_OPER_INFO']) - - -@app.route('/NetworkDriver.DeleteEndpoint', methods=['POST']) -def network_driver_delete_endpoint(): - """Deletes Neutron Subnets and a Port with the given EndpointID. - - This function takes the following JSON data and delegates the actual - endpoint deletion to the Neutron client mapping it into Subnet and Port. :: - - { - "NetworkID": string, - "EndpointID": string - } - - See the following link for more details about the spec: - - https://github.com/docker/libnetwork/blob/master/docs/remote.md#delete-endpoint # noqa - """ - json_data = flask.request.get_json(force=True) - app.logger.debug("Received JSON data %s for" - " /NetworkDriver.DeleteEndpoint", json_data) - jsonschema.validate(json_data, schemata.ENDPOINT_DELETE_SCHEMA) - - return flask.jsonify(const.SCHEMA['SUCCESS']) - - -@app.route('/NetworkDriver.Join', methods=['POST']) -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 %s for /NetworkDriver.Join", - json_data) - jsonschema.validate(json_data, schemata.JOIN_SCHEMA) - - neutron_network_identifier = _make_net_identifier(json_data['NetworkID'], - tags=app.tag) - endpoint_id = json_data['EndpointID'] - filtered_networks = _get_networks_by_identifier(neutron_network_identifier) - - if not filtered_networks: - return flask.jsonify({ - 'Err': "Neutron net associated with identifier {0} doesn't exit." - .format(neutron_network_identifier) - }) - 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) - if len(all_subnets) > 2: # subnets for IPv4 and/or IPv6 - raise exceptions.DuplicatedResourceException( - "Multiple Neutron subnets exist for the network_id={0} " - .format(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: %s.'), ex) - except processutils.ProcessExecutionError: - with excutils.save_and_reraise_exception(): - app.logger.error(_LE( - 'Could not bind the Neutron port to the veth endpoint.')) - - if app.vif_plug_is_fatal: - port_active = _port_active(neutron_port['id'], - app.vif_plug_timeout) - if not port_active: - raise exceptions.InactiveResourceException( - "Neutron port {0} did not become active on time." - .format(neutron_port_name)) - - 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.ROUTE_TYPE['NEXTHOP'] - static_route['NextHop'] = host_route['nexthop'] - else: - static_route['RouteType'] = const.ROUTE_TYPE['CONNECTED'] - join_response['StaticRoutes'].append(static_route) - - return flask.jsonify(join_response) - - -@app.route('/NetworkDriver.Leave', methods=['POST']) -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 %s for" - " /NetworkDriver.DeleteEndpoint", json_data) - jsonschema.validate(json_data, schemata.LEAVE_SCHEMA) - - neutron_network_identifier = _make_net_identifier(json_data['NetworkID'], - tags=app.tag) - endpoint_id = json_data['EndpointID'] - filtered_networks = _get_networks_by_identifier(neutron_network_identifier) - - if not filtered_networks: - return flask.jsonify({ - 'Err': "Neutron net associated with identifier {0} doesn't exit." - .format(neutron_network_identifier) - }) - 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(_LE( - 'Could not unbind the Neutron port from the veth ' - 'endpoint.')) - except exceptions.VethDeletionFailure: - with excutils.save_and_reraise_exception(): - app.logger.error(_LE('Cleaning the veth pair up was failed.')) - - return flask.jsonify(const.SCHEMA['SUCCESS']) - - -@app.route('/NetworkDriver.ProgramExternalConnectivity', methods=['POST']) -def network_driver_program_external_connectivity(): - """Peovides external connectivity fora given container. - - Performs the necessary programming to allow the external connectivity - dictated by the specified options - - See the following link for more details about the spec: - https://github.com/docker/libnetwork/blob/master/driverapi/driverapi.go - """ - json_data = flask.request.get_json(force=True) - app.logger.debug("Received JSON data %s for" - " /NetworkDriver.ProgramExternalConnectivity", json_data) - # TODO(namix): Add support for exposed ports - # TODO(namix): Add support for published ports - return flask.jsonify(const.SCHEMA['SUCCESS']) - - -@app.route('/NetworkDriver.RevokeExternalConnectivity', methods=['POST']) -def network_driver_revoke_external_connectivity(): - """Removes external connectivity for a given container. - - Performs the necessary programming to remove the external connectivity - of a container - - See the following link for more details about the spec: - https://github.com/docker/libnetwork/blob/master/driverapi/driverapi.go - """ - json_data = flask.request.get_json(force=True) - app.logger.debug("Received JSON data %s for" - " /NetworkDriver.RevokeExternalConnectivity", json_data) - # TODO(namix): Add support for removal of exposed ports - # TODO(namix): Add support for removal of published ports - return flask.jsonify(const.SCHEMA['SUCCESS']) - - -@app.route('/IpamDriver.GetCapabilities', methods=['POST']) -def ipam_get_capabilities(): - """Provides the IPAM driver capabilities. - - This function is called during the registration of the IPAM driver. - - See the following link for more details about the spec: - https://github.com/docker/libnetwork/blob/master/docs/ipam.md#getcapabilities # noqa - """ - app.logger.debug("Received /IpamDriver.GetCapabilities") - capabilities = {'RequiresMACAddress': False} - return flask.jsonify(capabilities) - - -@app.route('/IpamDriver.GetDefaultAddressSpaces', methods=['POST']) -def ipam_get_default_address_spaces(): - """Provides the default address spaces for the IPAM. - - This function is called after the registration of the IPAM driver and - the plugin set the returned values as the default address spaces for the - IPAM. The address spaces can be configured in the config file. - - See the following link for more details about the spec: - - https://github.com/docker/libnetwork/blob/master/docs/ipam.md#getdefaultaddressspaces # noqa - """ - app.logger.debug("Received /IpamDriver.GetDefaultAddressSpaces") - address_spaces = { - 'LocalDefaultAddressSpace': cfg.CONF.local_default_address_space, - 'GlobalDefaultAddressSpace': cfg.CONF.global_default_address_space} - return flask.jsonify(address_spaces) - - -@app.route('/IpamDriver.RequestPool', methods=['POST']) -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 %s for /IpamDriver.RequestPool", - 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 = '' - pool_name = '' - pools = [] - options = json_data.get('Options') - if options: - pool_name = options.get(const.NEUTRON_POOL_NAME_OPTION) - 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) - if not pool_name: - pool_name = utils.get_neutron_subnetpool_name(subnet_cidr) - pools = _get_subnetpools_by_attrs(name=pool_name) - if len(pools): - raise exceptions.KuryrException( - "Another pool with same cidr exist. ipam and network" - " options not used to pass pool name") - - 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) - - -@app.route('/IpamDriver.RequestAddress', methods=['POST']) -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 %s for /IpamDriver.RequestAddress", - json_data) - jsonschema.validate(json_data, schemata.REQUEST_ADDRESS_SCHEMA) - pool_id = json_data['PoolID'] - req_address = json_data['Address'] - is_gateway = False - allocated_address = '' - subnet_cidr = '' - subnet = {} - 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_by_cidr = _get_subnets_by_attrs(cidr=subnet_cidr) - # Check if the port is gateway - options = json_data.get('Options') - if options: - request_address_type = options.get(const.REQUEST_ADDRESS_TYPE) - if request_address_type == const.NETWORK_GATEWAY_OPTIONS: - is_gateway = True - if subnets_by_cidr: - if len(subnets_by_cidr) > 1: - for tmp_subnet in subnets_by_cidr: - if tmp_subnet.get('subnetpool_id', '') == pool_id: - subnet = tmp_subnet - if not any(subnet) and not is_gateway: - raise exceptions.KuryrException( - ("Subnet with cidr({0}) and pool {1}, does not " - "exist.").format(cidr, pool_id)) - else: - subnet = subnets_by_cidr[0] - - if is_gateway: - if any(subnet): - # check if request gateway ip same with existed gateway ip - existed_gateway_ip = subnet.get('gateway_ip', '') - if req_address == existed_gateway_ip: - allocated_address = '/'.join( - [req_address, pool_prefix_len]) - else: - raise exceptions.GatewayConflictFailure( - "Requested gateway {0} does not match with " - "gateway {1} in existed " - "network.".format(req_address, existed_gateway_ip)) - else: - allocated_address = '/'.join([req_address, pool_prefix_len]) - else: - # 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'] - app.logger.debug("created port %s", created_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 happened during ip allocation on " - "Neutron side: %s"), ex) - raise - - return flask.jsonify({'Address': allocated_address}) - - -@app.route('/IpamDriver.ReleasePool', methods=['POST']) -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 %s for /IpamDriver.ReleasePool", - 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 %s is still in use." - " It can't be deleted for now."), pool_id) - except n_exceptions.NeutronClientException as ex: - app.logger.error(_LE("Error happened during deleting a " - "Neutron subnetpool: %s"), ex) - raise - - return flask.jsonify(const.SCHEMA['SUCCESS']) - - -@app.route('/IpamDriver.ReleaseAddress', methods=['POST']) -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 %s for /IpamDriver.ReleaseAddress", - 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): - app.logger.info(_LI("Subnet already deleted.")) - return flask.jsonify(const.SCHEMA['SUCCESS']) - if len(subnets) > 1: - subnet = {} - for tmp_subnet in subnets: - if tmp_subnet['subnetpool_id'] == pool_id: - subnet = tmp_subnet - if not subnet: - raise exceptions.KuryrException( - ("Subnet with cidr({0}) and pool {1}, does not " - "exist.").format(cidr, pool_id)) - else: - 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 happened while fetching " - "and deleting port, %s"), ex) - raise - - return flask.jsonify(const.SCHEMA['SUCCESS']) diff --git a/kuryr/common/__init__.py b/kuryr/lib/__init__.py similarity index 100% rename from kuryr/common/__init__.py rename to kuryr/lib/__init__.py diff --git a/kuryr/_i18n.py b/kuryr/lib/_i18n.py similarity index 100% rename from kuryr/_i18n.py rename to kuryr/lib/_i18n.py diff --git a/kuryr/binding.py b/kuryr/lib/binding.py similarity index 98% rename from kuryr/binding.py rename to kuryr/lib/binding.py index 820e1637..64ed7023 100644 --- a/kuryr/binding.py +++ b/kuryr/lib/binding.py @@ -17,9 +17,9 @@ from oslo_concurrency import processutils from oslo_utils import excutils import pyroute2 -from kuryr.common import config -from kuryr.common import exceptions -from kuryr import utils +from kuryr.lib import config +from kuryr.lib import exceptions +from kuryr.lib import utils BINDING_SUBCOMMAND = 'bind' diff --git a/kuryr/common/config.py b/kuryr/lib/config.py similarity index 98% rename from kuryr/common/config.py rename to kuryr/lib/config.py index b7ab51db..49d89bb2 100644 --- a/kuryr/common/config.py +++ b/kuryr/lib/config.py @@ -19,8 +19,8 @@ import os from oslo_config import cfg from oslo_log import log -from kuryr._i18n import _ -from kuryr import version +from kuryr.lib._i18n import _ +from kuryr.lib import version core_opts = [ diff --git a/kuryr/common/constants.py b/kuryr/lib/constants.py similarity index 100% rename from kuryr/common/constants.py rename to kuryr/lib/constants.py diff --git a/kuryr/common/exceptions.py b/kuryr/lib/exceptions.py similarity index 100% rename from kuryr/common/exceptions.py rename to kuryr/lib/exceptions.py diff --git a/kuryr/opts.py b/kuryr/lib/opts.py similarity index 98% rename from kuryr/opts.py rename to kuryr/lib/opts.py index e76a811c..d0fa8690 100644 --- a/kuryr/opts.py +++ b/kuryr/lib/opts.py @@ -19,7 +19,7 @@ import itertools from oslo_log import _options -from kuryr.common import config +from kuryr.lib import config _core_opts_with_logging = config.core_opts diff --git a/kuryr/utils.py b/kuryr/lib/utils.py similarity index 52% rename from kuryr/utils.py rename to kuryr/lib/utils.py index 0eeed724..f3ebe5ca 100644 --- a/kuryr/utils.py +++ b/kuryr/lib/utils.py @@ -11,25 +11,14 @@ # under the License. import hashlib -import os import random import socket -import sys -import traceback -import flask -import jsonschema - -from neutronclient.common import exceptions as n_exceptions from neutronclient.neutron import client from neutronclient.v2_0 import client as client_v2 -from oslo_concurrency import processutils from oslo_config import cfg -from werkzeug import exceptions as w_exceptions -from kuryr._i18n import _LE -from kuryr.common import constants as const -from kuryr.common import exceptions +from kuryr.lib import constants as const DOCKER_NETNS_BASE = '/var/run/docker/netns' PORT_POSTFIX = 'port' @@ -50,64 +39,9 @@ def get_neutron_client(url, username, tenant_name, password, ca_cert=ca_cert, insecure=insecure) -# Return all errors as JSON. From http://flask.pocoo.org/snippets/83/ -def make_json_app(import_name, **kwargs): - """Creates a JSON-oriented Flask app. - - All error responses that you don't specifically manage yourself will have - application/json content type, and will contain JSON that follows the - libnetwork remote driver protocol. - - - { "Err": "405: Method Not Allowed" } - - - See: - - https://github.com/docker/libnetwork/blob/3c8e06bc0580a2a1b2440fe0792fbfcd43a9feca/docs/remote.md#errors # noqa - """ - app = flask.Flask(import_name, **kwargs) - - @app.errorhandler(exceptions.KuryrException) - @app.errorhandler(n_exceptions.NeutronClientException) - @app.errorhandler(jsonschema.ValidationError) - @app.errorhandler(processutils.ProcessExecutionError) - def make_json_error(ex): - app.logger.error(_LE("Unexpected error happened: %s"), ex) - traceback.print_exc(file=sys.stderr) - response = flask.jsonify({"Err": str(ex)}) - response.status_code = w_exceptions.InternalServerError.code - if isinstance(ex, w_exceptions.HTTPException): - response.status_code = ex.code - elif isinstance(ex, n_exceptions.NeutronClientException): - response.status_code = ex.status_code - elif isinstance(ex, jsonschema.ValidationError): - response.status_code = w_exceptions.BadRequest.code - content_type = 'application/vnd.docker.plugins.v1+json; charset=utf-8' - response.headers['Content-Type'] = content_type - return response - - for code in w_exceptions.default_exceptions: - app.register_error_handler(code, make_json_error) - - return app - - -def get_sandbox_key(container_id): - """Returns a sandbox key constructed with the given container ID. - - :param container_id: the ID of the Docker container as string - :returns: the constructed sandbox key as string - """ - return os.path.join(DOCKER_NETNS_BASE, container_id[:12]) - - -def get_neutron_port_name(docker_endpoint_id): - """Returns a Neutron port name. - - :param docker_endpoint_id: the EndpointID - :returns: the Neutron port name formatted appropriately - """ - return '-'.join([docker_endpoint_id, PORT_POSTFIX]) +def get_hostname(): + """Returns the host name.""" + return socket.gethostname() def get_veth_pair_names(port_id): @@ -118,11 +52,6 @@ def get_veth_pair_names(port_id): return ifname, peer_name -def get_hostname(): - """Returns the host name.""" - return socket.gethostname() - - def get_neutron_subnetpool_name(subnet_cidr): """Returns a Neutron subnetpool name. @@ -162,26 +91,6 @@ def get_hash(bit_size=256): return hashlib.sha256(getrandbits(bit_size=bit_size)).hexdigest() -def create_net_tags(tag): - tags = [] - tags.append(const.NEUTRON_ID_LH_OPTION + ':' + tag[:32]) - if len(tag) > 32: - tags.append(const.NEUTRON_ID_UH_OPTION + ':' + tag[32:64]) - - return tags - - -def make_net_tags(tag): - tags = create_net_tags(tag) - return ','.join(map(str, tags)) - - -def make_net_name(netid, tags=True): - if tags: - return const.NET_NAME_PREFIX + netid[:8] - return netid - - def string_mappings(mapping_list): """Make a string out of the mapping list""" details = '' diff --git a/kuryr/version.py b/kuryr/lib/version.py similarity index 100% rename from kuryr/version.py rename to kuryr/lib/version.py diff --git a/kuryr/schemata/__init__.py b/kuryr/schemata/__init__.py deleted file mode 100644 index ace6b999..00000000 --- a/kuryr/schemata/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr.schemata import endpoint_create -from kuryr.schemata import endpoint_delete -from kuryr.schemata import join -from kuryr.schemata import leave -from kuryr.schemata import network_create -from kuryr.schemata import network_delete -from kuryr.schemata import release_address -from kuryr.schemata import release_pool -from kuryr.schemata import request_address -from kuryr.schemata import request_pool - - -# Aliases for schemata in each module -ENDPOINT_CREATE_SCHEMA = endpoint_create.ENDPOINT_CREATE_SCHEMA -ENDPOINT_DELETE_SCHEMA = endpoint_delete.ENDPOINT_DELETE_SCHEMA -JOIN_SCHEMA = join.JOIN_SCHEMA -LEAVE_SCHEMA = leave.LEAVE_SCHEMA -NETWORK_CREATE_SCHEMA = network_create.NETWORK_CREATE_SCHEMA -NETWORK_DELETE_SCHEMA = network_delete.NETWORK_DELETE_SCHEMA -RELEASE_ADDRESS_SCHEMA = release_address.RELEASE_ADDRESS_SCHEMA -RELEASE_POOL_SCHEMA = release_pool.RELEASE_POOL_SCHEMA -REQUEST_ADDRESS_SCHEMA = request_address.REQUEST_ADDRESS_SCHEMA -REQUEST_POOL_SCHEMA = request_pool.REQUEST_POOL_SCHEMA diff --git a/kuryr/schemata/commons.py b/kuryr/schemata/commons.py deleted file mode 100755 index 33429e20..00000000 --- a/kuryr/schemata/commons.py +++ /dev/null @@ -1,249 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -EPSILON_PATTERN = '^$' -IPV4_PATTERN_BASE = (u'((25[0-5]|2[0-4][0-9]|1?[0-9]?[0-9])\\.){3}' - u'(25[0-5]|2[0-4][0-9]|1?[0-9]?[0-9])') -IPV4_PATTERN = EPSILON_PATTERN + u'|^' + IPV4_PATTERN_BASE + u'$' -CIDRV4_PATTERN = EPSILON_PATTERN + '|^(' + IPV4_PATTERN_BASE + \ - u'(/(1[0-2][0-8]|[1-9]?[0-9]))' + u')$' - -IPV6_PATTERN_BASE = (u'(' - u'([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|' - u'([0-9a-fA-F]{1,4}:){1,7}:|' - u'([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|' - u'([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|' - u'([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|' - u'([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|' - u'([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|' - u'[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|' - u':((:[0-9a-fA-F]{1,4}){1,7}|:)|' - u'fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|' - u'::(ffff(:0{1,4}){0,1}:){0,1}' - u'((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}' - u'(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|' - u'([0-9a-fA-F]{1,4}:){1,4}:' - u'((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}' - u'(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))') -IPV6_PATTERN = EPSILON_PATTERN + u'|^' + IPV6_PATTERN_BASE + u'$' -CIDRV6_PATTERN = EPSILON_PATTERN + u'|^(' + IPV6_PATTERN_BASE + \ - u'(/(1[0-2][0-8]|[1-9]?[0-9]))' + u')$' -IPV4_OR_IPV6_PATTERN = IPV4_PATTERN + u'|^' + IPV6_PATTERN_BASE + u'$' -UUID_BASE = u'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' -UUID_PATTERN = EPSILON_PATTERN + u'|' + UUID_BASE - -COMMONS = { - u'description': u'Common data schemata shared among other schemata.', - u'links': [], - u'title': u'Kuryr Common Data Schema Definitions', - u'properties': { - u'options': {u'$ref': u'/schemata/commons#/definitions/options'}, - u'mac': {u'$ref': u'/schemata/commons#/definitions/mac'}, - u'cidrv6': {u'$ref': u'/schemata/commons#/definitions/cidrv6'}, - u'interface': {u'$ref': u'/schemata/commons#/definitions/interface'}, - u'cidr': {u'$ref': u'/schemata/commons#/definitions/cidr'}, - u'id': {u'$ref': u'/schemata/commons#/definitions/id'}, - u'uuid': {u'$ref': u'/schemata/commons#/definitions/uuid'}, - u'ipv4': {u'$ref': u'/schemata/commons#/definitions/ipv4'}, - u'ipv4_or_ipv6': { - u'$ref': u'/schemata/commons#/definitions/ipv4_or_ipv6'} - }, - u'definitions': { - u'options': { - u'type': [u'object', u'null'], - u'description': u'Options.', - u'example': {} - }, - u'mac': { - u'pattern': (EPSILON_PATTERN + u'|' - u'^((?:[0-9a-f]{2}:){5}[0-9a-f]{2}|' - u'(?:[0-9A-F]{2}:){5}[0-9A-F]{2})$'), - u'type': u'string', - u'description': u'A MAC address.', - u'example': u'aa:bb:cc:dd:ee:ff' - }, - u'cidrv6': { - u'pattern': CIDRV6_PATTERN, - u'type': u'string', - u'description': u'A IPv6 CIDR of the subnet' - }, - u'interface': { - u'properties': { - u'ID': { - u'description': u'Index of the interface', - u'type': u'number', - }, - u'AddressIPv6': { - u'description': u'IPv6 CIDR', - u'$ref': u'#/definitions/commons/definitions/cidrv6' - }, - u'MacAddress': { - u'description': u'MAC address', - u'$ref': u'#/definitions/commons/definitions/mac' - }, - u'Address': { - u'description': u'IPv4 CIDR', - u'$ref': u'#/definitions/commons/definitions/cidr' - } - }, - u'type': [u'object', u'null'], - u'description': u'Interface used in requests against Endpoints.', - u'example': { - u'AddressIPv6': u'fe80::f816:3eff:fe20:57c3/64', - u'MacAddress': u'fa:16:3e:20:57:c3', - u'Address': u'192.168.1.42/24' - } - }, - u'cidr': { - u'pattern': CIDRV4_PATTERN, - u'type': u'string', - u'description': u'A IPv4 CIDR of the subnet.', - u'example': u'10.0.0.0/24' - }, - u'id': { - u'pattern': u'^([0-9a-f]{64})$', - u'type': u'string', - u'description': u'256 bits ID value of Docker.', - u'example': - u'51c75a2515d47edecc3f720bb541e287224416fb66715eb7802011d6ffd499f1' - }, - u'ipv4': { - u'pattern': IPV4_PATTERN, - u'type': u'string', - u'description': u'An IPv4 address', - u'example': u'10.0.0.1' - }, - u'ipv4datum': { - u'description': u'IPv4 data', - u'required': [ - u'AddressSpace', u'Pool'], - u'type': u'object', - u'example': { - u'AddressSpace': u'foo', - u'Pool': u'192.168.42.0/24', - u'Gateway': u'192.168.42.1/24', - u'AuxAddresses': { - u'web': u'192.168.42.2', - u'db': u'192.168.42.3' - } - }, - u'properties': { - u'AddressSpace': { - u'description': u'The name of the address space.', - u'type': u'string', - u'example': u'foo', - }, - u'Pool': { - u'description': u'A range of IP Addresses requested in ' - u'CIDR format address/mask.', - u'$ref': u'#/definitions/commons/definitions/cidr' - }, - u'Gateway': { - u'description': u'Optionally, the IPAM driver may provide ' - u'a Gateway for the subnet represented by ' - u'the Pool.', - u'$ref': u'#/definitions/commons/definitions/cidr', - }, - u'AuxAddresses': { - u'description': u'A list of pre-allocated ip-addresses ' - u'with an associated identifier as ' - u'provided by the user to assist network ' - u'driver if it requires specific ' - u'ip-addresses for its operation.', - u'type': u'object', - u'patternProperties': { - u'.+': { - u'description': u'key-value pair of the ID and ' - u'the IP address', - u'$ref': u'#/definitions/commons/definitions/ipv4' - } - } - } - } - }, - u'ipv6': { - u'pattern': IPV6_PATTERN, - u'type': u'string', - u'description': u'An IPv6 address.', - u'example': u'fe80::f816:3eff:fe20:57c4' - }, - u'ipv6datum': { - u'description': u'IPv6 data', - u'required': [ - u'AddressSpace', u'Pool', u'Gateway'], - u'type': u'object', - u'example': { - u'AddressCpace': u'bar', - u'Pool': u'fe80::/64', - u'Gateway': u'fe80::f816:3eff:fe20:57c3/64', - u'AuxAddresses': { - u'web': u'fe80::f816:3eff:fe20:57c4', - u'db': u'fe80::f816:3eff:fe20:57c5' - } - }, - u'properties': { - u'AddressSpace': { - u'description': u'The name of the address space.', - u'type': u'string', - u'example': u'foo', - }, - u'Pool': { - u'description': u'A range of IP Addresses requested in ' - u'CIDR format address/mask.', - u'$ref': u'#/definitions/commons/definitions/cidrv6' - }, - u'Gateway': { - u'description': u'Optionally, the IPAM driver may provide ' - u'a Gateway for the subnet represented by ' - u'the Pool.', - u'$ref': u'#/definitions/commons/definitions/cidrv6', - }, - u'AuxAddresses': { - u'description': u'A list of pre-allocated ip-addresses ' - u'with an associated identifier as ' - u'provided by the user to assist network ' - u'driver if it requires specific ' - u'ip-addresses for its operation.', - u'type': u'object', - u'patternProperties': { - u'.+': { - u'description': u'key-vavule pair of the ID and ' - u'the IP address', - u'$ref': u'#/definitions/commons/definitions/ipv6' - } - } - } - } - }, - u'ipv4_or_ipv6': { - u'pattern': IPV4_OR_IPV6_PATTERN, - u'type': u'string', - u'description': u'An IPv4 or IPv6 address.', - u'example': u'fe80::f816:3eff:fe20:57c4' - }, - u'sandbox_key': { - u'pattern': u'^(/var/run/docker/netns/[0-9a-f]{12})$', - u'type': u'string', - u'description': u'Sandbox information of netns.', - u'example': '/var/run/docker/netns/12bbda391ed0' - }, - u'uuid': { - u'pattern': UUID_PATTERN, - u'type': u'string', - u'description': u'uuid of neutron resources.', - u'example': 'dfe39822-ad5e-40bd-babd-3954113b3687' - } - }, - u'$schema': u'http://json-schema.org/draft-04/hyper-schema', - u'type': u'object', - u'id': u'schemata/commons' -} diff --git a/kuryr/schemata/endpoint_create.py b/kuryr/schemata/endpoint_create.py deleted file mode 100644 index 4a2fc125..00000000 --- a/kuryr/schemata/endpoint_create.py +++ /dev/null @@ -1,48 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr.schemata import commons - -ENDPOINT_CREATE_SCHEMA = { - u'links': [{ - u'method': u'POST', - u'href': u'/NetworkDriver.CreateEndpoint', - u'description': u'Create an Endpoint', - u'rel': u'self', - u'title': u'Create' - }], - u'title': u'Create endpoint', - u'required': [u'NetworkID', u'EndpointID', u'Options', u'Interface'], - u'definitions': {u'commons': {}}, - u'$schema': u'http://json-schema.org/draft-04/hyper-schema', - u'type': u'object', - u'properties': { - u'NetworkID': { - u'description': u'Network ID', - u'$ref': u'#/definitions/commons/definitions/id' - }, - u'Interface': { - u'$ref': u'#/definitions/commons/definitions/interface', - u'description': u'Interface information' - }, - u'Options': { - u'description': u'Options', - u'$ref': u'#/definitions/commons/definitions/options' - }, - u'EndpointID': { - u'description': u'Endpoint ID', - u'$ref': u'#/definitions/commons/definitions/id' - } - } -} - -ENDPOINT_CREATE_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS diff --git a/kuryr/schemata/endpoint_delete.py b/kuryr/schemata/endpoint_delete.py deleted file mode 100644 index 94a91069..00000000 --- a/kuryr/schemata/endpoint_delete.py +++ /dev/null @@ -1,40 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr.schemata import commons - -ENDPOINT_DELETE_SCHEMA = { - u'links': [{ - u'method': u'POST', - u'href': u'/NetworkDriver.DeleteEndpoint', - u'description': u'Delete an Endpoint', - u'rel': u'self', - u'title': u'Delete' - }], - u'title': u'Delete endpoint', - u'required': [u'NetworkID', u'EndpointID'], - u'definitions': {u'commons': {}}, - u'$schema': u'http://json-schema.org/draft-04/hyper-schema', - u'type': u'object', - u'properties': { - u'NetworkID': { - u'description': u'Network ID', - u'$ref': u'#/definitions/commons/definitions/id' - }, - u'EndpointID': { - u'description': u'Endpoint ID', - u'$ref': u'#/definitions/commons/definitions/id' - } - } -} - -ENDPOINT_DELETE_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS diff --git a/kuryr/schemata/join.py b/kuryr/schemata/join.py deleted file mode 100644 index b4569dad..00000000 --- a/kuryr/schemata/join.py +++ /dev/null @@ -1,52 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr.schemata.commons import COMMONS - - -JOIN_SCHEMA = { - u'links': [{ - u'method': u'POST', - u'href': u'/NetworkDriver.Join', - u'description': u'Join the network', - u'rel': u'self', - u'title': u'Create' - }], - u'title': u'Join endpoint', - u'required': [ - u'NetworkID', - u'EndpointID', - u'SandboxKey' - ], - u'properties': { - u'NetworkID': { - u'description': u'Network ID', - u'$ref': u'#/definitions/commons/definitions/id' - }, - u'SandboxKey': { - u'description': u'Sandbox Key', - u'$ref': u'#/definitions/commons/definitions/sandbox_key' - }, - u'Options': { - u'$ref': u'#/definitions/commons/definitions/options' - }, - u'EndpointID': { - u'description': u'Endpoint ID', - u'$ref': u'#/definitions/commons/definitions/id' - } - }, - u'definitions': {u'commons': {}}, - u'$schema': u'http://json-schema.org/draft-04/hyper-schema', - u'type': u'object', -} - -JOIN_SCHEMA[u'definitions'][u'commons'] = COMMONS diff --git a/kuryr/schemata/leave.py b/kuryr/schemata/leave.py deleted file mode 100644 index c5978aa8..00000000 --- a/kuryr/schemata/leave.py +++ /dev/null @@ -1,24 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr.schemata import endpoint_delete - - -LEAVE_SCHEMA = endpoint_delete.ENDPOINT_DELETE_SCHEMA -LEAVE_SCHEMA[u'title'] = u'Leave endpoint' -LEAVE_SCHEMA[u'links'] = [{ - u'method': u'POST', - u'href': u'/NetworkDriver.Leave', - u'description': u'Unbinds the endpoint from the container.', - u'rel': u'self', - u'title': u'Leave' -}] diff --git a/kuryr/schemata/network_create.py b/kuryr/schemata/network_create.py deleted file mode 100644 index 8f7a2cb8..00000000 --- a/kuryr/schemata/network_create.py +++ /dev/null @@ -1,55 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr.schemata import commons - -NETWORK_CREATE_SCHEMA = { - u'links': [{ - u'method': u'POST', - u'href': u'/NetworkDriver.CreateNetwork', - u'description': u'Create a Network', - u'rel': u'self', - u'title': u'Create' - }], - u'title': u'Create network', - u'required': [u'NetworkID', u'IPv4Data', u'IPv6Data'], - u'definitions': {u'commons': {}}, - u'$schema': u'http://json-schema.org/draft-04/hyper-schema', - u'type': u'object', - u'properties': { - u'NetworkID': { - u'description': u'ID of a Network to be created', - u'$ref': u'#/definitions/commons/definitions/id' - }, - u'IPv4Data': { - u'description': u'IPv4 data for the network', - u'type': u'array', - u'items': { - u'$ref': u'#/definitions/commons/definitions/ipv4datum' - } - }, - u'IPv6Data': { - u'description': u'IPv6 data for the network', - u'type': u'array', - u'items': { - u'$ref': u'#/definitions/commons/definitions/ipv6datum' - } - }, - u'Options': { - u'type': [u'object', u'null'], - u'description': u'Options', - u'example': {} - } - } -} - -NETWORK_CREATE_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS diff --git a/kuryr/schemata/network_delete.py b/kuryr/schemata/network_delete.py deleted file mode 100644 index c45991c6..00000000 --- a/kuryr/schemata/network_delete.py +++ /dev/null @@ -1,36 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr.schemata import commons - -NETWORK_DELETE_SCHEMA = { - u'links': [{ - u'method': u'POST', - u'href': u'/NetworkDriver.DeleteNetwork', - u'description': u'Delete a Network', - u'rel': u'self', - u'title': u'Delete' - }], - u'title': u'Delete network', - u'required': [u'NetworkID'], - u'definitions': {u'commons': {}}, - u'$schema': u'http://json-schema.org/draft-04/hyper-schema', - u'type': u'object', - u'properties': { - u'NetworkID': { - u'description': u'ID of the Network ID to be deleted', - u'$ref': u'#/definitions/commons/definitions/id' - } - } -} - -NETWORK_DELETE_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS diff --git a/kuryr/schemata/release_address.py b/kuryr/schemata/release_address.py deleted file mode 100644 index 30226d2b..00000000 --- a/kuryr/schemata/release_address.py +++ /dev/null @@ -1,41 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr.schemata import commons - -RELEASE_ADDRESS_SCHEMA = { - u'links': [{ - u'method': u'POST', - u'href': u'/IpamDriver.ReleaseAddress', - u'description': u'Release an ip address', - u'rel': u'self', - u'title': u'Release' - }], - u'title': u'Release an IP', - u'required': [u'PoolID', u'Address'], - u'definitions': {u'commons': {}}, - u'$schema': u'http://json-schema.org/draft-04/hyper-schema', - u'type': u'object', - u'properties': { - u'PoolID': { - u'description': u'neutron uuid of allocated subnetpool', - u'$ref': u'#/definitions/commons/definitions/uuid' - }, - u'Address': { - u'description': u'Address in IP(v4 or v6) form', - u'$ref': u'#/definitions/commons/definitions/ipv4_or_ipv6' - } - } - -} - -RELEASE_ADDRESS_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS diff --git a/kuryr/schemata/release_pool.py b/kuryr/schemata/release_pool.py deleted file mode 100644 index 2d5f8aa3..00000000 --- a/kuryr/schemata/release_pool.py +++ /dev/null @@ -1,36 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr.schemata import commons - -RELEASE_POOL_SCHEMA = { - u'links': [{ - u'method': u'POST', - u'href': u'/IpamDriver.ReleasePool', - u'description': u'Release an ip pool', - u'rel': u'self', - u'title': u'Release' - }], - u'title': u'Release an IP pool', - u'required': [u'PoolID'], - u'definitions': {u'commons': {}}, - u'$schema': u'http://json-schema.org/draft-04/hyper-schema', - u'type': u'object', - u'properties': { - u'PoolID': { - u'description': u'neutron ID of allocated subnetpool', - u'$ref': u'#/definitions/commons/definitions/uuid' - } - } -} - -RELEASE_POOL_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS diff --git a/kuryr/schemata/request_address.py b/kuryr/schemata/request_address.py deleted file mode 100755 index 981b2deb..00000000 --- a/kuryr/schemata/request_address.py +++ /dev/null @@ -1,47 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr.schemata import commons - -REQUEST_ADDRESS_SCHEMA = { - u'links': [{ - u'method': u'POST', - u'href': u'/IpamDriver.RequestAddress', - u'description': u'Allocate an ip addresses', - u'rel': u'self', - u'title': u'Create' - }], - u'title': u'Create an IP', - u'required': [u'PoolID', u'Address', u'Options'], - u'definitions': {u'commons': {}}, - u'$schema': u'http://json-schema.org/draft-04/hyper-schema', - u'type': u'object', - u'properties': { - u'PoolID': { - u'description': u'neutron uuid of allocated subnetpool', - u'$ref': u'#/definitions/commons/definitions/uuid' - }, - u'Address': { - u'description': u'Preferred address in regular IP form.', - u'example': u'10.0.0.1', - u'$ref': u'#/definitions/commons/definitions/ipv4_or_ipv6' - }, - u'Options': { - u'type': [u'object', u'null'], - u'description': u'Options', - u'example': {} - } - } - -} - -REQUEST_ADDRESS_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS diff --git a/kuryr/schemata/request_pool.py b/kuryr/schemata/request_pool.py deleted file mode 100644 index ed1c1d2a..00000000 --- a/kuryr/schemata/request_pool.py +++ /dev/null @@ -1,58 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr.schemata import commons - -REQUEST_POOL_SCHEMA = { - u'links': [{ - u'method': u'POST', - u'href': u'/IpamDriver.RequestPool', - u'description': u'Allocate pool of ip addresses', - u'rel': u'self', - u'title': u'Create' - }], - u'title': u'Create pool', - u'required': [u'AddressSpace', u'Pool', u'SubPool', u'V6'], - u'definitions': {u'commons': {}}, - u'$schema': u'http://json-schema.org/draft-04/hyper-schema', - u'type': u'object', - u'properties': { - u'AddressSpace': { - u'description': u'The name of the address space.', - u'type': u'string', - u'example': u'foo', - }, - u'Pool': { - u'description': u'A range of IP Addresses represented in ' - u'CIDR format address/mask.', - u'$ref': u'#/definitions/commons/definitions/cidr' - }, - u'SubPool': { - u'description': u'A subset of IP range from Pool in' - u'CIDR format address/mask.', - u'$ref': u'#/definitions/commons/definitions/cidr' - }, - u'Options': { - u'type': [u'object', u'null'], - u'description': u'Options', - u'example': {}, - }, - u'V6': { - u'description': u'If set to "True", requesting IPv6 pool and ' - u'vice-versa.', - u'type': u'boolean', - u'example': False - } - } -} - -REQUEST_POOL_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS diff --git a/kuryr/server.py b/kuryr/server.py deleted file mode 100644 index 4f41c4b6..00000000 --- a/kuryr/server.py +++ /dev/null @@ -1,36 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import sys - -from oslo_log import log - -from kuryr import app -from kuryr.common import config -from kuryr import controllers - - -config.init(sys.argv[1:]) -controllers.neutron_client() -controllers.check_for_neutron_ext_support() -controllers.check_for_neutron_ext_tag() - -log.setup(config.CONF, 'Kuryr') - - -def start(): - port = int(config.CONF.kuryr_uri.split(':')[-1]) - app.run("0.0.0.0", port) - - -if __name__ == '__main__': - start() diff --git a/kuryr/tests/contrib/gate_hook.sh b/kuryr/tests/contrib/gate_hook.sh index 5f37f831..81bb416e 100644 --- a/kuryr/tests/contrib/gate_hook.sh +++ b/kuryr/tests/contrib/gate_hook.sh @@ -2,9 +2,9 @@ set -ex -VENV=${1:-"fullstack"} +VENV=${1:-"debug-py27"} GATE_DEST=$BASE/new DEVSTACK_PATH=$GATE_DEST/devstack -$BASE/new/devstack-gate/devstack-vm-gate.sh \ No newline at end of file +$BASE/new/devstack-gate/devstack-vm-gate.sh diff --git a/kuryr/tests/contrib/post_test_hook.sh b/kuryr/tests/contrib/post_test_hook.sh index b62cd3c6..d00d646e 100644 --- a/kuryr/tests/contrib/post_test_hook.sh +++ b/kuryr/tests/contrib/post_test_hook.sh @@ -6,7 +6,7 @@ KURYR_DIR="$BASE/new/kuryr" TEMPEST_DIR="$BASE/new/tempest" SCRIPTS_DIR="/usr/os-testr-env/bin/" -venv=${1:-"fullstack"} +venv=${1:-"debug-py27"} function generate_test_logs { local path="$1" @@ -57,4 +57,4 @@ set -e # Collect and parse results generate_testr_results -exit $testr_exit_code \ No newline at end of file +exit $testr_exit_code diff --git a/kuryr/tests/fullstack/__init__.py b/kuryr/tests/fullstack/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/kuryr/tests/fullstack/kuryr_base.py b/kuryr/tests/fullstack/kuryr_base.py deleted file mode 100644 index 408683d2..00000000 --- a/kuryr/tests/fullstack/kuryr_base.py +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import docker - -from oslotest import base - -from kuryr import controllers - - -class KuryrBaseTest(base.BaseTestCase): - """Basic class for Kuryr fullstack testing - - This class has common code shared for Kuryr fullstack testing - including the various clients (docker, neutron) and common - setup/cleanup code. - """ - def setUp(self): - super(KuryrBaseTest, self).setUp() - self.docker_client = docker.Client( - base_url='tcp://0.0.0.0:2375') - self.neutron_client = controllers.get_neutron_client() diff --git a/kuryr/tests/fullstack/test_container.py b/kuryr/tests/fullstack/test_container.py deleted file mode 100644 index e2b904f0..00000000 --- a/kuryr/tests/fullstack/test_container.py +++ /dev/null @@ -1,88 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kuryr.tests.fullstack import kuryr_base -from kuryr import utils - - -class ContainerTest(kuryr_base.KuryrBaseTest): - """Test Container related operations - - Test container connect/disconnect from docker to Neutron - """ - def setUp(self): - super(ContainerTest, self).setUp() - self.docker_client.pull(repository='busybox', tag='1') - - fake_ipam = { - "Driver": "kuryr", - "Options": {}, - "Config": [ - { - "Subnet": "10.3.0.0/16", - "IPRange": "10.3.0.0/24", - "Gateway": "10.3.0.1" - } - ] - } - net_name = utils.get_random_string(8) - res = self.docker_client.create_network(name=net_name, - driver='kuryr', - ipam=fake_ipam) - self.net_id = res.get('Id') - - networks = self.neutron_client.list_networks( - tags=utils.make_net_tags(self.net_id)) - self.assertEqual(1, len(networks['networks'])) - self.neutron_net_id = networks['networks'][0]['id'] - - def tearDown(self): - self.docker_client.remove_network(self.net_id) - networks = self.neutron_client.list_networks( - tags=utils.make_net_tags(self.net_id)) - self.assertEqual(0, len(networks['networks'])) - super(ContainerTest, self).tearDown() - - def test_connect_disconnect_container(self): - # Test if support connect/disconnect operations - container_name = utils.get_random_string(8) - container = self.docker_client.create_container( - image='busybox:1', - command='/bin/sleep 600', - hostname='kuryr_test_container', - name=container_name) - warn_msg = container.get('Warning') - container_id = container.get('Id') - self.assertIsNone(warn_msg, 'Warn in creating container') - self.assertIsNotNone(container_id, 'Create container id must not ' - 'be None') - self.docker_client.start(container=container_id) - self.docker_client.connect_container_to_network(container_id, - self.net_id) - ports = self.neutron_client.list_ports( - network_id=self.neutron_net_id) - # A dhcp port gets created as well; dhcp is enabled by default - self.assertEqual(2, len(ports['ports'])) - self.docker_client.disconnect_container_from_network(container_id, - self.net_id) - ports = self.neutron_client.list_ports( - network_id=self.neutron_net_id) - self.assertEqual(1, len(ports['ports'])) - self.docker_client.stop(container=container_id) - - # TODO(banix) Stopping the container is enough for the - # container to get disconnected from the network. Therefore, - # the following is not necessary for this test. The problem - # with removing container is not related to the networking - # but we should find out how the container can be removed. - # self.docker_client.remove_container(container=container_id, - # force=True) diff --git a/kuryr/tests/fullstack/test_network.py b/kuryr/tests/fullstack/test_network.py deleted file mode 100644 index a68d3cce..00000000 --- a/kuryr/tests/fullstack/test_network.py +++ /dev/null @@ -1,125 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from kuryr.tests.fullstack import kuryr_base -from kuryr import utils - - -class NetworkTest(kuryr_base.KuryrBaseTest): - """Test Networks operation - - Test networks creation/deletion from docker to Neutron - """ - def test_create_delete_network_with_kuryr_driver(self): - """Create and Delete docker network with Kuryr - - This method creates a docker network with Kuryr driver - and tests it was created in Neutron. - It then deletes the docker network and tests that it was - deleted from Neutron. - """ - fake_ipam = { - "Driver": "kuryr", - "Options": {}, - "Config": [ - { - "Subnet": "10.0.0.0/16", - "IPRange": "10.0.0.0/24", - "Gateway": "10.0.0.1" - } - ] - } - net_name = utils.get_random_string(8) - res = self.docker_client.create_network(name=net_name, driver='kuryr', - ipam=fake_ipam) - net_id = res['Id'] - network = self.neutron_client.list_networks( - tags=utils.make_net_tags(net_id)) - self.assertEqual(1, len(network['networks'])) - self.docker_client.remove_network(net_id) - network = self.neutron_client.list_networks( - tags=utils.make_net_tags(net_id)) - self.assertEqual(0, len(network['networks'])) - - def test_create_delete_network_without_kuryr_driver(self): - """Create and Delete docker network without Kuryr - - This method create a docker network with the default - docker driver, It tests that it was created correctly, but - not added to Neutron - """ - net_name = utils.get_random_string(8) - res = self.docker_client.create_network(name=net_name) - net_id = res['Id'] - network = self.neutron_client.list_networks( - tags=utils.make_net_tags(net_id)) - self.assertEqual(0, len(network['networks'])) - docker_networks = self.docker_client.networks() - network_found = False - for docker_net in docker_networks: - if docker_net['Id'] == net_id: - network_found = True - self.assertTrue(network_found) - self.docker_client.remove_network(net_id) - - def test_create_network_with_same_name(self): - """Create docker network with same name - - Create two docker networks with same name, - delete them and see that neutron networks are - deleted as well - """ - fake_ipam_1 = { - "Driver": "kuryr", - "Options": {}, - "Config": [ - { - "Subnet": "10.1.0.0/16", - "IPRange": "10.1.0.0/24", - "Gateway": "10.1.0.1" - } - ] - } - fake_ipam_2 = { - "Driver": "kuryr", - "Options": {}, - "Config": [ - { - "Subnet": "10.2.0.0/16", - "IPRange": "10.2.0.0/24", - "Gateway": "10.2.0.1" - } - ] - } - net_name = utils.get_random_string(8) - res = self.docker_client.create_network(name=net_name, driver='kuryr', - ipam=fake_ipam_1) - net_id1 = res['Id'] - - res = self.docker_client.create_network(name=net_name, driver='kuryr', - ipam=fake_ipam_2) - net_id2 = res['Id'] - network = self.neutron_client.list_networks( - tags=utils.make_net_tags(net_id1)) - self.assertEqual(1, len(network['networks'])) - network = self.neutron_client.list_networks( - tags=utils.make_net_tags(net_id2)) - self.assertEqual(1, len(network['networks'])) - self.docker_client.remove_network(net_id1) - self.docker_client.remove_network(net_id2) - network = self.neutron_client.list_networks( - tags=utils.make_net_tags(net_id1)) - self.assertEqual(0, len(network['networks'])) - network = self.neutron_client.list_networks( - tags=utils.make_net_tags(net_id2)) - self.assertEqual(0, len(network['networks'])) diff --git a/kuryr/tests/unit/base.py b/kuryr/tests/unit/base.py index 80a84210..df6bb37c 100644 --- a/kuryr/tests/unit/base.py +++ b/kuryr/tests/unit/base.py @@ -10,274 +10,11 @@ # License for the specific language governing permissions and limitations # under the License. -from neutronclient.tests.unit import test_cli20 - -from kuryr import app -from kuryr import binding -from kuryr.common import constants as const -from kuryr import controllers -from kuryr import utils +from oslotest import base -class TestCase(test_cli20.CLITestV20Base): +class TestCase(base.BaseTestCase): """Test case base class for all unit tests.""" def setUp(self): super(TestCase, self).setUp() - app.config['DEBUG'] = True - app.config['TESTING'] = True - self.app = app.test_client() - self.app.neutron = self.client - app.tag = True - - -class TestKuryrBase(TestCase): - """Base class for all Kuryr unittests.""" - - def setUp(self): - super(TestKuryrBase, self).setUp() - controllers.neutron_client() - self.app.neutron.format = 'json' - self.addCleanup(self.mox.VerifyAll) - self.addCleanup(self.mox.UnsetStubs) - if hasattr(app, 'DEFAULT_POOL_IDS'): - del app.DEFAULT_POOL_IDS - - def _mock_out_binding(self, endpoint_id, neutron_port, neutron_subnets): - self.mox.StubOutWithMock(binding, 'port_bind') - fake_binding_response = ( - 'fake-veth', 'fake-veth_c', ('fake stdout', '')) - binding.port_bind(endpoint_id, neutron_port, - neutron_subnets).AndReturn(fake_binding_response) - self.mox.ReplayAll() - return fake_binding_response - - def _mock_out_unbinding(self, endpoint_id, neutron_port): - self.mox.StubOutWithMock(binding, 'port_unbind') - fake_unbinding_response = ('fake stdout', '') - binding.port_unbind(endpoint_id, neutron_port).AndReturn( - fake_unbinding_response) - self.mox.ReplayAll() - return fake_unbinding_response - - def _mock_out_network(self, neutron_network_id, docker_network_id, - check_existing=False): - no_networks_response = { - "networks": [] - } - fake_list_response = { - "networks": [{ - "status": "ACTIVE", - "subnets": [], - "admin_state_up": True, - "tenant_id": "9bacb3c5d39d41a79512987f338cf177", - "router:external": False, - "segments": [], - "shared": False, - "id": neutron_network_id - }] - } - self.mox.StubOutWithMock(app.neutron, 'list_networks') - t = utils.make_net_tags(docker_network_id) - if check_existing: - te = t + ',' + const.KURYR_EXISTING_NEUTRON_NET - app.neutron.list_networks(tags=te).AndReturn( - no_networks_response) - app.neutron.list_networks(tags=t).AndReturn(fake_list_response) - - self.mox.ReplayAll() - return neutron_network_id - - @staticmethod - def _get_fake_v4_subnetpools(subnetpool_id, prefixes=["192.168.1.0/24"], - name="kuryr"): - # The following fake response is retrieved from the Neutron doc: - # http://developer.openstack.org/api-ref-networking-v2-ext.html#listSubnetPools # noqa - v4_subnetpools = { - "subnetpools": [{ - "min_prefixlen": "24", - "address_scope_id": None, - "default_prefixlen": "24", - "id": subnetpool_id, - "max_prefixlen": "24", - "name": name, - "default_quota": None, - "tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08", - "prefixes": prefixes, - "ip_version": 4, - "shared": False - }] - } - - return v4_subnetpools - - @staticmethod - def _get_fake_v6_subnetpools(subnetpool_id, prefixes=['fe80::/64']): - # The following fake response is retrieved from the Neutron doc: - # http://developer.openstack.org/api-ref-networking-v2-ext.html#listSubnetPools # noqa - v6_subnetpools = { - "subnetpools": [{ - "min_prefixlen": "64", - "address_scope_id": None, - "default_prefixlen": "64", - "id": subnetpool_id, - "max_prefixlen": "64", - "name": "kuryr6", - "default_quota": None, - "tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08", - "prefixes": prefixes, - "ip_version": 6, - "shared": False - }] - } - - return v6_subnetpools - - @staticmethod - def _get_fake_subnets(docker_endpoint_id, neutron_network_id, - fake_neutron_subnet_v4_id, - fake_neutron_subnet_v6_id): - # The following fake response is retrieved from the Neutron doc: - # http://developer.openstack.org/api-ref-networking-v2.html#createSubnet # noqa - fake_subnet_response = { - "subnets": [ - {"name": '-'.join([docker_endpoint_id, '192.168.1.0']), - "network_id": neutron_network_id, - "tenant_id": "c1210485b2424d48804aad5d39c61b8f", - "allocation_pools": [{"start": "192.168.1.2", - "end": "192.168.1.254"}], - "gateway_ip": "192.168.1.1", - "ip_version": 4, - "cidr": "192.168.1.0/24", - "id": fake_neutron_subnet_v4_id, - "enable_dhcp": True, - "subnetpool_id": ''}, - {"name": '-'.join([docker_endpoint_id, 'fe80::']), - "network_id": neutron_network_id, - "tenant_id": "c1210485b2424d48804aad5d39c61b8f", - "allocation_pools": [{"start": "fe80::f816:3eff:fe20:57c4", - "end": "fe80::ffff:ffff:ffff:ffff"}], - "gateway_ip": "fe80::f816:3eff:fe20:57c3", - "ip_version": 6, - "cidr": "fe80::/64", - "id": fake_neutron_subnet_v6_id, - "enable_dhcp": True, - "subnetpool_id": ''} - ] - } - return fake_subnet_response - - @staticmethod - def _get_fake_port(docker_endpoint_id, neutron_network_id, - neutron_port_id, - neutron_port_status=const.PORT_STATUS_DOWN, - neutron_subnet_v4_id=None, - neutron_subnet_v6_id=None, - neutron_subnet_v4_address="192.168.1.2", - neutron_subnet_v6_address="fe80::f816:3eff:fe20:57c4"): - # The following fake response is retrieved from the Neutron doc: - # http://developer.openstack.org/api-ref-networking-v2.html#createPort # noqa - fake_port = { - 'port': { - "status": neutron_port_status, - "name": utils.get_neutron_port_name(docker_endpoint_id), - "allowed_address_pairs": [], - "admin_state_up": True, - "network_id": neutron_network_id, - "tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa", - "device_owner": "", - "mac_address": "fa:16:3e:20:57:c3", - "fixed_ips": [], - "id": neutron_port_id, - "security_groups": [], - "device_id": "" - } - } - - if neutron_subnet_v4_id: - fake_port['port']['fixed_ips'].append({ - "subnet_id": neutron_subnet_v4_id, - "ip_address": neutron_subnet_v4_address - }) - if neutron_subnet_v6_id: - fake_port['port']['fixed_ips'].append({ - "subnet_id": neutron_subnet_v6_id, - "ip_address": neutron_subnet_v6_address - }) - return fake_port - - @classmethod - def _get_fake_ports(cls, docker_endpoint_id, neutron_network_id, - fake_neutron_port_id, neutron_port_status, - fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id): - fake_port = cls._get_fake_port( - docker_endpoint_id, neutron_network_id, - fake_neutron_port_id, neutron_port_status, - fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id) - fake_port = fake_port['port'] - fake_ports = { - 'ports': [ - fake_port - ] - } - - return fake_ports - - @staticmethod - def _get_fake_v4_subnet(neutron_network_id, docker_endpoint_id=None, - subnet_v4_id=None, subnetpool_id=None, - cidr='192.168.1.0/24', - name=None): - if not name: - name = str('-'.join([docker_endpoint_id, - '192.168.1.0'])) - fake_v4_subnet = { - 'subnet': { - "name": name, - "network_id": neutron_network_id, - "tenant_id": "c1210485b2424d48804aad5d39c61b8f", - "allocation_pools": [{ - "start": "192.168.1.2", - "end": "192.168.1.254" - }], - "gateway_ip": "192.168.1.1", - "ip_version": 4, - "cidr": '192.168.1.0/24', - "id": subnet_v4_id, - "enable_dhcp": True, - "subnetpool_id": '' - } - } - if subnetpool_id: - fake_v4_subnet['subnet'].update(subnetpool_id=subnetpool_id) - - return fake_v4_subnet - - @staticmethod - def _get_fake_v6_subnet(docker_network_id, docker_endpoint_id, - subnet_v6_id, subnetpool_id=None): - fake_v6_subnet = { - 'subnet': { - "name": '-'.join([docker_endpoint_id, - 'fe80::']), - "network_id": docker_network_id, - "tenant_id": "c1210485b2424d48804aad5d39c61b8f", - "allocation_pools": [{ - "start": "fe80::f816:3eff:fe20:57c4", - "end": "fe80::ffff:ffff:ffff:ffff" - }], - "gateway_ip": "fe80::f816:3eff:fe20:57c3", - "ip_version": 6, - "cidr": 'fe80::/64', - "id": subnet_v6_id, - "enable_dhcp": True - } - } - if subnetpool_id: - fake_v6_subnet['subnet'].update(subnetpool_id=subnetpool_id) - - return fake_v6_subnet - - -class TestKuryrFailures(TestKuryrBase): - """Unitests for checking if Kuryr handles the failures appropriately.""" diff --git a/kuryr/tests/unit/test_config.py b/kuryr/tests/unit/test_config.py index d8f13ad4..47c00487 100755 --- a/kuryr/tests/unit/test_config.py +++ b/kuryr/tests/unit/test_config.py @@ -10,18 +10,14 @@ # License for the specific language governing permissions and limitations # under the License. -import mock import os -from neutronclient.common import exceptions as n_exceptions -from kuryr.common import config -from kuryr.common import exceptions -from kuryr import controllers +from kuryr.lib import config from kuryr.tests.unit import base -class ConfigurationTest(base.TestKuryrBase): +class ConfigurationTest(base.TestCase): def test_defaults(self): basepath = os.path.abspath(os.path.join(os.path.dirname(__file__), @@ -44,16 +40,3 @@ class ConfigurationTest(base.TestKuryrBase): self.assertEqual('http://127.0.0.1:35357/v2.0', config.CONF.keystone_client.auth_uri) - - def test_check_for_neutron_ext_support_with_ex(self): - with mock.patch.object(controllers.app.neutron, - 'show_extension') as mock_extension: - ext_alias = "subnet_allocation" - err = n_exceptions.NotFound.status_code - ext_not_found_ex = n_exceptions.NeutronClientException( - status_code=err, - message="") - mock_extension.side_effect = ext_not_found_ex - ex = exceptions.MandatoryApiMissing - self.assertRaises(ex, controllers.check_for_neutron_ext_support) - mock_extension.assert_called_once_with(ext_alias) diff --git a/kuryr/tests/unit/test_ipam_pool.py b/kuryr/tests/unit/test_ipam_pool.py deleted file mode 100644 index 05341685..00000000 --- a/kuryr/tests/unit/test_ipam_pool.py +++ /dev/null @@ -1,94 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import ddt -from neutronclient.common import exceptions -from oslo_serialization import jsonutils - -from kuryr import app -from kuryr.tests.unit import base -from kuryr import utils - - -@ddt.ddt -class TestIpamRequestPoolFailures(base.TestKuryrFailures): - """Unit tests for testing request pool failures. - - This test covers error responses listed in the spec: - http://developer.openstack.org/api-ref-networking-v2-ext.html#createSubnetPool - http://developer.openstack.org/api-ref-networking-v2-ext.html#listSubnetPools - """ - def _invoke_create_request(self, pool): - fake_request = { - 'AddressSpace': '', - 'Pool': pool, - 'SubPool': '', # In the case --ip-range is not given - 'Options': {}, - 'V6': False - } - response = self.app.post('/IpamDriver.RequestPool', - content_type='application/json', - data=jsonutils.dumps(fake_request)) - return response - - @ddt.data(exceptions.Unauthorized, exceptions.Forbidden, - exceptions.NotFound) - def test_request_pool_create_failures(self, GivenException): - pool_name = utils.get_neutron_subnetpool_name("10.0.0.0/16") - new_subnetpool = { - 'name': pool_name, - 'default_prefixlen': 16, - 'prefixes': ['10.0.0.0/16']} - - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - fake_name = pool_name - app.neutron.list_subnetpools(name=fake_name).AndReturn( - {'subnetpools': []}) - - self.mox.StubOutWithMock(app.neutron, 'create_subnetpool') - app.neutron.create_subnetpool( - {'subnetpool': new_subnetpool}).AndRaise(GivenException) - - self.mox.ReplayAll() - - pool = '10.0.0.0/16' - response = self._invoke_create_request(pool) - - self.assertEqual(GivenException.status_code, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - self.assertEqual( - {'Err': GivenException.message}, decoded_json) - - def test_request_pool_bad_request_failure(self): - pool = 'pool-should-be-cidr' - response = self._invoke_create_request(pool) - - self.assertEqual(400, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - self.assertIn(pool, decoded_json['Err']) - self.assertIn('Pool', decoded_json['Err']) - - def test_request_pool_list_subnetpool_failure(self): - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - pool_name = utils.get_neutron_subnetpool_name("10.0.0.0/16") - fake_name = pool_name - ex = exceptions.Unauthorized - app.neutron.list_subnetpools(name=fake_name).AndRaise(ex) - - self.mox.ReplayAll() - - pool = '10.0.0.0/16' - response = self._invoke_create_request(pool) - - self.assertEqual(ex.status_code, response.status_code) diff --git a/kuryr/tests/unit/test_join.py b/kuryr/tests/unit/test_join.py deleted file mode 100644 index 5c49492f..00000000 --- a/kuryr/tests/unit/test_join.py +++ /dev/null @@ -1,127 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -import ddt -from oslo_concurrency import processutils -from oslo_serialization import jsonutils -from werkzeug import exceptions as w_exceptions - -from kuryr import app -from kuryr import binding -from kuryr.common import constants as const -from kuryr.common import exceptions -from kuryr.tests.unit import base -from kuryr import utils - - -@ddt.ddt -class TestKuryrJoinFailures(base.TestKuryrFailures): - """Unit tests for the failures for binding a Neutron port.""" - def _invoke_join_request(self, docker_network_id, - docker_endpoint_id, container_id): - data = { - 'NetworkID': docker_network_id, - 'EndpointID': docker_endpoint_id, - 'SandboxKey': utils.get_sandbox_key(container_id), - 'Options': {}, - } - response = self.app.post('/NetworkDriver.Join', - content_type='application/json', - data=jsonutils.dumps(data)) - - return response - - def _port_bind_with_exeption(self, docker_endpiont_id, neutron_port, - neutron_subnets, ex): - fake_ifname = 'fake-veth' - fake_binding_response = ( - fake_ifname, - const.CONTAINER_VETH_PREFIX + fake_ifname, - ('fake stdout', '') - ) - self.mox.StubOutWithMock(binding, 'port_bind') - if ex: - binding.port_bind( - docker_endpiont_id, neutron_port, neutron_subnets).AndRaise(ex) - else: - binding.port_bind( - docker_endpiont_id, neutron_port, neutron_subnets).AndReturn( - fake_binding_response) - self.mox.ReplayAll() - - return fake_binding_response - - @ddt.data(exceptions.VethCreationFailure, - processutils.ProcessExecutionError) - def test_join_veth_failures(self, GivenException): - fake_docker_network_id = utils.get_hash() - fake_docker_endpoint_id = utils.get_hash() - fake_container_id = utils.get_hash() - - fake_neutron_network_id = str(uuid.uuid4()) - self._mock_out_network(fake_neutron_network_id, fake_docker_network_id) - fake_neutron_port_id = str(uuid.uuid4()) - self.mox.StubOutWithMock(app.neutron, 'list_ports') - neutron_port_name = utils.get_neutron_port_name( - fake_docker_endpoint_id) - fake_neutron_v4_subnet_id = str(uuid.uuid4()) - fake_neutron_v6_subnet_id = str(uuid.uuid4()) - fake_neutron_ports_response = self._get_fake_ports( - fake_docker_endpoint_id, fake_neutron_network_id, - fake_neutron_port_id, const.PORT_STATUS_ACTIVE, - fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id) - app.neutron.list_ports(name=neutron_port_name).AndReturn( - fake_neutron_ports_response) - - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - fake_neutron_subnets_response = self._get_fake_subnets( - fake_docker_endpoint_id, fake_neutron_network_id, - fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id) - app.neutron.list_subnets(network_id=fake_neutron_network_id).AndReturn( - fake_neutron_subnets_response) - fake_neutron_port = fake_neutron_ports_response['ports'][0] - fake_neutron_subnets = fake_neutron_subnets_response['subnets'] - - fake_message = "fake message" - fake_exception = GivenException(fake_message) - self._port_bind_with_exeption( - fake_docker_endpoint_id, fake_neutron_port, - fake_neutron_subnets, fake_exception) - self.mox.ReplayAll() - - response = self._invoke_join_request( - fake_docker_network_id, fake_docker_endpoint_id, fake_container_id) - - self.assertEqual( - w_exceptions.InternalServerError.code, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - self.assertIn(fake_message, decoded_json['Err']) - - def test_join_bad_request(self): - fake_docker_network_id = utils.get_hash() - invalid_docker_endpoint_id = 'id-should-be-hexdigits' - fake_container_id = utils.get_hash() - - response = self._invoke_join_request( - fake_docker_network_id, invalid_docker_endpoint_id, - fake_container_id) - - self.assertEqual( - w_exceptions.BadRequest.code, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - # TODO(tfukushima): Add the better error message validation. - self.assertIn(invalid_docker_endpoint_id, decoded_json['Err']) - self.assertIn('EndpointID', decoded_json['Err']) diff --git a/kuryr/tests/unit/test_kuryr.py b/kuryr/tests/unit/test_kuryr.py deleted file mode 100644 index 19874886..00000000 --- a/kuryr/tests/unit/test_kuryr.py +++ /dev/null @@ -1,872 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -import ddt -from oslo_serialization import jsonutils - -from kuryr import app -from kuryr.common import config -from kuryr.common import constants -from kuryr.tests.unit import base -from kuryr import utils - - -@ddt.ddt -class TestKuryr(base.TestKuryrBase): - """Basic unitests for libnetwork remote driver URI endpoints. - - This test class covers the following HTTP methods and URIs as described in - the remote driver specification as below: - - https://github.com/docker/libnetwork/blob/3c8e06bc0580a2a1b2440fe0792fbfcd43a9feca/docs/remote.md # noqa - - - POST /Plugin.Activate - - POST /NetworkDriver.GetCapabilities - - POST /NetworkDriver.CreateNetwork - - POST /NetworkDriver.DeleteNetwork - - POST /NetworkDriver.CreateEndpoint - - POST /NetworkDriver.EndpointOperInfo - - POST /NetworkDriver.DeleteEndpoint - - POST /NetworkDriver.Join - - POST /NetworkDriver.Leave - - POST /NetworkDriver.DiscoverNew - - POST /NetworkDriver.DiscoverDelete - """ - @ddt.data(('/Plugin.Activate', constants.SCHEMA['PLUGIN_ACTIVATE']), - ('/NetworkDriver.GetCapabilities', - {'Scope': config.CONF.capability_scope}), - ('/NetworkDriver.DiscoverNew', constants.SCHEMA['SUCCESS']), - ('/NetworkDriver.DiscoverDelete', constants.SCHEMA['SUCCESS']), - ('/NetworkDriver.EndpointOperInfo', - constants.SCHEMA['ENDPOINT_OPER_INFO'])) - @ddt.unpack - def test_remote_driver_endpoint(self, endpoint, expected): - response = self.app.post(endpoint) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(expected, decoded_json) - - def test_network_driver_create_network(self): - docker_network_id = utils.get_hash() - self.mox.StubOutWithMock(app.neutron, "create_network") - fake_request = { - "network": { - "name": utils.make_net_name(docker_network_id), - "admin_state_up": True - } - } - # The following fake response is retrieved from the Neutron doc: - # http://developer.openstack.org/api-ref-networking-v2.html#createNetwork # noqa - fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - fake_response = { - "network": { - "status": "ACTIVE", - "subnets": [], - "name": utils.make_net_name(docker_network_id), - "admin_state_up": True, - "tenant_id": "9bacb3c5d39d41a79512987f338cf177", - "router:external": False, - "segments": [], - "shared": False, - "id": fake_neutron_net_id - } - } - app.neutron.create_network(fake_request).AndReturn(fake_response) - - self.mox.StubOutWithMock(app.neutron, "add_tag") - tags = utils.create_net_tags(docker_network_id) - for tag in tags: - app.neutron.add_tag('networks', fake_neutron_net_id, tag) - - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - fake_existing_subnets_response = { - "subnets": [] - } - fake_cidr_v4 = '192.168.42.0/24' - app.neutron.list_subnets( - network_id=fake_neutron_net_id, - cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response) - - self.mox.StubOutWithMock(app.neutron, 'create_subnet') - fake_subnet_request = { - "subnets": [{ - 'name': fake_cidr_v4, - 'network_id': fake_neutron_net_id, - 'ip_version': 4, - 'cidr': fake_cidr_v4, - 'enable_dhcp': app.enable_dhcp, - 'gateway_ip': '192.168.42.1', - }] - } - subnet_v4_id = str(uuid.uuid4()) - fake_v4_subnet = self._get_fake_v4_subnet( - fake_neutron_net_id, subnet_v4_id, - name=fake_cidr_v4, cidr=fake_cidr_v4) - fake_subnet_response = { - 'subnets': [ - fake_v4_subnet['subnet'] - ] - } - app.neutron.create_subnet( - fake_subnet_request).AndReturn(fake_subnet_response) - - self.mox.ReplayAll() - - network_request = { - 'NetworkID': docker_network_id, - 'IPv4Data': [{ - 'AddressSpace': 'foo', - 'Pool': '192.168.42.0/24', - 'Gateway': '192.168.42.1/24', - }], - 'IPv6Data': [{ - 'AddressSpace': 'bar', - 'Pool': 'fe80::/64', - 'Gateway': 'fe80::f816:3eff:fe20:57c3/64', - }], - 'Options': {} - } - response = self.app.post('/NetworkDriver.CreateNetwork', - content_type='application/json', - data=jsonutils.dumps(network_request)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) - - def test_network_driver_create_network_with_net_name_option(self): - docker_network_id = utils.get_hash() - fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - self.mox.StubOutWithMock(app.neutron, "list_networks") - fake_neutron_net_name = 'my_network_name' - fake_existing_networks_response = { - "networks": [{ - "status": "ACTIVE", - "subnets": [], - "admin_state_up": True, - "tenant_id": "9bacb3c5d39d41a79512987f338cf177", - "router:external": False, - "segments": [], - "shared": False, - "id": fake_neutron_net_id, - "name": "my_network_name" - }] - } - app.neutron.list_networks( - name=fake_neutron_net_name).AndReturn( - fake_existing_networks_response) - - self.mox.StubOutWithMock(app.neutron, "add_tag") - tags = utils.create_net_tags(docker_network_id) - for tag in tags: - app.neutron.add_tag('networks', fake_neutron_net_id, tag) - - app.neutron.add_tag( - 'networks', fake_neutron_net_id, 'kuryr.net.existing') - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - fake_existing_subnets_response = { - "subnets": [] - } - fake_cidr_v4 = '192.168.42.0/24' - app.neutron.list_subnets( - network_id=fake_neutron_net_id, - cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response) - - self.mox.StubOutWithMock(app.neutron, 'create_subnet') - fake_subnet_request = { - "subnets": [{ - 'name': fake_cidr_v4, - 'network_id': fake_neutron_net_id, - 'ip_version': 4, - 'cidr': fake_cidr_v4, - 'enable_dhcp': app.enable_dhcp, - 'gateway_ip': '192.168.42.1', - }] - } - subnet_v4_id = str(uuid.uuid4()) - fake_v4_subnet = self._get_fake_v4_subnet( - fake_neutron_net_id, subnet_v4_id, - name=fake_cidr_v4, cidr=fake_cidr_v4) - fake_subnet_response = { - 'subnets': [ - fake_v4_subnet['subnet'] - ] - } - app.neutron.create_subnet( - fake_subnet_request).AndReturn(fake_subnet_response) - - self.mox.ReplayAll() - - network_request = { - 'NetworkID': docker_network_id, - 'IPv4Data': [{ - 'AddressSpace': 'foo', - 'Pool': '192.168.42.0/24', - 'Gateway': '192.168.42.1/24', - }], - 'IPv6Data': [{ - 'AddressSpace': 'bar', - 'Pool': 'fe80::/64', - 'Gateway': 'fe80::f816:3eff:fe20:57c3/64', - }], - 'Options': { - 'com.docker.network.enable_ipv6': False, - 'com.docker.network.generic': { - 'neutron.net.name': 'my_network_name' - } - } - } - response = self.app.post('/NetworkDriver.CreateNetwork', - content_type='application/json', - data=jsonutils.dumps(network_request)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) - - def test_network_driver_create_network_with_netid_option(self): - docker_network_id = utils.get_hash() - fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - self.mox.StubOutWithMock(app.neutron, "list_networks") - fake_existing_networks_response = { - "networks": [{ - "status": "ACTIVE", - "subnets": [], - "admin_state_up": True, - "tenant_id": "9bacb3c5d39d41a79512987f338cf177", - "router:external": False, - "segments": [], - "shared": False, - "id": fake_neutron_net_id, - }] - } - app.neutron.list_networks( - id=fake_neutron_net_id).AndReturn( - fake_existing_networks_response) - - self.mox.StubOutWithMock(app.neutron, "add_tag") - tags = utils.create_net_tags(docker_network_id) - for tag in tags: - app.neutron.add_tag('networks', fake_neutron_net_id, tag) - - app.neutron.add_tag( - 'networks', fake_neutron_net_id, 'kuryr.net.existing') - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - fake_existing_subnets_response = { - "subnets": [] - } - fake_cidr_v4 = '192.168.42.0/24' - app.neutron.list_subnets( - network_id=fake_neutron_net_id, - cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response) - - self.mox.StubOutWithMock(app.neutron, 'create_subnet') - fake_subnet_request = { - "subnets": [{ - 'name': fake_cidr_v4, - 'network_id': fake_neutron_net_id, - 'ip_version': 4, - 'cidr': fake_cidr_v4, - 'enable_dhcp': app.enable_dhcp, - 'gateway_ip': '192.168.42.1', - }] - } - subnet_v4_id = str(uuid.uuid4()) - fake_v4_subnet = self._get_fake_v4_subnet( - fake_neutron_net_id, subnet_v4_id, - name=fake_cidr_v4, cidr=fake_cidr_v4) - fake_subnet_response = { - 'subnets': [ - fake_v4_subnet['subnet'] - ] - } - app.neutron.create_subnet( - fake_subnet_request).AndReturn(fake_subnet_response) - - self.mox.ReplayAll() - - network_request = { - 'NetworkID': docker_network_id, - 'IPv4Data': [{ - 'AddressSpace': 'foo', - 'Pool': '192.168.42.0/24', - 'Gateway': '192.168.42.1/24', - }], - 'IPv6Data': [{ - 'AddressSpace': 'bar', - 'Pool': 'fe80::/64', - 'Gateway': 'fe80::f816:3eff:fe20:57c3/64', - }], - 'Options': { - 'com.docker.network.enable_ipv6': False, - 'com.docker.network.generic': { - 'neutron.net.uuid': '4e8e5957-649f-477b-9e5b-f1f75b21c03c' - } - } - } - response = self.app.post('/NetworkDriver.CreateNetwork', - content_type='application/json', - data=jsonutils.dumps(network_request)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) - - def test_network_driver_create_network_with_pool_name_option(self): - - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - fake_kuryr_subnetpool_id = str(uuid.uuid4()) - fake_name = "fake_pool_name" - kuryr_subnetpools = self._get_fake_v4_subnetpools( - fake_kuryr_subnetpool_id, name=fake_name) - app.neutron.list_subnetpools(name=fake_name).AndReturn( - {'subnetpools': kuryr_subnetpools['subnetpools']}) - docker_network_id = utils.get_hash() - self.mox.StubOutWithMock(app.neutron, "create_network") - fake_request = { - "network": { - "name": utils.make_net_name(docker_network_id), - "admin_state_up": True - } - } - # The following fake response is retrieved from the Neutron doc: - # http://developer.openstack.org/api-ref-networking-v2.html#createNetwork # noqa - fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - fake_response = { - "network": { - "status": "ACTIVE", - "subnets": [], - "name": utils.make_net_name(docker_network_id), - "admin_state_up": True, - "tenant_id": "9bacb3c5d39d41a79512987f338cf177", - "router:external": False, - "segments": [], - "shared": False, - "id": fake_neutron_net_id - } - } - app.neutron.create_network(fake_request).AndReturn(fake_response) - - self.mox.StubOutWithMock(app.neutron, "add_tag") - tags = utils.create_net_tags(docker_network_id) - for tag in tags: - app.neutron.add_tag('networks', fake_neutron_net_id, tag) - - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - fake_existing_subnets_response = { - "subnets": [] - } - fake_cidr_v4 = '192.168.42.0/24' - app.neutron.list_subnets( - network_id=fake_neutron_net_id, - cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response) - - self.mox.StubOutWithMock(app.neutron, 'create_subnet') - fake_subnet_request = { - "subnets": [{ - 'name': fake_cidr_v4, - 'network_id': fake_neutron_net_id, - 'ip_version': 4, - 'cidr': fake_cidr_v4, - 'enable_dhcp': app.enable_dhcp, - 'gateway_ip': '192.168.42.1', - 'subnetpool_id': fake_kuryr_subnetpool_id, - }] - } - subnet_v4_id = str(uuid.uuid4()) - fake_v4_subnet = self._get_fake_v4_subnet( - fake_neutron_net_id, subnet_v4_id, - name=fake_cidr_v4, cidr=fake_cidr_v4) - fake_subnet_response = { - 'subnets': [ - fake_v4_subnet['subnet'] - ] - } - app.neutron.create_subnet( - fake_subnet_request).AndReturn(fake_subnet_response) - - self.mox.ReplayAll() - - network_request = { - 'NetworkID': docker_network_id, - 'IPv4Data': [{ - 'AddressSpace': 'foo', - 'Pool': '192.168.42.0/24', - 'Gateway': '192.168.42.1/24', - }], - 'IPv6Data': [{ - 'AddressSpace': 'bar', - 'Pool': 'fe80::/64', - 'Gateway': 'fe80::f816:3eff:fe20:57c3/64', - }], - 'Options': { - 'com.docker.network.enable_ipv6': False, - 'com.docker.network.generic': { - 'neutron.pool.name': 'fake_pool_name' - } - } - } - response = self.app.post('/NetworkDriver.CreateNetwork', - content_type='application/json', - data=jsonutils.dumps(network_request)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) - - def test_network_driver_create_network_wo_gw(self): - docker_network_id = utils.get_hash() - self.mox.StubOutWithMock(app.neutron, "create_network") - fake_request = { - "network": { - "name": utils.make_net_name(docker_network_id), - "admin_state_up": True - } - } - # The following fake response is retrieved from the Neutron doc: - # http://developer.openstack.org/api-ref-networking-v2.html#createNetwork # noqa - fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - fake_response = { - "network": { - "status": "ACTIVE", - "subnets": [], - "name": utils.make_net_name(docker_network_id), - "admin_state_up": True, - "tenant_id": "9bacb3c5d39d41a79512987f338cf177", - "router:external": False, - "segments": [], - "shared": False, - "id": fake_neutron_net_id - } - } - app.neutron.create_network(fake_request).AndReturn(fake_response) - - self.mox.StubOutWithMock(app.neutron, "add_tag") - tags = utils.create_net_tags(docker_network_id) - for tag in tags: - app.neutron.add_tag('networks', fake_neutron_net_id, tag) - - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - fake_existing_subnets_response = { - "subnets": [] - } - fake_cidr_v4 = '192.168.42.0/24' - app.neutron.list_subnets( - network_id=fake_neutron_net_id, - cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response) - - self.mox.StubOutWithMock(app.neutron, 'create_subnet') - fake_subnet_request = { - "subnets": [{ - 'name': fake_cidr_v4, - 'network_id': fake_neutron_net_id, - 'ip_version': 4, - 'cidr': fake_cidr_v4, - 'enable_dhcp': app.enable_dhcp, - }] - } - subnet_v4_id = str(uuid.uuid4()) - fake_v4_subnet = self._get_fake_v4_subnet( - fake_neutron_net_id, subnet_v4_id, - name=fake_cidr_v4, cidr=fake_cidr_v4) - fake_subnet_response = { - 'subnets': [ - fake_v4_subnet['subnet'] - ] - } - app.neutron.create_subnet( - fake_subnet_request).AndReturn(fake_subnet_response) - - self.mox.ReplayAll() - - network_request = { - 'NetworkID': docker_network_id, - 'IPv4Data': [{ - 'AddressSpace': 'foo', - 'Pool': '192.168.42.0/24', - }], - 'IPv6Data': [{ - 'AddressSpace': 'bar', - 'Pool': 'fe80::/64', - 'Gateway': 'fe80::f816:3eff:fe20:57c3/64', - }], - 'Options': {} - } - response = self.app.post('/NetworkDriver.CreateNetwork', - content_type='application/json', - data=jsonutils.dumps(network_request)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) - - def test_network_driver_create_network_with_network_id_not_exist(self): - docker_network_id = utils.get_hash() - - self.mox.StubOutWithMock(app.neutron, "list_networks") - fake_neutron_net_id = str(uuid.uuid4()) - fake_existing_networks_response = { - "networks": [] - } - app.neutron.list_networks( - id=fake_neutron_net_id).AndReturn( - fake_existing_networks_response) - self.mox.ReplayAll() - network_request = { - 'NetworkID': docker_network_id, - 'IPv4Data': [{ - 'AddressSpace': 'foo', - 'Pool': '192.168.42.0/24', - }], - 'IPv6Data': [{ - 'AddressSpace': 'bar', - 'Pool': 'fe80::/64', - 'Gateway': 'fe80::f816:3eff:fe20:57c3/64', - }], - 'Options': { - constants.NETWORK_GENERIC_OPTIONS: { - constants.NEUTRON_UUID_OPTION: fake_neutron_net_id - } - } - } - response = self.app.post('/NetworkDriver.CreateNetwork', - content_type='application/json', - data=jsonutils.dumps(network_request)) - self.assertEqual(500, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - err_message = ("Specified network id/name({0}) does not " - "exist.").format(fake_neutron_net_id) - self.assertEqual({'Err': err_message}, decoded_json) - - def test_network_driver_create_network_with_network_name_not_exist(self): - docker_network_id = utils.get_hash() - - self.mox.StubOutWithMock(app.neutron, "list_networks") - fake_neutron_network_name = "fake_network" - fake_existing_networks_response = { - "networks": [] - } - app.neutron.list_networks( - name=fake_neutron_network_name).AndReturn( - fake_existing_networks_response) - self.mox.ReplayAll() - network_request = { - 'NetworkID': docker_network_id, - 'IPv4Data': [{ - 'AddressSpace': 'foo', - 'Pool': '192.168.42.0/24', - }], - 'IPv6Data': [{ - 'AddressSpace': 'bar', - 'Pool': 'fe80::/64', - 'Gateway': 'fe80::f816:3eff:fe20:57c3/64', - }], - 'Options': { - constants.NETWORK_GENERIC_OPTIONS: { - constants.NEUTRON_NAME_OPTION: fake_neutron_network_name - } - } - } - response = self.app.post('/NetworkDriver.CreateNetwork', - content_type='application/json', - data=jsonutils.dumps(network_request)) - self.assertEqual(500, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - err_message = ("Specified network id/name({0}) does not " - "exist.").format(fake_neutron_network_name) - self.assertEqual({'Err': err_message}, decoded_json) - - def test_network_driver_delete_network(self): - docker_network_id = utils.get_hash() - fake_neutron_net_id = str(uuid.uuid4()) - self._mock_out_network(fake_neutron_net_id, docker_network_id, - check_existing=True) - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - fake_neutron_subnets_response = {"subnets": []} - app.neutron.list_subnets(network_id=fake_neutron_net_id).AndReturn( - fake_neutron_subnets_response) - - self.mox.StubOutWithMock(app.neutron, 'delete_network') - app.neutron.delete_network(fake_neutron_net_id).AndReturn(None) - self.mox.ReplayAll() - - data = {'NetworkID': docker_network_id} - response = self.app.post('/NetworkDriver.DeleteNetwork', - content_type='application/json', - data=jsonutils.dumps(data)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) - - def test_network_driver_delete_network_with_subnets(self): - docker_network_id = utils.get_hash() - docker_endpoint_id = utils.get_hash() - - fake_neutron_net_id = str(uuid.uuid4()) - self._mock_out_network(fake_neutron_net_id, docker_network_id, - check_existing=True) - # The following fake response is retrieved from the Neutron doc: - # http://developer.openstack.org/api-ref-networking-v2.html#createSubnet # noqa - subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031" - subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51" - fake_v4_subnet = self._get_fake_v4_subnet( - docker_network_id, docker_endpoint_id, subnet_v4_id) - fake_v6_subnet = self._get_fake_v6_subnet( - docker_network_id, docker_endpoint_id, subnet_v6_id) - fake_subnets_response = { - "subnets": [ - fake_v4_subnet['subnet'], - fake_v6_subnet['subnet'] - ] - } - - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - app.neutron.list_subnets(network_id=fake_neutron_net_id).AndReturn( - fake_subnets_response) - - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - fake_subnetpools_response = {"subnetpools": []} - app.neutron.list_subnetpools(name='kuryr').AndReturn( - fake_subnetpools_response) - app.neutron.list_subnetpools(name='kuryr6').AndReturn( - fake_subnetpools_response) - - self.mox.StubOutWithMock(app.neutron, 'delete_subnet') - app.neutron.delete_subnet(subnet_v4_id).AndReturn(None) - app.neutron.delete_subnet(subnet_v6_id).AndReturn(None) - - self.mox.StubOutWithMock(app.neutron, 'delete_network') - app.neutron.delete_network(fake_neutron_net_id).AndReturn(None) - self.mox.ReplayAll() - - data = {'NetworkID': docker_network_id} - response = self.app.post('/NetworkDriver.DeleteNetwork', - content_type='application/json', - data=jsonutils.dumps(data)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) - - def test_network_driver_create_endpoint(self): - docker_network_id = utils.get_hash() - docker_endpoint_id = utils.get_hash() - - fake_neutron_net_id = str(uuid.uuid4()) - self._mock_out_network(fake_neutron_net_id, docker_network_id) - - # The following fake response is retrieved from the Neutron doc: - # http://developer.openstack.org/api-ref-networking-v2.html#createSubnet # noqa - subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031" - subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51" - fake_v4_subnet = self._get_fake_v4_subnet( - docker_network_id, docker_endpoint_id, subnet_v4_id) - fake_v6_subnet = self._get_fake_v6_subnet( - docker_network_id, docker_endpoint_id, subnet_v6_id) - - fake_subnetv4_response = { - "subnets": [ - fake_v4_subnet['subnet'] - ] - } - fake_subnetv6_response = { - "subnets": [ - fake_v6_subnet['subnet'] - ] - } - - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - app.neutron.list_subnets(network_id=fake_neutron_net_id, - cidr='192.168.1.0/24').AndReturn(fake_subnetv4_response) - app.neutron.list_subnets( - network_id=fake_neutron_net_id, - cidr='fe80::/64').AndReturn(fake_subnetv6_response) - - fake_ipv4cidr = '192.168.1.2/24' - fake_ipv6cidr = 'fe80::f816:3eff:fe20:57c4/64' - fake_port_id = str(uuid.uuid4()) - fake_port = self._get_fake_port( - docker_endpoint_id, fake_neutron_net_id, - fake_port_id, constants.PORT_STATUS_ACTIVE, - subnet_v4_id, subnet_v6_id) - fake_fixed_ips = ['subnet_id=%s' % subnet_v4_id, - 'ip_address=192.168.1.2', - 'subnet_id=%s' % subnet_v6_id, - 'ip_address=fe80::f816:3eff:fe20:57c4'] - fake_port_response = { - "ports": [ - fake_port['port'] - ] - } - self.mox.StubOutWithMock(app.neutron, 'list_ports') - app.neutron.list_ports(fixed_ips=fake_fixed_ips).AndReturn( - fake_port_response) - fake_updated_port = fake_port['port'] - fake_updated_port['name'] = '-'.join([docker_endpoint_id, 'port']) - self.mox.StubOutWithMock(app.neutron, 'update_port') - app.neutron.update_port(fake_updated_port['id'], {'port': { - 'name': fake_updated_port['name'], - 'device_owner': constants.DEVICE_OWNER, - 'device_id': docker_endpoint_id}}).AndReturn(fake_port) - self.mox.ReplayAll() - - data = { - 'NetworkID': docker_network_id, - 'EndpointID': docker_endpoint_id, - 'Options': {}, - 'Interface': { - 'Address': fake_ipv4cidr, - 'AddressIPv6': fake_ipv6cidr, - 'MacAddress': "fa:16:3e:20:57:c3" - } - } - response = self.app.post('/NetworkDriver.CreateEndpoint', - content_type='application/json', - data=jsonutils.dumps(data)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - expected = {'Interface': {}} - self.assertEqual(expected, decoded_json) - - def test_network_driver_delete_endpoint(self): - docker_network_id = utils.get_hash() - docker_endpoint_id = utils.get_hash() - data = { - 'NetworkID': docker_network_id, - 'EndpointID': docker_endpoint_id, - } - response = self.app.post('/NetworkDriver.DeleteEndpoint', - content_type='application/json', - data=jsonutils.dumps(data)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) - - @ddt.data( - (False), (True)) - def test_network_driver_join(self, vif_plug_is_fatal): - if vif_plug_is_fatal: - self.mox.StubOutWithMock(app, "vif_plug_is_fatal") - app.vif_plug_is_fatal = True - - fake_docker_net_id = utils.get_hash() - fake_docker_endpoint_id = utils.get_hash() - fake_container_id = utils.get_hash() - - fake_neutron_net_id = str(uuid.uuid4()) - self._mock_out_network(fake_neutron_net_id, fake_docker_net_id) - fake_neutron_port_id = str(uuid.uuid4()) - self.mox.StubOutWithMock(app.neutron, 'list_ports') - neutron_port_name = utils.get_neutron_port_name( - fake_docker_endpoint_id) - fake_neutron_v4_subnet_id = str(uuid.uuid4()) - fake_neutron_v6_subnet_id = str(uuid.uuid4()) - fake_neutron_ports_response = self._get_fake_ports( - fake_docker_endpoint_id, fake_neutron_net_id, - fake_neutron_port_id, constants.PORT_STATUS_DOWN, - fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id) - app.neutron.list_ports(name=neutron_port_name).AndReturn( - fake_neutron_ports_response) - - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - fake_neutron_subnets_response = self._get_fake_subnets( - fake_docker_endpoint_id, fake_neutron_net_id, - fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id) - app.neutron.list_subnets(network_id=fake_neutron_net_id).AndReturn( - fake_neutron_subnets_response) - fake_neutron_port = fake_neutron_ports_response['ports'][0] - fake_neutron_subnets = fake_neutron_subnets_response['subnets'] - _, fake_peer_name, _ = self._mock_out_binding( - fake_docker_endpoint_id, fake_neutron_port, fake_neutron_subnets) - - if vif_plug_is_fatal: - self.mox.StubOutWithMock(app.neutron, 'show_port') - fake_neutron_ports_response_2 = self._get_fake_port( - fake_docker_endpoint_id, fake_neutron_net_id, - fake_neutron_port_id, constants.PORT_STATUS_ACTIVE, - fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id) - app.neutron.show_port(fake_neutron_port_id).AndReturn( - fake_neutron_ports_response_2) - - self.mox.ReplayAll() - - fake_subnets_dict_by_id = {subnet['id']: subnet - for subnet in fake_neutron_subnets} - - join_request = { - 'NetworkID': fake_docker_net_id, - 'EndpointID': fake_docker_endpoint_id, - 'SandboxKey': utils.get_sandbox_key(fake_container_id), - 'Options': {}, - } - response = self.app.post('/NetworkDriver.Join', - content_type='application/json', - data=jsonutils.dumps(join_request)) - - self.assertEqual(200, response.status_code) - - decoded_json = jsonutils.loads(response.data) - fake_neutron_v4_subnet = fake_subnets_dict_by_id[ - fake_neutron_v4_subnet_id] - fake_neutron_v6_subnet = fake_subnets_dict_by_id[ - fake_neutron_v6_subnet_id] - expected_response = { - 'Gateway': fake_neutron_v4_subnet['gateway_ip'], - 'GatewayIPv6': fake_neutron_v6_subnet['gateway_ip'], - 'InterfaceName': { - 'DstPrefix': config.CONF.binding.veth_dst_prefix, - 'SrcName': fake_peer_name, - }, - 'StaticRoutes': [] - } - self.assertEqual(expected_response, decoded_json) - - def test_network_driver_leave(self): - fake_docker_net_id = utils.get_hash() - fake_docker_endpoint_id = utils.get_hash() - - fake_neutron_net_id = str(uuid.uuid4()) - self._mock_out_network(fake_neutron_net_id, fake_docker_net_id) - fake_neutron_port_id = str(uuid.uuid4()) - self.mox.StubOutWithMock(app.neutron, 'list_ports') - neutron_port_name = utils.get_neutron_port_name( - fake_docker_endpoint_id) - fake_neutron_v4_subnet_id = str(uuid.uuid4()) - fake_neutron_v6_subnet_id = str(uuid.uuid4()) - fake_neutron_ports_response = self._get_fake_ports( - fake_docker_endpoint_id, fake_neutron_net_id, - fake_neutron_port_id, constants.PORT_STATUS_ACTIVE, - fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id) - app.neutron.list_ports(name=neutron_port_name).AndReturn( - fake_neutron_ports_response) - - fake_neutron_port = fake_neutron_ports_response['ports'][0] - self._mock_out_unbinding(fake_docker_endpoint_id, fake_neutron_port) - - leave_request = { - 'NetworkID': fake_docker_net_id, - 'EndpointID': fake_docker_endpoint_id, - } - response = self.app.post('/NetworkDriver.Leave', - content_type='application/json', - data=jsonutils.dumps(leave_request)) - - self.mox.ReplayAll() - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) diff --git a/kuryr/tests/unit/test_kuryr_endpoint.py b/kuryr/tests/unit/test_kuryr_endpoint.py deleted file mode 100644 index 48305b17..00000000 --- a/kuryr/tests/unit/test_kuryr_endpoint.py +++ /dev/null @@ -1,252 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -import ddt -from neutronclient.common import exceptions -from oslo_serialization import jsonutils - -from kuryr import app -from kuryr.common import constants -from kuryr.tests.unit import base -from kuryr import utils - - -class TestKuryrEndpointFailures(base.TestKuryrFailures): - """Base class that has the methods commonly shared among endpoint tests. - - This class mainly has the methods for mocking API calls against Neutron. - """ - def _create_subnet_with_exception(self, neutron_network_id, - docker_endpoint_id, ex): - fake_neutron_subnet_v4_id = str(uuid.uuid4()) - fake_neutron_subnet_v6_id = str(uuid.uuid4()) - - self.mox.StubOutWithMock(app.neutron, 'create_subnet') - fake_subnet_request = { - 'subnets': [{ - 'name': '-'.join([docker_endpoint_id, '192.168.1.0']), - 'network_id': neutron_network_id, - 'ip_version': 4, - "cidr": '192.168.1.0/24', - 'enable_dhcp': 'False', - 'subnetpool_id': '' - }, { - 'name': '-'.join([docker_endpoint_id, 'fe80::']), - 'network_id': neutron_network_id, - 'ip_version': 6, - "cidr": 'fe80::/64', - 'enable_dhcp': 'False', - 'subnetpool_id': '' - }] - } - fake_subnets = self._get_fake_subnets( - docker_endpoint_id, neutron_network_id, - fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id) - - if ex: - app.neutron.create_subnet(fake_subnet_request).AndRaise(ex) - else: - app.neutron.create_subnet( - fake_subnet_request).AndReturn(fake_subnets) - self.mox.ReplayAll() - - return (fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id) - - def _delete_subnet_with_exception(self, neutron_subnet_id, ex): - self.mox.StubOutWithMock(app.neutron, 'delete_subnet') - if ex: - app.neutron.delete_subnet(neutron_subnet_id).AndRaise(ex) - else: - app.neutron.delete_subnet(neutron_subnet_id).AndReturn(None) - self.mox.ReplayAll() - - def _delete_subnets_with_exception(self, neutron_subnet_ids, ex): - self.mox.StubOutWithMock(app.neutron, 'delete_subnet') - for neutron_subnet_id in neutron_subnet_ids: - if ex: - app.neutron.delete_subnet(neutron_subnet_id).AndRaise(ex) - else: - app.neutron.delete_subnet(neutron_subnet_id).AndReturn(None) - self.mox.ReplayAll() - - def _create_port_with_exception(self, neutron_network_id, - docker_endpoint_id, neutron_subnetv4_id, - neutron_subnetv6_id, ex): - self.mox.StubOutWithMock(app.neutron, 'create_port') - fake_port_request = { - 'port': { - 'name': utils.get_neutron_port_name(docker_endpoint_id), - 'admin_state_up': True, - "binding:host_id": utils.get_hostname(), - 'device_owner': constants.DEVICE_OWNER, - 'device_id': docker_endpoint_id, - 'fixed_ips': [{ - 'subnet_id': neutron_subnetv4_id, - 'ip_address': '192.168.1.2' - }, { - 'subnet_id': neutron_subnetv6_id, - 'ip_address': 'fe80::f816:3eff:fe20:57c4' - }], - 'mac_address': "fa:16:3e:20:57:c3", - 'network_id': neutron_network_id - } - } - # The following fake response is retrieved from the Neutron doc: - # http://developer.openstack.org/api-ref-networking-v2.html#createPort # noqa - fake_port = { - "port": { - "status": "DOWN", - "name": utils.get_neutron_port_name(docker_endpoint_id), - "allowed_address_pairs": [], - "admin_state_up": True, - "binding:host_id": utils.get_hostname(), - "network_id": neutron_network_id, - "tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa", - "device_owner": constants.DEVICE_OWNER, - 'device_id': docker_endpoint_id, - "mac_address": "fa:16:3e:20:57:c3", - 'fixed_ips': [{ - 'subnet_id': neutron_subnetv4_id, - 'ip_address': '192.168.1.2' - }, { - 'subnet_id': neutron_subnetv6_id, - 'ip_address': 'fe80::f816:3eff:fe20:57c4' - }], - "id": "65c0ee9f-d634-4522-8954-51021b570b0d", - "security_groups": [], - "device_id": "" - } - } - if ex: - app.neutron.create_port(fake_port_request).AndRaise(ex) - else: - app.neutron.create_port(fake_port_request).AndReturn(fake_port) - self.mox.ReplayAll() - - def _delete_port_with_exception(self, neutron_port_id, ex): - self.mox.StubOutWithMock(app.neutron, "delete_port") - if ex: - app.neutron.delete_port(neutron_port_id).AndRaise(ex) - else: - app.neutron.delete_port(neutron_port_id).AndReturn(None) - self.mox.ReplayAll() - - -@ddt.ddt -class TestKuryrEndpointCreateFailures(TestKuryrEndpointFailures): - """Unit tests for the failures for creating endpoints. - - This test covers error responses listed in the spec: - http://developer.openstack.org/api-ref-networking-v2.html#createSubnet # noqa - http://developer.openstack.org/api-ref-networking-v2-ext.html#createPort # noqa - """ - def _invoke_create_request(self, docker_network_id, docker_endpoint_id): - data = { - 'NetworkID': docker_network_id, - 'EndpointID': docker_endpoint_id, - 'Options': {}, - 'Interface': { - 'Address': '192.168.1.2/24', - 'AddressIPv6': 'fe80::f816:3eff:fe20:57c4/64', - 'MacAddress': "fa:16:3e:20:57:c3" - } - } - response = self.app.post('/NetworkDriver.CreateEndpoint', - content_type='application/json', - data=jsonutils.dumps(data)) - return response - - @ddt.data(exceptions.Unauthorized, exceptions.Forbidden, - exceptions.NotFound, exceptions.ServiceUnavailable) - def test_create_endpoint_port_failures(self, GivenException): - fake_docker_network_id = utils.get_hash() - fake_docker_endpoint_id = utils.get_hash() - fake_neutron_network_id = str(uuid.uuid4()) - fake_neutron_subnet_v4_id = str(uuid.uuid4()) - fake_neutron_subnet_v6_id = str(uuid.uuid4()) - fake_subnets = self._get_fake_subnets( - fake_docker_endpoint_id, fake_neutron_network_id, - fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id) - - fake_fixed_ips = ['subnet_id=%s' % fake_neutron_subnet_v4_id, - 'ip_address=192.168.1.2', - 'subnet_id=%s' % fake_neutron_subnet_v6_id, - 'ip_address=fe80::f816:3eff:fe20:57c4'] - fake_port_response = {"ports": []} - - self.mox.StubOutWithMock(app.neutron, 'list_ports') - app.neutron.list_ports(fixed_ips=fake_fixed_ips).AndReturn( - fake_port_response) - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - app.neutron.list_subnets( - network_id=fake_neutron_network_id, - cidr='192.168.1.0/24').AndReturn(fake_subnets) - app.neutron.list_subnets( - network_id=fake_neutron_network_id, - cidr='fe80::/64').AndReturn({'subnets': []}) - - self._create_port_with_exception(fake_neutron_network_id, - fake_docker_endpoint_id, - fake_neutron_subnet_v4_id, - fake_neutron_subnet_v6_id, - GivenException()) - self._mock_out_network(fake_neutron_network_id, fake_docker_network_id) - - response = self._invoke_create_request( - fake_docker_network_id, fake_docker_endpoint_id) - - self.assertEqual(GivenException.status_code, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - self.assertEqual({'Err': GivenException.message}, decoded_json) - - def test_create_endpoint_bad_request(self): - fake_docker_network_id = utils.get_hash() - invalid_docker_endpoint_id = 'id-should-be-hexdigits' - - response = self._invoke_create_request( - fake_docker_network_id, invalid_docker_endpoint_id) - - self.assertEqual(400, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - # TODO(tfukushima): Add the better error message validation. - self.assertIn(invalid_docker_endpoint_id, decoded_json['Err']) - self.assertIn('EndpointID', decoded_json['Err']) - - -@ddt.ddt -class TestKuryrEndpointDeleteFailures(TestKuryrEndpointFailures): - """Unit tests for the failures for deleting endpoints.""" - def _invoke_delete_request(self, docker_network_id, docker_endpoint_id): - data = {'NetworkID': docker_network_id, - 'EndpointID': docker_endpoint_id} - response = self.app.post('/NetworkDriver.DeleteEndpoint', - content_type='application/json', - data=jsonutils.dumps(data)) - return response - - def test_delete_endpoint_bad_request(self): - fake_docker_network_id = utils.get_hash() - invalid_docker_endpoint_id = 'id-should-be-hexdigits' - - response = self._invoke_delete_request( - fake_docker_network_id, invalid_docker_endpoint_id) - - self.assertEqual(400, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - # TODO(tfukushima): Add the better error message validation. - self.assertIn(invalid_docker_endpoint_id, decoded_json['Err']) - self.assertIn('EndpointID', decoded_json['Err']) diff --git a/kuryr/tests/unit/test_kuryr_existing_network.py b/kuryr/tests/unit/test_kuryr_existing_network.py deleted file mode 100644 index b3aa2695..00000000 --- a/kuryr/tests/unit/test_kuryr_existing_network.py +++ /dev/null @@ -1,181 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -import ddt -from oslo_serialization import jsonutils - -from kuryr import app -from kuryr.common import constants as const -from kuryr.tests.unit import base -from kuryr import utils - - -@ddt.ddt -class TestKuryrNetworkPreExisting(base.TestKuryrBase): - - def _ids(self): - docker_network_id = utils.get_hash() - fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - fake_response = { - 'networks': - [ - { - "status": "ACTIVE", - "subnets": [], - "admin_state_up": True, - "tenant_id": "9bacb3c5d39d41a79512987f338cf177", - "router:external": False, - "segments": [], - "shared": False, - "id": fake_neutron_net_id - } - ] - } - return docker_network_id, fake_neutron_net_id, fake_response - - @ddt.data( - (True), (False)) - def test_create_network_pre_existing(self, use_tags): - if not use_tags: - self.mox.StubOutWithMock(app, "tag") - app.tag = use_tags - - docker_network_id, fake_neutron_net_id, fake_response = self._ids() - - self.mox.StubOutWithMock(app.neutron, "list_networks") - app.neutron.list_networks(id=fake_neutron_net_id).AndReturn( - fake_response) - - if app.tag: - self.mox.StubOutWithMock(app.neutron, "add_tag") - tags = utils.create_net_tags(docker_network_id) - for tag in tags: - app.neutron.add_tag('networks', fake_neutron_net_id, tag) - app.neutron.add_tag('networks', fake_neutron_net_id, - const.KURYR_EXISTING_NEUTRON_NET) - else: - self.mox.StubOutWithMock(app.neutron, "update_network") - app.neutron.update_network( - fake_neutron_net_id, {'network': - {'name': docker_network_id}}).AndReturn( - fake_response) - - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - fake_existing_subnets_response = { - "subnets": [] - } - fake_cidr_v4 = '192.168.42.0/24' - app.neutron.list_subnets( - network_id=fake_neutron_net_id, - cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response) - - self.mox.StubOutWithMock(app.neutron, 'create_subnet') - fake_subnet_request = { - "subnets": [{ - 'name': fake_cidr_v4, - 'network_id': fake_neutron_net_id, - 'ip_version': 4, - 'cidr': fake_cidr_v4, - 'enable_dhcp': app.enable_dhcp, - 'gateway_ip': '192.168.42.1', - }] - } - subnet_v4_id = str(uuid.uuid4()) - fake_v4_subnet = self._get_fake_v4_subnet( - fake_neutron_net_id, subnet_v4_id, - name=fake_cidr_v4, cidr=fake_cidr_v4) - fake_subnet_response = { - 'subnets': [ - fake_v4_subnet['subnet'] - ] - } - app.neutron.create_subnet( - fake_subnet_request).AndReturn(fake_subnet_response) - - self.mox.ReplayAll() - - network_request = { - 'NetworkID': docker_network_id, - 'IPv4Data': [{ - 'AddressSpace': 'foo', - 'Pool': '192.168.42.0/24', - 'Gateway': '192.168.42.1/24', - }], - 'IPv6Data': [{ - 'AddressSpace': 'bar', - 'Pool': 'fe80::/64', - 'Gateway': 'fe80::f816:3eff:fe20:57c3/64', - }], - 'Options': { - const.NETWORK_GENERIC_OPTIONS: { - const.NEUTRON_UUID_OPTION: fake_neutron_net_id - } - } - } - response = self.app.post('/NetworkDriver.CreateNetwork', - content_type='application/json', - data=jsonutils.dumps(network_request)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(const.SCHEMA['SUCCESS'], decoded_json) - - @ddt.data( - (True), (False)) - def test_delete_network_pre_existing(self, use_tags): - if not use_tags: - self.mox.StubOutWithMock(app, "tag") - app.tag = use_tags - - docker_network_id, fake_neutron_net_id, fake_response = self._ids() - - if app.tag: - self.mox.StubOutWithMock(app.neutron, 'list_networks') - t = utils.make_net_tags(docker_network_id) - te = t + ',' + const.KURYR_EXISTING_NEUTRON_NET - app.neutron.list_networks(tags=te).AndReturn( - fake_response) - - self.mox.StubOutWithMock(app.neutron, "remove_tag") - tags = utils.create_net_tags(docker_network_id) - for tag in tags: - app.neutron.remove_tag('networks', fake_neutron_net_id, tag) - app.neutron.remove_tag('networks', fake_neutron_net_id, - const.KURYR_EXISTING_NEUTRON_NET) - else: - - self.mox.StubOutWithMock(app.neutron, 'list_networks') - app.neutron.list_networks(name=docker_network_id).AndReturn( - fake_response) - - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - fake_existing_subnets_response = { - "subnets": [] - } - app.neutron.list_subnets( - network_id=fake_neutron_net_id).AndReturn( - fake_existing_subnets_response) - - self.mox.StubOutWithMock(app.neutron, 'delete_network') - app.neutron.delete_network(fake_neutron_net_id).AndReturn(None) - - self.mox.ReplayAll() - data = {'NetworkID': docker_network_id} - response = self.app.post('/NetworkDriver.DeleteNetwork', - content_type='application/json', - data=jsonutils.dumps(data)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(const.SCHEMA['SUCCESS'], decoded_json) diff --git a/kuryr/tests/unit/test_kuryr_ipam.py b/kuryr/tests/unit/test_kuryr_ipam.py deleted file mode 100644 index 1e17dc9f..00000000 --- a/kuryr/tests/unit/test_kuryr_ipam.py +++ /dev/null @@ -1,485 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import ddt -from oslo_serialization import jsonutils -import uuid - -from kuryr.common import config -from kuryr.common import constants as const -from kuryr.controllers import app -from kuryr.tests.unit import base -from kuryr import utils - - -FAKE_IP4_CIDR = '10.0.0.0/16' - - -@ddt.ddt -class TestKuryrIpam(base.TestKuryrBase): - """Basic unit tests for libnetwork remote IPAM driver URI endpoints. - - This test class covers the following HTTP methods and URIs as described in - the remote IPAM driver specification as below: - - https://github.com/docker/libnetwork/blob/9bf339f27e9f5c7c922036706c9bcc410899f249/docs/ipam.md # noqa - - - POST /IpamDriver.GetDefaultAddressSpaces - - POST /IpamDriver.RequestPool - - POST /IpamDriver.ReleasePool - - POST /IpamDriver.RequestAddress - - POST /IpamDriver.ReleaseAddress - """ - @ddt.data( - ('/IpamDriver.GetDefaultAddressSpaces', - {"LocalDefaultAddressSpace": - config.CONF.local_default_address_space, - "GlobalDefaultAddressSpace": - config.CONF.global_default_address_space}), - ('/IpamDriver.GetCapabilities', - {"RequiresMACAddress": False})) - @ddt.unpack - def test_remote_ipam_driver_endpoint(self, endpoint, expected): - response = self.app.post(endpoint) - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(expected, decoded_json) - - def test_ipam_driver_request_pool_with_user_pool(self): - pool_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR) - new_subnetpool = { - 'name': pool_name, - 'default_prefixlen': 16, - 'prefixes': [FAKE_IP4_CIDR]} - - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - fake_kuryr_subnetpool_id = str(uuid.uuid4()) - fake_name = pool_name - kuryr_subnetpools = self._get_fake_v4_subnetpools( - fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR], - name=fake_name) - app.neutron.list_subnetpools(name=fake_name).AndReturn( - {'subnetpools': []}) - fake_subnetpool_response = { - 'subnetpool': kuryr_subnetpools['subnetpools'][0] - } - - self.mox.StubOutWithMock(app.neutron, 'create_subnetpool') - app.neutron.create_subnetpool( - {'subnetpool': new_subnetpool}).AndReturn(fake_subnetpool_response) - - self.mox.ReplayAll() - - fake_request = { - 'AddressSpace': '', - 'Pool': FAKE_IP4_CIDR, - 'SubPool': '', # In the case --ip-range is not given - 'Options': {}, - 'V6': False - } - response = self.app.post('/IpamDriver.RequestPool', - content_type='application/json', - data=jsonutils.dumps(fake_request)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(fake_kuryr_subnetpool_id, decoded_json['PoolID']) - - def test_ipam_driver_request_pool_with_pool_name_option(self): - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - fake_kuryr_subnetpool_id = str(uuid.uuid4()) - fake_name = 'fake_pool_name' - new_subnetpool = { - 'name': fake_name, - 'default_prefixlen': 16, - 'prefixes': [FAKE_IP4_CIDR]} - - kuryr_subnetpools = self._get_fake_v4_subnetpools( - fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR], - name=fake_name) - fake_subnetpool_response = { - 'subnetpool': kuryr_subnetpools['subnetpools'][0] - } - - self.mox.StubOutWithMock(app.neutron, 'create_subnetpool') - app.neutron.create_subnetpool( - {'subnetpool': new_subnetpool}).AndReturn(fake_subnetpool_response) - - self.mox.ReplayAll() - - fake_request = { - 'AddressSpace': '', - 'Pool': FAKE_IP4_CIDR, - 'SubPool': '', # In the case --ip-range is not given - 'Options': {'neutron.pool.name': 'fake_pool_name'}, - 'V6': False - } - response = self.app.post('/IpamDriver.RequestPool', - content_type='application/json', - data=jsonutils.dumps(fake_request)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(fake_kuryr_subnetpool_id, decoded_json['PoolID']) - - def test_ipam_driver_request_pool_with_default_v6pool(self): - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - fake_kuryr_subnetpool_id = str(uuid.uuid4()) - fake_name = 'kuryr6' - kuryr_subnetpools = self._get_fake_v6_subnetpools( - fake_kuryr_subnetpool_id, prefixes=['fe80::/64']) - app.neutron.list_subnetpools(name=fake_name).AndReturn( - {'subnetpools': kuryr_subnetpools['subnetpools']}) - - self.mox.ReplayAll() - - fake_request = { - 'AddressSpace': '', - 'Pool': '', - 'SubPool': '', # In the case --ip-range is not given - 'Options': {}, - 'V6': True - } - response = self.app.post('/IpamDriver.RequestPool', - content_type='application/json', - data=jsonutils.dumps(fake_request)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual(fake_kuryr_subnetpool_id, decoded_json['PoolID']) - - def test_ipam_driver_release_pool(self): - fake_kuryr_subnetpool_id = str(uuid.uuid4()) - self.mox.StubOutWithMock(app.neutron, 'delete_subnetpool') - app.neutron.delete_subnetpool(fake_kuryr_subnetpool_id).AndReturn( - {}) - - self.mox.ReplayAll() - - fake_request = { - 'PoolID': fake_kuryr_subnetpool_id - } - response = self.app.post('/IpamDriver.ReleasePool', - content_type='application/json', - data=jsonutils.dumps(fake_request)) - - self.assertEqual(200, response.status_code) - - def test_ipam_driver_request_address(self): - # faking list_subnetpools - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - fake_kuryr_subnetpool_id = str(uuid.uuid4()) - fake_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR) - kuryr_subnetpools = self._get_fake_v4_subnetpools( - fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR], - name=fake_name) - app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn( - kuryr_subnetpools) - - # faking list_subnets - docker_endpoint_id = utils.get_hash() - neutron_network_id = str(uuid.uuid4()) - subnet_v4_id = str(uuid.uuid4()) - fake_v4_subnet = self._get_fake_v4_subnet( - neutron_network_id, docker_endpoint_id, subnet_v4_id, - subnetpool_id=fake_kuryr_subnetpool_id, - cidr=FAKE_IP4_CIDR) - fake_subnet_response = { - 'subnets': [ - fake_v4_subnet['subnet'] - ] - } - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn( - fake_subnet_response) - - # faking create_port - fake_neutron_port_id = str(uuid.uuid4()) - fake_port = base.TestKuryrBase._get_fake_port( - docker_endpoint_id, neutron_network_id, - fake_neutron_port_id, const.PORT_STATUS_ACTIVE, - subnet_v4_id, - neutron_subnet_v4_address="10.0.0.5") - port_request = { - 'name': 'kuryr-unbound-port', - 'admin_state_up': True, - 'network_id': neutron_network_id, - 'binding:host_id': utils.get_hostname(), - } - fixed_ips = port_request['fixed_ips'] = [] - fixed_ip = {'subnet_id': subnet_v4_id} - fixed_ips.append(fixed_ip) - self.mox.StubOutWithMock(app.neutron, 'create_port') - app.neutron.create_port({'port': port_request}).AndReturn(fake_port) - - # Apply mocks - self.mox.ReplayAll() - - # Testing container ip allocation - fake_request = { - 'PoolID': fake_kuryr_subnetpool_id, - 'Address': '', # Querying for container address - 'Options': {} - } - response = self.app.post('/IpamDriver.RequestAddress', - content_type='application/json', - data=jsonutils.dumps(fake_request)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual('10.0.0.5/16', decoded_json['Address']) - - def test_ipam_driver_request_address_overlapping_cidr(self): - # faking list_subnetpools - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - - fake_kuryr_subnetpool_id = str(uuid.uuid4()) - fake_kuryr_subnetpool_id2 = str(uuid.uuid4()) - - fake_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR) - kuryr_subnetpools = self._get_fake_v4_subnetpools( - fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR], - name=fake_name) - app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn( - kuryr_subnetpools) - - # faking list_subnets - docker_endpoint_id = utils.get_hash() - - neutron_network_id = str(uuid.uuid4()) - neutron_network_id2 = str(uuid.uuid4()) - - neutron_subnet_v4_id = str(uuid.uuid4()) - neutron_subnet_v4_id2 = str(uuid.uuid4()) - - fake_v4_subnet = self._get_fake_v4_subnet( - neutron_network_id, docker_endpoint_id, neutron_subnet_v4_id, - subnetpool_id=fake_kuryr_subnetpool_id, - cidr=FAKE_IP4_CIDR) - - fake_v4_subnet2 = self._get_fake_v4_subnet( - neutron_network_id2, docker_endpoint_id, neutron_subnet_v4_id2, - subnetpool_id=fake_kuryr_subnetpool_id2, - cidr=FAKE_IP4_CIDR) - - fake_subnet_response = { - 'subnets': [ - fake_v4_subnet2['subnet'], - fake_v4_subnet['subnet'] - ] - } - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn( - fake_subnet_response) - # faking create_port - fake_neutron_port_id = str(uuid.uuid4()) - fake_port = base.TestKuryrBase._get_fake_port( - docker_endpoint_id, neutron_network_id, - fake_neutron_port_id, - neutron_subnet_v4_id=neutron_subnet_v4_id, - neutron_subnet_v4_address="10.0.0.5") - port_request = { - 'name': 'kuryr-unbound-port', - 'admin_state_up': True, - 'network_id': neutron_network_id, - 'binding:host_id': utils.get_hostname(), - } - port_request['fixed_ips'] = [] - fixed_ip = {'subnet_id': neutron_subnet_v4_id} - port_request['fixed_ips'].append(fixed_ip) - self.mox.StubOutWithMock(app.neutron, 'create_port') - app.neutron.create_port({'port': port_request}).AndReturn(fake_port) - - # Apply mocks - self.mox.ReplayAll() - - # Testing container ip allocation - fake_request = { - 'PoolID': fake_kuryr_subnetpool_id, - 'Address': '', # Querying for container address - 'Options': {} - } - response = self.app.post('/IpamDriver.RequestAddress', - content_type='application/json', - data=jsonutils.dumps(fake_request)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual('10.0.0.5/16', decoded_json['Address']) - - def test_ipam_driver_request_address_for_same_gateway(self): - # faking list_subnetpools - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - fake_kuryr_subnetpool_id = str(uuid.uuid4()) - fake_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR) - kuryr_subnetpools = self._get_fake_v4_subnetpools( - fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR], - name=fake_name) - app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn( - kuryr_subnetpools) - - # faking list_subnets - docker_endpoint_id = utils.get_hash() - neutron_network_id = str(uuid.uuid4()) - subnet_v4_id = str(uuid.uuid4()) - fake_v4_subnet = self._get_fake_v4_subnet( - neutron_network_id, docker_endpoint_id, subnet_v4_id, - subnetpool_id=fake_kuryr_subnetpool_id, - cidr=FAKE_IP4_CIDR) - fake_v4_subnet['subnet'].update(gateway_ip='10.0.0.1') - fake_subnet_response = { - 'subnets': [ - fake_v4_subnet['subnet'] - ] - } - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn( - fake_subnet_response) - - # Apply mocks - self.mox.ReplayAll() - - # Testing container ip allocation - fake_request = { - 'PoolID': fake_kuryr_subnetpool_id, - 'Address': '10.0.0.1', - 'Options': { - const.REQUEST_ADDRESS_TYPE: const.NETWORK_GATEWAY_OPTIONS - } - } - response = self.app.post('/IpamDriver.RequestAddress', - content_type='application/json', - data=jsonutils.dumps(fake_request)) - - self.assertEqual(200, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertEqual('10.0.0.1/16', decoded_json['Address']) - - def test_ipam_driver_request_address_for_different_gateway(self): - # faking list_subnetpools - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - fake_kuryr_subnetpool_id = str(uuid.uuid4()) - fake_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR) - kuryr_subnetpools = self._get_fake_v4_subnetpools( - fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR], - name=fake_name) - app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn( - kuryr_subnetpools) - - # faking list_subnets - docker_endpoint_id = utils.get_hash() - neutron_network_id = str(uuid.uuid4()) - subnet_v4_id = str(uuid.uuid4()) - fake_v4_subnet = self._get_fake_v4_subnet( - neutron_network_id, docker_endpoint_id, subnet_v4_id, - subnetpool_id=fake_kuryr_subnetpool_id, - cidr=FAKE_IP4_CIDR) - fake_v4_subnet['subnet'].update(gateway_ip='10.0.0.1') - fake_subnet_response = { - 'subnets': [ - fake_v4_subnet['subnet'] - ] - } - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn( - fake_subnet_response) - - # Apply mocks - self.mox.ReplayAll() - - # Testing container ip allocation - fake_request = { - 'PoolID': fake_kuryr_subnetpool_id, - 'Address': '10.0.0.5', # Different with existed gw ip - 'Options': { - const.REQUEST_ADDRESS_TYPE: const.NETWORK_GATEWAY_OPTIONS - } - } - response = self.app.post('/IpamDriver.RequestAddress', - content_type='application/json', - data=jsonutils.dumps(fake_request)) - - self.assertEqual(500, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - err_message = ("Requested gateway {0} does not match with " - "gateway {1} in existed network.").format( - '10.0.0.5', '10.0.0.1') - self.assertEqual({'Err': err_message}, decoded_json) - - def test_ipam_driver_release_address(self): - # faking list_subnetpools - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - fake_kuryr_subnetpool_id = str(uuid.uuid4()) - fake_name = str('-'.join(['kuryrPool', FAKE_IP4_CIDR])) - kuryr_subnetpools = self._get_fake_v4_subnetpools( - fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR], name=fake_name) - app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn( - kuryr_subnetpools) - fake_ip4 = '10.0.0.5' - - # faking list_subnets - docker_network_id = utils.get_hash() - docker_endpoint_id = utils.get_hash() - neutron_network_id = docker_network_id = str(uuid.uuid4()) - subnet_v4_id = str(uuid.uuid4()) - fake_v4_subnet = self._get_fake_v4_subnet( - docker_network_id, docker_endpoint_id, subnet_v4_id, - subnetpool_id=fake_kuryr_subnetpool_id, - cidr=FAKE_IP4_CIDR) - fake_subnet_response = { - 'subnets': [ - fake_v4_subnet['subnet'] - ] - } - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn( - fake_subnet_response) - - #faking list_ports and delete_port - fake_neutron_port_id = str(uuid.uuid4()) - fake_port = base.TestKuryrBase._get_fake_port( - docker_endpoint_id, neutron_network_id, - fake_neutron_port_id, const.PORT_STATUS_ACTIVE, - subnet_v4_id, - neutron_subnet_v4_address=fake_ip4) - port_request = { - 'name': 'demo-port', - 'admin_state_up': True, - 'network_id': neutron_network_id, - } - rel_fixed_ips = port_request['fixed_ips'] = [] - fixed_ip = {'subnet_id': subnet_v4_id} - fixed_ip['ip_address'] = fake_ip4 - rel_fixed_ips.append(fixed_ip) - self.mox.StubOutWithMock(app.neutron, 'list_ports') - - list_port_response = {'ports': [fake_port['port']]} - app.neutron.list_ports().AndReturn( - list_port_response) - - self.mox.StubOutWithMock(app.neutron, 'delete_port') - app.neutron.delete_port(fake_port['port']['id']).AndReturn({}) - - # Apply mocks - self.mox.ReplayAll() - - fake_request = { - 'PoolID': fake_kuryr_subnetpool_id, - 'Address': fake_ip4 - } - - response = self.app.post('/IpamDriver.ReleaseAddress', - content_type='application/json', - data=jsonutils.dumps(fake_request)) - - self.assertEqual(200, response.status_code) diff --git a/kuryr/tests/unit/test_kuryr_network.py b/kuryr/tests/unit/test_kuryr_network.py deleted file mode 100644 index 00bc8a50..00000000 --- a/kuryr/tests/unit/test_kuryr_network.py +++ /dev/null @@ -1,256 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ddt import data -from ddt import ddt -from neutronclient.common import exceptions -from oslo_serialization import jsonutils - -from kuryr import app -from kuryr.common import constants as const -from kuryr.tests.unit import base -from kuryr import utils - - -class TestKuryrNetworkCreateFailures(base.TestKuryrFailures): - """Unittests for the failures for creating networks. - - This test covers error responses listed in the spec: - http://developer.openstack.org/api-ref-networking-v2-ext.html#createProviderNetwork # noqa - """ - - def _create_network_with_exception(self, network_name, ex): - self.mox.StubOutWithMock(app.neutron, "create_network") - fake_request = { - "network": { - "name": utils.make_net_name(network_name), - "admin_state_up": True - } - } - app.neutron.create_network(fake_request).AndRaise(ex) - self.mox.ReplayAll() - - def _invoke_create_request(self, network_name): - network_request = { - 'NetworkID': network_name, - 'IPv4Data': [{ - 'AddressSpace': 'foo', - 'Pool': '192.168.42.0/24', - 'Gateway': '192.168.42.1/24', - 'AuxAddresses': {} - }], - 'IPv6Data': [{ - 'AddressSpace': 'bar', - 'Pool': 'fe80::/64', - 'Gateway': 'fe80::f816:3eff:fe20:57c3/64', - 'AuxAddresses': {} - }], - 'Options': {} - } - response = self.app.post('/NetworkDriver.CreateNetwork', - content_type='application/json', - data=jsonutils.dumps(network_request)) - return response - - def test_create_network_unauthorized(self): - docker_network_id = utils.get_hash() - self._create_network_with_exception( - docker_network_id, exceptions.Unauthorized()) - - response = self._invoke_create_request(docker_network_id) - - self.assertEqual(401, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - self.assertEqual( - {'Err': exceptions.Unauthorized.message}, decoded_json) - - def test_create_network_bad_request(self): - invalid_docker_network_id = 'id-should-be-hexdigits' - response = self._invoke_create_request(invalid_docker_network_id) - - self.assertEqual(400, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - # TODO(tfukushima): Add the better error message validation. - self.assertIn(invalid_docker_network_id, decoded_json['Err']) - self.assertIn('NetworkID', decoded_json['Err']) - - -@ddt -class TestKuryrNetworkDeleteFailures(base.TestKuryrFailures): - """Unittests for the failures for deleting networks. - - This test covers error responses listed in the spec: - http://developer.openstack.org/api-ref-networking-v2-ext.html#deleteProviderNetwork # noqa - """ - def _delete_network_with_exception(self, network_id, ex): - fake_neutron_network_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - no_networks_response = { - "networks": [] - } - if ex == exceptions.NotFound: - fake_networks_response = no_networks_response - else: - fake_networks_response = { - "networks": [{ - "status": "ACTIVE", - "subnets": [], - "name": network_id, - "admin_state_up": True, - "tenant_id": "9bacb3c5d39d41a79512987f338cf177", - "router:external": False, - "segments": [], - "shared": False, - "id": fake_neutron_network_id - }] - } - self.mox.StubOutWithMock(app.neutron, 'list_networks') - t = utils.make_net_tags(network_id) - te = t + ',' + const.KURYR_EXISTING_NEUTRON_NET - app.neutron.list_networks(tags=te).AndReturn(no_networks_response) - app.neutron.list_networks(tags=t).AndReturn(fake_networks_response) - subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031" - subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51" - - docker_network_id = utils.get_hash() - docker_endpoint_id = utils.get_hash() - - fake_v4_subnet = self._get_fake_v4_subnet( - docker_network_id, docker_endpoint_id, subnet_v4_id) - fake_v6_subnet = self._get_fake_v6_subnet( - docker_network_id, docker_endpoint_id, subnet_v6_id) - fake_subnets_response = { - "subnets": [ - fake_v4_subnet['subnet'], - fake_v6_subnet['subnet'] - ] - } - - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - app.neutron.list_subnets(network_id=fake_neutron_network_id).AndReturn( - fake_subnets_response) - - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - fake_subnetpools_response = {"subnetpools": []} - app.neutron.list_subnetpools(name='kuryr').AndReturn( - fake_subnetpools_response) - app.neutron.list_subnetpools(name='kuryr6').AndReturn( - fake_subnetpools_response) - - self.mox.StubOutWithMock(app.neutron, 'delete_subnet') - app.neutron.delete_subnet(subnet_v4_id).AndReturn(None) - app.neutron.delete_subnet(subnet_v6_id).AndReturn(None) - - self.mox.StubOutWithMock(app.neutron, 'delete_network') - app.neutron.delete_network(fake_neutron_network_id).AndRaise(ex) - self.mox.ReplayAll() - - def _delete_network_with_subnet_exception(self, network_id, ex): - fake_neutron_network_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - no_networks_response = { - "networks": [] - } - fake_networks_response = { - "networks": [{ - "status": "ACTIVE", - "subnets": [], - "name": network_id, - "admin_state_up": True, - "tenant_id": "9bacb3c5d39d41a79512987f338cf177", - "router:external": False, - "segments": [], - "shared": False, - "id": fake_neutron_network_id - }] - } - self.mox.StubOutWithMock(app.neutron, 'list_networks') - t = utils.make_net_tags(network_id) - te = t + ',' + const.KURYR_EXISTING_NEUTRON_NET - app.neutron.list_networks(tags=te).AndReturn(no_networks_response) - app.neutron.list_networks(tags=t).AndReturn(fake_networks_response) - subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031" - subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51" - - docker_network_id = utils.get_hash() - docker_endpoint_id = utils.get_hash() - - fake_v4_subnet = self._get_fake_v4_subnet( - docker_network_id, docker_endpoint_id, subnet_v4_id) - fake_v6_subnet = self._get_fake_v6_subnet( - docker_network_id, docker_endpoint_id, subnet_v6_id) - fake_subnets_response = { - "subnets": [ - fake_v4_subnet['subnet'], - fake_v6_subnet['subnet'] - ] - } - - self.mox.StubOutWithMock(app.neutron, 'list_subnets') - app.neutron.list_subnets(network_id=fake_neutron_network_id).AndReturn( - fake_subnets_response) - - self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') - fake_subnetpools_response = {"subnetpools": []} - app.neutron.list_subnetpools(name='kuryr').AndReturn( - fake_subnetpools_response) - app.neutron.list_subnetpools(name='kuryr6').AndReturn( - fake_subnetpools_response) - - self.mox.StubOutWithMock(app.neutron, 'delete_subnet') - app.neutron.delete_subnet(subnet_v4_id).AndRaise(ex) - self.mox.ReplayAll() - - def _invoke_delete_request(self, network_name): - data = {'NetworkID': network_name} - response = self.app.post('/NetworkDriver.DeleteNetwork', - content_type='application/json', - data=jsonutils.dumps(data)) - return response - - @data(exceptions.Unauthorized, exceptions.NotFound, exceptions.Conflict) - def test_delete_network_failures(self, GivenException): - docker_network_id = utils.get_hash() - self._delete_network_with_exception( - docker_network_id, GivenException()) - - response = self._invoke_delete_request(docker_network_id) - - self.assertEqual(GivenException.status_code, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - self.assertEqual({'Err': GivenException.message}, decoded_json) - - def test_delete_network_bad_request(self): - invalid_docker_network_id = 'invalid-network-id' - - response = self._invoke_delete_request(invalid_docker_network_id) - - self.assertEqual(400, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - self.assertIn(invalid_docker_network_id, decoded_json['Err']) - self.assertIn('NetworkID', decoded_json['Err']) - - @data(exceptions.Unauthorized, exceptions.NotFound, exceptions.Conflict) - def test_delete_network_with_subnet_deletion_failures(self, - GivenException): - docker_network_id = utils.get_hash() - self._delete_network_with_subnet_exception( - docker_network_id, GivenException()) - - response = self._invoke_delete_request(docker_network_id) - - self.assertEqual(GivenException.status_code, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - self.assertEqual({'Err': GivenException.message}, decoded_json) diff --git a/kuryr/tests/unit/test_leave.py b/kuryr/tests/unit/test_leave.py deleted file mode 100644 index a2e1be5d..00000000 --- a/kuryr/tests/unit/test_leave.py +++ /dev/null @@ -1,104 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -import ddt -from oslo_concurrency import processutils -from oslo_serialization import jsonutils -from werkzeug import exceptions as w_exceptions - -from kuryr import app -from kuryr import binding -from kuryr.common import constants as const -from kuryr.common import exceptions -from kuryr.tests.unit import base -from kuryr import utils - - -@ddt.ddt -class TestKuryrLeaveFailures(base.TestKuryrFailures): - """Unit tests for the failures for unbinding a Neutron port.""" - def _invoke_leave_request(self, docker_network_id, - docker_endpoint_id): - data = { - 'NetworkID': docker_network_id, - 'EndpointID': docker_endpoint_id, - } - response = self.app.post('/NetworkDriver.Leave', - content_type='application/json', - data=jsonutils.dumps(data)) - - return response - - def _port_unbind_with_exception(self, docker_endpoint_id, - neutron_port, ex): - fake_unbinding_response = ('fake stdout', '') - self.mox.StubOutWithMock(binding, 'port_unbind') - if ex: - binding.port_unbind(docker_endpoint_id, neutron_port).AndRaise(ex) - else: - binding.port_unbind(docker_endpoint_id, neutron_port).AndReturn( - fake_unbinding_response) - self.mox.ReplayAll() - - return fake_unbinding_response - - @ddt.data(exceptions.VethDeletionFailure, - processutils.ProcessExecutionError) - def test_leave_unbinding_failure(self, GivenException): - fake_docker_network_id = utils.get_hash() - fake_docker_endpoint_id = utils.get_hash() - - fake_neutron_network_id = str(uuid.uuid4()) - self._mock_out_network(fake_neutron_network_id, fake_docker_network_id) - fake_neutron_port_id = str(uuid.uuid4()) - self.mox.StubOutWithMock(app.neutron, 'list_ports') - neutron_port_name = utils.get_neutron_port_name( - fake_docker_endpoint_id) - fake_neutron_v4_subnet_id = str(uuid.uuid4()) - fake_neutron_v6_subnet_id = str(uuid.uuid4()) - fake_neutron_ports_response = self._get_fake_ports( - fake_docker_endpoint_id, fake_neutron_network_id, - fake_neutron_port_id, const.PORT_STATUS_ACTIVE, - fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id) - app.neutron.list_ports(name=neutron_port_name).AndReturn( - fake_neutron_ports_response) - fake_neutron_port = fake_neutron_ports_response['ports'][0] - - fake_message = "fake message" - fake_exception = GivenException(fake_message) - self._port_unbind_with_exception( - fake_docker_endpoint_id, fake_neutron_port, fake_exception) - - response = self._invoke_leave_request( - fake_docker_network_id, fake_docker_endpoint_id) - - self.assertEqual( - w_exceptions.InternalServerError.code, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - self.assertIn(fake_message, decoded_json['Err']) - - def test_leave_bad_request(self): - fake_docker_network_id = utils.get_hash() - invalid_docker_endpoint_id = 'id-should-be-hexdigits' - - response = self._invoke_leave_request( - fake_docker_network_id, invalid_docker_endpoint_id) - - self.assertEqual(w_exceptions.BadRequest.code, response.status_code) - decoded_json = jsonutils.loads(response.data) - self.assertIn('Err', decoded_json) - # TODO(tfukushima): Add the better error message validation. - self.assertIn(invalid_docker_endpoint_id, decoded_json['Err']) - self.assertIn('EndpointID', decoded_json['Err']) diff --git a/kuryr/tests/unit/test_utils.py b/kuryr/tests/unit/test_utils.py index 1a1a7249..af56b216 100644 --- a/kuryr/tests/unit/test_utils.py +++ b/kuryr/tests/unit/test_utils.py @@ -13,30 +13,18 @@ import uuid import ddt + from oslo_config import cfg -from kuryr.common import constants as const +from kuryr.lib import constants as const +from kuryr.lib import utils from kuryr.tests.unit import base -from kuryr import utils @ddt.ddt -class TestKuryrUtils(base.TestKuryrBase): +class TestKuryrUtils(base.TestCase): """Unit tests for utilities.""" - @ddt.data(utils.get_hash(), '51c75a2515d4' '51c75a') - def test_get_sandbox_key(self, fake_container_id): - sandbox_key = utils.get_sandbox_key(fake_container_id) - expected = '/'.join([utils.DOCKER_NETNS_BASE, fake_container_id[:12]]) - self.assertEqual(expected, sandbox_key) - - def test_get_port_name(self): - fake_docker_endpoint_id = utils.get_hash() - generated_neutron_port_name = utils.get_neutron_port_name( - fake_docker_endpoint_id) - self.assertIn(utils.PORT_POSTFIX, generated_neutron_port_name) - self.assertIn(fake_docker_endpoint_id, generated_neutron_port_name) - def test_get_veth_pair_names(self): fake_neutron_port_id = str(uuid.uuid4()) generated_ifname, generated_peer = utils.get_veth_pair_names( @@ -60,18 +48,3 @@ class TestKuryrUtils(base.TestKuryrBase): name_prefix = cfg.CONF.subnetpool_name_prefix self.assertIn(name_prefix, generated_neutron_subnetpool_name) self.assertIn(fake_subnet_cidr, generated_neutron_subnetpool_name) - - def test_get_dict_format_fixed_ips_from_kv_format(self): - fake_fixed_ips_kv_format = \ - ['subnet_id=5083bda8-1b7c-4625-97f3-1d4c33bfeea8', - 'ip_address=192.168.1.2', - 'subnet_id=6607a230-f3eb-4937-b09f-9dd659211139', - 'ip_address=fdfa:8456:1afa:0:f816:3eff:fe67:885e'] - expected_dict_form = \ - [{'subnet_id': '5083bda8-1b7c-4625-97f3-1d4c33bfeea8', - 'ip_address': '192.168.1.2'}, - {'subnet_id': '6607a230-f3eb-4937-b09f-9dd659211139', - 'ip_address': 'fdfa:8456:1afa:0:f816:3eff:fe67:885e'}] - fixed_ips = utils.get_dict_format_fixed_ips_from_kv_format( - fake_fixed_ips_kv_format) - self.assertEqual(expected_dict_form, fixed_ips) diff --git a/setup.cfg b/setup.cfg index b668a91d..c130907c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,10 +22,7 @@ classifier = [entry_points] oslo.config.opts = - kuryr = kuryr.opts:list_kuryr_opts - -console_scripts = - kuryr-server = kuryr.server:start + kuryr = kuryr.lib.opts:list_kuryr_opts [files] packages = @@ -38,7 +35,6 @@ data_files = usr/libexec/kuryr/ovs usr/libexec/kuryr/tap usr/libexec/kuryr/unbound - /usr/lib/docker/plugins/kuryr = etc/kuryr.spec [build_sphinx] source-dir = doc/source