Deterministic ordering of fixed_ips

This adds an order_by clause to the fixed_ips relationship
on the port object to ensure that the fixed_ip ordering is
consistent between a create, an update, and a get request
for a port. Without it we were at the mercy of the sql backend
to determine how it felt like ordering them on the join condition.

Closes-Bug: #1630410
Change-Id: I523e0ab6e376f5ff6205b1cc1748aa6d546919cb
This commit is contained in:
Kevin Benton 2016-10-04 18:38:07 -06:00
parent b516691490
commit bd1c454c4f
3 changed files with 21 additions and 2 deletions

View File

@ -87,7 +87,9 @@ class Port(standard_attr.HasStandardAttributes, model_base.BASEV2,
network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id"),
nullable=False)
fixed_ips = orm.relationship(IPAllocation, backref='port', lazy='joined',
cascade='all, delete-orphan')
cascade='all, delete-orphan',
order_by=(IPAllocation.ip_address,
IPAllocation.subnet_id))
mac_address = sa.Column(sa.String(32), nullable=False)
admin_state_up = sa.Column(sa.Boolean(), nullable=False)

View File

@ -186,4 +186,5 @@ class DvrDbMixinTestCase(test_plugin.Ml2PluginV2TestCase):
dvr_ports = self.mixin.get_ports_on_host_by_subnet(
self.ctx, HOST, subnet['subnet']['id'])
self.assertEqual(len(expected_ids), len(dvr_ports))
self.assertEqual(expected_ids, [port['id'] for port in dvr_ports])
self.assertItemsEqual(expected_ids,
[port['id'] for port in dvr_ports])

View File

@ -798,6 +798,22 @@ class TestMl2PortsV2(test_plugin.TestPortsV2, Ml2PluginV2TestCase):
with self.port():
self.assertTrue(cp.called)
def test_create_update_get_port_same_fixed_ips_order(self):
ctx = context.get_admin_context()
plugin = manager.NeutronManager.get_plugin()
initial_fixed_ips = [{'ip_address': '10.0.0.5'},
{'ip_address': '10.0.0.7'},
{'ip_address': '10.0.0.6'}]
with self.port(fixed_ips=initial_fixed_ips) as port:
show = plugin.get_port(ctx, port['port']['id'])
self.assertEqual(port['port']['fixed_ips'], show['fixed_ips'])
new_fixed_ips = list(reversed(initial_fixed_ips))
port['port']['fixed_ips'] = new_fixed_ips
updated = plugin.update_port(ctx, port['port']['id'], port)
self.assertEqual(show['fixed_ips'], updated['fixed_ips'])
updated = plugin.get_port(ctx, port['port']['id'])
self.assertEqual(show['fixed_ips'], updated['fixed_ips'])
def test_update_port_fixed_ip_changed(self):
ctx = context.get_admin_context()
plugin = manager.NeutronManager.get_plugin()