Skip to content

Commit 60b4c47

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Remove any IPAM allocation if port bulk creation fails" into stable/2023.1
2 parents 50fb47b + a4c0367 commit 60b4c47

File tree

3 files changed

+44
-4
lines changed

3 files changed

+44
-4
lines changed

neutron/plugins/ml2/plugin.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,18 +1655,17 @@ def create_port_bulk(self, context, ports):
16551655
for port in port_list:
16561656
self._before_create_port(context, port)
16571657

1658-
port_list, net_cache = self.allocate_macs_and_ips_for_ports(
1659-
context, port_list)
1660-
16611658
try:
1659+
port_list, net_cache = self.allocate_macs_and_ips_for_ports(
1660+
context, port_list)
16621661
return self._create_port_bulk(context, port_list, net_cache)
16631662
except Exception:
16641663
with excutils.save_and_reraise_exception():
16651664
# If any issue happened allocated IP addresses needs to be
16661665
# deallocated now
16671666
for port in port_list:
16681667
self.ipam.deallocate_ips_from_port(
1669-
context, port, port['ipams'])
1668+
context, port, port.get('ipams'))
16701669

16711670
@db_api.retry_if_session_inactive()
16721671
def _create_port_bulk(self, context, port_list, network_cache):

neutron/tests/unit/plugins/ml2/test_plugin.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
from neutron.db import provisioning_blocks
5656
from neutron.db import securitygroups_db as sg_db
5757
from neutron.db import segments_db
58+
from neutron.ipam import driver
5859
from neutron.objects import base as base_obj
5960
from neutron.objects import network as network_obj
6061
from neutron.objects import ports as port_obj
@@ -1741,6 +1742,39 @@ def test_create_ports_bulk_with_extra_dhcp_opts(self):
17411742
ports_out = self.plugin.create_port_bulk(ctx, ports_in)
17421743
self.assertEqual(edo, ports_out[0]['extra_dhcp_opts'])
17431744

1745+
def test_create_ports_bulk_with_wrong_fixed_ips(self):
1746+
cidr = '10.0.10.0/24'
1747+
with self.network() as net:
1748+
with self.subnet(net, cidr=cidr) as snet:
1749+
net_id = net['network']['id']
1750+
data = [{'network_id': net_id,
1751+
'fixed_ips': [{'subnet_id': snet['subnet']['id'],
1752+
'ip_address': '10.0.10.100'}],
1753+
'tenant_id': snet['subnet']['tenant_id']
1754+
},
1755+
{'network_id': net_id,
1756+
'fixed_ips': [{'subnet_id': snet['subnet']['id'],
1757+
'ip_address': '10.0.20.101'}],
1758+
'tenant_id': snet['subnet']['tenant_id']
1759+
}]
1760+
res = self._create_bulk_from_list(self.fmt, 'port',
1761+
data, as_admin=True)
1762+
self.assertEqual(webob.exc.HTTPBadRequest.code, res.status_int)
1763+
self.assertIn('IP address 10.0.20.101 is not a valid IP for '
1764+
'the specified subnet.',
1765+
res.json['NeutronError']['message'])
1766+
1767+
ipam_driver = driver.Pool.get_instance(None, self.context)
1768+
ipam_allocator = ipam_driver.get_allocator([cidr])
1769+
with db_api.CONTEXT_READER.using(self.context):
1770+
ipam_subnet = ipam_allocator._driver.get_subnet(
1771+
snet['subnet']['id'])
1772+
allocations = ipam_subnet.subnet_manager.list_allocations(
1773+
self.context)
1774+
# There are no leftovers (e.g.: 10.0.10.100) in the
1775+
# "IpamAllocation" registers
1776+
self.assertEqual([], allocations)
1777+
17441778
def test_delete_port_no_notify_in_disassociate_floatingips(self):
17451779
ctx = context.get_admin_context()
17461780
plugin = directory.get_plugin()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
fixes:
3+
- |
4+
During the port bulk creation, if an IPAM allocation fails (for example, if
5+
the IP address is outside of the subnet CIDR), the other IPAM allocations
6+
already created are deleted before raising the exception. Fixes bug
7+
`2039550 <https://launchpad.net/bugs/2039550>`_.

0 commit comments

Comments
 (0)