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
This commit is contained in:
Wei Wang 2014-09-25 17:49:59 +08:00
parent 043f6c3091
commit 1025baec55
2 changed files with 32 additions and 10 deletions

View 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

View 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',