Skip to content

Commit b61c340

Browse files
committed
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 commit d7b0907)
1 parent ab7712e commit b61c340

File tree

3 files changed

+54
-2
lines changed

3 files changed

+54
-2
lines changed

octavia/api/v2/controllers/member.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from octavia.common import exceptions
3232
from octavia.common import validate
3333
from octavia.db import prepare as db_prepare
34+
from octavia.i18n import _
3435

3536

3637
LOG = logging.getLogger(__name__)
@@ -365,12 +366,21 @@ def put(self, additive_only=False, members_=None):
365366
# Find members that are brand new or updated
366367
new_members = []
367368
updated_members = []
369+
updated_member_uniques = set()
368370
for m in members:
369-
if (m.address, m.protocol_port) not in old_member_uniques:
371+
key = (m.address, m.protocol_port)
372+
if key not in old_member_uniques:
370373
validate.ip_not_reserved(m.address)
371374
new_members.append(m)
372375
else:
373-
m.id = old_member_uniques[(m.address, m.protocol_port)]
376+
m.id = old_member_uniques[key]
377+
if key in updated_member_uniques:
378+
LOG.error("Member %s is updated multiple times in "
379+
"the same batch request.", m.id)
380+
raise exceptions.ValidationException(
381+
detail=_("Member must be updated only once in the "
382+
"same request."))
383+
updated_member_uniques.add(key)
374384
updated_members.append(m)
375385

376386
# Find members that are deleted

octavia/tests/functional/api/v2/test_member.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,38 @@ def test_update_members_subnet_duplicate(
913913
m_subnet_exists.assert_called_once_with(
914914
member1['subnet_id'], context=mock.ANY)
915915

916+
@mock.patch('octavia.api.drivers.driver_factory.get_driver')
917+
@mock.patch('octavia.api.drivers.utils.call_provider')
918+
def test_update_members_member_duplicate(
919+
self, mock_provider, mock_get_driver):
920+
mock_driver = mock.MagicMock()
921+
mock_driver.name = 'noop_driver'
922+
mock_get_driver.return_value = mock_driver
923+
subnet_id = uuidutils.generate_uuid()
924+
925+
member1 = {'address': '192.0.2.1', 'protocol_port': 80,
926+
'project_id': self.project_id, 'subnet_id': subnet_id}
927+
928+
req_dict = [member1]
929+
body = {self.root_tag_list: req_dict}
930+
path = self.MEMBERS_PATH.format(pool_id=self.pool_id)
931+
self.put(path, body, status=202)
932+
933+
self.set_lb_status(self.lb_id)
934+
935+
# Same member (same address and protocol_port) updated twice in the
936+
# same PUT request
937+
member1 = {'address': '192.0.2.1', 'protocol_port': 80,
938+
'project_id': self.project_id, 'subnet_id': subnet_id,
939+
'name': 'member1'}
940+
member2 = {'address': '192.0.2.1', 'protocol_port': 80,
941+
'project_id': self.project_id, 'subnet_id': subnet_id,
942+
'name': 'member2'}
943+
944+
req_dict = [member1, member2]
945+
body = {self.root_tag_list: req_dict}
946+
self.put(path, body, status=400)
947+
916948
@mock.patch('octavia.api.drivers.driver_factory.get_driver')
917949
@mock.patch('octavia.api.drivers.utils.call_provider')
918950
def test_update_members_subnet_not_found(
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
fixes:
3+
- |
4+
Added a validation step in the batch member API request that checks if a
5+
member is included multiple times in the list of updated members, this
6+
additional check prevents the load balancer from being stuck in
7+
PENDING_UPDATE. Duplicate members in the batch member flow triggered an
8+
exception in Taskflow.
9+
The API now returns 400 (ValidationException) if a member is already
10+
present in the body of the request.

0 commit comments

Comments
 (0)