]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Fix duplicate entry catch for allowed address pairs
authorWei Wang <wangwei@unitedstack.com>
Thu, 25 Sep 2014 09:49:59 +0000 (17:49 +0800)
committerWei Wang <wangwei@unitedstack.com>
Fri, 10 Jul 2015 10:55:58 +0000 (18:55 +0800)
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
neutron/tests/unit/db/test_allowedaddresspairs_db.py

index b648c8c479e9a71a87ee29fe6f1bbb0542f1bc05..44faddcd896ec5ff7746846347086c2ca0b3a385 100644 (file)
@@ -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
 
index 2af639f70896a1c9909ebe73c7922f1af5820a45..2d3788a5b6ed042d73af3950a76cbd3cc580bb0a 100644 (file)
@@ -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',