Remove any IPAM allocation if port bulk creation fails
During the port bulk creation, if an IPAM allocation fails (for example, if the IP address is outside of the subnet CIDR), the other IPAM allocations already created are deleted before raising the exception. Conflicts: neutron/tests/unit/plugins/ml2/test_plugin.py Closes-Bug: #2039550 Change-Id: I7fd6e38016d099c03f80874bfa1fb8bdaff8bd2c (cherry picked from commit 71a7abb498fded6d8d60453074efdef9657f416e) (cherry picked from commit a4c03671f2b8784cb6bec227ddbd56a16fffbcf1)
This commit is contained in:
parent
a1cec66f3a
commit
717eb38991
@ -1652,10 +1652,9 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
for port in port_list:
|
for port in port_list:
|
||||||
self._before_create_port(context, port)
|
self._before_create_port(context, port)
|
||||||
|
|
||||||
port_list, net_cache = self.allocate_macs_and_ips_for_ports(
|
|
||||||
context, port_list)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
port_list, net_cache = self.allocate_macs_and_ips_for_ports(
|
||||||
|
context, port_list)
|
||||||
return self._create_port_bulk(context, port_list, net_cache)
|
return self._create_port_bulk(context, port_list, net_cache)
|
||||||
except Exception:
|
except Exception:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
@ -1663,7 +1662,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
# deallocated now
|
# deallocated now
|
||||||
for port in port_list:
|
for port in port_list:
|
||||||
self.ipam.deallocate_ips_from_port(
|
self.ipam.deallocate_ips_from_port(
|
||||||
context, port, port['ipams'])
|
context, port, port.get('ipams'))
|
||||||
|
|
||||||
@db_api.retry_if_session_inactive()
|
@db_api.retry_if_session_inactive()
|
||||||
def _create_port_bulk(self, context, port_list, network_cache):
|
def _create_port_bulk(self, context, port_list, network_cache):
|
||||||
|
@ -55,6 +55,7 @@ from neutron.db import ipam_pluggable_backend
|
|||||||
from neutron.db import provisioning_blocks
|
from neutron.db import provisioning_blocks
|
||||||
from neutron.db import securitygroups_db as sg_db
|
from neutron.db import securitygroups_db as sg_db
|
||||||
from neutron.db import segments_db
|
from neutron.db import segments_db
|
||||||
|
from neutron.ipam import driver
|
||||||
from neutron.objects import base as base_obj
|
from neutron.objects import base as base_obj
|
||||||
from neutron.objects import network as network_obj
|
from neutron.objects import network as network_obj
|
||||||
from neutron.objects import ports as port_obj
|
from neutron.objects import ports as port_obj
|
||||||
@ -1741,6 +1742,39 @@ class TestMl2PortsV2(test_plugin.TestPortsV2, Ml2PluginV2TestCase):
|
|||||||
ports_out = self.plugin.create_port_bulk(ctx, ports_in)
|
ports_out = self.plugin.create_port_bulk(ctx, ports_in)
|
||||||
self.assertEqual(edo, ports_out[0]['extra_dhcp_opts'])
|
self.assertEqual(edo, ports_out[0]['extra_dhcp_opts'])
|
||||||
|
|
||||||
|
def test_create_ports_bulk_with_wrong_fixed_ips(self):
|
||||||
|
cidr = '10.0.10.0/24'
|
||||||
|
with self.network() as net:
|
||||||
|
with self.subnet(net, cidr=cidr) as snet:
|
||||||
|
net_id = net['network']['id']
|
||||||
|
data = [{'network_id': net_id,
|
||||||
|
'fixed_ips': [{'subnet_id': snet['subnet']['id'],
|
||||||
|
'ip_address': '10.0.10.100'}],
|
||||||
|
'tenant_id': snet['subnet']['tenant_id']
|
||||||
|
},
|
||||||
|
{'network_id': net_id,
|
||||||
|
'fixed_ips': [{'subnet_id': snet['subnet']['id'],
|
||||||
|
'ip_address': '10.0.20.101'}],
|
||||||
|
'tenant_id': snet['subnet']['tenant_id']
|
||||||
|
}]
|
||||||
|
res = self._create_bulk_from_list(self.fmt, 'port',
|
||||||
|
data, as_admin=True)
|
||||||
|
self.assertEqual(webob.exc.HTTPBadRequest.code, res.status_int)
|
||||||
|
self.assertIn('IP address 10.0.20.101 is not a valid IP for '
|
||||||
|
'the specified subnet.',
|
||||||
|
res.json['NeutronError']['message'])
|
||||||
|
|
||||||
|
ipam_driver = driver.Pool.get_instance(None, self.context)
|
||||||
|
ipam_allocator = ipam_driver.get_allocator([cidr])
|
||||||
|
with db_api.CONTEXT_READER.using(self.context):
|
||||||
|
ipam_subnet = ipam_allocator._driver.get_subnet(
|
||||||
|
snet['subnet']['id'])
|
||||||
|
allocations = ipam_subnet.subnet_manager.list_allocations(
|
||||||
|
self.context)
|
||||||
|
# There are no leftovers (e.g.: 10.0.10.100) in the
|
||||||
|
# "IpamAllocation" registers
|
||||||
|
self.assertEqual([], allocations)
|
||||||
|
|
||||||
def test_delete_port_no_notify_in_disassociate_floatingips(self):
|
def test_delete_port_no_notify_in_disassociate_floatingips(self):
|
||||||
ctx = context.get_admin_context()
|
ctx = context.get_admin_context()
|
||||||
plugin = directory.get_plugin()
|
plugin = directory.get_plugin()
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
During the port bulk creation, if an IPAM allocation fails (for example, if
|
||||||
|
the IP address is outside of the subnet CIDR), the other IPAM allocations
|
||||||
|
already created are deleted before raising the exception. Fixes bug
|
||||||
|
`2039550 <https://launchpad.net/bugs/2039550>`_.
|
Loading…
x
Reference in New Issue
Block a user