From 1025baec55235bf4981872390f1bb65f4e3ae7e6 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 25 Sep 2014 17:49:59 +0800 Subject: [PATCH] Fix duplicate entry catch for allowed address pairs If None is submitted as a MAC address in an allowed_address_pair, the port MAC will be used. So if two entries are submitted with the same IP and one's MAC is None while the others is the port's MAC, they will pass the API duplication check and fail to insert into the DB due to a unique constraint violation. This patch catches the db error and turns it into the same exception the API uses on duplicate entries. Closes-bug: #1373756 Change-Id: Ide995810d6fe0481d3add206bf0674cbbde7f05f --- neutron/db/allowedaddresspairs_db.py | 27 ++++++++++++------- .../unit/db/test_allowedaddresspairs_db.py | 15 +++++++++++ 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/neutron/db/allowedaddresspairs_db.py b/neutron/db/allowedaddresspairs_db.py index b648c8c47..44faddcd8 100644 --- a/neutron/db/allowedaddresspairs_db.py +++ b/neutron/db/allowedaddresspairs_db.py @@ -14,6 +14,8 @@ # import sqlalchemy as sa + +from oslo_db import exception as db_exc from sqlalchemy import orm from neutron.api.v2 import attributes as attr @@ -43,16 +45,21 @@ class AllowedAddressPairsMixin(object): allowed_address_pairs): if not attr.is_attr_set(allowed_address_pairs): return [] - with context.session.begin(subtransactions=True): - for address_pair in allowed_address_pairs: - # use port.mac_address if no mac address in address pair - if 'mac_address' not in address_pair: - address_pair['mac_address'] = port['mac_address'] - db_pair = AllowedAddressPair( - port_id=port['id'], - mac_address=address_pair['mac_address'], - ip_address=address_pair['ip_address']) - context.session.add(db_pair) + try: + with context.session.begin(subtransactions=True): + for address_pair in allowed_address_pairs: + # use port.mac_address if no mac address in address pair + if 'mac_address' not in address_pair: + address_pair['mac_address'] = port['mac_address'] + db_pair = AllowedAddressPair( + port_id=port['id'], + mac_address=address_pair['mac_address'], + ip_address=address_pair['ip_address']) + context.session.add(db_pair) + except db_exc.DBDuplicateEntry: + raise addr_pair.DuplicateAddressPairInRequest( + mac_address=address_pair['mac_address'], + ip_address=address_pair['ip_address']) return allowed_address_pairs diff --git a/neutron/tests/unit/db/test_allowedaddresspairs_db.py b/neutron/tests/unit/db/test_allowedaddresspairs_db.py index 2af639f70..2d3788a5b 100644 --- a/neutron/tests/unit/db/test_allowedaddresspairs_db.py +++ b/neutron/tests/unit/db/test_allowedaddresspairs_db.py @@ -279,6 +279,21 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): res = req.get_response(self.api) self.assertEqual(409, res.status_int) + def test_update_with_none_and_own_mac_for_duplicate_ip(self): + with self.network() as net: + res = self._create_port(self.fmt, net['network']['id']) + port = self.deserialize(self.fmt, res) + mac_address = port['port']['mac_address'] + address_pairs = [{'ip_address': '10.0.0.1'}, + {'mac_address': mac_address, + 'ip_address': '10.0.0.1'}] + update_port = {'port': {addr_pair.ADDRESS_PAIRS: + address_pairs}} + req = self.new_update_request('ports', update_port, + port['port']['id']) + res = req.get_response(self.api) + self.assertEqual(400, res.status_int) + def test_create_port_remove_allowed_address_pairs(self): with self.network() as net: address_pairs = [{'mac_address': '00:00:00:00:00:01', -- 2.45.2