Add check for duplicate members in batch update
If a user requests a batch update of the members and includes the same member twice in the body of the request, taskflow triggers an exception (because of a duplicate Atom) and the load balancer is stuck in PENDING_UPDATE. Now the API denies such calls and returns a ValidationException if a member is updated more than once in the same call. Story 2010399 Task 46777 Change-Id: Ide2d5e637e5feb2dad43f952d5be1a195da1ae37 (cherry picked from commitd7b0907025
) (cherry picked from commitb61c340b09
)
This commit is contained in:
parent
8832cefaa0
commit
70ecbcc8be
@ -31,6 +31,7 @@ from octavia.common import data_models
|
||||
from octavia.common import exceptions
|
||||
from octavia.common import validate
|
||||
from octavia.db import prepare as db_prepare
|
||||
from octavia.i18n import _
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -366,12 +367,21 @@ class MembersController(MemberController):
|
||||
# Find members that are brand new or updated
|
||||
new_members = []
|
||||
updated_members = []
|
||||
updated_member_uniques = set()
|
||||
for m in members:
|
||||
if (m.address, m.protocol_port) not in old_member_uniques:
|
||||
key = (m.address, m.protocol_port)
|
||||
if key not in old_member_uniques:
|
||||
validate.ip_not_reserved(m.address)
|
||||
new_members.append(m)
|
||||
else:
|
||||
m.id = old_member_uniques[(m.address, m.protocol_port)]
|
||||
m.id = old_member_uniques[key]
|
||||
if key in updated_member_uniques:
|
||||
LOG.error("Member %s is updated multiple times in "
|
||||
"the same batch request.", m.id)
|
||||
raise exceptions.ValidationException(
|
||||
detail=_("Member must be updated only once in the "
|
||||
"same request."))
|
||||
updated_member_uniques.add(key)
|
||||
updated_members.append(m)
|
||||
|
||||
# Find members that are deleted
|
||||
|
@ -913,6 +913,38 @@ class TestMember(base.BaseAPITest):
|
||||
m_subnet_exists.assert_called_once_with(
|
||||
member1['subnet_id'], context=mock.ANY)
|
||||
|
||||
@mock.patch('octavia.api.drivers.driver_factory.get_driver')
|
||||
@mock.patch('octavia.api.drivers.utils.call_provider')
|
||||
def test_update_members_member_duplicate(
|
||||
self, mock_provider, mock_get_driver):
|
||||
mock_driver = mock.MagicMock()
|
||||
mock_driver.name = 'noop_driver'
|
||||
mock_get_driver.return_value = mock_driver
|
||||
subnet_id = uuidutils.generate_uuid()
|
||||
|
||||
member1 = {'address': '192.0.2.1', 'protocol_port': 80,
|
||||
'project_id': self.project_id, 'subnet_id': subnet_id}
|
||||
|
||||
req_dict = [member1]
|
||||
body = {self.root_tag_list: req_dict}
|
||||
path = self.MEMBERS_PATH.format(pool_id=self.pool_id)
|
||||
self.put(path, body, status=202)
|
||||
|
||||
self.set_lb_status(self.lb_id)
|
||||
|
||||
# Same member (same address and protocol_port) updated twice in the
|
||||
# same PUT request
|
||||
member1 = {'address': '192.0.2.1', 'protocol_port': 80,
|
||||
'project_id': self.project_id, 'subnet_id': subnet_id,
|
||||
'name': 'member1'}
|
||||
member2 = {'address': '192.0.2.1', 'protocol_port': 80,
|
||||
'project_id': self.project_id, 'subnet_id': subnet_id,
|
||||
'name': 'member2'}
|
||||
|
||||
req_dict = [member1, member2]
|
||||
body = {self.root_tag_list: req_dict}
|
||||
self.put(path, body, status=400)
|
||||
|
||||
@mock.patch('octavia.api.drivers.driver_factory.get_driver')
|
||||
@mock.patch('octavia.api.drivers.utils.call_provider')
|
||||
def test_update_members_subnet_not_found(
|
||||
|
@ -0,0 +1,10 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Added a validation step in the batch member API request that checks if a
|
||||
member is included multiple times in the list of updated members, this
|
||||
additional check prevents the load balancer from being stuck in
|
||||
PENDING_UPDATE. Duplicate members in the batch member flow triggered an
|
||||
exception in Taskflow.
|
||||
The API now returns 400 (ValidationException) if a member is already
|
||||
present in the body of the request.
|
Loading…
Reference in New Issue
Block a user