Code refactoring: /NetworkDriver.DeleteNetwork & /NetworkDriver.DeleteEndpoint

Currently subnets are deleted while endpoint deletion, which is not
correct. Subnets are created in /NetworkDriver.CreateNetwork so subnet
deletion should happen in /NetworkDriver.DeleteNetwork

Change-Id: Ia5670f8dee1f4319a624a855b3bc7d3dffeeb880
Closes-Bug: #1525758
This commit is contained in:
Vikas Choudhary 2015-12-14 10:48:15 +05:30
parent cbb6f4e158
commit 255ce9ec69
4 changed files with 196 additions and 204 deletions

@ -470,9 +470,12 @@ def network_driver_delete_network():
jsonschema.validate(json_data, schemata.NETWORK_DELETE_SCHEMA)
neutron_network_name = json_data['NetworkID']
filtered_networks = _get_networks_by_attrs(name=neutron_network_name)
try:
filtered_networks = _get_networks_by_attrs(name=neutron_network_name)
except n_exceptions.NeutronClientException as ex:
app.logger.error("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
@ -480,7 +483,38 @@ def network_driver_delete_network():
# 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
neutron_network_id = filtered_networks[0]['id']
app.neutron.delete_network(neutron_network_id)
filtered_subnets = _get_subnets_by_attrs(
network_id=neutron_network_id)
for subnet in filtered_subnets:
try:
subnetpool_id = subnet.get('subnetpool_id', None)
_cache_default_subnetpool_ids(app)
if subnetpool_id not in app.DEFAULT_POOL_IDS:
# If the subnet to be deleted has any port, when some ports
# are referring to the subnets in other words,
# delete_subnet throws an exception, SubnetInUse that
# extends Conflict. This can happen when the multiple
# Docker endpoints are created with the same subnet CIDR
# and it's totally the normal case. So we'd just log that
# and continue to proceed.
app.neutron.delete_subnet(subnet['id'])
except n_exceptions.Conflict as ex:
app.logger.error("Subnet, {0}, is in use. "
"Network cant be deleted.".format(subnet['id']))
raise
except n_exceptions.NeutronClientException as ex:
app.logger.error("Error happened during deleting a "
"Neutron subnets: {0}".format(ex))
raise
try:
app.neutron.delete_network(neutron_network_id)
except n_exceptions.NeutronClientException as ex:
app.logger.error("Error happened during deleting a "
"Neutron network: {0}".format(ex))
raise
app.logger.info("Deleted the network with ID {0} successfully"
.format(neutron_network_id))
return flask.jsonify(constants.SCHEMA['SUCCESS'])
@ -578,61 +612,7 @@ def network_driver_delete_endpoint():
.format(json_data))
jsonschema.validate(json_data, schemata.ENDPOINT_DELETE_SCHEMA)
neutron_network_name = json_data['NetworkID']
endpoint_id = json_data['EndpointID']
filtered_networks = _get_networks_by_attrs(name=neutron_network_name)
if not filtered_networks:
return flask.jsonify({
'Err': "Neutron network associated with ID {0} doesn't exist."
.format(neutron_network_name)
})
else:
neutron_network_id = filtered_networks[0]['id']
concerned_subnet_ids = []
try:
filtered_ports = app.neutron.list_ports(
network_id=neutron_network_id)
filtered_ports = [port for port in filtered_ports['ports']
if endpoint_id in port['name']]
for port in filtered_ports:
fixed_ips = port.get('fixed_ips', [])
for fixed_ip in fixed_ips:
concerned_subnet_ids.append(fixed_ip['subnet_id'])
app.neutron.delete_port(port['id'])
except n_exceptions.NeutronClientException as ex:
app.logger.error("Error happened during deleting a "
"Neutron ports: {0}".format(ex))
raise
for subnet_id in concerned_subnet_ids:
try:
subnet = app.neutron.show_subnet(subnet_id)
subnet = subnet['subnet']
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.info("The subnet with ID {0} is still referred "
"from other ports and it can't be deleted for "
"now.".format(subnet_id))
except n_exceptions.NeutronClientException as ex:
app.logger.error("Error happened during deleting a "
"Neutron subnets: {0}".format(ex))
raise
return flask.jsonify(constants.SCHEMA['SUCCESS'])
return flask.jsonify(constants.SCHEMA['SUCCESS'])
@app.route('/NetworkDriver.Join', methods=['POST'])

@ -145,6 +145,61 @@ class TestKuryr(base.TestKuryrBase):
str(random.getrandbits(256))).hexdigest()
fake_neutron_network_id = str(uuid.uuid4())
self._mock_out_network(fake_neutron_network_id, docker_network_id)
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
fake_neutron_subnets_response = {"subnets": []}
app.neutron.list_subnets(network_id=fake_neutron_network_id).AndReturn(
fake_neutron_subnets_response)
self.mox.StubOutWithMock(app.neutron, 'delete_network')
app.neutron.delete_network(fake_neutron_network_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 = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()
docker_endpoint_id = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()
fake_neutron_network_id = str(uuid.uuid4())
self._mock_out_network(fake_neutron_network_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_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).AndReturn(None)
@ -236,45 +291,6 @@ class TestKuryr(base.TestKuryrBase):
str(random.getrandbits(256))).hexdigest()
docker_endpoint_id = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()
fake_neutron_network_id = str(uuid.uuid4())
self._mock_out_network(fake_neutron_network_id, docker_network_id)
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
fake_default_v4_subnetpool_id = str(uuid.uuid4())
app.neutron.list_subnetpools(name='kuryr').AndReturn(
self._get_fake_v4_subnetpools(
fake_default_v4_subnetpool_id))
fake_default_v6_subnetpool_id = str(uuid.uuid4())
app.neutron.list_subnetpools(name='kuryr6').AndReturn(
self._get_fake_v6_subnetpools(
fake_default_v6_subnetpool_id))
self.mox.ReplayAll()
fake_subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031"
fake_subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51"
self.mox.StubOutWithMock(app.neutron, 'show_subnet')
fake_v4_subnet = self._get_fake_v4_subnet(
docker_network_id, docker_endpoint_id, fake_subnet_v4_id,
subnetpool_id=fake_default_v4_subnetpool_id)
app.neutron.show_subnet(fake_subnet_v4_id).AndReturn(fake_v4_subnet)
fake_v6_subnet = self._get_fake_v6_subnet(
docker_network_id, docker_endpoint_id, fake_subnet_v6_id,
subnetpool_id=fake_default_v6_subnetpool_id)
app.neutron.show_subnet(fake_subnet_v6_id).AndReturn(fake_v6_subnet)
fake_neutron_port_id = '65c0ee9f-d634-4522-8954-51021b570b0d'
fake_ports = self._get_fake_ports(
docker_endpoint_id, fake_neutron_network_id, fake_neutron_port_id,
fake_subnet_v4_id, fake_subnet_v6_id)
self.mox.StubOutWithMock(app.neutron, 'list_ports')
app.neutron.list_ports(
network_id=fake_neutron_network_id).AndReturn(fake_ports)
self.mox.StubOutWithMock(app.neutron, 'delete_port')
app.neutron.delete_port(fake_neutron_port_id).AndReturn(None)
self.mox.ReplayAll()
data = {
'NetworkID': docker_network_id,
'EndpointID': docker_endpoint_id,

@ -231,11 +231,7 @@ class TestKuryrEndpointCreateFailures(TestKuryrEndpointFailures):
@ddt.ddt
class TestKuryrEndpointDeleteFailures(TestKuryrEndpointFailures):
"""Unit tests for the failures for deleting endpoints.
This test covers error responses listed in the spec:
http://developer.openstack.org/api-ref-networking-v2-ext.html#deleteProviderNetwork # noqa
"""
"""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}
@ -244,107 +240,6 @@ class TestKuryrEndpointDeleteFailures(TestKuryrEndpointFailures):
data=jsonutils.dumps(data))
return response
@ddt.data(exceptions.Unauthorized, exceptions.NotFound,
exceptions.Conflict)
def test_delete_endpoint_subnet_failures(self, GivenException):
fake_docker_network_id = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()
fake_docker_endpoint_id = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()
fake_neutron_network_id = str(uuid.uuid4())
fake_neutron_port_id = str(uuid.uuid4())
fake_neutron_subnet_v4_id = str(uuid.uuid4())
fake_neutron_subnet_v6_id = str(uuid.uuid4())
self._mock_out_network(fake_neutron_network_id, fake_docker_network_id)
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
fake_default_v4_subnetpool_id = str(uuid.uuid4())
app.neutron.list_subnetpools(name='kuryr').AndReturn(
self._get_fake_v4_subnetpools(
fake_default_v4_subnetpool_id))
fake_default_v6_subnetpool_id = str(uuid.uuid4())
app.neutron.list_subnetpools(name='kuryr6').AndReturn(
self._get_fake_v6_subnetpools(
fake_default_v6_subnetpool_id))
fake_ports = self._get_fake_ports(
fake_docker_endpoint_id, fake_neutron_network_id,
fake_neutron_port_id,
fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id)
self.mox.StubOutWithMock(app.neutron, 'list_ports')
app.neutron.list_ports(
network_id=fake_neutron_network_id).AndReturn(fake_ports)
self.mox.StubOutWithMock(app.neutron, 'delete_port')
app.neutron.delete_port(fake_neutron_port_id).AndReturn(None)
self.mox.StubOutWithMock(app.neutron, 'show_subnet')
fake_v4_subnet = self._get_fake_v4_subnet(
fake_docker_network_id, fake_docker_endpoint_id,
fake_neutron_subnet_v4_id)
app.neutron.show_subnet(
fake_neutron_subnet_v4_id).AndReturn(fake_v4_subnet)
if GivenException is exceptions.Conflict:
fake_v6_subnet = self._get_fake_v6_subnet(
fake_docker_network_id, fake_docker_endpoint_id,
fake_neutron_subnet_v6_id)
app.neutron.show_subnet(
fake_neutron_subnet_v6_id).AndReturn(fake_v6_subnet)
self.mox.ReplayAll()
if GivenException is exceptions.Conflict:
self._delete_subnets_with_exception(
[fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id],
GivenException())
else:
self._delete_subnet_with_exception(
fake_neutron_subnet_v4_id, GivenException())
response = self._invoke_delete_request(
fake_docker_network_id, fake_docker_endpoint_id)
if GivenException is exceptions.Conflict:
self.assertEqual(200, response.status_code)
decoded_json = jsonutils.loads(response.data)
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
else:
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)
@ddt.data(exceptions.Unauthorized, exceptions.NotFound,
exceptions.Conflict)
def test_delete_endpiont_port_failures(self, GivenException):
fake_docker_network_id = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()
fake_docker_endpoint_id = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()
fake_neutron_network_id = str(uuid.uuid4())
fake_neutron_subnet_v4_id = str(uuid.uuid4())
fake_neutron_subnet_v6_id = str(uuid.uuid4())
fake_neutron_port_id = str(uuid.uuid4())
self._mock_out_network(fake_neutron_network_id, fake_docker_network_id)
self.mox.StubOutWithMock(app.neutron, 'list_ports')
fake_ports = self._get_fake_ports(
fake_docker_endpoint_id, fake_neutron_network_id,
fake_neutron_port_id,
fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id)
app.neutron.list_ports(
network_id=fake_neutron_network_id).AndReturn(fake_ports)
self._delete_port_with_exception(fake_neutron_port_id, GivenException)
response = self._invoke_delete_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_delete_endpoint_bad_request(self):
fake_docker_network_id = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()

@ -113,10 +113,96 @@ class TestKuryrNetworkDeleteFailures(base.TestKuryrFailures):
self.mox.StubOutWithMock(app.neutron, 'list_networks')
app.neutron.list_networks(
name=network_id).AndReturn(fake_networks_response)
subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031"
subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51"
docker_network_id = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()
docker_endpoint_id = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()
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"
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')
app.neutron.list_networks(
name=network_id).AndReturn(fake_networks_response)
subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031"
subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51"
docker_network_id = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()
docker_endpoint_id = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()
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',
@ -148,3 +234,18 @@ class TestKuryrNetworkDeleteFailures(base.TestKuryrFailures):
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 = hashlib.sha256(
str(random.getrandbits(256))).hexdigest()
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)