From 669352706a5a2f69a3c91fc6b0352e84e4059b27 Mon Sep 17 00:00:00 2001 From: Hongbin Lu Date: Sun, 22 Jul 2018 21:57:12 +0000 Subject: [PATCH] Add fullstack test for release overlap address Related-Bug: #1782947 Change-Id: I25164449d053d5a4287aa0cf3fccb33b8c6f367d --- kuryr_libnetwork/controllers.py | 26 +-- kuryr_libnetwork/tests/fullstack/test_ipam.py | 153 ++++++++++++++++++ kuryr_libnetwork/utils.py | 24 +++ 3 files changed, 179 insertions(+), 24 deletions(-) diff --git a/kuryr_libnetwork/controllers.py b/kuryr_libnetwork/controllers.py index 631706df..4b0b570a 100644 --- a/kuryr_libnetwork/controllers.py +++ b/kuryr_libnetwork/controllers.py @@ -18,7 +18,6 @@ from itertools import groupby import jsonschema from operator import itemgetter import six -import time from neutronclient.common import exceptions as n_exceptions from oslo_concurrency import processutils @@ -405,27 +404,6 @@ def _get_networks_by_identifier(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: - LOG.error('Could not get the port %s to check ' - 'its status', ex) - else: - if port['port']['status'] == lib_const.PORT_STATUS_ACTIVE: - port_active = True - if port_active or (vif_plug_timeout > 0 and 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 - - def _program_expose_ports(options, port_id): exposed_ports = options.get(const.DOCKER_EXPOSED_PORTS_OPTION) if not exposed_ports: @@ -1175,8 +1153,8 @@ def network_driver_create_endpoint(): LOG.error('Failed to set up the interface: %s', ex) if app.vif_plug_is_fatal: - port_active = _port_active(neutron_port['id'], - app.vif_plug_timeout) + port_active = utils.wait_for_port_active( + app.neutron, neutron_port['id'], app.vif_plug_timeout) if not port_active: neutron_port_name = neutron_port['name'] raise exceptions.InactiveResourceException( diff --git a/kuryr_libnetwork/tests/fullstack/test_ipam.py b/kuryr_libnetwork/tests/fullstack/test_ipam.py index 9175c508..c9ccc7f4 100644 --- a/kuryr_libnetwork/tests/fullstack/test_ipam.py +++ b/kuryr_libnetwork/tests/fullstack/test_ipam.py @@ -482,3 +482,156 @@ class IpamTest(kuryr_base.KuryrBaseTest): self.neutron_client.delete_subnet( neutron_v6_subnet['subnets'][0]['id']) self.neutron_client.delete_network(neutron_network['network']['id']) + + def test_container_ipam_release_address_with_existing_port_same_ip(self): + ipv4_address = "10.15.0.10" + + # pre-created the first Neutron network and subnet and port + neutron_net_name = lib_utils.get_random_string(8) + neutron_network = self.neutron_client.create_network( + {'network': {'name': neutron_net_name, + "admin_state_up": True}}) + neutron_subnet_name = lib_utils.get_random_string(8) + subnet_param = [{ + 'name': neutron_subnet_name, + 'network_id': neutron_network['network']['id'], + 'ip_version': 4, + 'cidr': "10.15.0.0/24", + }] + neutron_subnet = self.neutron_client.create_subnet( + {'subnets': subnet_param}) + existing_neutron_port = self.neutron_client.create_port( + {'port': {'network_id': neutron_network['network']['id'], + 'fixed_ips': [{'ip_address': ipv4_address}]}}) + fake_ipam = { + "Driver": "kuryr", + "Options": { + 'neutron.subnet.name': neutron_subnet_name + }, + "Config": [ + { + "Subnet": "10.15.0.0/24", + "Gateway": "10.15.0.1" + } + ] + } + # Create docker network using existing Neutron network + options = {'neutron.net.name': neutron_net_name, + 'neutron.subnet.name': neutron_subnet_name} + container_net_name = lib_utils.get_random_string(8) + container_net = self.docker_client.create_network( + name=container_net_name, + driver='kuryr', + options=options, + ipam=fake_ipam) + container_net_id = container_net.get('Id') + + # pre-created the second Neutron network and subnet and port + neutron_net_name2 = lib_utils.get_random_string(8) + neutron_network2 = self.neutron_client.create_network( + {'network': {'name': neutron_net_name2, + "admin_state_up": True}}) + neutron_subnet_name2 = lib_utils.get_random_string(8) + subnet_param2 = [{ + 'name': neutron_subnet_name2, + 'network_id': neutron_network2['network']['id'], + 'ip_version': 4, + 'cidr': "10.15.0.0/24", + }] + neutron_subnet2 = self.neutron_client.create_subnet( + {'subnets': subnet_param2}) + existing_neutron_port2 = self.neutron_client.create_port( + {'port': {'network_id': neutron_network2['network']['id'], + 'fixed_ips': [{'ip_address': ipv4_address}]}}) + fake_ipam2 = { + "Driver": "kuryr", + "Options": { + 'neutron.subnet.name': neutron_subnet_name2 + }, + "Config": [ + { + "Subnet": "10.15.0.0/24", + "Gateway": "10.15.0.1" + } + ] + } + # Create docker network using existing Neutron network + options = {'neutron.net.name': neutron_net_name2, + 'neutron.subnet.name': neutron_subnet_name2} + container_net_name2 = lib_utils.get_random_string(8) + container_net2 = self.docker_client.create_network( + name=container_net_name2, + driver='kuryr', + options=options, + ipam=fake_ipam2) + container_net_id2 = container_net2.get('Id') + + # Boot the first container, and connect to the first docker network. + endpoint_config = self.docker_client.create_endpoint_config( + ipv4_address=ipv4_address) + network_config = self.docker_client.create_networking_config({ + container_net_id: endpoint_config}) + container_name = lib_utils.get_random_string(8) + container = self.docker_client.create_container( + image='kuryr/busybox', + command='/bin/sleep 600', + hostname='kuryr_test_container', + name=container_name, + networking_config=network_config) + container_id = container.get('Id') + self.docker_client.start(container=container_id) + + # Boot the second container, and connect to the second docker network. + endpoint_config = self.docker_client.create_endpoint_config( + ipv4_address=ipv4_address) + network_config = self.docker_client.create_networking_config({ + container_net_id2: endpoint_config}) + container_name2 = lib_utils.get_random_string(8) + container2 = self.docker_client.create_container( + image='kuryr/busybox', + command='/bin/sleep 600', + hostname='kuryr_test_container2', + name=container_name2, + networking_config=network_config) + container_id2 = container2.get('Id') + self.docker_client.start(container=container_id2) + + # Assert both existing neutron ports active + for port_id in (existing_neutron_port['port']['id'], + existing_neutron_port2['port']['id']): + utils.wait_for_port_active( + self.neutron_client, port_id, 60) + neutron_port = self.neutron_client.show_port(port_id) + self.assertEqual('ACTIVE', neutron_port['port']['status']) + + # Disconnect the first container from network and + # assert the first neutron port is down and the second is still active + self.docker_client.disconnect_container_from_network(container_id, + container_net_id) + existing_neutron_port = self.neutron_client.show_port( + existing_neutron_port['port']['id']) + self.assertEqual('DOWN', existing_neutron_port['port']['status']) + existing_neutron_port2 = self.neutron_client.show_port( + existing_neutron_port2['port']['id']) + self.assertEqual('ACTIVE', existing_neutron_port2['port']['status']) + + # Disconnect the second container from network and + # assert both neutron ports are down. + self.docker_client.disconnect_container_from_network(container_id2, + container_net_id2) + for port_id in (existing_neutron_port['port']['id'], + existing_neutron_port2['port']['id']): + neutron_port = self.neutron_client.show_port(port_id) + self.assertEqual('DOWN', neutron_port['port']['status']) + + # Cleanup resources + self.docker_client.stop(container=container_id) + self.docker_client.stop(container=container_id2) + self.docker_client.remove_network(container_net_id) + self.docker_client.remove_network(container_net_id2) + self.neutron_client.delete_port(existing_neutron_port['port']['id']) + self.neutron_client.delete_port(existing_neutron_port2['port']['id']) + self.neutron_client.delete_subnet(neutron_subnet['subnets'][0]['id']) + self.neutron_client.delete_subnet(neutron_subnet2['subnets'][0]['id']) + self.neutron_client.delete_network(neutron_network['network']['id']) + self.neutron_client.delete_network(neutron_network2['network']['id']) diff --git a/kuryr_libnetwork/utils.py b/kuryr_libnetwork/utils.py index 999e674e..3ae907c4 100644 --- a/kuryr_libnetwork/utils.py +++ b/kuryr_libnetwork/utils.py @@ -12,6 +12,7 @@ import os import sys +import time import traceback import flask @@ -22,6 +23,7 @@ from oslo_concurrency import processutils from oslo_log import log from werkzeug import exceptions as w_exceptions +from kuryr.lib import constants as lib_const from kuryr.lib import exceptions from kuryr.lib import utils as lib_utils from kuryr_libnetwork import constants as const @@ -126,3 +128,25 @@ def make_net_name(netid, tags=True): def make_subnet_name(pool_cidr): return const.SUBNET_NAME_PREFIX + pool_cidr + + +def wait_for_port_active(neutron_client, neutron_port_id, vif_plug_timeout): + port_active = False + tries = 0 + while True: + try: + port = neutron_client.show_port(neutron_port_id) + except n_exceptions.NeutronClientException as ex: + LOG.error('Could not get the port %s to check ' + 'its status', ex) + else: + if port['port']['status'] == lib_const.PORT_STATUS_ACTIVE: + port_active = True + if port_active or (vif_plug_timeout > 0 and + 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