Delete port created by kuryr
In current code, we get the port's subnet by checking the subnet's subnetpool_id equal with the given PoolID, but in existing environment, the subnet may lack subnetpool_id, hence we will not get the port's subnet and leaves the kuryr-libnetwork port undeleted. This patch checks the port's device owner and determines the given POOL's subnet_id and ip_address is equal to port's fixed_ips attribute. Change-Id: I736adbb2409b50a5e11d3aa7d31778944cfdeae1 Co-Authored-By: Liping Mao <limao@cisco.com> Closes-Bug: #1651015
This commit is contained in:
parent
e5f7672a20
commit
4af7e1cdd8
|
@ -1500,29 +1500,15 @@ def ipam_release_address():
|
|||
app.logger.info(_LI("Subnet already deleted."))
|
||||
return flask.jsonify(const.SCHEMA['SUCCESS'])
|
||||
|
||||
subnet = {}
|
||||
for tmp_subnet in subnets:
|
||||
if tmp_subnet['subnetpool_id'] == pool_id:
|
||||
subnet = tmp_subnet
|
||||
break
|
||||
if not subnet:
|
||||
app.logger.info(_LI("Subnet already deleted."))
|
||||
return flask.jsonify(const.SCHEMA['SUCCESS'])
|
||||
|
||||
iface = ipaddress.ip_interface(six.text_type(rel_address))
|
||||
rcvd_fixed_ips = []
|
||||
fixed_ip = {'subnet_id': subnet['id']}
|
||||
fixed_ip['ip_address'] = six.text_type(iface.ip)
|
||||
rcvd_fixed_ips.append(fixed_ip)
|
||||
|
||||
rel_ip_address = six.text_type(iface.ip)
|
||||
try:
|
||||
filtered_ports = []
|
||||
all_ports = app.neutron.list_ports()
|
||||
all_ports = app.neutron.list_ports(device_owner=lib_const.DEVICE_OWNER)
|
||||
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'])
|
||||
for tmp_subnet in subnets:
|
||||
if (port['fixed_ips'][0]['subnet_id'] == tmp_subnet['id'] and
|
||||
port['fixed_ips'][0]['ip_address'] == rel_ip_address):
|
||||
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)
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
# 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.lib import constants as lib_const
|
||||
from kuryr.lib import utils as lib_utils
|
||||
from kuryr_libnetwork.tests.fullstack import kuryr_base
|
||||
from kuryr_libnetwork import utils
|
||||
|
||||
|
||||
class IpamTest(kuryr_base.KuryrBaseTest):
|
||||
"""Test Container IPAM related operations
|
||||
|
||||
Test container IPAM operations(request/release pool|address)
|
||||
"""
|
||||
|
||||
def test_container_ipam_release_address(self):
|
||||
# pre-created Neutron network and subnet
|
||||
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.10.0.0/24",
|
||||
'enable_dhcp': True,
|
||||
}]
|
||||
self.neutron_client.create_subnet({'subnets': subnet_param})
|
||||
|
||||
fake_ipam = {
|
||||
"Driver": "kuryr",
|
||||
"Options": {},
|
||||
"Config": [
|
||||
{
|
||||
"Subnet": "10.10.0.0/16",
|
||||
"IPRange": "10.10.0.0/24",
|
||||
"Gateway": "10.10.0.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Create docker network using existing Neutron network
|
||||
options = {'neutron.net.name': neutron_net_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')
|
||||
try:
|
||||
networks = self.neutron_client.list_networks(
|
||||
tags=utils.make_net_tags(container_net_id))
|
||||
except Exception as e:
|
||||
self.docker_client.remove_network(container_net_id)
|
||||
message = ("Failed to list neutron networks: %s")
|
||||
self.fail(message % e.args[0])
|
||||
self.assertEqual(1, len(networks['networks']))
|
||||
|
||||
# Boot a container, and connect to the docker network.
|
||||
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)
|
||||
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,
|
||||
container_net_id)
|
||||
try:
|
||||
ports = self.neutron_client.list_ports(
|
||||
network_id=neutron_network['network']['id'])
|
||||
except Exception as e:
|
||||
self.docker_client.disconnect_container_from_network(
|
||||
container_id,
|
||||
container_net_id)
|
||||
message = ("Failed to list neutron ports: %s")
|
||||
self.fail(message % e.args[0])
|
||||
|
||||
# A dhcp port gets created as well; dhcp is enabled by default
|
||||
self.assertEqual(2, len(ports['ports']))
|
||||
# Find the kuryr port
|
||||
kuryr_port_param = {"network_id": neutron_network['network']['id'],
|
||||
"device_owner": lib_const.DEVICE_OWNER}
|
||||
kuryr_ports = self.neutron_client.list_ports(
|
||||
**kuryr_port_param)
|
||||
self.assertEqual(1, len(kuryr_ports['ports']))
|
||||
|
||||
# Disconnect container from network, this release ip address.
|
||||
self.docker_client.disconnect_container_from_network(container_id,
|
||||
container_net_id)
|
||||
ports = self.neutron_client.list_ports(
|
||||
network_id=neutron_network['network']['id'])
|
||||
self.assertEqual(1, len(ports['ports']))
|
||||
kuryr_ports = self.neutron_client.list_ports(
|
||||
**kuryr_port_param)
|
||||
self.assertEqual(0, len(kuryr_ports['ports']))
|
||||
|
||||
# Cleanup resources
|
||||
self.docker_client.stop(container=container_id)
|
||||
self.docker_client.remove_network(container_net_id)
|
||||
self.neutron_client.delete_network(neutron_network['network']['id'])
|
|
@ -189,7 +189,8 @@ class TestKuryrBase(TestCase):
|
|||
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"):
|
||||
neutron_subnet_v6_address="fe80::f816:3eff:fe20:57c4",
|
||||
device_owner=None):
|
||||
# The following fake response is retrieved from the Neutron doc:
|
||||
# http://developer.openstack.org/api-ref-networking-v2.html#createPort # noqa
|
||||
fake_port = {
|
||||
|
@ -200,7 +201,7 @@ class TestKuryrBase(TestCase):
|
|||
"admin_state_up": True,
|
||||
"network_id": neutron_network_id,
|
||||
"tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa",
|
||||
"device_owner": "",
|
||||
"device_owner": device_owner,
|
||||
"mac_address": "fa:16:3e:20:57:c3",
|
||||
"fixed_ips": [],
|
||||
"id": neutron_port_id,
|
||||
|
|
|
@ -571,12 +571,10 @@ class TestKuryrIpam(base.TestKuryrBase):
|
|||
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
||||
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR], name=fake_name)
|
||||
mock_list_subnetpools.return_value = kuryr_subnetpools
|
||||
fake_ip4 = '10.0.0.5'
|
||||
|
||||
# faking list_subnets
|
||||
docker_network_id = lib_utils.get_hash()
|
||||
docker_endpoint_id = lib_utils.get_hash()
|
||||
neutron_network_id = docker_network_id = uuidutils.generate_uuid()
|
||||
subnet_v4_id = uuidutils.generate_uuid()
|
||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
||||
docker_network_id, docker_endpoint_id, subnet_v4_id,
|
||||
|
@ -589,22 +587,20 @@ class TestKuryrIpam(base.TestKuryrBase):
|
|||
}
|
||||
mock_list_subnets.return_value = fake_subnet_response
|
||||
|
||||
#faking list_ports and delete_port
|
||||
fake_ip4 = '10.0.0.5'
|
||||
# faking list_ports and delete_port
|
||||
neutron_network_id = uuidutils.generate_uuid()
|
||||
fake_neutron_port_id = uuidutils.generate_uuid()
|
||||
fake_port = base.TestKuryrBase._get_fake_port(
|
||||
docker_endpoint_id, neutron_network_id,
|
||||
fake_neutron_port_id, lib_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)
|
||||
neutron_subnet_v4_address=fake_ip4,
|
||||
device_owner=lib_const.DEVICE_OWNER)
|
||||
|
||||
fake_port['port']['fixed_ips'] = [
|
||||
{'subnet_id': subnet_v4_id, 'ip_address': fake_ip4}
|
||||
]
|
||||
|
||||
list_port_response = {'ports': [fake_port['port']]}
|
||||
mock_list_ports.return_value = list_port_response
|
||||
|
@ -624,53 +620,7 @@ class TestKuryrIpam(base.TestKuryrBase):
|
|||
id=fake_kuryr_subnetpool_id)
|
||||
mock_list_subnets.assert_called_with(
|
||||
cidr=FAKE_IP4_CIDR)
|
||||
self.assertTrue(mock_list_ports.called)
|
||||
mock_list_ports.assert_called_with(
|
||||
device_owner=lib_const.DEVICE_OWNER)
|
||||
mock_delete_port.assert_called_with(
|
||||
fake_port['port']['id'])
|
||||
|
||||
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets')
|
||||
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnetpools')
|
||||
def test_ipam_driver_release_address_with_one_subnet_deleted(
|
||||
self, mock_list_subnetpools, mock_list_subnets):
|
||||
"""Another unittest for release address.
|
||||
|
||||
For those two subnets have same cidrs, one of them had already deleted.
|
||||
"""
|
||||
|
||||
# Faking list_subnetpools
|
||||
fake_kuryr_subnetpool_id = uuidutils.generate_uuid()
|
||||
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)
|
||||
mock_list_subnetpools.return_value = kuryr_subnetpools
|
||||
|
||||
# Faking list_subnets
|
||||
docker_network_id = uuidutils.generate_uuid()
|
||||
docker_endpoint_id = uuidutils.generate_uuid()
|
||||
docker_network_id = uuidutils.generate_uuid()
|
||||
subnet_v4_id = uuidutils.generate_uuid()
|
||||
# Make two subnets have different subnetpool id
|
||||
another_fake_kuryr_subnetpool_id = uuidutils.generate_uuid()
|
||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
||||
docker_network_id, docker_endpoint_id, subnet_v4_id,
|
||||
subnetpool_id=another_fake_kuryr_subnetpool_id,
|
||||
cidr=FAKE_IP4_CIDR)
|
||||
fake_subnet_response = {
|
||||
'subnets': [
|
||||
fake_v4_subnet['subnet']
|
||||
]
|
||||
}
|
||||
mock_list_subnets.return_value = fake_subnet_response
|
||||
|
||||
fake_ip4 = '10.0.0.5'
|
||||
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)
|
||||
mock_list_subnetpools.assert_called_with(id=fake_kuryr_subnetpool_id)
|
||||
mock_list_subnets.assert_called_with(cidr=FAKE_IP4_CIDR)
|
||||
|
|
Loading…
Reference in New Issue