Discard batch-update-members not valid request
An out of sync has been identified between the changes applied over the OVN NB DB and Octavia DB when a batch-update-members includes some unsupported option for any of the member to be modified. To prevent such inconsistencies, this patch rejects the entire request if any of the proposed changes are identified as unsupported. The user will be notified of the reason for the rejection. Closes-Bug: 2017216 Change-Id: I6e132ab5c23c9c53176612f74bb500e46c89024fchanges/98/881198/4
parent
0285967056
commit
5f27384805
|
@ -346,7 +346,6 @@ class OvnProviderDriver(driver_base.ProviderDriver):
|
|||
|
||||
def member_batch_update(self, pool_id, members):
|
||||
request_list = []
|
||||
skipped_members = []
|
||||
pool_key, ovn_lb = self._ovn_helper._find_ovn_lb_by_pool_id(pool_id)
|
||||
external_ids = copy.deepcopy(ovn_lb.external_ids)
|
||||
pool = external_ids[pool_key]
|
||||
|
@ -354,10 +353,16 @@ class OvnProviderDriver(driver_base.ProviderDriver):
|
|||
members_to_delete = copy.copy(existing_members)
|
||||
pool_subnet_id = None
|
||||
for member in members:
|
||||
if (self._check_monitor_options(member) or
|
||||
member.address and self._ip_version_differs(member)):
|
||||
skipped_members.append(member.member_id)
|
||||
continue
|
||||
# NOTE(froyo): in order to keep sync with Octavia DB, we raise
|
||||
# not supporting exceptions as soon as posible, considering the
|
||||
# full request as not valid
|
||||
if (self._check_monitor_options(member)):
|
||||
msg = 'OVN provider does not support monitor options'
|
||||
raise driver_exceptions.UnsupportedOptionError(
|
||||
user_fault_string=msg,
|
||||
operator_fault_string=msg)
|
||||
if (member.address and self._ip_version_differs(member)):
|
||||
raise ovn_exc.IPVersionsMixingNotSupportedError()
|
||||
# NOTE(froyo): if subnet_id not provided, lets try to get it
|
||||
# from the member pool_id
|
||||
subnet_id = member.subnet_id
|
||||
|
@ -419,12 +424,6 @@ class OvnProviderDriver(driver_base.ProviderDriver):
|
|||
|
||||
for request in request_list:
|
||||
self._ovn_helper.add_request(request)
|
||||
if skipped_members:
|
||||
msg = (_('OVN provider does not support monitor options, '
|
||||
'so following members skipped: %s') % skipped_members)
|
||||
raise driver_exceptions.UnsupportedOptionError(
|
||||
user_fault_string=msg,
|
||||
operator_fault_string=msg)
|
||||
|
||||
def create_vip_port(self, lb_id, project_id, vip_dict,
|
||||
additional_vip_dicts=None):
|
||||
|
|
|
@ -464,4 +464,14 @@ class TestOvnOctaviaProviderDriver(ovn_base.TestOvnOctaviaBase):
|
|||
# Deleting one member, while keeping the other member available
|
||||
self._update_members_in_batch_and_validate(lb_data, pool_id,
|
||||
[m_member])
|
||||
# Create Member-3 with monitor options
|
||||
m_member = self._create_member_model(pool_id,
|
||||
lb_data['vip_net_info'][1],
|
||||
'10.0.0.12')
|
||||
m_member.monitor_port = 8080
|
||||
members = [m_member]
|
||||
self.assertRaises(o_exceptions.UnsupportedOptionError,
|
||||
self.ovn_driver.member_batch_update,
|
||||
pool_id,
|
||||
members)
|
||||
self._delete_load_balancer_and_validate(lb_data)
|
||||
|
|
|
@ -415,6 +415,22 @@ class TestOvnProviderDriver(ovn_base.TestOvnOctaviaBase):
|
|||
[self.ref_member, self.update_member])
|
||||
self.assertEqual(self.mock_add_request.call_count, 3)
|
||||
|
||||
def test_member_batch_update_member_delete(self):
|
||||
info_md = {
|
||||
'id': self.ref_member.member_id,
|
||||
'address': mock.ANY,
|
||||
'protocol_port': mock.ANY,
|
||||
'pool_id': self.ref_member.pool_id,
|
||||
'subnet_id': self.ref_member.subnet_id}
|
||||
expected_dict_md = {
|
||||
'type': ovn_const.REQ_TYPE_MEMBER_DELETE,
|
||||
'info': info_md}
|
||||
expected = [
|
||||
mock.call(expected_dict_md)]
|
||||
self.driver.member_batch_update(self.pool_id, [])
|
||||
self.assertEqual(self.mock_add_request.call_count, 1)
|
||||
self.mock_add_request.assert_has_calls(expected)
|
||||
|
||||
def test_member_batch_update_no_members(self):
|
||||
pool_key = 'pool_%s' % self.pool_id
|
||||
ovn_lb = copy.copy(self.ovn_lb)
|
||||
|
@ -443,6 +459,26 @@ class TestOvnProviderDriver(ovn_base.TestOvnOctaviaBase):
|
|||
self.driver.member_batch_update(self.pool_id, [self.ref_member])
|
||||
self.assertEqual(self.mock_add_request.call_count, 2)
|
||||
|
||||
def test_member_batch_update_toggle_admin_state_up(self):
|
||||
info_mu = {
|
||||
'id': self.ref_member.member_id,
|
||||
'address': self.member_address,
|
||||
'protocol_port': self.member_port,
|
||||
'pool_id': self.ref_member.pool_id,
|
||||
'subnet_id': self.ref_member.subnet_id,
|
||||
'admin_state_up': False}
|
||||
expected_dict_mu = {
|
||||
'type': ovn_const.REQ_TYPE_MEMBER_UPDATE,
|
||||
'info': info_mu}
|
||||
expected = [
|
||||
mock.call(expected_dict_mu)]
|
||||
self.ref_member.admin_state_up = False
|
||||
self.ref_member.address = self.member_address
|
||||
self.ref_member.protocol_port = self.member_port
|
||||
self.driver.member_batch_update(self.pool_id, [self.ref_member])
|
||||
self.assertEqual(self.mock_add_request.call_count, 1)
|
||||
self.mock_add_request.assert_has_calls(expected)
|
||||
|
||||
def test_member_batch_update_missing_subnet_id(self):
|
||||
self.ref_member.subnet_id = None
|
||||
self.assertRaises(exceptions.UnsupportedOptionError,
|
||||
|
|
Loading…
Reference in New Issue