From b25eca0d7dbbc63b6db7a3ed9fa471f247857e15 Mon Sep 17 00:00:00 2001 From: Mohammad Banikazemi Date: Mon, 28 Mar 2016 15:18:39 -0400 Subject: [PATCH] Support for existing Neutron nets An existing Neutron network can be specified as the network being used for a Docker network being created. The Neutron network id or name can be specified. If a Docker network is deleted, the corresponding pre existing Neutron network will not be deleted. Usage: docker network create -d kuryr --ipam-driver=kuryr --subnet=10.10.0.0/24 --gateway=10.10.0.1 -o neutron.net.uuid=d98d1259-03d1-4b45-9b86-b039cba1d90d mynet docker network create -d kuryr --ipam-driver=kuryr --subnet=10.10.0.0/24 --gateway=10.10.0.1 -o neutron.net.name=my_neutron_net mynet If subnet being specified does not exist, it will be created by Kuryr. If exists it will be used. Blueprint existing-neutron-network Change-Id: I570aa4e77c906d3f04768e882f02050cd0cad558 --- kuryr/common/constants.py | 5 + kuryr/controllers.py | 92 ++++++++--- kuryr/tests/unit/base.py | 14 +- kuryr/tests/unit/test_kuryr.py | 76 ++++----- .../tests/unit/test_kuryr_existing_network.py | 147 ++++++++++++++++++ kuryr/tests/unit/test_kuryr_network.py | 15 +- 6 files changed, 288 insertions(+), 61 deletions(-) create mode 100644 kuryr/tests/unit/test_kuryr_existing_network.py diff --git a/kuryr/common/constants.py b/kuryr/common/constants.py index b710d503..8ea7f262 100644 --- a/kuryr/common/constants.py +++ b/kuryr/common/constants.py @@ -23,3 +23,8 @@ DEVICE_OWNER = 'kuryr:container' NEUTRON_ID_LH_OPTION = 'kuryr.net.uuid.lh' NEUTRON_ID_UH_OPTION = 'kuryr.net.uuid.uh' NET_NAME_PREFIX = 'kuryr-net-' + +NETWORK_GENERIC_OPTIONS = 'com.docker.network.generic' +NEUTRON_UUID_OPTION = 'neutron.net.uuid' +NEUTRON_NAME_OPTION = 'neutron.net.name' +KURYR_EXISTING_NEUTRON_NET = 'kuryr.net.existing' diff --git a/kuryr/controllers.py b/kuryr/controllers.py index 05706f7a..1a96b880 100644 --- a/kuryr/controllers.py +++ b/kuryr/controllers.py @@ -327,10 +327,24 @@ def _create_or_update_port(neutron_network_id, endpoint_id, return response_interface -def _neutron_add_tags(netid, tag): +def _neutron_net_add_tag(netid, tag): + app.neutron.add_tag('networks', netid, tag) + + +def _neutron_net_add_tags(netid, tag): tags = utils.create_net_tags(tag) for tag in tags: - app.neutron.add_tag('networks', netid, tag) + _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) @app.route('/Plugin.Activate', methods=['POST']) @@ -449,23 +463,50 @@ def network_driver_create_network(): app.logger.debug("gateway_cidr {0}, gateway_ip {1}" .format(gateway_cidr, gateway_ip)) - network = app.neutron.create_network( - {'network': {'name': neutron_network_name, "admin_state_up": True}}) - _neutron_add_tags(network['network']['id'], container_net_id) + neutron_uuid = None + neutron_name = None + options = json_data.get('Options') + if options: + generic_options = options.get(const.NETWORK_GENERIC_OPTIONS) + if generic_options: + neutron_uuid = generic_options.get(const.NEUTRON_UUID_OPTION) + neutron_name = generic_options.get(const.NEUTRON_NAME_OPTION) - app.logger.info(_LI("Created a new network with name {0}" - " successfully: {1}") - .format(neutron_network_name, network)) + if not neutron_uuid and not neutron_name: + network = app.neutron.create_network( + {'network': {'name': neutron_network_name, + "admin_state_up": True}}) + network_id = network['network']['id'] + _neutron_net_add_tags(network['network']['id'], container_net_id) + + app.logger.info(_LI("Created a new network with name {0}" + " successfully: {1}") + .format(neutron_network_name, network)) + else: + try: + if neutron_uuid: + networks = _get_networks_by_attrs(id=neutron_uuid) + else: + networks = _get_networks_by_attrs(name=neutron_name) + network_id = networks[0]['id'] + except n_exceptions.NeutronClientException as ex: + app.logger.error(_LE("Error happened during listing " + "Neutron networks: {0}").format(ex)) + raise + _neutron_net_add_tags(network_id, container_net_id) + _neutron_net_add_tag(network_id, const.KURYR_EXISTING_NEUTRON_NET) + app.logger.info(_LI("Using existing network {0} successfully") + .format(neutron_uuid)) cidr = netaddr.IPNetwork(pool_cidr) subnet_network = str(cidr.network) subnet_cidr = '/'.join([subnet_network, str(cidr.prefixlen)]) subnets = _get_subnets_by_attrs( - network_id=network['network']['id'], cidr=subnet_cidr) + network_id=network_id, cidr=subnet_cidr) if not subnets: new_subnets = [{ 'name': pool_cidr, - 'network_id': network['network']['id'], + 'network_id': network_id, 'ip_version': cidr.version, 'cidr': subnet_cidr, 'enable_dhcp': app.enable_dhcp, @@ -498,21 +539,36 @@ def network_driver_delete_network(): " /NetworkDriver.DeleteNetwork".format(json_data)) jsonschema.validate(json_data, schemata.NETWORK_DELETE_SCHEMA) - neutron_network_tags = utils.make_net_tags(json_data['NetworkID']) + container_net_id = json_data['NetworkID'] + neutron_network_tags = utils.make_net_tags(container_net_id) + existing_network_tags = neutron_network_tags + ',' + existing_network_tags += const.KURYR_EXISTING_NEUTRON_NET + try: + existing_networks = _get_networks_by_attrs(tags=existing_network_tags) + except n_exceptions.NeutronClientException as ex: + app.logger.error(_LE("Error happened during listing " + "Neutron networks: {0}").format(ex)) + raise + + if existing_networks: + app.logger.warn(_LW("Network is a pre existing Neutron network, " + "not deleting in Neutron. removing tags: {0}") + .format(existing_network_tags)) + neutron_net_id = existing_networks[0]['id'] + _neutron_net_remove_tags(neutron_net_id, container_net_id) + _neutron_net_remove_tag(neutron_net_id, + const.KURYR_EXISTING_NEUTRON_NET) + return flask.jsonify(const.SCHEMA['SUCCESS']) + try: filtered_networks = _get_networks_by_attrs(tags=neutron_network_tags) except n_exceptions.NeutronClientException as ex: app.logger.error(_LE("Error happened during listing " "Neutron networks: {0}").format(ex)) raise - # We assume Neutron's Network names are not conflicted in Kuryr because - # they are Docker IDs, 256 bits hashed values, which are rarely conflicted. - # However, if there're multiple networks associated with the single - # NetworkID, it raises DuplicatedResourceException and stops processes. - # See the following doc for more details about Docker's IDs: - # https://github.com/docker/docker/blob/master/docs/terms/container.md#container-ids # noqa + if not filtered_networks: - app.logger.warn("Network with tags {0} cannot be found" + app.logger.warn(_LW("Network with tags {0} cannot be found") .format(neutron_network_tags)) else: neutron_network_id = filtered_networks[0]['id'] diff --git a/kuryr/tests/unit/base.py b/kuryr/tests/unit/base.py index 28990af5..b2821f73 100644 --- a/kuryr/tests/unit/base.py +++ b/kuryr/tests/unit/base.py @@ -14,6 +14,7 @@ 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 utils @@ -56,12 +57,15 @@ class TestKuryrBase(TestCase): self.mox.ReplayAll() return fake_unbinding_response - def _mock_out_network(self, neutron_network_id, docker_network_id): + 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": [], - "name": utils.make_net_name(docker_network_id), "admin_state_up": True, "tenant_id": "9bacb3c5d39d41a79512987f338cf177", "router:external": False, @@ -72,9 +76,13 @@ class TestKuryrBase(TestCase): } 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() + self.mox.ReplayAll() return neutron_network_id @staticmethod diff --git a/kuryr/tests/unit/test_kuryr.py b/kuryr/tests/unit/test_kuryr.py index 7ccf3edc..6cbf1c50 100644 --- a/kuryr/tests/unit/test_kuryr.py +++ b/kuryr/tests/unit/test_kuryr.py @@ -69,7 +69,7 @@ class TestKuryr(base.TestKuryrBase): } # The following fake response is retrieved from the Neutron doc: # http://developer.openstack.org/api-ref-networking-v2.html#createNetwork # noqa - fake_neutron_network_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c" fake_response = { "network": { "status": "ACTIVE", @@ -80,7 +80,7 @@ class TestKuryr(base.TestKuryrBase): "router:external": False, "segments": [], "shared": False, - "id": fake_neutron_network_id + "id": fake_neutron_net_id } } app.neutron.create_network(fake_request).AndReturn(fake_response) @@ -88,7 +88,7 @@ class TestKuryr(base.TestKuryrBase): 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_network_id, tag) + app.neutron.add_tag('networks', fake_neutron_net_id, tag) self.mox.StubOutWithMock(app.neutron, 'list_subnets') fake_existing_subnets_response = { @@ -96,14 +96,14 @@ class TestKuryr(base.TestKuryrBase): } fake_cidr_v4 = '192.168.42.0/24' app.neutron.list_subnets( - network_id=fake_neutron_network_id, + 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_network_id, + 'network_id': fake_neutron_net_id, 'ip_version': 4, 'cidr': fake_cidr_v4, 'enable_dhcp': app.enable_dhcp, @@ -112,7 +112,7 @@ class TestKuryr(base.TestKuryrBase): } subnet_v4_id = str(uuid.uuid4()) fake_v4_subnet = self._get_fake_v4_subnet( - fake_neutron_network_id, subnet_v4_id, + fake_neutron_net_id, subnet_v4_id, name=fake_cidr_v4, cidr=fake_cidr_v4) fake_subnet_response = { 'subnets': [ @@ -158,7 +158,7 @@ class TestKuryr(base.TestKuryrBase): } # The following fake response is retrieved from the Neutron doc: # http://developer.openstack.org/api-ref-networking-v2.html#createNetwork # noqa - fake_neutron_network_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c" fake_response = { "network": { "status": "ACTIVE", @@ -169,7 +169,7 @@ class TestKuryr(base.TestKuryrBase): "router:external": False, "segments": [], "shared": False, - "id": fake_neutron_network_id + "id": fake_neutron_net_id } } app.neutron.create_network(fake_request).AndReturn(fake_response) @@ -177,7 +177,7 @@ class TestKuryr(base.TestKuryrBase): 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_network_id, tag) + app.neutron.add_tag('networks', fake_neutron_net_id, tag) self.mox.StubOutWithMock(app.neutron, 'list_subnets') fake_existing_subnets_response = { @@ -185,14 +185,14 @@ class TestKuryr(base.TestKuryrBase): } fake_cidr_v4 = '192.168.42.0/24' app.neutron.list_subnets( - network_id=fake_neutron_network_id, + 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_network_id, + 'network_id': fake_neutron_net_id, 'ip_version': 4, 'cidr': fake_cidr_v4, 'enable_dhcp': app.enable_dhcp, @@ -200,7 +200,7 @@ class TestKuryr(base.TestKuryrBase): } subnet_v4_id = str(uuid.uuid4()) fake_v4_subnet = self._get_fake_v4_subnet( - fake_neutron_network_id, subnet_v4_id, + fake_neutron_net_id, subnet_v4_id, name=fake_cidr_v4, cidr=fake_cidr_v4) fake_subnet_response = { 'subnets': [ @@ -236,15 +236,16 @@ class TestKuryr(base.TestKuryrBase): def test_network_driver_delete_network(self): docker_network_id = hashlib.sha256( utils.getrandbits(256)).hexdigest() - fake_neutron_network_id = str(uuid.uuid4()) - self._mock_out_network(fake_neutron_network_id, docker_network_id) + 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_network_id).AndReturn( + 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_network_id).AndReturn(None) + app.neutron.delete_network(fake_neutron_net_id).AndReturn(None) self.mox.ReplayAll() data = {'NetworkID': docker_network_id} @@ -262,8 +263,9 @@ class TestKuryr(base.TestKuryrBase): docker_endpoint_id = hashlib.sha256( utils.getrandbits(256)).hexdigest() - fake_neutron_network_id = str(uuid.uuid4()) - self._mock_out_network(fake_neutron_network_id, docker_network_id) + 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" @@ -280,7 +282,7 @@ class TestKuryr(base.TestKuryrBase): } self.mox.StubOutWithMock(app.neutron, 'list_subnets') - app.neutron.list_subnets(network_id=fake_neutron_network_id).AndReturn( + app.neutron.list_subnets(network_id=fake_neutron_net_id).AndReturn( fake_subnets_response) self.mox.StubOutWithMock(app.neutron, 'list_subnetpools') @@ -295,7 +297,7 @@ class TestKuryr(base.TestKuryrBase): app.neutron.delete_subnet(subnet_v6_id).AndReturn(None) self.mox.StubOutWithMock(app.neutron, 'delete_network') - app.neutron.delete_network(fake_neutron_network_id).AndReturn(None) + app.neutron.delete_network(fake_neutron_net_id).AndReturn(None) self.mox.ReplayAll() data = {'NetworkID': docker_network_id} @@ -313,8 +315,8 @@ class TestKuryr(base.TestKuryrBase): docker_endpoint_id = hashlib.sha256( utils.getrandbits(256)).hexdigest() - fake_neutron_network_id = str(uuid.uuid4()) - self._mock_out_network(fake_neutron_network_id, docker_network_id) + 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 @@ -337,17 +339,17 @@ class TestKuryr(base.TestKuryrBase): } self.mox.StubOutWithMock(app.neutron, 'list_subnets') - app.neutron.list_subnets(network_id=fake_neutron_network_id, + 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_network_id, + 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_network_id, + docker_endpoint_id, fake_neutron_net_id, fake_port_id, subnet_v4_id, subnet_v6_id) fake_fixed_ips = ['subnet_id=%s' % subnet_v4_id, @@ -408,15 +410,15 @@ class TestKuryr(base.TestKuryrBase): self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) def test_network_driver_join(self): - fake_docker_network_id = hashlib.sha256( + fake_docker_net_id = hashlib.sha256( utils.getrandbits(256)).hexdigest() fake_docker_endpoint_id = hashlib.sha256( utils.getrandbits(256)).hexdigest() fake_container_id = hashlib.sha256( utils.getrandbits(256)).hexdigest() - fake_neutron_network_id = str(uuid.uuid4()) - self._mock_out_network(fake_neutron_network_id, fake_docker_network_id) + 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( @@ -424,7 +426,7 @@ class TestKuryr(base.TestKuryrBase): 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_docker_endpoint_id, fake_neutron_net_id, fake_neutron_port_id, fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id) app.neutron.list_ports(name=neutron_port_name).AndReturn( @@ -432,9 +434,9 @@ class TestKuryr(base.TestKuryrBase): self.mox.StubOutWithMock(app.neutron, 'list_subnets') fake_neutron_subnets_response = self._get_fake_subnets( - fake_docker_endpoint_id, fake_neutron_network_id, + 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_network_id).AndReturn( + 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'] @@ -446,7 +448,7 @@ class TestKuryr(base.TestKuryrBase): for subnet in fake_neutron_subnets} join_request = { - 'NetworkID': fake_docker_network_id, + 'NetworkID': fake_docker_net_id, 'EndpointID': fake_docker_endpoint_id, 'SandboxKey': utils.get_sandbox_key(fake_container_id), 'Options': {}, @@ -474,13 +476,13 @@ class TestKuryr(base.TestKuryrBase): self.assertEqual(expected_response, decoded_json) def test_network_driver_leave(self): - fake_docker_network_id = hashlib.sha256( + fake_docker_net_id = hashlib.sha256( utils.getrandbits(256)).hexdigest() fake_docker_endpoint_id = hashlib.sha256( utils.getrandbits(256)).hexdigest() - fake_neutron_network_id = str(uuid.uuid4()) - self._mock_out_network(fake_neutron_network_id, fake_docker_network_id) + 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( @@ -488,7 +490,7 @@ class TestKuryr(base.TestKuryrBase): 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_docker_endpoint_id, fake_neutron_net_id, fake_neutron_port_id, fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id) app.neutron.list_ports(name=neutron_port_name).AndReturn( @@ -498,7 +500,7 @@ class TestKuryr(base.TestKuryrBase): self._mock_out_unbinding(fake_docker_endpoint_id, fake_neutron_port) leave_request = { - 'NetworkID': fake_docker_network_id, + 'NetworkID': fake_docker_net_id, 'EndpointID': fake_docker_endpoint_id, } response = self.app.post('/NetworkDriver.Leave', diff --git a/kuryr/tests/unit/test_kuryr_existing_network.py b/kuryr/tests/unit/test_kuryr_existing_network.py new file mode 100644 index 00000000..9b3ac786 --- /dev/null +++ b/kuryr/tests/unit/test_kuryr_existing_network.py @@ -0,0 +1,147 @@ +# 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 hashlib +import uuid + +from ddt 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 +class TestKuryrNetworkPreExisting(base.TestKuryrBase): + + def _ids(self): + docker_network_id = hashlib.sha256( + utils.getrandbits(256)).hexdigest() + 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 + + def test_create_network_pre_existing(self): + 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) + + 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) + + 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) + + def test_delete_network_pre_existing(self): + docker_network_id, fake_neutron_net_id, fake_response = self._ids() + + 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) + + 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_network.py b/kuryr/tests/unit/test_kuryr_network.py index 4fae29ba..43a310ea 100644 --- a/kuryr/tests/unit/test_kuryr_network.py +++ b/kuryr/tests/unit/test_kuryr_network.py @@ -18,6 +18,7 @@ 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 @@ -97,10 +98,11 @@ class TestKuryrNetworkDeleteFailures(base.TestKuryrFailures): """ 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 = { - "networks": [] - } + fake_networks_response = no_networks_response else: fake_networks_response = { "networks": [{ @@ -117,6 +119,8 @@ class TestKuryrNetworkDeleteFailures(base.TestKuryrFailures): } 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" @@ -158,6 +162,9 @@ class TestKuryrNetworkDeleteFailures(base.TestKuryrFailures): 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", @@ -173,6 +180,8 @@ class TestKuryrNetworkDeleteFailures(base.TestKuryrFailures): } 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"