diff --git a/ovn_octavia_provider/driver.py b/ovn_octavia_provider/driver.py index 82cbe4d4..002c3286 100644 --- a/ovn_octavia_provider/driver.py +++ b/ovn_octavia_provider/driver.py @@ -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): diff --git a/ovn_octavia_provider/tests/functional/test_driver.py b/ovn_octavia_provider/tests/functional/test_driver.py index b89ebb29..7181b116 100644 --- a/ovn_octavia_provider/tests/functional/test_driver.py +++ b/ovn_octavia_provider/tests/functional/test_driver.py @@ -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) diff --git a/ovn_octavia_provider/tests/unit/test_driver.py b/ovn_octavia_provider/tests/unit/test_driver.py index babbfe04..84e8d0ea 100644 --- a/ovn_octavia_provider/tests/unit/test_driver.py +++ b/ovn_octavia_provider/tests/unit/test_driver.py @@ -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,