Files
ovn-octavia-provider/ovn_octavia_provider/tests/unit/test_helper.py
Fernando Royo f034bab144 Remove leftover OVN LB HM port upon deletion of a member
When a load balancer pool has a Health Monitor associated with it,
an OVN LB Health Monitor port is created for each backend member
subnet added.

When removing backend members, the OVN LB Health Monitor port is
cleaned up only if no more members are associated with the Health
Monitor pool. However, this assumption is incorrect. This patch
corrects this behavior by checking instead if there are more members
from the same subnet associated with the pool. It ensures that the
OVN LB Health Monitor port is deleted only when the last member from
the subnet is deleted. If the port is being used by another different
LB Health Monitor, `_clean_up_hm_port` will handle it.

Closes-Bug: #2062965
Change-Id: I4c35cc5c6af14bb208f4313bb86e3519df0a30fa
2024-04-30 12:01:16 +02:00

5665 lines
261 KiB
Python

#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import collections
import copy
from unittest import mock
from neutron_lib import constants as n_const
from neutronclient.common import exceptions as n_exc
from octavia_lib.api.drivers import data_models
from octavia_lib.api.drivers import exceptions
from octavia_lib.common import constants
import openstack
from oslo_serialization import jsonutils
from oslo_utils import uuidutils
from ovsdbapp.backend.ovs_idl import idlutils
from ovn_octavia_provider.common import clients
from ovn_octavia_provider.common import config as ovn_conf
from ovn_octavia_provider.common import constants as ovn_const
from ovn_octavia_provider import event as ovn_event
from ovn_octavia_provider import helper as ovn_helper
from ovn_octavia_provider.tests.unit import base as ovn_base
from ovn_octavia_provider.tests.unit import fakes
Port = collections.namedtuple('Port', 'id, name, network_id, fixed_ips',
defaults=[None, '', None, []])
class TestOvnProviderHelper(ovn_base.TestOvnOctaviaBase):
def setUp(self):
super().setUp()
ovn_conf.register_opts()
self.helper = ovn_helper.OvnProviderHelper()
self.real_helper_find_ovn_lb_with_pool_key = (
self.helper._find_ovn_lb_with_pool_key)
mock.patch.object(self.helper, '_update_status_to_octavia').start()
self.octavia_driver_lib = mock.patch.object(
self.helper, '_octavia_driver_lib').start()
self.listener = {'id': self.listener_id,
'loadbalancer_id': self.loadbalancer_id,
'protocol': 'TCP',
'protocol_port': 80,
'default_pool_id': self.pool_id,
'admin_state_up': False}
self.lb = {'id': self.loadbalancer_id,
'vip_address': self.vip_address,
'cascade': False,
'vip_network_id': self.vip_network_id,
'admin_state_up': False}
self.ports = [Port(
fixed_ips=[{'ip_address': self.vip_address,
'subnet_id': uuidutils.generate_uuid()}],
network_id=self.vip_network_id,
id=self.port1_id)]
self.pool = {'id': self.pool_id,
'loadbalancer_id': self.loadbalancer_id,
'listener_id': self.listener_id,
'protocol': 'TCP',
'lb_algorithm': constants.LB_ALGORITHM_SOURCE_IP_PORT,
'admin_state_up': False}
self.member = {'id': self.member_id,
'address': self.member_address,
'protocol_port': self.member_port,
'subnet_id': self.member_subnet_id,
'pool_id': self.member_pool_id,
'admin_state_up': True,
'old_admin_state_up': True}
self.health_monitor = {'id': self.healthmonitor_id,
'pool_id': self.pool_id,
'type': constants.HEALTH_MONITOR_TCP,
'interval': 6,
'timeout': 7,
'failure_count': 5,
'success_count': 3,
'admin_state_up': True}
self.health_mon_udp = {'id': self.healthmonitor_id,
'pool_id': self.pool_id,
'type': constants.HEALTH_MONITOR_UDP_CONNECT,
'interval': 6,
'timeout': 7,
'failure_count': 5,
'success_count': 3,
'admin_state_up': True}
self.ovn_nbdb_api = mock.patch.object(self.helper, 'ovn_nbdb_api')
self.ovn_nbdb_api.start()
add_req_thread = mock.patch.object(ovn_helper.OvnProviderHelper,
'add_request')
self.mock_add_request = add_req_thread.start()
self.ovn_lb = mock.MagicMock()
self.ovn_lb.protocol = ['tcp']
self.ovn_lb.uuid = uuidutils.generate_uuid()
self.ovn_lb.health_check = []
self.ovn_hm_lb = mock.MagicMock()
self.ovn_hm_lb.protocol = ['tcp']
self.ovn_hm_lb.uuid = uuidutils.generate_uuid()
self.ovn_hm = mock.MagicMock()
self.ovn_hm.uuid = self.healthmonitor_id
self.ovn_hm.external_ids = {
ovn_const.LB_EXT_IDS_HM_KEY: self.ovn_hm.uuid,
ovn_const.LB_EXT_IDS_HM_POOL_KEY: self.pool_id,
ovn_const.LB_EXT_IDS_HM_VIP: '10.22.33.99'}
self.ovn_hm_lb.health_check = [self.ovn_hm.uuid]
self.member_line = (
'member_%s_%s:%s_%s' %
(self.member_id, self.member_address,
self.member_port, self.member_subnet_id))
self.ovn_lb.external_ids = {
ovn_const.LB_EXT_IDS_VIP_KEY: '10.22.33.4',
ovn_const.LB_EXT_IDS_VIP_FIP_KEY: '123.123.123.123',
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: 'foo_port',
'enabled': True,
'pool_%s' % self.pool_id: self.member_line,
'listener_%s' % self.listener_id: '80:pool_%s' % self.pool_id,
ovn_const.OVN_MEMBER_STATUS_KEY: '{"%s": "%s"}'
% (self.member_id, constants.NO_MONITOR)}
self.ovn_hm_lb.external_ids = {
ovn_const.LB_EXT_IDS_VIP_KEY: '10.22.33.99',
ovn_const.LB_EXT_IDS_VIP_FIP_KEY: '123.123.123.99',
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: 'foo_hm_port',
ovn_const.LB_EXT_IDS_HMS_KEY: '["%s"]' % (self.ovn_hm.uuid),
'enabled': True,
'pool_%s' % self.pool_id: '',
'listener_%s' % self.listener_id: '80:pool_%s' % self.pool_id,
ovn_const.OVN_MEMBER_STATUS_KEY: '{}'}
self.helper.ovn_nbdb_api.db_find.return_value.\
execute.return_value = [self.ovn_lb]
self.helper.ovn_nbdb_api.db_list_rows.return_value.\
execute.return_value = [self.ovn_lb]
self.mock_find_lb_pool_key = mock.patch.object(
self.helper,
'_find_ovn_lb_with_pool_key',
return_value=self.ovn_lb).start()
self.mock_find_ovn_lbs = mock.patch.object(
ovn_helper.OvnProviderHelper, '_find_ovn_lbs',
side_effect=lambda x, protocol=None:
self.ovn_lb if protocol else [self.ovn_lb])
self.mock_find_ovn_lbs.start()
self._get_pool_listeners = mock.patch.object(
self.helper,
'_get_pool_listeners',
return_value=[])
self._get_pool_listeners.start()
self._update_lb_to_ls_association = mock.patch.object(
self.helper,
'_update_lb_to_ls_association',
return_value=[])
self._update_lb_to_ls_association.start()
self._get_lb_to_ls_association_commands = mock.patch.object(
self.helper,
'_get_lb_to_ls_association_commands',
return_value=[])
self._get_lb_to_ls_association_commands.start()
self._update_lb_to_lr_association = mock.patch.object(
self.helper,
'_update_lb_to_lr_association',
return_value=[])
self._update_lb_to_lr_association.start()
self._get_lb_to_lr_association_commands = mock.patch.object(
self.helper,
'_get_lb_to_lr_association_commands',
return_value=[])
self._get_lb_to_lr_association_commands.start()
self._update_lb_to_lr_association_by_step = \
mock.patch.object(
self.helper,
'_update_lb_to_lr_association_by_step',
return_value=[])
self._update_lb_to_lr_association_by_step.start()
# NOTE(mjozefcz): Create foo router and network.
net_id = uuidutils.generate_uuid()
router_id = uuidutils.generate_uuid()
self.ref_lb1 = fakes.FakeLB(
uuid=uuidutils.generate_uuid(),
admin_state_up=True,
listeners=[],
loadbalancer_id=self.loadbalancer_id,
name='favorite_lb1',
project_id=self.project_id,
vip_address=self.vip_address,
vip_network_id=self.vip_network_id,
ext_ids={
ovn_const.LB_EXT_IDS_LR_REF_KEY: 'neutron-%s' % net_id,
ovn_const.LB_EXT_IDS_LS_REFS_KEY:
'{\"neutron-%s\": 1}' % net_id,
ovn_const.LB_EXT_IDS_VIP_KEY: self.vip_address})
self.ref_lb2 = fakes.FakeLB(
uuid=uuidutils.generate_uuid(),
admin_state_up=True,
listeners=[],
loadbalancer_id=self.loadbalancer_id,
name='favorite_lb2',
project_id=self.project_id,
vip_address=self.vip_address,
vip_network_id=self.vip_network_id,
ext_ids={
ovn_const.LB_EXT_IDS_LR_REF_KEY: 'neutron-%s' % net_id,
ovn_const.LB_EXT_IDS_LS_REFS_KEY:
'{\"neutron-%s\": 1}' % net_id,
ovn_const.LB_EXT_IDS_VIP_KEY: self.vip_address})
# TODO(mjozefcz): Consider using FakeOVNRouter.
self.router = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'load_balancer': [self.ref_lb1],
'name': 'neutron-%s' % router_id,
'ports': []})
# TODO(mjozefcz): Consider using FakeOVNSwitch.
self.network = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'load_balancer': [self.ref_lb2],
'name': 'neutron-%s' % net_id,
'ports': [],
'uuid': net_id})
self.mock_get_nw = mock.patch.object(
self.helper, '_get_nw_router_info_on_interface_event',
return_value=(self.router, self.network))
self.mock_get_nw.start()
(self.helper.ovn_nbdb_api.ls_get.return_value.
execute.return_value) = self.network
def test__update_hm_member_no_members(self):
pool_key = 'pool_%s' % self.pool_id
self.ovn_lb.external_ids[pool_key] = ''
self.assertEqual(self.helper._update_hm_member(
self.ovn_lb, pool_key, '10.0.0.4'), constants.ERROR)
def test__update_hm_member_backend_ip_not_match(self):
pool_key = 'pool_%s' % self.pool_id
self.ovn_lb.external_ids[pool_key] = self.member_line
with mock.patch.object(ovn_helper.OvnProviderHelper,
'_get_member_lsp'):
self.assertEqual(self.helper._update_hm_member(
self. ovn_lb, pool_key, '10.0.0.4'), constants.ERROR)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_ensure_hm_ovn_port')
def test__update_hm_member_hm_port_multiple_ip(self, ensure_hm_port):
hm_port = {
'fixed_ips': [{
'subnet_id': 'ipv6_foo',
'ip_address': '2001:db8::199'}, {
'subnet_id': self.member_subnet_id,
'ip_address': '10.0.0.4'}]}
ensure_hm_port.return_value = hm_port
pool_key = 'pool_%s' % self.pool_id
with mock.patch.object(ovn_helper.OvnProviderHelper,
'_get_member_lsp'):
self.assertEqual(self.helper._update_hm_member(
self.ovn_lb, pool_key, self.member_address), constants.ONLINE)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_ensure_hm_ovn_port')
def test__update_hm_member_hm_port_not_found(self, ensure_hm_port):
ensure_hm_port.return_value = None
pool_key = 'pool_%s' % self.pool_id
with mock.patch.object(ovn_helper.OvnProviderHelper,
'_get_member_lsp'):
self.assertIsNone(
self.helper._update_hm_member(self.ovn_lb,
pool_key,
self.member_address))
def test__clean_ip_port_mappings(self):
self.helper._clean_ip_port_mappings(self.ovn_hm_lb)
self.helper.ovn_nbdb_api.db_clear.assert_called_once_with(
'Load_Balancer', self.ovn_hm_lb.uuid, 'ip_port_mappings')
def test__clean_ip_port_mappings_two_hm_pools_sharing_members(self):
self.member_line_pool1 = 'member_uuid1_address1:port1_subnet1, \
member_uuid2_address2:port2_subnet1'
self.member_line_pool2 = 'member_uuid3_address1:port3_subnet1, \
member_uuid4_address4:port4_subnet1'
self.ovn_hm_lb.external_ids['pool_1'] = self.member_line_pool1
self.ovn_hm_lb.external_ids['pool_2'] = self.member_line_pool2
self.ovn_hm_lb.external_ids[ovn_const.OVN_MEMBER_STATUS_KEY] = \
'{"uuid1": "ONLINE", "uuid2": "ONLINE", \
"uuid3": "ONLINE", "uuid4": "ONLINE"}'
self.helper._clean_ip_port_mappings(self.ovn_hm_lb, 'pool_1')
self.helper.ovn_nbdb_api.db_clear.assert_not_called()
self.helper.ovn_nbdb_api.lb_del_ip_port_mapping.\
assert_called_once_with(self.ovn_hm_lb.uuid, 'address2')
def test__clean_ip_port_mappings_one_hm_pools_sharing_members(self):
self.member_line_pool1 = 'member_uuid1_address1:port1_subnet1, \
member_uuid2_address2:port2_subnet1'
self.member_line_pool2 = 'member_uuid3_address1:port3_subnet1, \
member_uuid4_address2:port4_subnet1'
self.ovn_hm_lb.external_ids['pool_1'] = self.member_line_pool1
self.ovn_hm_lb.external_ids['pool_2'] = self.member_line_pool2
self.ovn_hm_lb.external_ids[ovn_const.OVN_MEMBER_STATUS_KEY] = \
'{"uuid1": "ONLINE", "uuid2": "ONLINE", \
"uuid3": "NO_MONITOR", "uuid4": "NO_MONITOR"}'
self.helper._clean_ip_port_mappings(self.ovn_hm_lb, 'pool_1')
self.helper.ovn_nbdb_api.db_clear.assert_not_called()
self.helper.ovn_nbdb_api.lb_del_ip_port_mapping.\
assert_has_calls([mock.call(self.ovn_hm_lb.uuid, 'address1'),
mock.ANY,
mock.call(self.ovn_hm_lb.uuid, 'address2'),
mock.ANY])
def test__clean_ip_port_mappings_two_hm_pools_not_sharing_members(self):
self.member_line_pool1 = 'member_uuid1_address1:port1_subnet1, \
member_uuid2_address2:port2_subnet1'
self.member_line_pool2 = 'member_uuid3_address3:port3_subnet1, \
member_uuid4_address4:port4_subnet1'
self.ovn_hm_lb.external_ids['pool_1'] = self.member_line_pool1
self.ovn_hm_lb.external_ids['pool_2'] = self.member_line_pool2
self.ovn_hm_lb.external_ids[ovn_const.OVN_MEMBER_STATUS_KEY] = \
'{"uuid1": "ONLINE", "uuid2": "ONLINE", \
"uuid3": "ONLINE", "uuid4": "ONLINE"}'
self.helper._clean_ip_port_mappings(self.ovn_hm_lb, 'pool_1')
self.helper.ovn_nbdb_api.db_clear.assert_not_called()
self.helper.ovn_nbdb_api.lb_del_ip_port_mapping.\
assert_has_calls([mock.call(self.ovn_hm_lb.uuid, 'address1'),
mock.ANY,
mock.call(self.ovn_hm_lb.uuid, 'address2'),
mock.ANY])
def test__update_ip_port_mappings_del_backend_member(self):
src_ip = '10.22.33.4'
self.helper._update_ip_port_mappings(
self.ovn_lb, self.member_address, 'a-logical-port', src_ip,
delete=True)
self.helper.ovn_nbdb_api.lb_del_ip_port_mapping.\
assert_called_once_with(self.ovn_lb.uuid, self.member_address)
def test__update_ip_port_mappings_add_backend_member(self):
src_ip = '10.22.33.4'
self.helper._update_ip_port_mappings(
self.ovn_lb, self.member_address, 'a-logical-port', src_ip)
self.helper.ovn_nbdb_api.lb_add_ip_port_mapping.\
assert_called_once_with(self.ovn_lb.uuid, self.member_address,
'a-logical-port', src_ip)
def test__update_ip_port_mappings_del_backend_member_ipv6(self):
member_address = 'fda2:918e:5869:0:f816:3eff:feab:cdef'
src_ip = 'fda2:918e:5869:0:f816:3eff:fecd:398a'
self.helper._update_ip_port_mappings(
self.ovn_lb, member_address, 'a-logical-port', src_ip,
delete=True)
self.helper.ovn_nbdb_api.lb_del_ip_port_mapping.\
assert_called_once_with(self.ovn_lb.uuid, member_address)
def test__update_ip_port_mappings_add_backend_member_ipv6(self):
member_address = 'fda2:918e:5869:0:f816:3eff:feab:cdef'
src_ip = 'fda2:918e:5869:0:f816:3eff:fecd:398a'
self.helper._update_ip_port_mappings(
self.ovn_lb, member_address, 'a-logical-port', src_ip)
self.helper.ovn_nbdb_api.lb_add_ip_port_mapping.\
assert_called_once_with(
self.ovn_lb.uuid, member_address, 'a-logical-port', src_ip)
def test__update_external_ids_member_status(self):
self.helper._update_external_ids_member_status(
self.ovn_lb, self.member_id, constants.NO_MONITOR)
member_status = {
ovn_const.OVN_MEMBER_STATUS_KEY: '{"%s": "%s"}'
% (self.member_id, constants.NO_MONITOR)}
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid, ('external_ids', member_status))
def test__update_external_ids_member_status_delete(self):
self.helper._update_external_ids_member_status(
self.ovn_lb, self.member_id, None, True)
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid, 'external_ids',
ovn_const.OVN_MEMBER_STATUS_KEY)
def test__update_external_ids_member_status_delete_not_found(self):
self.helper._update_external_ids_member_status(
self.ovn_lb, 'fool', None, True)
member_status = {
ovn_const.OVN_MEMBER_STATUS_KEY: '{"%s": "%s"}'
% (self.member_id, constants.NO_MONITOR)}
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid, ('external_ids', member_status))
def test__find_member_status(self):
status = self.helper._find_member_status(self.ovn_lb, self.member_id)
self.assertEqual(status, constants.NO_MONITOR)
status = self.helper._find_member_status(
self.ovn_hm_lb, self.member_id)
self.assertEqual(status, constants.NO_MONITOR)
def test__find_member_status_exception(self):
status = self.helper._find_member_status(self.ovn_hm_lb, 'foo')
self.assertEqual(status, constants.NO_MONITOR)
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
def test__clean_lb_if_empty(self, lb):
lb.side_effect = [idlutils.RowNotFound]
self.ovn_lb.external_ids.pop('listener_%s' % self.listener_id)
self.ovn_lb.external_ids.pop('pool_%s' % self.pool_id)
commands, lb_to_delete = self.helper._clean_lb_if_empty(
self.ovn_lb, self.ovn_lb.uuid, self.ovn_lb.external_ids)
self.assertEqual([], commands)
self.assertFalse(lb_to_delete)
def test__is_lb_empty(self):
f = self.helper._is_lb_empty
self.assertFalse(f(self.ovn_lb.external_ids))
self.ovn_lb.external_ids.pop('listener_%s' % self.listener_id)
self.assertFalse(f(self.ovn_lb.external_ids))
self.ovn_lb.external_ids.pop('pool_%s' % self.pool_id)
self.assertTrue(f(self.ovn_lb.external_ids))
def test__delete_disabled_from_status(self):
f = self.helper._delete_disabled_from_status
status = {
'pools': [
{'id': 'f:D', 'provisioning_status': 'ACTIVE',
'operating_status': 'ONLINE'}],
'members': [
{'id': 'foo:D',
'provisioning_status': 'ACTIVE'}]}
expected = {
'pools': [
{'id': 'f', 'provisioning_status': 'ACTIVE',
'operating_status': 'ONLINE'}],
'members': [
{'id': 'foo',
'provisioning_status': 'ACTIVE'}]}
self.assertEqual(f(status), expected)
self.assertEqual(f(expected), expected)
status = {}
self.assertFalse(f(status))
def test__find_ovn_lb_with_pool_key(self):
pool_key = self.helper._get_pool_key(uuidutils.generate_uuid())
test_lb = mock.MagicMock()
test_lb.external_ids = {
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
ovn_const.PORT_FORWARDING_PLUGIN,
pool_key: 'it_is_a_pool_party',
}
self.helper.ovn_nbdb_api.db_list_rows.return_value.\
execute.return_value = [test_lb]
f = self.real_helper_find_ovn_lb_with_pool_key
# Ensure lb is not found, due to its device owner
found = f(pool_key)
self.assertIsNone(found)
# Remove device owner from test_lb.external_ids and make sure test_lb
# is found as expected
test_lb.external_ids.pop(ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY)
found = f(pool_key)
self.assertEqual(found, test_lb)
# Ensure lb is not found, due to its pool_key not found
found = f(self.helper._get_pool_key(uuidutils.generate_uuid()))
self.assertIsNone(found)
def test__find_ovn_lbs(self):
self.mock_find_ovn_lbs.stop()
f = self.helper._find_ovn_lbs
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = [self.ovn_lb]
# Without protocol specified return a list
found = f(self.ovn_lb.id)
self.assertListEqual(found, [self.ovn_lb])
self.helper.ovn_nbdb_api.db_find_rows.assert_called_once_with(
'Load_Balancer', ('name', '=', self.ovn_lb.id))
self.helper.ovn_nbdb_api.db_find_rows.reset_mock()
# With protocol specified return an instance
found = f(self.ovn_lb.id, protocol='tcp')
self.assertEqual(found, self.ovn_lb)
self.helper.ovn_nbdb_api.db_find_rows.reset_mock()
# LB with given protocol not found
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = []
self.assertRaises(
idlutils.RowNotFound,
f,
self.ovn_lb.id,
protocol='UDP')
# LB with given protocol not found
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = []
self.assertRaises(
idlutils.RowNotFound,
f,
self.ovn_lb.id,
protocol='SCTP')
# Multiple protocols
udp_lb = copy.copy(self.ovn_lb)
udp_lb.protocol = ['udp']
sctp_lb = copy.copy(self.ovn_lb)
sctp_lb.protocol = ['sctp']
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = [self.ovn_lb, udp_lb, sctp_lb]
found = f(self.ovn_lb.id)
self.assertListEqual(found, [self.ovn_lb, udp_lb, sctp_lb])
# Multiple protocols, just one with correct protocol
udp_lb = copy.copy(self.ovn_lb)
udp_lb.protocol = ['udp']
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = [udp_lb, self.ovn_lb]
found = f(self.ovn_lb.id, protocol='tcp')
self.assertEqual(found, self.ovn_lb)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test__get_subnet_from_pool(self, net_cli):
net_cli.return_value.get_subnet.return_value = (
fakes.FakeSubnet.create_one_subnet(
attrs={'cidr': '10.22.33.0/24'}))
f = self.helper._get_subnet_from_pool
lb = data_models.LoadBalancer(
loadbalancer_id=self.loadbalancer_id,
name='The LB',
vip_address=self.vip_address,
vip_subnet_id=self.vip_subnet_id,
vip_network_id=self.vip_network_id)
lb_pool = data_models.Pool(
loadbalancer_id=self.loadbalancer_id,
name='The pool',
pool_id=self.pool_id,
protocol='TCP')
with mock.patch.object(self.helper, '_octavia_driver_lib') as dlib:
dlib.get_pool.return_value = None
found = f('not_found')
self.assertEqual((None, None), found)
dlib.get_pool.return_value = lb_pool
dlib.get_loadbalancer.return_value = lb
found = f(self.pool_id)
self.assertEqual(found, (lb.vip_subnet_id, '10.22.33.0/24'))
def test__check_lbhc_vip_format(self):
vip = "192.168.0.1:8080"
result = self.helper._check_lbhc_vip_format(vip)
self.assertTrue(result)
vip = "192.168.0.1"
result = self.helper._check_lbhc_vip_format(vip)
self.assertFalse(result)
vip = "[2001:db8:3333:4444:5555:6666:7777:8888]:8080"
result = self.helper._check_lbhc_vip_format(vip)
self.assertTrue(result)
vip = "[2001:db8:3333:4444:5555:6666:7777:8888]"
result = self.helper._check_lbhc_vip_format(vip)
self.assertFalse(result)
vip = ""
result = self.helper._check_lbhc_vip_format(vip)
self.assertFalse(result)
def test__get_subnet_from_pool_lb_no_vip_subnet_id(self):
f = self.helper._get_subnet_from_pool
lb = data_models.LoadBalancer(
loadbalancer_id=self.loadbalancer_id,
name='The LB',
vip_address=self.vip_address,
vip_network_id=self.vip_network_id)
lb_pool = data_models.Pool(
loadbalancer_id=self.loadbalancer_id,
name='The pool',
pool_id=self.pool_id,
protocol='TCP')
with mock.patch.object(self.helper, '_octavia_driver_lib') as dlib:
dlib.get_pool.return_value = None
found = f('not_found')
self.assertEqual((None, None), found)
dlib.get_pool.return_value = lb_pool
dlib.get_loadbalancer.return_value = lb
found = f(self.pool_id)
self.assertEqual((None, None), found)
def test__get_or_create_ovn_lb_no_lb_found(self):
self.mock_find_ovn_lbs.stop()
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = []
self.assertRaises(
idlutils.RowNotFound,
self.helper._get_or_create_ovn_lb,
self.ovn_lb.name,
protocol='TCP',
admin_state_up='True')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'lb_create')
def test__get_or_create_ovn_lb_required_proto_not_found(self, lbc):
udp_lb = copy.copy(self.ovn_lb)
udp_lb.protocol = ['udp']
udp_lb.external_ids[ovn_const.LB_EXT_IDS_ADDIT_VIP_FIP_KEY] = 'foo'
self.mock_find_ovn_lbs.stop()
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.side_effect = [[udp_lb], [self.ovn_lb]]
self.helper._get_or_create_ovn_lb(
self.ovn_lb.name,
protocol='TCP',
admin_state_up='True')
expected_lb_info = {
'id': self.ovn_lb.name,
'protocol': 'tcp',
'lb_algorithm': constants.LB_ALGORITHM_SOURCE_IP_PORT,
'vip_address': udp_lb.external_ids.get(
ovn_const.LB_EXT_IDS_VIP_KEY),
'vip_port_id':
udp_lb.external_ids.get(
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY),
ovn_const.LB_EXT_IDS_LR_REF_KEY:
udp_lb.external_ids.get(
ovn_const.LB_EXT_IDS_LR_REF_KEY),
ovn_const.LB_EXT_IDS_LS_REFS_KEY:
udp_lb.external_ids.get(
ovn_const.LB_EXT_IDS_LS_REFS_KEY),
constants.ADDITIONAL_VIPS: [],
'admin_state_up': 'True',
ovn_const.LB_EXT_IDS_VIP_FIP_KEY:
udp_lb.external_ids.get(
ovn_const.LB_EXT_IDS_VIP_FIP_KEY),
ovn_const.LB_EXT_IDS_ADDIT_VIP_FIP_KEY:
udp_lb.external_ids.get(
ovn_const.LB_EXT_IDS_ADDIT_VIP_FIP_KEY)}
lbc.assert_called_once_with(expected_lb_info, protocol='tcp')
def test__get_or_create_ovn_lb_found(self):
self.mock_find_ovn_lbs.stop()
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = [self.ovn_lb]
found = self.helper._get_or_create_ovn_lb(
self.ovn_lb.name,
protocol='TCP',
admin_state_up='True')
self.assertEqual(found, self.ovn_lb)
def test__get_or_create_ovn_lb_lb_without_protocol(self):
self.mock_find_ovn_lbs.stop()
self.ovn_lb.protocol = []
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = [self.ovn_lb]
found = self.helper._get_or_create_ovn_lb(
self.ovn_lb.name,
protocol='TCP',
admin_state_up='True')
self.assertEqual(found, self.ovn_lb)
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid, ('protocol', 'tcp'))
@mock.patch.object(ovn_helper.OvnProviderHelper, 'lb_create')
def test__get_or_create_ovn_lb_no_vip_fip(self, lbc):
self.mock_find_ovn_lbs.stop()
udp_lb = copy.copy(self.ovn_lb)
udp_lb.external_ids.pop(ovn_const.LB_EXT_IDS_VIP_FIP_KEY)
udp_lb.protocol = ['udp']
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.side_effect = [[udp_lb], [self.ovn_lb]]
self.helper._get_or_create_ovn_lb(
self.ovn_lb.name,
protocol='TCP',
admin_state_up='True')
expected_lb_info = {
'id': self.ovn_lb.name,
'protocol': 'tcp',
'lb_algorithm': constants.LB_ALGORITHM_SOURCE_IP_PORT,
'vip_address': udp_lb.external_ids.get(
ovn_const.LB_EXT_IDS_VIP_KEY),
'vip_port_id':
udp_lb.external_ids.get(
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY),
ovn_const.LB_EXT_IDS_LR_REF_KEY:
udp_lb.external_ids.get(
ovn_const.LB_EXT_IDS_LR_REF_KEY),
ovn_const.LB_EXT_IDS_LS_REFS_KEY:
udp_lb.external_ids.get(
ovn_const.LB_EXT_IDS_LS_REFS_KEY),
constants.ADDITIONAL_VIPS: [],
'admin_state_up': 'True'}
lbc.assert_called_once_with(expected_lb_info, protocol='tcp')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_lb_create_disabled(self, net_cli):
self.lb['admin_state_up'] = False
net_cli.return_value.ports.return_value = self.ports
status = self.helper.lb_create(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.db_create.assert_called_once_with(
'Load_Balancer', external_ids={
ovn_const.LB_EXT_IDS_VIP_KEY: mock.ANY,
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
'enabled': 'False'},
name=mock.ANY,
protocol=[],
selection_fields=['ip_src', 'ip_dst', 'tp_src', 'tp_dst'])
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_lb_create_enabled(self, net_cli):
self.lb['admin_state_up'] = True
net_cli.return_value.ports.return_value = self.ports
status = self.helper.lb_create(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)
self.helper.ovn_nbdb_api.db_create.assert_called_once_with(
'Load_Balancer', external_ids={
ovn_const.LB_EXT_IDS_VIP_KEY: mock.ANY,
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
'enabled': 'True'},
name=mock.ANY,
protocol=[],
selection_fields=['ip_src', 'ip_dst', 'tp_src', 'tp_dst'])
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_lb_create_with_additional_vips(self, net_cli):
self.lb['admin_state_up'] = True
self.lb['additional_vips'] = self.additional_vips
net_cli.return_value.ports.return_value = self.ports
status = self.helper.lb_create(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)
self.helper.ovn_nbdb_api.db_create.assert_called_once_with(
'Load_Balancer', external_ids={
ovn_const.LB_EXT_IDS_VIP_KEY: mock.ANY,
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
ovn_const.LB_EXT_IDS_ADDIT_VIP_KEY:
self.additional_vips[0]['ip_address'],
ovn_const.LB_EXT_IDS_ADDIT_VIP_PORT_ID_KEY:
self.additional_vips[0]['port_id'],
'enabled': 'True'},
name=mock.ANY,
protocol=[],
selection_fields=['ip_src', 'ip_dst', 'tp_src', 'tp_dst'])
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_get_port_from_info')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_create_with_additional_vips_exception_no_ports_leftover(
self, del_port, gpfi, net_cli):
gpfi.side_effect = [
(Port(name=ovn_const.LB_VIP_PORT_PREFIX + self.loadbalancer_id,
id='port_vip_id'), None),
(Port(name=ovn_const.LB_VIP_ADDIT_PORT_PREFIX + '1-' +
self.loadbalancer_id, id='port_addi_vip_id'), None),
RuntimeError]
self.additional_vips.append({})
self.lb['additional_vips'] = self.additional_vips
status = self.helper.lb_create(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
self.helper.ovn_nbdb_api.db_create.assert_not_called()
expected_calls = [
mock.call('port_vip_id'),
mock.call('port_addi_vip_id')]
del_port.assert_has_calls(expected_calls)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper,
'_update_lb_to_ls_association')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_get_port_from_info')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_create_with_addi_vips_exception_no_ports_leftover_on_create(
self, del_port, gpfi, update_lb_ls, net_cli):
self.lb['admin_state_up'] = True
self.lb['additional_vips'] = self.additional_vips
gpfi.side_effect = [
(Port(name=ovn_const.LB_VIP_PORT_PREFIX + self.loadbalancer_id,
id='port_vip_id'), None),
(Port(name=ovn_const.LB_VIP_ADDIT_PORT_PREFIX + '1-' +
self.loadbalancer_id, id='port_addi_vip_id'), None)]
update_lb_ls.side_efffect = [RuntimeError]
net_cli.return_value.ports.return_value = self.ports
status = self.helper.lb_create(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
self.helper.ovn_nbdb_api.db_create.assert_called_once_with(
'Load_Balancer', external_ids={
ovn_const.LB_EXT_IDS_VIP_KEY: mock.ANY,
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
ovn_const.LB_EXT_IDS_ADDIT_VIP_KEY:
self.additional_vips[0]['ip_address'],
ovn_const.LB_EXT_IDS_ADDIT_VIP_PORT_ID_KEY:
self.additional_vips[0]['port_id'],
'enabled': 'True'},
name=mock.ANY,
protocol=[],
selection_fields=['ip_src', 'ip_dst', 'tp_src', 'tp_dst'])
expected_calls = [
mock.call('port_vip_id'),
mock.call('port_addi_vip_id')]
del_port.assert_has_calls(expected_calls)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_lr_of_ls')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_lb_create_assoc_lb_to_lr_by_step(self, net_cli, f_lr):
self.mock_find_ovn_lbs.stop()
self.helper._find_ovn_lbs
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = [self.ovn_lb]
self._update_lb_to_ls_association.stop()
self.lb['admin_state_up'] = True
f_lr.return_value = self.router
net_cli.return_value.ports.return_value = self.ports
self.helper._update_lb_to_lr_association.side_effect = [
idlutils.RowNotFound]
status = self.helper.lb_create(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)
self.helper.ovn_nbdb_api.db_create.assert_called_once_with(
'Load_Balancer', external_ids={
ovn_const.LB_EXT_IDS_VIP_KEY: mock.ANY,
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
'enabled': 'True'},
name=mock.ANY,
protocol=[],
selection_fields=['ip_src', 'ip_dst', 'tp_src', 'tp_dst'])
self.helper._update_lb_to_lr_association.assert_called_once_with(
self.ovn_lb, self.router
)
self.helper._update_lb_to_lr_association_by_step \
.assert_called_once_with(
self.ovn_lb,
self.router)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_lb_create_selection_fields_not_supported(self, net_cli):
self.lb['admin_state_up'] = True
net_cli.return_value.ports.return_value = self.ports
self.helper._are_selection_fields_supported = (
mock.Mock(return_value=False))
status = self.helper.lb_create(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)
self.helper.ovn_nbdb_api.db_create.assert_called_once_with(
'Load_Balancer', external_ids={
ovn_const.LB_EXT_IDS_VIP_KEY: mock.ANY,
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
'enabled': 'True'},
name=mock.ANY,
protocol=[])
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_lb_create_selection_fields_not_supported_algo(self, net_cli):
self.lb['admin_state_up'] = True
net_cli.return_value.ports.return_value = self.ports
net_cli.return_value.get_subnet.return_value = mock.MagicMock()
self.pool['lb_algoritm'] = 'foo'
status = self.helper.lb_create(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)
# NOTE(mjozefcz): Make sure that we use the same selection
# fields as for default algorithm - source_ip_port.
self.helper.ovn_nbdb_api.db_create.assert_called_once_with(
'Load_Balancer', external_ids={
ovn_const.LB_EXT_IDS_VIP_KEY: mock.ANY,
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
'enabled': 'True'},
name=mock.ANY,
protocol=[],
selection_fields=['ip_src', 'ip_dst', 'tp_src', 'tp_dst'])
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def _test_lb_create_on_multi_protocol(self, protocol, provider, net_cli):
"""This test situation when new protocol is added
to the same loadbalancer and we need to add
additional OVN lb with the same name.
"""
self.lb['admin_state_up'] = True
self.lb['protocol'] = protocol
self.lb[ovn_const.LB_EXT_IDS_LR_REF_KEY] = 'foo'
self.lb[ovn_const.LB_EXT_IDS_LS_REFS_KEY] = '{\"neutron-foo\": 1}'
net_cli.return_value.ports.return_value = self.ports
fake_network = mock.MagicMock()
fake_network.id = self.lb['vip_network_id']
fake_network.provider_physical_network = provider
net_cli.return_value.get_network.return_value = fake_network
status = self.helper.lb_create(self.lb, protocol=protocol)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)
self.helper.ovn_nbdb_api.db_create.assert_called_once_with(
'Load_Balancer', external_ids={
ovn_const.LB_EXT_IDS_VIP_KEY: mock.ANY,
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: mock.ANY,
ovn_const.LB_EXT_IDS_LR_REF_KEY: 'foo',
'enabled': 'True'},
name=mock.ANY,
protocol=protocol.lower(),
selection_fields=['ip_src', 'ip_dst', 'tp_src', 'tp_dst'])
if provider:
self.helper._update_lb_to_ls_association.assert_not_called()
else:
self.helper._update_lb_to_ls_association.assert_has_calls([
mock.call(self.ovn_lb, associate=True,
network_id=self.lb['vip_network_id'],
update_ls_ref=True, additional_vips=True),
mock.call(self.ovn_lb, associate=True, network_id='foo',
update_ls_ref=True)])
def test_lb_create_on_multi_protocol_UDP(self):
self._test_lb_create_on_multi_protocol('UDP', None)
def test_lb_create_on_multi_protocol_SCTP(self):
self._test_lb_create_on_multi_protocol('SCTP', None)
def _test_lb_create_on_provider_network(self):
# Test case for LB created on provider network.
# Ensure LB is not associated to the LS in that case
self._test_lb_create_on_multi_protocol('TCP', "provider")
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_lb_create_neutron_client_exception(self, net_cli):
net_cli.return_value.ports.return_value = self.ports
net_cli.return_value.get_subnet.side_effect = [
openstack.exceptions.ResourceNotFound]
status = self.helper.lb_create(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_create_exception(self, del_port, net_cli):
self.helper._find_ovn_lbs.side_effect = [RuntimeError]
net_cli.return_value.ports.return_value = self.ports
status = self.helper.lb_create(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
del_port.assert_called_once_with(self.ports[0].id)
del_port.side_effect = [Exception]
status = self.helper.lb_create(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_delete(self, del_port, net_cli):
net_cli.return_value.delete_port.return_value = None
status = self.helper.lb_delete(self.ovn_lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
self.ovn_lb.uuid)
del_port.assert_called_once_with('foo_port')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_delete_with_health_monitor(self, del_port, net_cli):
net_cli.return_value.delete_port.return_value = None
self.ovn_lb.health_check = [self.ovn_hm]
status = self.helper.lb_delete(self.ovn_lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
self.ovn_lb.uuid)
del_port.assert_called_once_with('foo_port')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_delete_additional_vips(self, del_port, net_cli):
net_cli.return_value.delete_port.return_value = None
self.ovn_lb.external_ids[ovn_const.LB_EXT_IDS_ADDIT_VIP_KEY] = \
'10.24.34.4,10.25.35.4'
self.ovn_lb.external_ids[
ovn_const.LB_EXT_IDS_ADDIT_VIP_PORT_ID_KEY] = \
'addi_foo_port,addi_foo_port_2'
status = self.helper.lb_delete(self.ovn_lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
self.ovn_lb.uuid)
expected_calls = [
mock.call('foo_port'),
mock.call('addi_foo_port'),
mock.call('addi_foo_port_2')]
del_port.assert_has_calls(expected_calls)
@mock.patch.object(ovn_helper.OvnProviderHelper,
'_get_vip_port_from_loadbalancer_id')
@mock.patch.object(ovn_helper.OvnProviderHelper,
'_get_additional_vips_from_loadbalancer_id')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_delete_row_not_found(
self, del_port, get_addi_vip_port, get_vip_port):
self.helper._find_ovn_lbs.side_effect = [idlutils.RowNotFound]
get_vip_port.return_value = None
get_addi_vip_port.return_value = []
status = self.helper.lb_delete(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
del_port.assert_not_called()
get_vip_port.assert_called_once_with(self.lb['id'])
@mock.patch.object(ovn_helper.OvnProviderHelper,
'_get_vip_port_from_loadbalancer_id')
@mock.patch.object(ovn_helper.OvnProviderHelper,
'_get_additional_vips_from_loadbalancer_id')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_delete_row_not_found_with_additional_vips(self, del_port,
get_addi_vip_port,
get_vip_port):
self.helper._find_ovn_lbs.side_effect = [idlutils.RowNotFound]
get_vip_port.return_value = None
get_addi_vip_port.return_value = [{'port_id': 'addi_foo_port'},
{'port_id': 'addi_foo_port_2'}]
status = self.helper.lb_delete(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
expected_calls = [
mock.call('addi_foo_port'),
mock.call('addi_foo_port_2')]
del_port.assert_has_calls(expected_calls)
get_vip_port.assert_called_once_with(self.lb['id'])
@mock.patch.object(ovn_helper.OvnProviderHelper,
'_get_vip_port_from_loadbalancer_id')
@mock.patch.object(ovn_helper.OvnProviderHelper,
'_get_additional_vips_from_loadbalancer_id')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_delete_row_not_found_port_leftover(
self, del_port, get_addi_vip_port, get_vip_port):
self.helper._find_ovn_lbs.side_effect = [idlutils.RowNotFound]
get_vip_port.return_value = 'foo'
get_addi_vip_port.return_value = []
del_port.side_effect = [Exception]
status = self.helper.lb_delete(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
del_port.assert_called_once_with('foo')
get_vip_port.assert_called_once_with(self.lb['id'])
@mock.patch.object(ovn_helper.OvnProviderHelper,
'_get_vip_port_from_loadbalancer_id')
@mock.patch.object(ovn_helper.OvnProviderHelper,
'_get_additional_vips_from_loadbalancer_id')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_delete_row_not_found_vip_leak(
self, del_port, get_addi_vip_port, get_vip_port):
self.helper._find_ovn_lbs.side_effect = [idlutils.RowNotFound]
get_vip_port.return_value = 'foo_port'
get_addi_vip_port.return_value = []
status = self.helper.lb_delete(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
del_port.assert_called_once_with('foo_port')
get_vip_port.assert_called_once_with(self.lb['id'])
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_delete_exception(self, del_port):
self.helper.ovn_nbdb_api.lb_del.side_effect = [RuntimeError]
status = self.helper.lb_delete(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
self.ovn_lb.uuid)
del_port.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_delete_step_by_step(self, del_port):
self.helper.ovn_nbdb_api.lr_lb_del.side_effect = [idlutils.RowNotFound]
status = self.helper.lb_delete(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
self.ovn_lb.uuid)
del_port.assert_called_once_with('foo_port')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_delete_step_by_step_exception(self, del_port):
self.helper.ovn_nbdb_api.lb_del.side_effect = [idlutils.RowNotFound]
status = self.helper.lb_delete(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
self.ovn_lb.uuid)
del_port.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_delete_port_not_found(self, del_port, net_cli):
net_cli.return_value.delete_port.side_effect = (
[n_exc.PortNotFoundClient])
status = self.helper.lb_delete(self.ovn_lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
self.ovn_lb.uuid)
del_port.assert_called_once_with('foo_port')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_lb_delete_port_exception(self, del_port, net_cli):
del_port.side_effect = [Exception]
status = self.helper.lb_delete(self.ovn_lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
self.ovn_lb.uuid)
del_port.assert_called_once_with('foo_port')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_lb_delete_cascade(self, net_cli):
net_cli.return_value.delete_port.return_value = None
self.lb['cascade'] = True
status = self.helper.lb_delete(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.OFFLINE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.DELETED)
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
self.ovn_lb.uuid)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_lb_delete_ls_lr(self, net_cli):
self.ovn_lb.external_ids.update({
ovn_const.LB_EXT_IDS_LR_REF_KEY: self.router.name,
ovn_const.LB_EXT_IDS_LS_REFS_KEY:
'{\"neutron-%s\": 1}' % self.network.uuid})
net_cli.return_value.delete_port.return_value = None
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
return_value) = self.network
self.helper.ovn_nbdb_api.lookup.return_value = self.router
self.helper.lb_delete(self.ovn_lb)
self.helper.ovn_nbdb_api.ls_lb_del.assert_called_once_with(
self.network.uuid, self.ovn_lb.uuid)
self.helper.ovn_nbdb_api.lr_lb_del.assert_called_once_with(
self.router.uuid, self.ovn_lb.uuid)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_lb_delete_multiple_protocols(self, net_cli):
net_cli.return_value.delete_port.return_value = None
self.mock_find_ovn_lbs.stop()
udp_lb = copy.copy(self.ovn_lb)
udp_lb.protocol = ['udp']
udp_lb.uuid = 'foo_uuid'
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = [self.ovn_lb, udp_lb]
self.helper.lb_delete(self.lb)
self.helper.ovn_nbdb_api.lb_del.assert_has_calls([
mock.call(self.ovn_lb.uuid),
mock.call(udp_lb.uuid)])
@mock.patch.object(ovn_helper.OvnProviderHelper, '_refresh_lb_vips')
def test_lb_update_disabled(self, refresh_vips):
self.lb['admin_state_up'] = False
status = self.helper.lb_update(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.OFFLINE)
refresh_vips.assert_called_once_with(
self.ovn_lb, self.ovn_lb.external_ids)
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
('external_ids', {'enabled': 'False'}))
@mock.patch.object(ovn_helper.OvnProviderHelper, '_refresh_lb_vips')
def test_lb_update_enabled(self, refresh_vips):
# Change the mock, its enabled by default.
self.ovn_lb.external_ids.update({'enabled': False})
self.lb['admin_state_up'] = True
status = self.helper.lb_update(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)
refresh_vips.assert_called_once_with(
self.ovn_lb, self.ovn_lb.external_ids)
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
('external_ids', {'enabled': 'True'}))
# update to re-enable
self.ovn_lb.external_ids.update({'enabled': True})
self.lb['admin_state_up'] = True
status = self.helper.lb_update(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)
refresh_vips.assert_called_once_with(
self.ovn_lb, self.ovn_lb.external_ids)
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
('external_ids', {'enabled': 'True'}))
@mock.patch.object(ovn_helper.OvnProviderHelper, '_refresh_lb_vips')
def test_lb_update_enabled_multiple_protocols(self, refresh_vips):
self.mock_find_ovn_lbs.stop()
self.ovn_lb.external_ids.update({'enabled': 'False'})
udp_lb = copy.deepcopy(self.ovn_lb)
udp_lb.protocol = ['udp']
udp_lb.uuid = 'foo_uuid'
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = [self.ovn_lb, udp_lb]
self.lb['admin_state_up'] = True
status = self.helper.lb_update(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)
refresh_vips.assert_has_calls([
mock.call(self.ovn_lb, self.ovn_lb.external_ids),
mock.ANY,
mock.ANY,
mock.call(udp_lb, udp_lb.external_ids)],
any_order=False)
self.helper.ovn_nbdb_api.db_set.assert_has_calls([
mock.call('Load_Balancer', self.ovn_lb.uuid,
('external_ids', {'enabled': 'True'})),
mock.call('Load_Balancer', udp_lb.uuid,
('external_ids', {'enabled': 'True'}))])
def test_lb_update_exception(self):
self.helper._find_ovn_lbs.side_effect = [RuntimeError]
status = self.helper.lb_update(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
def test_lb_update_no_admin_state_up(self):
self.lb.pop('admin_state_up')
status = self.helper.lb_update(self.lb)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.helper._find_ovn_lbs.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_refresh_lb_vips')
def test_listener_create_disabled(self, refresh_vips):
self.ovn_lb.external_ids.pop('listener_%s' % self.listener_id)
status = self.helper.listener_create(self.listener)
# Set expected as disabled
self.ovn_lb.external_ids.update({
'listener_%s:D' % self.listener_id: '80:pool_%s' % self.pool_id})
refresh_vips.assert_called_once_with(
self.ovn_lb, self.ovn_lb.external_ids)
expected_calls = [
mock.call(
'Load_Balancer', self.ovn_lb.uuid,
('external_ids', {
'listener_%s:D' % self.listener_id:
'80:pool_%s' % self.pool_id})),
mock.call('Load_Balancer', self.ovn_lb.uuid, ('protocol', 'tcp'))]
self.helper.ovn_nbdb_api.db_set.assert_has_calls(expected_calls)
self.assertEqual(
len(expected_calls),
self.helper.ovn_nbdb_api.db_set.call_count)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.OFFLINE)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_refresh_lb_vips')
def test_listener_create_enabled(self, refresh_vips):
self.listener['admin_state_up'] = True
status = self.helper.listener_create(self.listener)
refresh_vips.assert_called_once_with(
self.ovn_lb, self.ovn_lb.external_ids)
expected_calls = [
mock.call(
'Load_Balancer', self.ovn_lb.uuid,
('external_ids', {
'listener_%s' % self.listener_id:
'80:pool_%s' % self.pool_id}))]
self.helper.ovn_nbdb_api.db_set.assert_has_calls(expected_calls)
self.assertEqual(
len(expected_calls),
self.helper.ovn_nbdb_api.db_set.call_count)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.ONLINE)
def test_listener_create_no_default_pool(self):
self.listener['admin_state_up'] = True
self.listener.pop('default_pool_id')
self.helper.listener_create(self.listener)
expected_calls = [
mock.call('Load_Balancer', self.ovn_lb.uuid, ('external_ids', {
'listener_%s' % self.listener_id: '80:'})),
mock.call('Load_Balancer', self.ovn_lb.uuid,
('vips', {}))]
self.helper.ovn_nbdb_api.db_set.assert_has_calls(
expected_calls)
self.assertEqual(
len(expected_calls),
self.helper.ovn_nbdb_api.db_set.call_count)
def test_listener_create_exception(self):
self.helper.ovn_nbdb_api.db_set.side_effect = [RuntimeError]
status = self.helper.listener_create(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.ERROR)
def test_listener_update(self):
status = self.helper.listener_update(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.OFFLINE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.listener['admin_state_up'] = True
status = self.helper.listener_update(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
def test_listener_update_row_not_found(self):
self.helper._find_ovn_lbs.side_effect = [idlutils.RowNotFound]
status = self.helper.listener_update(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ERROR)
self.helper.ovn_nbdb_api.db_set.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_refresh_lb_vips')
def test_listener_update_exception(self, refresh_vips):
refresh_vips.side_effect = [RuntimeError]
status = self.helper.listener_update(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ERROR)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_refresh_lb_vips')
def test_listener_update_listener_enabled(self, refresh_vips):
self.listener['admin_state_up'] = True
# Update the listener port.
self.listener.update({'protocol_port': 123})
status = self.helper.listener_update(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
('external_ids', {
'listener_%s' % self.listener_id:
'123:pool_%s' % self.pool_id}))
# Update expected listener, because it was updated.
self.ovn_lb.external_ids.pop('listener_%s' % self.listener_id)
self.ovn_lb.external_ids.update(
{'listener_%s' % self.listener_id: '123:pool_%s' % self.pool_id})
refresh_vips.assert_called_once_with(
self.ovn_lb, self.ovn_lb.external_ids)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_refresh_lb_vips')
def test_listener_update_listener_disabled(self, refresh_vips):
self.listener['admin_state_up'] = False
status = self.helper.listener_update(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.OFFLINE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid, 'external_ids',
'listener_%s' % self.listener_id)
# It gets disabled, so update the key
self.ovn_lb.external_ids.pop('listener_%s' % self.listener_id)
self.ovn_lb.external_ids.update(
{'listener_%s:D' % self.listener_id: '80:pool_%s' % self.pool_id})
refresh_vips.assert_called_once_with(
self.ovn_lb, self.ovn_lb.external_ids)
# As it is marked disabled, a second call should not try and remove it
self.helper.ovn_nbdb_api.db_remove.reset_mock()
status = self.helper.listener_update(self.listener)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.db_remove.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_refresh_lb_vips')
def test_listener_update_no_admin_state_up(self, refresh_vips):
self.listener.pop('admin_state_up')
status = self.helper.listener_update(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.helper.ovn_nbdb_api.db_remove.assert_not_called()
refresh_vips.assert_called_once_with(
self.ovn_lb, self.ovn_lb.external_ids)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_refresh_lb_vips')
def test_listener_update_no_admin_state_up_or_default_pool_id(
self, refresh_vips):
self.listener.pop('admin_state_up')
self.listener.pop('default_pool_id')
status = self.helper.listener_update(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.helper.ovn_nbdb_api.db_remove.assert_not_called()
refresh_vips.assert_not_called()
def test_listener_delete_no_external_id(self):
self.ovn_lb.external_ids.pop('listener_%s' % self.listener_id)
status = self.helper.listener_delete(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.db_remove.assert_not_called()
def test_listener_delete_row_not_found(self):
self.helper._find_ovn_lbs.side_effect = [idlutils.RowNotFound]
status = self.helper.listener_delete(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.OFFLINE)
def test_listener_delete_exception(self):
self.helper.ovn_nbdb_api.db_remove.side_effect = [RuntimeError]
status = self.helper.listener_delete(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.ERROR)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_refresh_lb_vips')
def test_listener_delete_external_id(self, refresh_vips):
status = self.helper.listener_delete(self.listener)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
'external_ids', 'listener_%s' % self.listener_id)
self.ovn_lb.external_ids.pop('listener_%s' % self.listener_id)
refresh_vips.assert_called_once_with(
self.ovn_lb, self.ovn_lb.external_ids)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_is_lb_empty')
def test_listener_delete_ovn_lb_not_empty(self, lb_empty):
lb_empty.return_value = False
self.helper.listener_delete(self.listener)
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
'external_ids', 'listener_%s' % self.listener_id)
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_is_lb_empty')
def test_listener_delete_ovn_lb_empty_octavia_lb_empty(self, lb_empty):
"""That test situation when the OVN and Octavia LBs are empty.
That test situation when both OVN and Octavia LBs are empty,
but we cannot remove OVN LB row.
"""
lb_empty.return_value = True
self.helper.listener_delete(self.listener)
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
'external_ids', 'listener_%s' % self.listener_id)
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
# Assert that protocol has been set to [].
self.helper.ovn_nbdb_api.db_set.assert_has_calls([
mock.call('Load_Balancer', self.ovn_lb.uuid,
('protocol', []))])
@mock.patch.object(ovn_helper.OvnProviderHelper, '_is_lb_empty')
def test_listener_delete_ovn_lb_empty_octavia_lb_not_empty(self, lb_empty):
"""We test if we can remove one LB with not used protocol"""
ovn_lb_udp = copy.copy(self.ovn_lb)
ovn_lb_udp.protocol = ['udp']
self.mock_find_ovn_lbs.stop()
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.side_effect = [[self.ovn_lb], [self.ovn_lb, ovn_lb_udp]]
lb_empty.return_value = True
self.helper.listener_delete(self.listener)
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
'external_ids', 'listener_%s' % self.listener_id)
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
self.ovn_lb.uuid)
# Validate that the vips column hasn't been touched, because
# in previous command we remove the LB, so there is no need
# to update it.
self.helper.ovn_nbdb_api.db_set.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_is_lb_empty')
def test_listener_delete_ovn_lb_empty_ovn_lb_not_found(self, lb_empty):
"""That test situation when the OVN and Octavia LBs are empty.
That test situation when both OVN and Octavia LBs are empty,
but we cannot find the OVN LB row when cleaning.
"""
self.helper._find_ovn_lbs.side_effect = [
self.ovn_lb, idlutils.RowNotFound]
lb_empty.return_value = True
self.helper.listener_delete(self.listener)
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
'external_ids', 'listener_%s' % self.listener_id)
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
# vip refresh will have been called
self.helper.ovn_nbdb_api.db_clear.assert_has_calls([
mock.call('Load_Balancer', self.ovn_lb.uuid,
('vips'))])
self.helper.ovn_nbdb_api.db_set.assert_has_calls([
mock.call('Load_Balancer', self.ovn_lb.uuid,
('vips', {}))])
def test_pool_create(self):
status = self.helper.pool_create(self.pool)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ONLINE)
self.pool['admin_state_up'] = True
# Pool Operating status shouldnt change if member isnt present.
status = self.helper.pool_create(self.pool)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ONLINE)
# Pool without listener set should be OFFLINE
self.pool['listener_id'] = None
status = self.helper.pool_create(self.pool)
self.assertEqual(status['pools'][0]['operating_status'],
constants.OFFLINE)
def test_pool_create_exception(self):
self.helper.ovn_nbdb_api.db_set.side_effect = [
RuntimeError, RuntimeError]
status = self.helper.pool_create(self.pool)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.pool['listener_id'] = None
status = self.helper.pool_create(self.pool)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
def test_pool_update(self):
status = self.helper.pool_update(self.pool)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.OFFLINE)
self.pool['admin_state_up'] = True
status = self.helper.pool_update(self.pool)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ONLINE)
def test_pool_update_exception_not_found(self):
self.helper._find_ovn_lbs.side_effect = [idlutils.RowNotFound]
status = self.helper.pool_update(self.pool)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ERROR)
def test_pool_update_exception(self):
self.helper._get_pool_listeners.side_effect = [RuntimeError]
status = self.helper.pool_update(self.pool)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ERROR)
def test_pool_update_unset_admin_state_up(self):
self.pool.pop('admin_state_up')
status = self.helper.pool_update(self.pool)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
def test_pool_update_pool_disabled_change_to_up(self):
self.pool.update({'admin_state_up': True})
disabled_p_key = self.helper._get_pool_key(self.pool_id,
is_enabled=False)
p_key = self.helper._get_pool_key(self.pool_id)
self.ovn_lb.external_ids.update({
disabled_p_key: self.member_line})
self.ovn_lb.external_ids.pop(p_key)
status = self.helper.pool_update(self.pool)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ONLINE)
expected_calls = [
mock.call('Load_Balancer', self.ovn_lb.uuid,
('external_ids',
{'pool_%s' % self.pool_id: self.member_line})),
mock.call('Load_Balancer', self.ovn_lb.uuid,
('vips', {'10.22.33.4:80': '192.168.2.149:1010',
'123.123.123.123:80': '192.168.2.149:1010'}))]
self.helper.ovn_nbdb_api.db_set.assert_has_calls(
expected_calls)
def test_pool_update_pool_disabled_change_to_down(self):
self.pool.update({'admin_state_up': False})
disabled_p_key = self.helper._get_pool_key(self.pool_id,
is_enabled=False)
p_key = self.helper._get_pool_key(self.pool_id)
self.ovn_lb.external_ids.update({
disabled_p_key: self.member_line})
self.ovn_lb.external_ids.pop(p_key)
status = self.helper.pool_update(self.pool)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.db_set.assert_not_called()
def test_pool_update_pool_up_change_to_disabled(self):
self.pool.update({'admin_state_up': False})
status = self.helper.pool_update(self.pool)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.OFFLINE)
expected_calls = [
mock.call('Load_Balancer', self.ovn_lb.uuid,
('external_ids',
{'pool_%s:D' % self.pool_id: self.member_line})),
mock.call('Load_Balancer', self.ovn_lb.uuid, ('vips', {}))]
self.helper.ovn_nbdb_api.db_set.assert_has_calls(
expected_calls)
def test_pool_update_listeners(self):
self.helper._get_pool_listeners.return_value = ['listener1']
status = self.helper.pool_update(self.pool)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
def test_pool_update_listeners_none(self):
status = self.helper.pool_update(self.pool)
self.assertFalse(status['listeners'])
def test_pool_delete(self):
status = self.helper.pool_delete(self.pool)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.DELETED)
self.helper.ovn_nbdb_api.db_clear.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid, 'vips')
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
'external_ids', 'pool_%s' % self.pool_id)
expected_calls = [
mock.call('Load_Balancer', self.ovn_lb.uuid, ('vips', {})),
mock.call(
'Load_Balancer', self.ovn_lb.uuid,
('external_ids', {
ovn_const.LB_EXT_IDS_VIP_KEY: '10.22.33.4',
ovn_const.LB_EXT_IDS_VIP_FIP_KEY: '123.123.123.123',
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: 'foo_port',
'enabled': True,
'listener_%s' % self.listener_id: '80:',
ovn_const.OVN_MEMBER_STATUS_KEY: '{"%s": "%s"}'
% (self.member_id, constants.NO_MONITOR)}))]
self.assertEqual(self.helper.ovn_nbdb_api.db_set.call_count,
len(expected_calls))
self.helper.ovn_nbdb_api.db_set.assert_has_calls(
expected_calls)
def test_pool_delete_row_not_found(self):
self.helper._find_ovn_lbs.side_effect = [idlutils.RowNotFound]
status = self.helper.pool_delete(self.pool)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.DELETED)
self.helper.ovn_nbdb_api.db_remove.assert_not_called()
self.helper.ovn_nbdb_api.db_set.assert_not_called()
def test_pool_delete_exception(self):
self.helper.ovn_nbdb_api.db_set.side_effect = [RuntimeError]
status = self.helper.pool_delete(self.pool)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ERROR)
def test_pool_delete_associated_listeners(self):
self.helper._get_pool_listeners.return_value = ['listener1']
status = self.helper.pool_delete(self.pool)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.helper.ovn_nbdb_api.db_set.assert_called_with(
'Load_Balancer', self.ovn_lb.uuid,
('external_ids', {
'enabled': True,
'listener_%s' % self.listener_id: '80:',
ovn_const.LB_EXT_IDS_VIP_KEY: '10.22.33.4',
ovn_const.LB_EXT_IDS_VIP_FIP_KEY: '123.123.123.123',
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: 'foo_port',
ovn_const.OVN_MEMBER_STATUS_KEY: '{"%s": "%s"}'
% (self.member_id, constants.NO_MONITOR)}))
def test_pool_delete_pool_disabled(self):
disabled_p_key = self.helper._get_pool_key(self.pool_id,
is_enabled=False)
p_key = self.helper._get_pool_key(self.pool_id)
self.ovn_lb.external_ids.update({
disabled_p_key: self.member_line})
self.ovn_lb.external_ids.pop(p_key)
status = self.helper.pool_delete(self.pool)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.DELETED)
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
'external_ids', 'pool_%s:D' % self.pool_id)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_is_lb_empty')
def test_pool_delete_ovn_lb_not_empty(self, lb_empty):
lb_empty.return_value = False
self.helper.pool_delete(self.pool)
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
'external_ids', 'pool_%s' % self.pool_id)
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_is_lb_empty')
def test_pool_delete_ovn_lb_empty_lb_empty(self, lb_empty):
lb_empty.return_value = True
self.helper.pool_delete(self.pool)
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
'external_ids', 'pool_%s' % self.pool_id)
self.helper.ovn_nbdb_api.lb_del.assert_not_called()
# Assert that protocol has been set to [].
self.helper.ovn_nbdb_api.db_set.assert_called_with(
'Load_Balancer', self.ovn_lb.uuid,
('protocol', []))
@mock.patch.object(ovn_helper.OvnProviderHelper, '_is_lb_empty')
def test_pool_delete_ovn_lb_empty_lb_not_empty(self, lb_empty):
ovn_lb_udp = copy.copy(self.ovn_lb)
self.mock_find_ovn_lbs.stop()
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.side_effect = [[self.ovn_lb], [self.ovn_lb, ovn_lb_udp]]
lb_empty.return_value = True
self.helper.pool_delete(self.pool)
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ovn_lb.uuid,
'external_ids', 'pool_%s' % self.pool_id)
self.helper.ovn_nbdb_api.lb_del.assert_called_once_with(
self.ovn_lb.uuid)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_member_create_disabled(self, net_cli):
net_cli.return_value.show_subnet.side_effect = [idlutils.RowNotFound]
self._update_external_ids_member_status(self.ovn_lb, self.member['id'],
'offline')
self.member['admin_state_up'] = False
status = self.helper.member_create(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.OFFLINE)
self.helper.ovn_nbdb_api.db_clear.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_lr_of_ls')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_member_create_lb_add_from_lr(self, net_cli, f_lr, folbpi):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
net_cli.return_value.get_subnet.return_value = fake_subnet
f_lr.return_value = self.router
pool_key = 'pool_%s' % self.pool_id
folbpi.return_value = (pool_key, self.ovn_lb)
self.ovn_lb.external_ids = mock.MagicMock()
status = self.helper.member_create(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
f_lr.assert_called_once_with(self.network, fake_subnet['gateway_ip'])
self.helper._update_lb_to_lr_association.assert_called_once_with(
self.ovn_lb, self.router)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ls_for_lr')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_lr_of_ls')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_member_create_lb_add_from_lr_no_ls(self, net_cli, f_lr, f_ls):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
net_cli.return_value.get_subnet.return_value = fake_subnet
self.ovn_lb.external_ids = mock.MagicMock()
(self.helper.ovn_nbdb_api.ls_get.return_value.
execute.side_effect) = [openstack.exceptions.ResourceNotFound]
status = self.helper.member_create(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
assert_called_once_with(check_error=True))
f_lr.assert_not_called()
f_ls.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_add_member')
def test_member_create_exception(self, mock_add_member):
mock_add_member.side_effect = [RuntimeError]
self._update_external_ids_member_status(self.ovn_lb, self.member_id,
'error')
status = self.helper.member_create(self.member)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ERROR)
def test_member_create_lb_disabled(self):
self.helper._find_ovn_lb_with_pool_key.side_effect = [
None, self.ovn_lb]
self.helper.member_create(self.member)
self.helper._find_ovn_lb_with_pool_key.assert_has_calls(
[mock.call('pool_%s' % self.pool_id),
mock.call('pool_%s%s' % (self.pool_id, ':D'))])
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_lr_of_ls')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_member_create_lb_add_from_lr_retry(self, net_cli, f_lr, folbpi):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
net_cli.return_value.get_subnet.return_value = fake_subnet
f_lr.return_value = self.router
pool_key = 'pool_%s' % self.pool_id
folbpi.return_value = (pool_key, self.ovn_lb)
self.helper._update_lb_to_lr_association.side_effect = [
idlutils.RowNotFound]
self.ovn_lb.external_ids = mock.MagicMock()
status = self.helper.member_create(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
f_lr.assert_called_once_with(self.network, fake_subnet.gateway_ip)
self.helper._update_lb_to_lr_association.assert_called_once_with(
self.ovn_lb, self.router)
self.helper._update_lb_to_lr_association_by_step \
.assert_called_once_with(
self.ovn_lb,
self.router)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_member_create(self, net_cli):
net_cli.return_value.get_subnet.side_effect = [idlutils.RowNotFound]
status = self.helper.member_create(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['members'][0]['id'],
self.member_id)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.NO_MONITOR)
def test_member_create_already_exists(self):
status = self.helper.member_create(self.member)
member_status = {
ovn_const.OVN_MEMBER_STATUS_KEY: '{"%s": "%s"}'
% (self.member_id, constants.NO_MONITOR)}
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer',
self.ovn_lb.uuid,
('external_ids', member_status))
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.NO_MONITOR)
def test_member_create_first_member_in_pool(self):
self.ovn_lb.external_ids.update({
'pool_' + self.pool_id: ''})
self.helper.member_create(self.member)
expected_calls = [
mock.call('Load_Balancer', self.ovn_lb.uuid,
('external_ids',
{'pool_%s' % self.pool_id: self.member_line})),
mock.call('Load_Balancer', self.ovn_lb.uuid,
('vips', {
'10.22.33.4:80': '192.168.2.149:1010',
'123.123.123.123:80': '192.168.2.149:1010'}))]
self.helper.ovn_nbdb_api.db_set.assert_has_calls(
expected_calls)
def test_member_create_second_member_in_pool(self):
member2_id = uuidutils.generate_uuid()
member2_subnet_id = uuidutils.generate_uuid()
member2_port = '1010'
member2_address = '192.168.2.150'
member2_line = ('member_%s_%s:%s_%s' %
(member2_id, member2_address,
member2_port, member2_subnet_id))
self.ovn_lb.external_ids.update(
{'pool_%s' % self.pool_id: member2_line})
self.helper.member_create(self.member)
all_member_line = (
'%s,member_%s_%s:%s_%s' %
(member2_line, self.member_id,
self.member_address, self.member_port,
self.member_subnet_id))
# We have two members now.
expected_calls = [
mock.call('Load_Balancer', self.ovn_lb.uuid,
('external_ids', {
'pool_%s' % self.pool_id: all_member_line})),
mock.call(
'Load_Balancer', self.ovn_lb.uuid,
('vips', {
'10.22.33.4:80':
'192.168.2.150:1010,192.168.2.149:1010',
'123.123.123.123:80':
'192.168.2.150:1010,192.168.2.149:1010'}))]
self.helper.ovn_nbdb_api.db_set.assert_has_calls(
expected_calls)
def test_member_update(self):
status = self.helper.member_update(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.NO_MONITOR)
self.member['admin_state_up'] = False
self._update_external_ids_member_status(self.ovn_lb, self.member_id,
'offline')
status = self.helper.member_update(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.OFFLINE)
self.member.pop('admin_state_up')
status = self.helper.member_update(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.member['old_admin_state_up'] = False
self.member['admin_state_up'] = True
self._update_external_ids_member_status(self.ovn_lb, self.member_id,
'online')
status = self.helper.member_update(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.NO_MONITOR)
fake_member = fakes.FakeMember(
uuid=self.member_id,
admin_state_up=True,
address=self.member_address,
protocol_port=self.member_port)
self.octavia_driver_lib.get_member.return_value = fake_member
self.member['old_admin_state_up'] = None
status = self.helper.member_update(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.NO_MONITOR)
def test_member_update_disabled_lb(self):
self.helper._find_ovn_lb_with_pool_key.side_effect = [
None, self.ovn_lb]
self.helper.member_update(self.member)
self.helper._find_ovn_lb_with_pool_key.assert_has_calls(
[mock.call('pool_%s' % self.pool_id),
mock.call('pool_%s%s' % (self.pool_id, ':D'))])
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_member_status')
def test_member_update_exception(self, mock_find_member_status):
mock_find_member_status.side_effect = [TypeError]
status = self.helper.member_update(self.member)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_refresh_lb_vips')
def test_member_delete(self, mock_vip_command):
status = self.helper.member_delete(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.DELETED)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_remove_member')
@mock.patch.object(ovn_helper.OvnProviderHelper,
'_update_external_ids_member_status')
def test_member_delete_one_left(self, update_external_ids_members,
rmmember):
member2_id = uuidutils.generate_uuid()
member2_port = '1010'
member2_address = '192.168.2.150'
member2_subnet_id = uuidutils.generate_uuid()
member_line = (
'member_%s_%s:%s_%s,member_%s_%s:%s_%s' %
(self.member_id, self.member_address, self.member_port,
self.member_subnet_id,
member2_id, member2_address, member2_port, member2_subnet_id))
self.ovn_lb.external_ids.update({
'pool_' + self.pool_id: member_line})
status = self.helper.member_delete(self.member)
rmmember.assert_called_once_with(
self.member, self.ovn_lb, 'pool_' + self.pool_id)
update_external_ids_members.assert_called_once_with(
self.ovn_lb, self.member_id, None, delete=True)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_update_hm_member')
def test_member_delete_hm(self, uhm, folbpi):
pool_key = 'pool_%s' % self.pool_id
self.ovn_hm_lb.external_ids[pool_key] = self.member_line
self.ovn_hm_lb.external_ids[ovn_const.OVN_MEMBER_STATUS_KEY] = \
'{"%s": "%s"}' % (self.member_id, constants.ONLINE)
folbpi.return_value = (pool_key, self.ovn_hm_lb)
self.helper.member_delete(self.member)
uhm.assert_called_once_with(self.ovn_hm_lb,
pool_key,
self.member_address,
delete=True)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_update_hm_member')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_clean_up_hm_port')
def test_member_delete_keep_hm_port(self, del_hm_port, uhm, folbpi):
pool_key = 'pool_%s' % self.pool_id
member2_id = uuidutils.generate_uuid()
member2_address = '192.168.2.150'
member2_line = (
'member_%s_%s:%s_%s' %
(member2_id, member2_address,
self.member_port, self.member_subnet_id))
self.ovn_hm_lb.external_ids[pool_key] = ','.join([self.member_line,
member2_line])
self.ovn_hm_lb.external_ids[ovn_const.OVN_MEMBER_STATUS_KEY] = \
'{"%s": "%s","%s": "%s"}' % (self.member_id, constants.ONLINE,
member2_id, constants.ONLINE)
folbpi.return_value = (pool_key, self.ovn_hm_lb)
self.helper.member_delete(self.member)
uhm.assert_called_once_with(self.ovn_hm_lb,
pool_key,
self.member_address,
delete=True)
del_hm_port.assert_not_called()
def test_member_delete_not_found_in_pool(self):
self.ovn_lb.external_ids.update({'pool_' + self.pool_id: ''})
self.ovn_lb.external_ids[ovn_const.OVN_MEMBER_STATUS_KEY] = '{}'
status = self.helper.member_delete(self.member)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ERROR)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_remove_member')
def test_member_delete_exception(self, mock_remove_member):
mock_remove_member.side_effect = [RuntimeError]
status = self.helper.member_delete(self.member)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
def test_member_delete_disabled_lb(self):
self.helper._find_ovn_lb_with_pool_key.side_effect = [
None, self.ovn_lb]
self.helper.member_delete(self.member)
self.helper._find_ovn_lb_with_pool_key.assert_has_calls(
[mock.call('pool_%s' % self.pool_id),
mock.call('pool_%s%s' % (self.pool_id, ':D'))])
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_logical_router_port_event_create(self, net_cli):
self.router_port_event = ovn_event.LogicalRouterPortEvent(
self.helper)
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'external_ids': {ovn_const.OVN_ROUTER_IS_EXT_GW: 'False'}})
self.router_port_event.run('create', row, mock.ANY)
expected = {
'info':
{'router': self.router,
'network': self.network,
'is_gw_port': False},
'type': 'lb_create_lrp_assoc'}
self.mock_add_request.assert_called_once_with(expected)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_logical_router_port_event_delete(self, net_cli):
self.router_port_event = ovn_event.LogicalRouterPortEvent(
self.helper)
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={})
self.router_port_event.run('delete', row, mock.ANY)
expected = {
'info':
{'router': self.router,
'network': self.network},
'type': 'lb_delete_lrp_assoc'}
self.mock_add_request.assert_called_once_with(expected)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_logical_router_port_event_gw_port(self, net_cli):
self.router_port_event = ovn_event.LogicalRouterPortEvent(
self.helper)
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'external_ids': {ovn_const.OVN_ROUTER_IS_EXT_GW: 'True'}})
self.router_port_event.run(mock.ANY, row, mock.ANY)
expected = {
'info':
{'router': self.router,
'network': self.network,
'is_gw_port': True},
'type': 'lb_create_lrp_assoc'}
self.mock_add_request.assert_called_once_with(expected)
def test__get_pool_listeners(self):
self._get_pool_listeners.stop()
self.ovn_lb.external_ids = {
ovn_const.LB_EXT_IDS_VIP_KEY: 'fc00::',
ovn_const.LB_EXT_IDS_VIP_FIP_KEY: '2002::',
'listener_%s' % self.listener_id: '80:pool_%s' % self.pool_id}
ret = self.helper._get_pool_listeners(
self.ovn_lb, 'pool_%s' % self.pool_id)
self.assertEqual([self.listener_id], ret)
def test__get_pool_listeners_not_found(self):
self._get_pool_listeners.stop()
self.ovn_lb.external_ids = {
ovn_const.LB_EXT_IDS_VIP_KEY: 'fc00::',
ovn_const.LB_EXT_IDS_VIP_FIP_KEY: '2002::',
'listener_%s' % self.listener_id: '80:pool_%s' % self.pool_id}
ret = self.helper._get_pool_listeners(
self.ovn_lb, 'pool_foo')
self.assertEqual([], ret)
def test___get_pool_listener_port(self):
self._get_pool_listeners.stop()
self.ovn_lb.external_ids = {
ovn_const.LB_EXT_IDS_VIP_KEY: 'fc00::',
ovn_const.LB_EXT_IDS_VIP_FIP_KEY: '2002::',
'listener_%s' % self.listener_id: '80:pool_%s' % self.pool_id}
ret = self.helper._get_pool_listener_port(
self.ovn_lb, 'pool_foo')
self.assertIsNone(ret)
def test__get_nw_router_info_on_interface_event(self):
self.mock_get_nw.stop()
lrp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1',
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'network1'}
})
self.helper._get_nw_router_info_on_interface_event(lrp)
expected_calls = [
mock.call.lookup('Logical_Router', 'neutron-router1'),
mock.call.lookup('Logical_Switch', 'network1')]
self.helper.ovn_nbdb_api.assert_has_calls(expected_calls)
def test__get_nw_router_info_on_interface_event_not_found(self):
self.mock_get_nw.stop()
self.helper.ovn_nbdb_api.lookup.side_effect = [idlutils.RowNotFound]
lrp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1'}
})
self.assertRaises(
idlutils.RowNotFound,
self.helper._get_nw_router_info_on_interface_event,
lrp)
def test_lb_delete_lrp_assoc_handler(self):
lrp = fakes.FakeOvsdbRow.create_one_ovsdb_row()
self.helper.lb_delete_lrp_assoc_handler(lrp)
expected = {
'info':
{'router': self.router,
'network': self.network},
'type': 'lb_delete_lrp_assoc'}
self.mock_add_request.assert_called_once_with(expected)
def test_lb_delete_lrp_assoc_handler_info_not_found(self):
self.mock_get_nw.stop()
self.helper.ovn_nbdb_api.lookup.side_effect = [idlutils.RowNotFound]
lrp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1'}
})
self.helper.lb_delete_lrp_assoc_handler(lrp)
self.mock_add_request.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_execute_commands')
def test_lb_delete_lrp_assoc_no_net_lb_no_r_lb(self, mock_execute):
info = {
'network': self.network,
'router': self.router,
}
self.network.load_balancer = []
self.router.load_balancer = []
self.helper.lb_delete_lrp_assoc(info)
self.helper._update_lb_to_lr_association.assert_not_called()
mock_execute.assert_not_called()
def test_lb_delete_lrp_assoc_no_net_lb_r_lb(self):
info = {
'network': self.network,
'router': self.router,
}
self.network.load_balancer = []
self.helper.lb_delete_lrp_assoc(info)
self.helper._update_lb_to_lr_association.assert_not_called()
self.helper._update_lb_to_ls_association.assert_called_once_with(
self.router.load_balancer[0],
network_id=info['network'].uuid,
associate=False,
update_ls_ref=False
)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_execute_commands')
def test_lb_delete_lrp_assoc_net_lb_no_r_lb(self, mock_execute):
info = {
'network': self.network,
'router': self.router,
}
self.router.load_balancer = []
self.helper.lb_delete_lrp_assoc(info)
mock_execute.assert_not_called()
self.helper._update_lb_to_lr_association.assert_called_once_with(
self.network.load_balancer[0], self.router, delete=True
)
def test_lb_delete_lrp_assoc_r_lb_exception(self):
info = {
'network': self.network,
'router': self.router,
}
self.helper._update_lb_to_ls_association.side_effect = [
idlutils.RowNotFound]
with self.assertLogs(level='WARN') as cm:
self.helper.lb_delete_lrp_assoc(info)
self.assertEqual(
cm.output,
['WARNING:ovn_octavia_provider.helper:'
'The disassociation of loadbalancer '
'%s to the logical switch %s failed, just keep going on'
% (self.router.load_balancer[0].uuid, self.network.uuid)])
def test_lb_delete_lrp_assoc(self):
info = {
'network': self.network,
'router': self.router,
}
self.helper.lb_delete_lrp_assoc(info)
self.helper._update_lb_to_lr_association.assert_called_once_with(
self.network.load_balancer[0], self.router, delete=True
)
self.helper._update_lb_to_ls_association.assert_called_once_with(
self.router.load_balancer[0],
network_id=self.network.uuid,
associate=False, update_ls_ref=False
)
def test_lb_delete_lrp_assoc_ls_by_step(self):
self._update_lb_to_ls_association.stop()
info = {
'network': self.network,
'router': self.router,
}
self.helper._update_lb_to_lr_association.side_effect = [
idlutils.RowNotFound]
self.helper.lb_delete_lrp_assoc(info)
self.helper._update_lb_to_lr_association.assert_called_once_with(
self.network.load_balancer[0], self.router, delete=True
)
self.helper._update_lb_to_lr_association_by_step \
.assert_called_once_with(
self.network.load_balancer[0],
self.router, delete=True)
def test_lb_create_lrp_assoc_handler(self):
lrp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'external_ids': {ovn_const.OVN_ROUTER_IS_EXT_GW: 'False'}})
self.helper.lb_create_lrp_assoc_handler(lrp)
expected = {
'info':
{'router': self.router,
'network': self.network,
'is_gw_port': False},
'type': 'lb_create_lrp_assoc'}
self.mock_add_request.assert_called_once_with(expected)
def test_lb_create_lrp_assoc_handler_row_not_found(self):
self.mock_get_nw.stop()
self.helper.ovn_nbdb_api.lookup.side_effect = [idlutils.RowNotFound]
lrp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1'}
})
self.helper.lb_create_lrp_assoc_handler(lrp)
self.mock_add_request.assert_not_called()
def test_lb_create_lrp_assoc(self):
info = {
'network': self.network,
'router': self.router,
'is_gw_port': False,
}
self.helper.lb_create_lrp_assoc(info)
self.helper._update_lb_to_lr_association.assert_called_once_with(
self.network.load_balancer[0], self.router
)
def test_lb_create_lrp_assoc_r_lb_exception(self):
info = {
'network': self.network,
'router': self.router,
'is_gw_port': False,
}
self.helper._update_lb_to_ls_association.side_effect = [
idlutils.RowNotFound]
with self.assertLogs(level='WARN') as cm:
self.helper.lb_create_lrp_assoc(info)
self.assertEqual(
cm.output,
['WARNING:ovn_octavia_provider.helper:'
'The association of loadbalancer '
'%s to the logical switch %s failed, just keep going on'
% (self.router.load_balancer[0].uuid, self.network.uuid)])
def test_lb_create_lrp_assoc_ls_by_step(self):
self._update_lb_to_ls_association.stop()
info = {
'network': self.network,
'router': self.router,
'is_gw_port': True,
}
self.helper._update_lb_to_lr_association.side_effect = [
idlutils.RowNotFound]
self.helper.lb_create_lrp_assoc(info)
self.helper._update_lb_to_lr_association.assert_called_once_with(
self.network.load_balancer[0], self.router
)
self.helper._update_lb_to_lr_association_by_step \
.assert_called_once_with(
self.network.load_balancer[0],
self.router)
def test_lb_create_lrp_assoc_uniq_lb(self):
info = {
'network': self.network,
'router': self.router,
'is_gw_port': True,
}
# Make it already uniq.
self.network.load_balancer = self.router.load_balancer
self.helper.lb_create_lrp_assoc(info)
self.helper._update_lb_to_lr_association.assert_not_called()
def test__find_lb_in_ls(self):
net_lb = self.helper._find_lb_in_ls(self.network)
for lb in self.network.load_balancer:
self.assertIn(lb, net_lb)
def test__find_lb_in_ls_wrong_ref(self):
# lets break external_ids refs
self.network.load_balancer[0].external_ids.update({
ovn_const.LB_EXT_IDS_LS_REFS_KEY: 'foo'})
net_lb = self.helper._find_lb_in_ls(self.network)
for lb in self.network.load_balancer:
self.assertNotIn(lb, net_lb)
def test__find_ls_for_lr(self):
p1 = fakes.FakeOVNPort.create_one_port(attrs={
'gateway_chassis': [],
'external_ids': {
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'foo1'},
'networks': ["10.0.0.1/24"]})
p2 = fakes.FakeOVNPort.create_one_port(attrs={
'gateway_chassis': [],
'external_ids': {
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'foo2'},
'networks': ["10.0.10.1/24"]})
self.router.ports.append(p1)
self.router.ports.append(p2)
res = self.helper._find_ls_for_lr(self.router, n_const.IP_VERSION_4)
self.assertListEqual(['neutron-foo1', 'neutron-foo2'], res)
def test__find_ls_for_lr_net_not_found(self):
p1 = fakes.FakeOVNPort.create_one_port(attrs={
'gateway_chassis': [],
'external_ids': {
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'foo1'},
'networks': ["10.0.0.1/24"]})
p2 = fakes.FakeOVNPort.create_one_port(attrs={
'gateway_chassis': [],
'external_ids': {},
'networks': ["10.0.10.1/24"]})
self.router.ports.append(p2)
self.router.ports.append(p1)
res = self.helper._find_ls_for_lr(self.router, n_const.IP_VERSION_4)
self.assertListEqual(['neutron-foo1'], res)
def test__find_ls_for_lr_different_ip_version(self):
p1 = fakes.FakeOVNPort.create_one_port(attrs={
'gateway_chassis': [],
'external_ids': {
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'foo1'},
'networks': ["10.0.0.1/24"]})
p2 = fakes.FakeOVNPort.create_one_port(attrs={
'gateway_chassis': [],
'external_ids': {
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'foo2'},
'networks': ["fdaa:4ad8:e8fb::/64"]})
self.router.ports.append(p2)
self.router.ports.append(p1)
res = self.helper._find_ls_for_lr(self.router, n_const.IP_VERSION_4)
self.assertListEqual(['neutron-foo1'], res)
res = self.helper._find_ls_for_lr(self.router, n_const.IP_VERSION_6)
self.assertListEqual(['neutron-foo2'], res)
def test__find_ls_for_lr_gw_port(self):
p1 = fakes.FakeOVNPort.create_one_port(attrs={
'gateway_chassis': ['foo-gw-chassis'],
'external_ids': {
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY: 'foo1'},
'networks': ["10.0.0.1/24"]})
self.router.ports.append(p1)
result = self.helper._find_ls_for_lr(self.router, n_const.IP_VERSION_4)
self.assertListEqual([], result)
@mock.patch.object(
ovn_helper.OvnProviderHelper, '_del_lb_to_lr_association')
@mock.patch.object(
ovn_helper.OvnProviderHelper, '_add_lb_to_lr_association')
def test__get_lb_to_lr_association_commands(self, add, delete):
self._get_lb_to_lr_association_commands.stop()
self.helper._get_lb_to_lr_association_commands(
self.ref_lb1, self.router)
lr_ref = self.ref_lb1.external_ids.get(
ovn_const.LB_EXT_IDS_LR_REF_KEY)
add.assert_called_once_with(self.ref_lb1, self.router, lr_ref)
delete.assert_not_called()
@mock.patch.object(
ovn_helper.OvnProviderHelper, '_del_lb_to_lr_association')
@mock.patch.object(
ovn_helper.OvnProviderHelper, '_add_lb_to_lr_association')
def test__get_lb_to_lr_association_commands_delete(self, add, delete):
self._get_lb_to_lr_association_commands.stop()
self.helper._get_lb_to_lr_association_commands(
self.ref_lb1, self.router, delete=True)
lr_ref = self.ref_lb1.external_ids.get(
ovn_const.LB_EXT_IDS_LR_REF_KEY)
add.assert_not_called()
delete.assert_called_once_with(self.ref_lb1, self.router, lr_ref)
@mock.patch.object(
ovn_helper.OvnProviderHelper, '_del_lb_to_lr_association')
@mock.patch.object(
ovn_helper.OvnProviderHelper, '_add_lb_to_lr_association')
def test__get_lb_to_lr_association_commands_by_step(
self, add, delete):
self._update_lb_to_lr_association_by_step.stop()
self._get_lb_to_lr_association_commands.stop()
self.helper._update_lb_to_lr_association_by_step(
self.ref_lb1, self.router)
lr_ref = self.ref_lb1.external_ids.get(
ovn_const.LB_EXT_IDS_LR_REF_KEY)
add.assert_called_once_with(self.ref_lb1, self.router, lr_ref)
delete.assert_not_called()
@mock.patch.object(
ovn_helper.OvnProviderHelper, '_del_lb_to_lr_association')
@mock.patch.object(
ovn_helper.OvnProviderHelper, '_add_lb_to_lr_association')
def test__get_lb_to_lr_association_commands_by_step_delete(
self, add, delete):
self._update_lb_to_lr_association_by_step.stop()
self._get_lb_to_lr_association_commands.stop()
self.helper._update_lb_to_lr_association_by_step(
self.ref_lb1, self.router, delete=True)
lr_ref = self.ref_lb1.external_ids.get(
ovn_const.LB_EXT_IDS_LR_REF_KEY)
add.assert_not_called()
delete.assert_called_once_with(self.ref_lb1, self.router, lr_ref)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test__del_lb_to_lr_association(self, net_cli):
lr_ref = self.ref_lb1.external_ids.get(
ovn_const.LB_EXT_IDS_LR_REF_KEY)
upd_lr_ref = '%s,%s' % (lr_ref, self.router.name)
self.helper._del_lb_to_lr_association(
self.ref_lb1, self.router, upd_lr_ref)
expected_calls = [
mock.call.db_set(
'Load_Balancer', self.ref_lb1.uuid,
(('external_ids',
{ovn_const.LB_EXT_IDS_LR_REF_KEY: lr_ref}))),
mock.call.lr_lb_del(
self.router.uuid, self.ref_lb1.uuid,
if_exists=True)]
self.helper.ovn_nbdb_api.assert_has_calls(
expected_calls)
self.helper.ovn_nbdb_api.db_remove.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test__del_lb_to_lr_association_no_lr_ref(self, net_cli):
lr_ref = ''
self.helper._del_lb_to_lr_association(
self.ref_lb1, self.router, lr_ref)
self.helper.ovn_nbdb_api.db_set.assert_not_called()
self.helper.ovn_nbdb_api.db_remove.assert_not_called()
self.helper.ovn_nbdb_api.lr_lb_del.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test__del_lb_to_lr_association_lr_ref_empty_after(self, net_cli):
lr_ref = self.router.name
self.helper._del_lb_to_lr_association(
self.ref_lb1, self.router, lr_ref)
self.helper.ovn_nbdb_api.db_remove.assert_called_once_with(
'Load_Balancer', self.ref_lb1.uuid, 'external_ids',
ovn_const.LB_EXT_IDS_LR_REF_KEY)
self.helper.ovn_nbdb_api.lr_lb_del.assert_called_once_with(
self.router.uuid, self.ref_lb1.uuid, if_exists=True)
self.helper.ovn_nbdb_api.db_set.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ls_for_lr')
def test__del_lb_to_lr_association_from_ls(self, f_ls):
# This test if LB is deleted from Logical_Router_Port
# Logical_Switch.
f_ls.return_value = ['neutron-xyz', 'neutron-qwr']
self.helper._del_lb_to_lr_association(self.ref_lb1, self.router, '')
self.helper.ovn_nbdb_api.ls_lb_del.assert_has_calls([
(mock.call('neutron-xyz', self.ref_lb1.uuid, if_exists=True)),
(mock.call('neutron-qwr', self.ref_lb1.uuid, if_exists=True))])
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ls_for_lr')
def test__add_lb_to_lr_association(self, f_ls):
lr_ref = 'foo'
f_ls.return_value = ['neutron-xyz', 'neutron-qwr']
self.helper._add_lb_to_lr_association(
self.ref_lb1, self.router, lr_ref)
self.helper.ovn_nbdb_api.lr_lb_add.assert_called_once_with(
self.router.uuid, self.ref_lb1.uuid, may_exist=True)
self.helper.ovn_nbdb_api.ls_lb_add.assert_has_calls([
(mock.call('neutron-xyz', self.ref_lb1.uuid, may_exist=True)),
(mock.call('neutron-qwr', self.ref_lb1.uuid, may_exist=True))])
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ref_lb1.uuid,
('external_ids', {'lr_ref': 'foo,%s' % self.router.name}))
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ls_for_lr')
def test__add_lb_to_lr_association_lr_already_associated(self, f_ls):
self.ref_lb1.external_ids.update({
ovn_const.LB_EXT_IDS_LR_REF_KEY: self.router.name})
lr_ref = self.ref_lb1.external_ids.get(ovn_const.LB_EXT_IDS_LR_REF_KEY)
f_ls.return_value = ['neutron-xyz', 'neutron-qwr']
self.helper._add_lb_to_lr_association(
self.ref_lb1,
self.router,
lr_ref)
self.helper.ovn_nbdb_api.lr_lb_add.assert_called_once_with(
self.router.uuid, self.ref_lb1.uuid, may_exist=True)
self.helper.ovn_nbdb_api.ls_lb_add.assert_has_calls([
(mock.call('neutron-xyz', self.ref_lb1.uuid, may_exist=True)),
(mock.call('neutron-qwr', self.ref_lb1.uuid, may_exist=True))])
self.helper.ovn_nbdb_api.db_set.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ls_for_lr')
def test__add_lb_to_lr_association_no_lr_rf(self, f_ls):
lr_ref = ''
f_ls.return_value = ['neutron-xyz', 'neutron-qwr']
self.helper._add_lb_to_lr_association(
self.ref_lb1, self.router, lr_ref)
self.helper.ovn_nbdb_api.lr_lb_add.assert_called_once_with(
self.router.uuid, self.ref_lb1.uuid, may_exist=True)
self.helper.ovn_nbdb_api.ls_lb_add.assert_has_calls([
(mock.call('neutron-xyz', self.ref_lb1.uuid, may_exist=True)),
(mock.call('neutron-qwr', self.ref_lb1.uuid, may_exist=True))])
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ref_lb1.uuid,
('external_ids', {'lr_ref': '%s' % self.router.name}))
def test__extract_listener_key_value(self):
self.assertEqual(
(None, None),
self.helper._extract_listener_key_value('listener'))
self.assertEqual(
('listener', '123'),
self.helper._extract_listener_key_value('listener:123'))
def test__find_lr_of_ls(self):
lsp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1',
'neutron:cidrs': '10.10.10.1/24',
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
n_const.DEVICE_OWNER_ROUTER_INTF},
'type': 'router',
'options': {
'router-port': 'lrp-foo-name'},
})
lsp2 = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router2',
'neutron:cidrs': '10.10.10.2/24',
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
n_const.DEVICE_OWNER_ROUTER_INTF},
'type': 'router',
'options': {
'router-port': 'lrp-bar-name'},
})
lrp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'name': 'lrp-foo-name',
})
lr = fakes.FakeOVNRouter.create_one_router(
attrs={
'name': 'router1',
'ports': [lrp]})
lrp2 = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'name': 'lrp-foo-name2',
})
lr2 = fakes.FakeOVNRouter.create_one_router(
attrs={
'name': 'router2',
'ports': [lrp2]})
ls = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'ports': [lsp2, lsp]})
(self.helper.ovn_nbdb_api.get_lrs.return_value.
execute.return_value) = [lr2, lr]
returned_lr = self.helper._find_lr_of_ls(ls, '10.10.10.1')
self.assertEqual(lr, returned_lr)
def test__find_lr_of_ls_multiple_address_ipv4(self):
lsp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1',
'neutron:cidrs': (
'10.10.10.1/24 10.10.20.1/24'
),
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
n_const.DEVICE_OWNER_ROUTER_INTF},
'type': 'router',
'options': {
'router-port': 'lrp-foo-name'},
})
lrp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'name': 'lrp-foo-name',
})
lr = fakes.FakeOVNRouter.create_one_router(
attrs={
'name': 'router1',
'ports': [lrp]})
ls = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'ports': [lsp]})
(self.helper.ovn_nbdb_api.get_lrs.return_value.
execute.return_value) = [lr]
returned_lr = self.helper._find_lr_of_ls(ls, '10.10.20.1')
self.assertEqual(lr, returned_lr)
def test__find_lr_of_ls_multiple_address_ipv6(self):
lsp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1',
'neutron:cidrs': (
'fd61:5fe4:978c:a334:0:3eff:24ab:f816/64 '
'fd8b:8a01:ab1d:0:f816:3eff:fe3d:24ab/64'
),
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
n_const.DEVICE_OWNER_ROUTER_INTF},
'type': 'router',
'options': {
'router-port': 'lrp-foo-name'},
})
lrp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'name': 'lrp-foo-name',
})
lr = fakes.FakeOVNRouter.create_one_router(
attrs={
'name': 'router1',
'ports': [lrp]})
ls = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'ports': [lsp]})
(self.helper.ovn_nbdb_api.get_lrs.return_value.
execute.return_value) = [lr]
returned_lr = self.helper._find_lr_of_ls(
ls, 'fd61:5fe4:978c:a334:0:3eff:24ab:f816')
self.assertEqual(lr, returned_lr)
def test__find_lr_of_ls_no_lrs(self):
lsp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1',
'neutron:cidrs': '10.10.10.1/24',
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
n_const.DEVICE_OWNER_ROUTER_INTF},
'type': 'router',
'options': {
'router-port': 'lrp-foo-name'},
})
lsp2 = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router2',
'neutron:cidrs': '10.10.10.2/24',
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
n_const.DEVICE_OWNER_ROUTER_INTF},
'type': 'router',
'options': {
'router-port': 'lrp-bar-name'},
})
ls = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'ports': [lsp2, lsp]})
(self.helper.ovn_nbdb_api.get_lrs.return_value.
execute.return_value) = []
returned_lr = self.helper._find_lr_of_ls(ls, '10.10.10.1')
self.assertIsNone(returned_lr)
def test__find_lr_of_ls_gw_port_id(self):
lsp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1',
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
n_const.DEVICE_OWNER_ROUTER_INTF},
'type': 'router',
'options': {
'router-port': 'lrp-lrp-foo-name'}
})
lr = fakes.FakeOVNRouter.create_one_router(
attrs={
'name': 'router1',
'ports': [],
'external_ids': {
'neutron:gw_port_id': 'lrp-foo-name'}})
ls = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'ports': [lsp]})
(self.helper.ovn_nbdb_api.get_lrs.return_value.
execute.return_value) = [lr]
returned_lr = self.helper._find_lr_of_ls(ls)
self.assertEqual(lr, returned_lr)
def test__find_lr_of_ls_no_lrp_name(self):
lsp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1',
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
n_const.DEVICE_OWNER_ROUTER_INTF},
'type': 'router',
'options': {
'router-port': None}
})
ls = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'ports': [lsp]})
returned_lr = self.helper._find_lr_of_ls(ls)
self.assertIsNone(returned_lr)
def test__find_lr_of_ls_no_router_type_port(self):
lsp = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: 'router1',
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
n_const.DEVICE_OWNER_ROUTER_INTF},
'type': 'foo',
'options': {
'router-port': None}
})
ls = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'ports': [lsp]})
returned_lr = self.helper._find_lr_of_ls(ls)
self.assertIsNone(returned_lr)
def test__find_lr_of_ls_no_lrp(self):
ls = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'ports': []})
returned_lr = self.helper._find_lr_of_ls(ls)
(self.helper.ovn_nbdb_api.tables['Logical_Router'].rows.
values.assert_not_called())
self.assertIsNone(returned_lr)
def test__get_lb_to_ls_association_command_empty_network_and_subnet(self):
self._get_lb_to_ls_association_commands.stop()
returned_commands = self.helper._get_lb_to_ls_association_commands(
self.ref_lb1, associate=True, update_ls_ref=True)
self.assertListEqual(returned_commands, [])
def test__get_member_info(self):
fake_member = fakes.FakeMember(
uuid=self.member['id'],
member_id=self.member['id'],
admin_state_up=True,
name='member_2',
project_id=self.project_id,
address=self.member['address'],
protocol_port=self.member['protocol_port'],
subnet_id=self.member['subnet_id'])
result = (
ovn_const.LB_EXT_IDS_MEMBER_PREFIX + fake_member.member_id +
'_' + fake_member.address + ':' + fake_member.protocol_port +
'_' + fake_member.subnet_id)
self.assertEqual(
result, self.helper._get_member_info(fake_member))
result = (
ovn_const.LB_EXT_IDS_MEMBER_PREFIX + self.member['id'] + '_' +
self.member['address'] + ':' + self.member['protocol_port'] +
'_' + self.member['subnet_id'])
self.assertEqual(
result, self.helper._get_member_info(self.member))
self.assertEqual('', self.helper._get_member_info(None))
def test__update_lb_to_ls_association_network(self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
associate=True, update_ls_ref=True)
self.helper.ovn_nbdb_api.ls_get.assert_called_once_with(
self.network.name)
ls_refs = {'ls_refs': '{"%s": 2}' % self.network.name}
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ref_lb1.uuid, ('external_ids', ls_refs))
def test__update_lb_to_ls_association_network_no_update_ls_ref(self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
associate=True, update_ls_ref=False)
self.helper.ovn_nbdb_api.ls_get.assert_called_once_with(
self.network.name)
self.helper.ovn_nbdb_api.db_set.assert_not_called()
def test__update_lb_to_ls_association_network_no_assoc_no_update_ls_ref(
self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
associate=False, update_ls_ref=False)
self.helper.ovn_nbdb_api.ls_get.assert_called_once_with(
self.network.name)
self.helper.ovn_nbdb_api.db_set.assert_not_called()
def test__update_lb_to_ls_association_network_no_assoc_update_ls_ref(
self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
associate=False, update_ls_ref=True)
self.helper.ovn_nbdb_api.ls_lb_del.assert_called_once_with(
self.network.uuid, self.ref_lb1.uuid, if_exists=True)
ls_refs = {'ls_refs': '{}'}
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ref_lb1.uuid, ('external_ids', ls_refs))
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test__update_lb_to_ls_association_subnet(self, net_cli):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
subnet = fakes.FakeSubnet.create_one_subnet(
attrs={'id': 'foo_subnet_id',
'name': 'foo_subnet_name',
'network_id': 'foo_network_id'})
net_cli.return_value.get_subnet.return_value = subnet
self.helper._update_lb_to_ls_association(
self.ref_lb1, subnet_id=subnet.id,
associate=True, update_ls_ref=True)
self.helper.ovn_nbdb_api.ls_get.assert_called_once_with(
'neutron-foo_network_id')
def test__update_lb_to_ls_association_empty_ls_refs_additional_vips(self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
return_value) = self.network
self.ref_lb1.external_ids.pop('ls_refs')
self.ref_lb1.external_ids.update({
ovn_const.LB_EXT_IDS_ADDIT_VIP_KEY: 'foo, anotherfoo'})
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
update_ls_ref=True, additional_vips=True)
self.helper.ovn_nbdb_api.ls_lb_add.assert_called_once_with(
self.network.uuid, self.ref_lb1.uuid, may_exist=True)
ls_refs = {'ls_refs': '{"%s": 3}' % self.network.name}
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ref_lb1.uuid, ('external_ids', ls_refs))
def test__update_lb_to_ls_association_empty_ls_refs(self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
return_value) = self.network
self.ref_lb1.external_ids.pop('ls_refs')
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
update_ls_ref=True, additional_vips=True)
self.helper.ovn_nbdb_api.ls_lb_add.assert_called_once_with(
self.network.uuid, self.ref_lb1.uuid, may_exist=True)
ls_refs = {'ls_refs': '{"%s": 1}' % self.network.name}
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ref_lb1.uuid, ('external_ids', ls_refs))
def test__update_lb_to_ls_association_empty_ls_refs_no_ls(self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
return_value) = None
self.ref_lb1.external_ids.pop('ls_refs')
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
update_ls_ref=False)
self.helper.ovn_nbdb_api.ls_lb_add.assert_not_called()
self.helper.ovn_nbdb_api.db_set.assert_not_called()
def test__update_lb_to_ls_association_no_ls(self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
side_effect) = [idlutils.RowNotFound]
returned_commands = self.helper._get_lb_to_ls_association_commands(
self.ref_lb1, network_id=self.network.uuid,
update_ls_ref=True)
self.helper.ovn_nbdb_api.ls_get.assert_called_once_with(
self.network.name)
self.assertListEqual([], returned_commands)
def test__update_lb_to_ls_association_network_disassociate(self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
return_value) = self.network
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
associate=False, update_ls_ref=True)
self.helper.ovn_nbdb_api.ls_get.assert_called_once_with(
self.network.name)
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ref_lb1.uuid,
('external_ids', {'ls_refs': '{}'}))
self.helper.ovn_nbdb_api.ls_lb_del.assert_called_once_with(
self.network.uuid, self.ref_lb1.uuid, if_exists=True)
def test__update_lb_to_ls_association_net_disassoc_no_update_ls_ref(self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
return_value) = self.network
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
associate=False, update_ls_ref=False)
self.helper.ovn_nbdb_api.ls_get.assert_called_once_with(
self.network.name)
self.helper.ovn_nbdb_api.db_set.assert_not_called()
self.helper.ovn_nbdb_api.ls_lb_del.assert_called_once_with(
self.network.uuid, self.ref_lb1.uuid, if_exists=True)
def test__update_lb_to_ls_association_dissasoc_net_not_assoc(self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
return_value) = self.network
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id='foo',
associate=False, update_ls_ref=False)
self.helper.ovn_nbdb_api.ls_get.assert_called_once_with(
'neutron-foo')
self.helper.ovn_nbdb_api.db_set.assert_not_called()
self.helper.ovn_nbdb_api.ls_lb_del.assert_called_once_with(
self.network.uuid, self.ref_lb1.uuid, if_exists=True)
def test__update_lb_to_ls_association_net_ls_ref_wrong_format(self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
return_value) = self.network
self.ref_lb1.external_ids.update({
ovn_const.LB_EXT_IDS_LS_REFS_KEY:
'{\"neutron-%s\"}'})
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
associate=False, update_ls_ref=False)
self.helper.ovn_nbdb_api.ls_get.assert_called_once_with(
self.network.name)
self.helper.ovn_nbdb_api.db_set.assert_not_called()
def test__update_lb_to_ls_association_network_dis_ls_not_found(self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
side_effect) = [idlutils.RowNotFound]
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
associate=False, update_ls_ref=True)
self.helper.ovn_nbdb_api.ls_get.assert_called_once_with(
self.network.name)
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ref_lb1.uuid,
('external_ids', {'ls_refs': '{}'}))
self.helper.ovn_nbdb_api.ls_lb_del.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test__update_lb_to_ls_association_network_dis_net_not_found(
self, net_cli):
net_cli.return_value.get_subnet.side_effect = (
openstack.exceptions.ResourceNotFound)
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
return_value) = self.network
self.helper._update_lb_to_ls_association(
self.ref_lb1, subnet_id='foo',
associate=False, update_ls_ref=True)
self.helper.ovn_nbdb_api.ls_get.assert_not_called()
self.helper.ovn_nbdb_api.db_set.assert_not_called()
self.helper.ovn_nbdb_api.ls_lb_del.assert_not_called()
def test__update_lb_to_ls_association_disassoc_ls_not_in_ls_refs(self):
self._update_lb_to_ls_association.stop()
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
return_value) = self.network
self.ref_lb1.external_ids.pop('ls_refs')
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
associate=False, update_ls_ref=True)
self.helper.ovn_nbdb_api.ls_lb_del.assert_not_called()
self.helper.ovn_nbdb_api.db_set.assert_not_called()
def test__update_lb_to_ls_association_disassoc_multiple_refs(self):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
(self.helper.ovn_nbdb_api.ls_get.return_value.execute.
return_value) = self.network
# multiple refs
ls_refs = {'ls_refs': '{"%s": 2}' % self.network.name}
self.ref_lb1.external_ids.update(ls_refs)
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid,
associate=False, update_ls_ref=True)
self.helper.ovn_nbdb_api.ls_get.assert_called_once_with(
self.network.name)
exp_ls_refs = {'ls_refs': '{"%s": 1}' % self.network.name}
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer', self.ref_lb1.uuid, ('external_ids', exp_ls_refs))
@mock.patch.object(ovn_helper.OvnProviderHelper, '_execute_commands')
def test__update_lb_to_ls_association_retry(self, execute):
self._update_lb_to_ls_association.stop()
self._get_lb_to_ls_association_commands.stop()
self.helper._update_lb_to_ls_association(
self.ref_lb1, network_id=self.network.uuid)
expected = self.helper._get_lb_to_ls_association_commands(
self.ref_lb1, network_id=self.network.uuid)
execute.assert_called_once_with(expected)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_execute_commands')
def test__update_lb_to_ls_association_retry_failed(self, execute):
execute.side_effect = [idlutils.RowNotFound for _ in range(4)]
self._update_lb_to_ls_association.stop()
self.assertRaises(
idlutils.RowNotFound,
self.helper._update_lb_to_ls_association,
self.ref_lb1,
network_id=self.network.uuid)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_logical_switch_port_update_event_vip_port_associate(self,
net_cli):
self.switch_port_event = ovn_event.LogicalSwitchPortUpdateEvent(
self.helper)
fake_port = fakes.FakePort.create_one_port()
net_cli.return_value.get_port.return_value = fake_port
port_name = '%s%s' % (ovn_const.LB_VIP_PORT_PREFIX, 'foo')
fip = '10.0.0.1'
attrs = {
'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name,
ovn_const.OVN_PORT_FIP_EXT_ID_KEY: fip}}
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs)
attrs_old = {
'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name}}
old = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs_old)
self.switch_port_event.run(mock.ANY, row, old)
expected_call = {
'info':
{'action': 'associate',
'vip_related': [fake_port.fixed_ips[0]['ip_address']],
'additional_vip_fip': False,
'vip_fip': fip,
'ovn_lb': self.ovn_lb},
'type': 'handle_vip_fip'}
self.mock_add_request.assert_called_once_with(expected_call)
def test_logical_switch_port_update_event_missing_port_name(self):
self.switch_port_event = ovn_event.LogicalSwitchPortUpdateEvent(
self.helper)
attrs = {'external_ids': {}}
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs)
self.assertFalse(self.switch_port_event.match_fn(
mock.ANY, row, mock.ANY))
self.mock_add_request.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_logical_switch_port_update_event_disassociate(self, net_cli):
self.switch_port_event = ovn_event.LogicalSwitchPortUpdateEvent(
self.helper)
fake_port = fakes.FakePort.create_one_port()
net_cli.return_value.get_port.return_value = fake_port
port_name = '%s%s' % (ovn_const.LB_VIP_PORT_PREFIX, 'foo')
fip = '172.24.4.4'
attrs = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name}}
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs)
attrs_old = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name,
ovn_const.OVN_PORT_FIP_EXT_ID_KEY: fip}}
old = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs_old)
self.switch_port_event.run(mock.ANY, row, old)
expected_call = {
'info':
{'action': 'disassociate',
'vip_fip': fip,
'additional_vip_fip': False,
'vip_related': [fake_port.fixed_ips[0]['ip_address']],
'ovn_lb': self.ovn_lb},
'type': 'handle_vip_fip'}
self.mock_add_request.assert_called_once_with(expected_call)
def test_logical_switch_port_update_event_update_unrelated(self):
self.switch_port_event = ovn_event.LogicalSwitchPortUpdateEvent(
self.helper)
port_name = '%s%s' % (ovn_const.LB_VIP_PORT_PREFIX, 'foo')
fip = '172.24.4.4'
attrs = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name,
ovn_const.OVN_PORT_FIP_EXT_ID_KEY: fip}}
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs)
attrs_old = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name,
ovn_const.OVN_PORT_FIP_EXT_ID_KEY: fip}}
old = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs_old)
self.switch_port_event.run(mock.ANY, row, old)
self.mock_add_request.assert_not_called()
def test_logical_switch_port_update_event_without_external_ids(self):
self.switch_port_event = ovn_event.LogicalSwitchPortUpdateEvent(
self.helper)
attrs = {}
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs)
old = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs)
self.switch_port_event.run(mock.ANY, row, old)
self.mock_add_request.assert_not_called()
def test_logical_switch_port_update_event_wrong_vip_port_name(self):
self.switch_port_event = ovn_event.LogicalSwitchPortUpdateEvent(
self.helper)
port_name = 'foo'
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name}})
attrs_old = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name,
ovn_const.OVN_PORT_FIP_EXT_ID_KEY: 'foo'}}
old = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs_old)
self.assertFalse(self.switch_port_event.match_fn(mock.ANY, row, old))
self.mock_add_request.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_delete_port_not_found(self, net_cli):
net_cli.return_value.delete_port.side_effect = (
[openstack.exceptions.ResourceNotFound])
self.helper.delete_port('foo')
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
def test_vip_port_update_handler_lb_not_found(self, lb):
lb.side_effect = [idlutils.RowNotFound for _ in range(5)]
self.switch_port_event = ovn_event.LogicalSwitchPortUpdateEvent(
self.helper)
port_name = '%s%s' % (ovn_const.LB_VIP_PORT_PREFIX, 'foo')
attrs = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name}}
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs)
attrs_old = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name,
ovn_const.OVN_PORT_FIP_EXT_ID_KEY: '172.24.4.40'}}
old = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs_old)
self.switch_port_event.run(mock.ANY, row, old)
self.mock_add_request.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_execute_commands')
def test__update_lb_to_lr_association_retry(self, execute):
self._update_lb_to_lr_association.stop()
self._get_lb_to_lr_association_commands.stop()
self.helper._update_lb_to_lr_association(self.ref_lb1, self.router)
expected = self.helper._get_lb_to_lr_association_commands(
self.ref_lb1, self.router)
execute.assert_called_once_with(expected)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_execute_commands')
def test__update_lb_to_lr_association_retry_failed(self, execute):
execute.side_effect = [idlutils.RowNotFound for _ in range(4)]
self._update_lb_to_lr_association.stop()
self.assertRaises(
idlutils.RowNotFound,
self.helper._update_lb_to_lr_association,
self.ref_lb1,
self.router)
def test__update_lb_to_lr_association_by_step(self):
self._get_lb_to_lr_association_commands.stop()
self._update_lb_to_lr_association_by_step.stop()
self.helper._update_lb_to_lr_association_by_step(
self.network.load_balancer[0],
self.router)
self.helper.ovn_nbdb_api.db_set.assert_called()
self.helper.ovn_nbdb_api.lr_lb_add.assert_called()
def test__update_lb_to_lr_association_by_step_exception_raise(
self):
self._get_lb_to_lr_association_commands.stop()
self._update_lb_to_lr_association_by_step.stop()
(self.helper.ovn_nbdb_api.db_set.return_value.execute.
side_effect) = [idlutils.RowNotFound]
self.assertRaises(
idlutils.RowNotFound,
self.helper._update_lb_to_lr_association_by_step,
self.network.load_balancer[0],
self.router)
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_vip_port_update_handler_multiple_lbs(self, net_cli, lb):
lb1 = mock.MagicMock()
lb2 = mock.MagicMock()
lb.return_value = [lb1, lb2]
self.switch_port_event = ovn_event.LogicalSwitchPortUpdateEvent(
self.helper)
fake_port = fakes.FakePort.create_one_port()
net_cli.return_value.get_port.return_value = fake_port
port_name = '%s%s' % (ovn_const.LB_VIP_PORT_PREFIX, 'foo')
attrs = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name}}
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs)
attrs_old = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name,
ovn_const.OVN_PORT_FIP_EXT_ID_KEY: '172.24.4.40'}}
old = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs_old)
self.switch_port_event.run(mock.ANY, row, old)
def expected_call(lb):
return {'type': 'handle_vip_fip',
'info':
{'action': mock.ANY,
'vip_fip': '172.24.4.40',
'vip_related': [fake_port.fixed_ips[0]['ip_address']],
'additional_vip_fip': False,
'ovn_lb': lb}}
self.mock_add_request.assert_has_calls([
mock.call(expected_call(lb1)),
mock.call(expected_call(lb2))])
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_vip_port_update_handler_additional_vip_dissasociate(self, net_cli,
lb):
lb1 = mock.MagicMock()
lb.return_value = [lb1]
fip = '10.0.0.123'
fake_port = fakes.FakePort.create_one_port()
net_cli.return_value.get_port.return_value = fake_port
self.switch_port_event = ovn_event.LogicalSwitchPortUpdateEvent(
self.helper)
port_name = '%s%s' % (ovn_const.LB_VIP_ADDIT_PORT_PREFIX, '1-foo')
attrs = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name}}
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs)
attrs_old = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name,
ovn_const.OVN_PORT_FIP_EXT_ID_KEY: fip}}
old = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs_old)
self.switch_port_event.run(mock.ANY, row, old)
def expected_call(lb):
return {'type': 'handle_vip_fip',
'info':
{'action': ovn_const.REQ_INFO_ACTION_DISASSOCIATE,
'vip_fip': fip,
'vip_related': [fake_port.fixed_ips[0]['ip_address']],
'additional_vip_fip': True,
'ovn_lb': lb}}
self.mock_add_request.assert_has_calls([
mock.call(expected_call(lb1))])
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_vip_port_update_handler_additional_vip_associate(self, net_cli,
lb):
lb1 = mock.MagicMock()
lb.return_value = [lb1]
fake_port = fakes.FakePort.create_one_port()
net_cli.return_value.get_port.return_value = fake_port
self.switch_port_event = ovn_event.LogicalSwitchPortUpdateEvent(
self.helper)
port_name = '%s%s' % (ovn_const.LB_VIP_ADDIT_PORT_PREFIX, '1-foo')
attrs = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name,
ovn_const.OVN_PORT_FIP_EXT_ID_KEY: '10.0.0.99'}}
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs)
attrs_old = {'external_ids':
{ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port_name}}
old = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs=attrs_old)
self.switch_port_event.run(mock.ANY, row, old)
def expected_call(lb):
return {'type': 'handle_vip_fip',
'info':
{'action': ovn_const.REQ_INFO_ACTION_ASSOCIATE,
'vip_fip': '10.0.0.99',
'vip_related': [fake_port.fixed_ips[0]['ip_address']],
'additional_vip_fip': True,
'ovn_lb': lb}}
self.mock_add_request.assert_has_calls([
mock.call(expected_call(lb1))])
lb1 = mock.MagicMock()
vip_fip = '10.0.0.123'
external_ids = {
ovn_const.LB_EXT_IDS_ADDIT_VIP_KEY: '172.26.21.20',
ovn_const.LB_EXT_IDS_ADDIT_VIP_FIP_KEY: vip_fip}
lb1.external_ids = external_ids
lb.return_value = [lb1]
self.switch_port_event = ovn_event.LogicalSwitchPortUpdateEvent(
self.helper)
self.switch_port_event.run(mock.ANY, row, old)
self.mock_add_request.reset()
self.mock_add_request.assert_has_calls([
mock.call(expected_call(lb1))])
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
def test_handle_vip_fip_disassociate(self, flb):
lb = mock.MagicMock()
vip_fip = '10.0.0.123'
external_ids = {
'neutron:vip': '172.26.21.20',
'neutron:vip_fip': vip_fip}
lb.external_ids = external_ids
lb_hc = mock.MagicMock()
lb_hc.uuid = "fake_lb_hc_vip"
lb_hc.vip = "{}:80".format('172.26.21.20')
lb_hc.external_ids = {
ovn_const.LB_EXT_IDS_HM_KEY: 'foo',
ovn_const.LB_EXT_IDS_HM_POOL_KEY: 'pool_foo',
ovn_const.LB_EXT_IDS_HM_VIP: '172.26.21.20'}
lb_hc_fip = mock.MagicMock()
lb_hc_fip.uuid = "fake_lb_hc_fip"
lb_hc_fip.vip = "{}:80".format(vip_fip)
lb_hc_fip.external_ids = {
ovn_const.LB_EXT_IDS_HM_KEY: 'foo',
ovn_const.LB_EXT_IDS_HM_POOL_KEY: 'pool_foo',
ovn_const.LB_EXT_IDS_HM_VIP: vip_fip}
lb.health_check = [lb_hc, lb_hc_fip]
fip_info = {
'action': 'disassociate',
'vip_fip': vip_fip,
'vip_related': ['172.26.21.20'],
'ovn_lb': lb}
flb.return_value = lb
self.helper.handle_vip_fip(fip_info)
calls = [
mock.call.db_remove(
'Load_Balancer', lb.uuid, 'external_ids', 'neutron:vip_fip'),
mock.call.db_remove(
'Load_Balancer', lb.uuid, 'health_check', lb_hc_fip.uuid),
mock.call.db_destroy('Load_Balancer_Health_Check', lb_hc_fip.uuid),
mock.call.db_clear('Load_Balancer', lb.uuid, 'vips'),
mock.call.db_set('Load_Balancer', lb.uuid, ('vips', {}))]
self.helper.ovn_nbdb_api.assert_has_calls(calls)
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
def test_handle_vip_fip_disassociate_no_lbhc(self, flb):
lb = mock.MagicMock()
vip_fip = '10.0.0.123'
external_ids = {
'neutron:vip': '172.26.21.20',
'neutron:vip_fip': vip_fip}
lb.external_ids = external_ids
lb.health_check = []
fip_info = {
'action': 'disassociate',
'vip_fip': vip_fip,
'ovn_lb': lb}
flb.return_value = lb
self.helper.handle_vip_fip(fip_info)
calls = [
mock.call.db_remove(
'Load_Balancer', lb.uuid, 'external_ids', 'neutron:vip_fip'),
mock.call.db_clear('Load_Balancer', lb.uuid, 'vips'),
mock.call.db_set('Load_Balancer', lb.uuid, ('vips', {}))]
self.helper.ovn_nbdb_api.assert_has_calls(calls)
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
def test_handle_vip_fip_disassociate_no_matching_lbhc(self, flb):
lb = mock.MagicMock()
vip_fip = '10.0.0.123'
external_ids = {
'neutron:vip': '172.26.21.20',
'neutron:vip_fip': vip_fip}
lb.external_ids = external_ids
lb_hc = mock.MagicMock()
lb_hc.uuid = "fake_lb_hc"
lb_hc.vip = "10.0.0.222:80"
lb.health_check = [lb_hc]
lb.health_check = []
fip_info = {
'action': 'disassociate',
'vip_fip': vip_fip,
'ovn_lb': lb}
flb.return_value = lb
self.helper.handle_vip_fip(fip_info)
calls = [
mock.call.db_remove(
'Load_Balancer', lb.uuid, 'external_ids', 'neutron:vip_fip'),
mock.call.db_clear('Load_Balancer', lb.uuid, 'vips'),
mock.call.db_set('Load_Balancer', lb.uuid, ('vips', {}))]
self.helper.ovn_nbdb_api.assert_has_calls(calls)
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
def test_handle_vip_fip_associate(self, fb):
lb = mock.MagicMock()
fip_info = {
'action': 'associate',
'vip_fip': '10.0.0.123',
'ovn_lb': lb}
members = 'member_%s_%s:%s_%s' % (self.member_id,
self.member_address,
self.member_port,
self.member_subnet_id)
external_ids = {
'listener_foo': '80:pool_%s' % self.pool_id,
'pool_%s' % self.pool_id: members,
'neutron:vip': '172.26.21.20'}
lb.external_ids = external_ids
fb.return_value = lb
self.helper.handle_vip_fip(fip_info)
expected_db_set_calls = [
mock.call('Load_Balancer', lb.uuid,
('external_ids', {'neutron:vip_fip': '10.0.0.123'})),
mock.call('Load_Balancer', lb.uuid,
('vips', {'10.0.0.123:80': '192.168.2.149:1010',
'172.26.21.20:80': '192.168.2.149:1010'}))
]
self.helper.ovn_nbdb_api.db_set.assert_has_calls(expected_db_set_calls)
self.helper.ovn_nbdb_api.db_clear.assert_called_once_with(
'Load_Balancer', lb.uuid, 'vips')
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
def test_handle_vip_fip_additional_vip_fip_disassociate(self, flb):
lb = mock.MagicMock()
vip_fip = '10.0.0.123'
external_ids = {
ovn_const.LB_EXT_IDS_ADDIT_VIP_KEY: '172.26.21.20',
ovn_const.LB_EXT_IDS_ADDIT_VIP_FIP_KEY: vip_fip}
lb.external_ids = external_ids
lb_hc = mock.MagicMock()
lb_hc.uuid = "fake_lb_hc_vip"
lb_hc.vip = "{}:80".format('172.26.21.20')
lb_hc.external_ids = {
ovn_const.LB_EXT_IDS_HM_KEY: 'foo',
ovn_const.LB_EXT_IDS_HM_POOL_KEY: 'pool_foo',
ovn_const.LB_EXT_IDS_HM_VIP: '172.26.21.20'}
lb_hc_fip = mock.MagicMock()
lb_hc_fip.uuid = "fake_lb_hc_fip"
lb_hc_fip.vip = "{}:80".format(vip_fip)
lb_hc_fip.external_ids = {
ovn_const.LB_EXT_IDS_HM_KEY: 'foo',
ovn_const.LB_EXT_IDS_HM_POOL_KEY: 'pool_foo',
ovn_const.LB_EXT_IDS_HM_VIP: vip_fip}
lb.health_check = [lb_hc, lb_hc_fip]
fip_info = {
'action': 'disassociate',
'vip_fip': vip_fip,
'vip_related': ['172.26.21.20'],
'additional_vip_fip': True,
'ovn_lb': lb}
flb.return_value = lb
self.helper.handle_vip_fip(fip_info)
calls = [
mock.call.db_remove(
'Load_Balancer', lb.uuid, 'external_ids',
ovn_const.LB_EXT_IDS_ADDIT_VIP_FIP_KEY),
mock.call.db_remove(
'Load_Balancer', lb.uuid, 'health_check', lb_hc_fip.uuid),
mock.call.db_destroy('Load_Balancer_Health_Check', lb_hc_fip.uuid),
mock.call.db_clear('Load_Balancer', lb.uuid, 'vips'),
mock.call.db_set('Load_Balancer', lb.uuid, ('vips', {}))]
self.helper.ovn_nbdb_api.assert_has_calls(calls)
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
def test_handle_vip_fip_additional_vip_fip_associate(self, fb):
lb = mock.MagicMock()
fip_info = {
'action': 'associate',
'vip_fip': '10.0.0.123',
'vip_related': ['172.26.21.20'],
'additional_vip_fip': True,
'ovn_lb': lb}
members = 'member_%s_%s:%s_%s' % (self.member_id,
self.member_address,
self.member_port,
self.member_subnet_id)
external_ids = {
'listener_foo': '80:pool_%s' % self.pool_id,
'pool_%s' % self.pool_id: members,
'neutron:vip': '172.26.21.20',
ovn_const.LB_EXT_IDS_ADDIT_VIP_KEY: '172.25.21.20'}
ovn_hm = mock.MagicMock()
ovn_hm.uuid = self.healthmonitor_id
ovn_hm.vip = '172.26.21.20:80'
ovn_hm.external_ids = {
ovn_const.LB_EXT_IDS_HM_KEY: ovn_hm.uuid,
ovn_const.LB_EXT_IDS_HM_POOL_KEY: self.pool_id,
ovn_const.LB_EXT_IDS_HM_VIP: '172.26.21.20'}
ovn_hm_addi = mock.MagicMock()
ovn_hm_addi.uuid = self.healthmonitor_id
ovn_hm_addi.vip = '172.25.21.20:80'
ovn_hm_addi.external_ids = {
ovn_const.LB_EXT_IDS_HM_KEY: ovn_hm_addi.uuid,
ovn_const.LB_EXT_IDS_HM_POOL_KEY: self.pool_id,
ovn_const.LB_EXT_IDS_HM_VIP: '172.25.21.20'}
lb.health_check = [ovn_hm, ovn_hm_addi]
lb.external_ids = external_ids
fb.return_value = lb
self.helper.handle_vip_fip(fip_info)
expected_db_create_calls = []
for lbhc in lb.health_check:
if lbhc.external_ids[ovn_const.LB_EXT_IDS_HM_VIP] == (
'172.26.21.20'):
lb_hc_external_ids = copy.deepcopy(lbhc.external_ids)
lb_hc_external_ids[ovn_const.LB_EXT_IDS_HM_VIP] = '10.0.0.123'
kwargs = {
'vip': fip_info['vip_fip'] + ':80',
'options': lbhc.options,
'external_ids': lb_hc_external_ids}
expected_db_create_calls.append(mock.call(
'Load_Balancer_Health_Check', **kwargs))
self.helper.ovn_nbdb_api.db_create.assert_has_calls(
expected_db_create_calls)
self.helper.ovn_nbdb_api.db_add.assert_called_once_with(
'Load_Balancer', lb.uuid, 'health_check', mock.ANY)
expected_db_set_calls = [
mock.call('Load_Balancer', lb.uuid,
('external_ids', {
ovn_const.LB_EXT_IDS_ADDIT_VIP_FIP_KEY: '10.0.0.123'}
)),
mock.call('Load_Balancer', lb.uuid,
('vips', {'10.0.0.123:80': '192.168.2.149:1010',
'172.26.21.20:80': '192.168.2.149:1010',
'172.25.21.20:80': '192.168.2.149:1010'}))
]
self.helper.ovn_nbdb_api.db_set.assert_has_calls(expected_db_set_calls)
self.helper.ovn_nbdb_api.db_clear.assert_called_once_with(
'Load_Balancer', lb.uuid, 'vips')
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
def test_handle_vip_fip_associate_no_lbhc(self, fb):
lb = mock.MagicMock()
fip_info = {
'action': 'associate',
'vip_fip': '10.0.0.123',
'ovn_lb': lb}
members = 'member_%s_%s:%s_%s' % (self.member_id,
self.member_address,
self.member_port,
self.member_subnet_id)
external_ids = {
'listener_foo': '80:pool_%s' % self.pool_id,
'pool_%s' % self.pool_id: members,
'neutron:vip': '172.26.21.20'}
lb.external_ids = external_ids
lb.health_check = []
fb.return_value = lb
self.helper.handle_vip_fip(fip_info)
self.helper.ovn_nbdb_api.db_create.assert_not_called()
self.helper.ovn_nbdb_api.db_add.assert_not_called()
expected_db_set_calls = [
mock.call('Load_Balancer', lb.uuid,
('external_ids', {'neutron:vip_fip': '10.0.0.123'})),
mock.call('Load_Balancer', lb.uuid,
('vips', {'10.0.0.123:80': '192.168.2.149:1010',
'172.26.21.20:80': '192.168.2.149:1010'}))
]
self.helper.ovn_nbdb_api.db_set.assert_has_calls(expected_db_set_calls)
self.helper.ovn_nbdb_api.db_clear.assert_called_once_with(
'Load_Balancer', lb.uuid, 'vips')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_handle_member_dvr_lb_has_no_fip(self, net_cli):
lb = mock.MagicMock()
info = {
'id': self.member_id,
'pool_id': self.pool_id,
'action': ovn_const.REQ_INFO_MEMBER_ADDED}
external_ids = {
'neutron:vip_fip': ''}
lb.external_ids = external_ids
self.mock_find_lb_pool_key.return_value = lb
self.helper.handle_member_dvr(info)
net_cli.get_subnet.assert_not_called()
self.helper.ovn_nbdb_api.db_clear.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_handle_member_dvr_lb_fip_no_ls_ports(self, net_cli):
lb = mock.MagicMock()
info = {
'id': self.member_id,
'subnet_id': self.member_subnet_id,
'pool_id': self.pool_id,
'action': ovn_const.REQ_INFO_MEMBER_ADDED}
external_ids = {
'neutron:vip_fip': '11.11.11.11'}
lb.external_ids = external_ids
self.mock_find_lb_pool_key.return_value = lb
fake_ls = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {},
'ports': {}})
self.helper.ovn_nbdb_api.lookup.return_value = fake_ls
self.helper.handle_member_dvr(info)
self.helper.ovn_nbdb_api.db_clear.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_handle_member_dvr_lb_fip_no_subnet(self, net_cli):
lb = mock.MagicMock()
info = {
'id': self.member_id,
'subnet_id': self.member_subnet_id,
'pool_id': self.pool_id,
'action': ovn_const.REQ_INFO_MEMBER_ADDED}
external_ids = {
'neutron:vip_fip': '11.11.11.11'}
lb.external_ids = external_ids
self.mock_find_lb_pool_key.return_value = lb
net_cli.return_value.get_subnet.side_effect = [
openstack.exceptions.ResourceNotFound]
self.helper.handle_member_dvr(info)
self.helper.ovn_nbdb_api.db_clear.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_handle_member_dvr_lb_fip_no_ls(self, net_cli):
lb = mock.MagicMock()
info = {
'id': self.member_id,
'subnet_id': self.member_subnet_id,
'pool_id': self.pool_id,
'action': ovn_const.REQ_INFO_MEMBER_ADDED}
external_ids = {
'neutron:vip_fip': '11.11.11.11'}
lb.external_ids = external_ids
self.mock_find_lb_pool_key.return_value = lb
self.helper.ovn_nbdb_api.lookup.side_effect = [idlutils.RowNotFound]
self.helper.handle_member_dvr(info)
self.helper.ovn_nbdb_api.db_clear.assert_not_called()
def _test_handle_member_dvr_lb_fip(
self, net_cli, action=ovn_const.REQ_INFO_MEMBER_ADDED):
lb = mock.MagicMock()
fake_port = fakes.FakePort.create_one_port(
attrs={'allowed_address_pairs': ''})
info = {
'id': self.member_id,
'address': fake_port['fixed_ips'][0]['ip_address'],
'pool_id': self.pool_id,
'subnet_id': fake_port['fixed_ips'][0]['subnet_id'],
'action': action}
member_subnet = fakes.FakeSubnet.create_one_subnet()
member_subnet.update({'id': self.member_subnet_id})
member_subnet.update({'network_id': 'foo'})
net_cli.return_value.get_subnet.return_value = member_subnet
fake_lsp = fakes.FakeOVNPort.from_neutron_port(
fake_port)
fake_ls = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {},
'name': 'foo',
'ports': [fake_lsp]})
self.helper.ovn_nbdb_api.lookup.return_value = fake_ls
fake_nat = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ip': '22.22.22.22',
'external_ids': {
ovn_const.OVN_FIP_EXT_ID_KEY: 'fip_id'}})
fip_info = {'description': 'bar'}
net_cli.return_value.get_ip.return_value = fip_info
self.helper.ovn_nbdb_api.db_find_rows.return_value. \
execute.return_value = [fake_nat]
external_ids = {
ovn_const.LB_EXT_IDS_VIP_FIP_KEY: '11.11.11.11'}
lb.external_ids = external_ids
self.mock_find_lb_pool_key.return_value = lb
self.helper.handle_member_dvr(info)
if action == ovn_const.REQ_INFO_MEMBER_ADDED:
calls = [
mock.call.lookup('Logical_Switch', 'neutron-foo'),
mock.call.db_find_rows('NAT', ('external_ids', '=', {
ovn_const.OVN_FIP_PORT_EXT_ID_KEY: fake_lsp.name})),
mock.ANY,
mock.call.db_clear('NAT', fake_nat.uuid, 'external_mac'),
mock.ANY,
mock.call.db_clear('NAT', fake_nat.uuid, 'logical_port'),
mock.ANY]
self.helper.ovn_nbdb_api.assert_has_calls(calls)
else:
(net_cli.return_value.get_ip.
assert_called_once_with('fip_id'))
(net_cli.return_value.update_ip.
assert_called_once_with('fip_id', description='bar'))
self.helper.ovn_nbdb_api.db_clear.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_handle_member_dvr_lb_fip_member_added(self, net_cli):
self._test_handle_member_dvr_lb_fip(net_cli)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_handle_member_dvr_lb_fip_member_deleted(self, net_cli):
self._test_handle_member_dvr_lb_fip(
net_cli, action=ovn_const.REQ_INFO_MEMBER_DELETED)
def test_ovsdb_connections(self):
ovn_helper.OvnProviderHelper.ovn_nbdb_api = None
ovn_helper.OvnProviderHelper.ovn_nbdb_api_for_events = None
prov_helper1 = ovn_helper.OvnProviderHelper()
prov_helper2 = ovn_helper.OvnProviderHelper()
# One connection for API requests
self.assertIs(prov_helper1.ovn_nbdb_api,
prov_helper2.ovn_nbdb_api)
# One connection to handle events
self.assertIs(prov_helper1.ovn_nbdb_api_for_events,
prov_helper2.ovn_nbdb_api_for_events)
prov_helper2.shutdown()
prov_helper1.shutdown()
def test_create_vip_port_vip_selected(self):
expected_dict = {
'name': '%s%s' % (ovn_const.LB_VIP_PORT_PREFIX,
self.loadbalancer_id),
'fixed_ips': [{
'subnet_id': self.vip_dict['vip_subnet_id'],
'ip_address': '10.1.10.1'}],
'network_id': self.vip_dict['vip_network_id'],
'admin_state_up': True,
'project_id': self.project_id}
with mock.patch.object(clients, 'get_neutron_client') as net_cli:
self.vip_dict['vip_address'] = '10.1.10.1'
self.helper.create_vip_port(self.project_id,
self.loadbalancer_id,
self.vip_dict)
expected_call = [
mock.call().create_port(**expected_dict)]
net_cli.assert_has_calls(expected_call)
def test_create_vip_port_vip_not_selected(self):
expected_dict = {
'name': '%s%s' % (ovn_const.LB_VIP_PORT_PREFIX,
self.loadbalancer_id),
'fixed_ips': [{
'subnet_id': self.vip_dict['vip_subnet_id']}],
'network_id': self.vip_dict['vip_network_id'],
'admin_state_up': True,
'project_id': self.project_id}
with mock.patch.object(clients, 'get_neutron_client') as net_cli:
self.helper.create_vip_port(self.project_id,
self.loadbalancer_id,
self.vip_dict)
expected_call = [
mock.call().create_port(**expected_dict)]
net_cli.assert_has_calls(expected_call)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_create_vip_port_vip_selected_already_exist(self, net_cli):
net_cli.return_value.create_port.side_effect = [
openstack.exceptions.ConflictException]
net_cli.return_value.find_port.return_value = (
Port(name='ovn-lb-vip-' + self.loadbalancer_id,
id=self.loadbalancer_id))
self.vip_dict['vip_address'] = '10.1.10.1'
ret, _ = self.helper.create_vip_port(
self.project_id,
self.loadbalancer_id,
self.vip_dict)
self.assertEqual(
'%s%s' % (ovn_const.LB_VIP_PORT_PREFIX,
self.loadbalancer_id), ret.name)
self.assertEqual(self.loadbalancer_id, ret.id)
expected_call = [
mock.call().find_port(
network_id='%s' % self.vip_dict['vip_network_id'],
name_or_id='%s%s' % (ovn_const.LB_VIP_PORT_PREFIX,
self.loadbalancer_id))]
net_cli.assert_has_calls(expected_call)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test_create_vip_port_vip_selected_other_allocation_exist(
self, net_cli):
net_cli.return_value.create_port.side_effect = [
openstack.exceptions.ConflictException]
net_cli.return_value.find_port.return_value = None
self.vip_dict['vip_address'] = '10.1.10.1'
self.assertRaises(
openstack.exceptions.ConflictException,
self.helper.create_vip_port,
self.project_id,
self.loadbalancer_id,
self.vip_dict)
expected_call = [
mock.call().find_port(
network_id='%s' % self.vip_dict['vip_network_id'],
name_or_id='%s%s' % (ovn_const.LB_VIP_PORT_PREFIX,
self.loadbalancer_id))]
net_cli.assert_has_calls(expected_call)
self.helper._update_status_to_octavia.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_create_vip_port_vip_neutron_client_other_exception(
self, del_port, net_cli):
net_cli.return_value.create_port.side_effect = [
openstack.exceptions.HttpException]
self.assertRaises(
openstack.exceptions.HttpException,
self.helper.create_vip_port,
self.project_id,
self.loadbalancer_id,
self.vip_dict)
del_port.assert_not_called()
self.helper._update_status_to_octavia.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test_create_vip_port_exception_on_additional_vip_ports(
self, del_port, net_cli):
additional_vip_dicts = [{
'ip_address': '192.168.100.109',
'network_id': self.vip_dict['vip_network_id'],
'port_id': uuidutils.generate_uuid(),
'subnet_id': uuidutils.generate_uuid()
}, {
'ip_address': '192.168.200.109',
'network_id': self.vip_dict['vip_network_id'],
'port_id': uuidutils.generate_uuid(),
'subnet_id': uuidutils.generate_uuid()
}]
net_cli.return_value.create_port.side_effect = [
Port(
network_id=self.vip_dict['vip_network_id'],
name=ovn_const.LB_VIP_PORT_PREFIX + self.loadbalancer_id,
id=self.pool_id),
Port(
network_id=self.vip_dict['vip_network_id'],
name=ovn_const.LB_VIP_ADDIT_PORT_PREFIX + '1-' +
self.loadbalancer_id,
fixed_ips=[{
'subnet_id': additional_vip_dicts[0]['subnet_id'],
'ip_address': additional_vip_dicts[0]['ip_address']}],
id=additional_vip_dicts[0]['port_id']),
openstack.exceptions.HttpException]
net_cli.return_value.find_port.side_effect = [
Port(
name=ovn_const.LB_VIP_PORT_PREFIX + self.loadbalancer_id,
id=self.pool_id),
Port(
name=ovn_const.LB_VIP_ADDIT_PORT_PREFIX + '1-' +
self.loadbalancer_id,
id=additional_vip_dicts[0]['port_id'])
]
self.assertRaises(
openstack.exceptions.HttpException,
self.helper.create_vip_port,
self.project_id,
self.loadbalancer_id,
self.vip_dict,
additional_vip_dicts)
expected_calls = [
mock.call(self.pool_id),
mock.call(additional_vip_dicts[0]['port_id'])]
del_port.assert_has_calls(expected_calls)
self.helper._update_status_to_octavia.assert_not_called()
def test_get_pool_member_id(self):
ret = self.helper.get_pool_member_id(
self.pool_id, mem_addr_port='192.168.2.149:1010')
self.assertEqual(self.member_id, ret)
def test_get_pool_member_id_not_found(self):
ret = self.helper.get_pool_member_id(
self.pool_id, mem_addr_port='192.168.2.149:9999')
self.assertIsNone(ret)
def test__get_existing_pool_members(self):
ret = self.helper._get_existing_pool_members(self.pool_id)
self.assertEqual(ret, self.member_line)
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lb_by_pool_id')
def test__get_existing_pool_members_exception(self, folbpi):
folbpi.return_value = (None, None)
self.assertRaises(exceptions.DriverError,
self.helper._get_existing_pool_members,
self.pool_id)
def test__frame_lb_vips(self):
ret = self.helper._frame_vip_ips(self.ovn_lb, self.ovn_lb.external_ids)
expected = {'10.22.33.4:80': '192.168.2.149:1010',
'123.123.123.123:80': '192.168.2.149:1010'}
self.assertEqual(expected, ret)
def test__frame_lb_vips_member_offline(self):
self.ovn_lb.external_ids[ovn_const.OVN_MEMBER_STATUS_KEY] = \
'{"%s": "%s"}' % (self.member_id, constants.OFFLINE)
ret = self.helper._frame_vip_ips(self.ovn_lb, self.ovn_lb.external_ids)
expected = {}
self.assertEqual(expected, ret)
def test__frame_lb_vips_no_vip_fip(self):
self.ovn_lb.external_ids.pop(ovn_const.LB_EXT_IDS_VIP_FIP_KEY)
ret = self.helper._frame_vip_ips(self.ovn_lb, self.ovn_lb.external_ids)
expected = {'10.22.33.4:80': '192.168.2.149:1010'}
self.assertEqual(expected, ret)
def test__frame_lb_vips_additional_vips_only_member_ipv4(self):
self.ovn_lb.external_ids[ovn_const.LB_EXT_IDS_ADDIT_VIP_KEY] = \
'10.24.34.4,2001:db8::1'
ret = self.helper._frame_vip_ips(self.ovn_lb, self.ovn_lb.external_ids)
expected = {'10.22.33.4:80': '192.168.2.149:1010',
'10.24.34.4:80': '192.168.2.149:1010',
'123.123.123.123:80': '192.168.2.149:1010'}
self.assertEqual(expected, ret)
def test__frame_lb_vips_additional_vips_mixing_member_ipv4_ipv6(self):
self.ovn_lb.external_ids[ovn_const.LB_EXT_IDS_ADDIT_VIP_KEY] = \
'10.24.34.4,2001:db8::1'
self.member_address = '2001:db8::3'
self.member_line = (
'member_%s_%s:%s_%s' %
(self.member_id, self.member_address,
self.member_port, self.member_subnet_id))
self.ovn_lb.external_ids['pool_%s' % self.pool_id] = ','.join([
self.ovn_lb.external_ids['pool_%s' % self.pool_id],
self.member_line])
ret = self.helper._frame_vip_ips(self.ovn_lb, self.ovn_lb.external_ids)
expected = {'10.22.33.4:80': '192.168.2.149:1010',
'10.24.34.4:80': '192.168.2.149:1010',
'123.123.123.123:80': '192.168.2.149:1010',
'[2001:db8::1]:80': '[2001:db8::3]:1010'}
self.assertEqual(expected, ret)
def test__frame_lb_vips_additional_vips_only_member_ipv6(self):
self.ovn_lb.external_ids[ovn_const.LB_EXT_IDS_ADDIT_VIP_KEY] = \
'10.24.34.4,2001:db8::1'
self.member_address = '2001:db8::3'
self.member_line = (
'member_%s_%s:%s_%s' %
(self.member_id, self.member_address,
self.member_port, self.member_subnet_id))
self.ovn_lb.external_ids['pool_%s' % self.pool_id] = self.member_line
ret = self.helper._frame_vip_ips(self.ovn_lb, self.ovn_lb.external_ids)
expected = {'[2001:db8::1]:80': '[2001:db8::3]:1010'}
self.assertEqual(expected, ret)
def test__frame_lb_vips_disabled(self):
self.ovn_lb.external_ids['enabled'] = 'False'
ret = self.helper._frame_vip_ips(self.ovn_lb, self.ovn_lb.external_ids)
self.assertEqual({}, ret)
def test__frame_lb_vips_ipv6(self):
self.member_address = '2001:db8::1'
self.member_line = (
'member_%s_%s:%s_%s' %
(self.member_id, self.member_address,
self.member_port, self.member_subnet_id))
self.ovn_lb.external_ids = {
ovn_const.LB_EXT_IDS_VIP_KEY: 'fc00::',
'pool_%s' % self.pool_id: self.member_line,
'listener_%s' % self.listener_id: '80:pool_%s' % self.pool_id}
ret = self.helper._frame_vip_ips(self.ovn_lb, self.ovn_lb.external_ids)
expected = {'[fc00::]:80': '[2001:db8::1]:1010'}
self.assertEqual(expected, ret)
def test_check_lb_protocol(self):
self.ovn_lb.protocol = ['tcp']
ret = self.helper.check_lb_protocol(self.listener_id, 'udp')
self.assertFalse(ret)
ret = self.helper.check_lb_protocol(self.listener_id, 'UDP')
self.assertFalse(ret)
ret = self.helper.check_lb_protocol(self.listener_id, 'sctp')
self.assertFalse(ret)
ret = self.helper.check_lb_protocol(self.listener_id, 'SCTP')
self.assertFalse(ret)
ret = self.helper.check_lb_protocol(self.listener_id, 'tcp')
self.assertTrue(ret)
ret = self.helper.check_lb_protocol(self.listener_id, 'TCP')
self.assertTrue(ret)
def test_check_lb_protocol_no_listener(self):
self.ovn_lb.external_ids = []
ret = self.helper.check_lb_protocol(self.listener_id, 'TCP')
self.assertTrue(ret)
@mock.patch('ovn_octavia_provider.helper.OvnProviderHelper.'
'_find_ovn_lbs')
def test_check_lb_protocol_no_lb(self, fol):
fol.return_value = None
ret = self.helper.check_lb_protocol(self.listener_id, 'TCP')
self.assertFalse(ret)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test__get_port_from_info_with_port_id(self, net_cli):
port_id = self.vip_port_id
subnet_id = self.vip_subnet_id
network_id = None
address = self.vip_address
fake_port = fakes.FakePort.create_one_port()
fake_port['fixed_ips'].append({
'ip_address': address,
'subnet_id': subnet_id})
subnet_data = {'id': subnet_id}
net_cli.get_port.return_value = fake_port
net_cli.get_subnet.return_value = {'id': subnet_id}
result_port, result_subnet = self.helper._get_port_from_info(
net_cli, port_id, network_id, address)
self.assertEqual(result_port, fake_port)
self.assertEqual(result_subnet, subnet_data)
net_cli.get_port.assert_called_once_with(port_id)
net_cli.get_subnet.assert_called_once_with(subnet_id)
result_port, result_subnet = self.helper._get_port_from_info(
net_cli, port_id, network_id, address, subnet_required=False)
self.assertEqual(result_port, fake_port)
self.assertIsNone(result_subnet)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_neutron_list_ports')
def test__get_port_from_info_with_network_id_and_address(self, list_ports,
net_cli):
port_id = None
network_id = self.vip_network_id
address = self.vip_address
fake_port = fakes.FakePort.create_one_port()
fake_port['fixed_ips'].append({
'ip_address': self.vip_address,
'subnet_id': self.vip_subnet_id})
fake_port2 = fakes.FakePort.create_one_port()
fake_port2['fixed_ips'].append({
'ip_address': '192.148.210.119',
'subnet_id': uuidutils.generate_uuid()})
subnet_data = {'id': self.vip_subnet_id}
ports_data = [fake_port, fake_port2]
net_cli.get_subnet.return_value = subnet_data
list_ports.return_value = ports_data
result_port, result_subnet = self.helper._get_port_from_info(
net_cli, port_id, network_id, address)
self.assertEqual(result_port, fake_port)
self.assertEqual(result_subnet, subnet_data)
list_ports.assert_called_once_with(net_cli, network_id=network_id)
net_cli.get_subnet.assert_called_once_with(self.vip_subnet_id)
result_port, result_subnet = self.helper._get_port_from_info(
net_cli, port_id, network_id, address, subnet_required=False)
self.assertEqual(result_port, fake_port)
self.assertIsNone(result_subnet)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test__get_port_from_info_port_not_without_match_address(self, net_cli):
port_id = self.vip_port_id
network_id = None
address = self.vip_address
fake_port = fakes.FakePort.create_one_port()
net_cli.get_port.return_value = fake_port
result_port, result_subnet = self.helper._get_port_from_info(
net_cli, port_id, network_id, address)
self.assertEqual(result_port, fake_port)
self.assertIsNone(result_subnet)
net_cli.get_port.assert_called_once_with(port_id)
net_cli.get_subnet.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test__get_port_from_info_port_insufficient_data(self, net_cli):
result_port, result_subnet = self.helper._get_port_from_info(
net_cli, None, None, None)
self.assertIsNone(result_port)
self.assertIsNone(result_subnet)
net_cli.get_port.assert_not_called()
net_cli.get_subnet.assert_not_called()
def test__get_vip_port_from_loadbalancer_id(self):
fake_lb = fakes.FakeLB(
uuid=uuidutils.generate_uuid(),
admin_state_up=True,
listeners=[],
loadbalancer_id=self.loadbalancer_id,
name='additional_vip_lb',
project_id=self.project_id,
vip_address=self.vip_address,
vip_port_id=self.vip_port_id,
vip_network_id=self.vip_network_id,
ext_ids={})
self.octavia_driver_lib.get_loadbalancer.return_value = fake_lb
lb_vip_port_id = self.helper._get_vip_port_from_loadbalancer_id(
self.loadbalancer_id)
self.assertEqual(lb_vip_port_id, self.vip_port_id)
def test__get_additional_vips_from_loadbalancer_id(self):
additional_vips_data = [
{
'port_id': uuidutils.generate_uuid(),
'ip_address': '10.0.0.50',
'network_id': self.vip_network_id,
'subnet_id': uuidutils.generate_uuid(),
},
{
'port_id': uuidutils.generate_uuid(),
'ip_address': '10.0.1.50',
'network_id': self.vip_network_id,
'subnet_id': uuidutils.generate_uuid(),
}]
fake_lb = fakes.FakeLB(
uuid=uuidutils.generate_uuid(),
admin_state_up=True,
listeners=[],
loadbalancer_id=self.loadbalancer_id,
name='additional_vip_lb',
project_id=self.project_id,
vip_address=self.vip_address,
vip_port_id=self.vip_port_id,
vip_network_id=self.vip_network_id,
additional_vips=additional_vips_data,
ext_ids={})
self.octavia_driver_lib.get_loadbalancer.return_value = fake_lb
lb_additional_vip = \
self.helper._get_additional_vips_from_loadbalancer_id(
self.loadbalancer_id)
self.assertEqual(lb_additional_vip, additional_vips_data)
fake_lb = fakes.FakeLB(
uuid=uuidutils.generate_uuid(),
admin_state_up=True,
listeners=[],
loadbalancer_id=self.loadbalancer_id,
name='additional_vip_lb',
project_id=self.project_id,
vip_address=self.vip_address,
vip_port_id=self.vip_port_id,
vip_network_id=self.vip_network_id,
ext_ids={})
self.octavia_driver_lib.get_loadbalancer.return_value = fake_lb
lb_additional_vip = \
self.helper._get_additional_vips_from_loadbalancer_id(
self.loadbalancer_id)
self.assertEqual([], lb_additional_vip)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_update_hm_member')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
def _test_hm_create(self, protocol, members, fip, folbpi, uhm,
net_cli):
self._get_pool_listeners.stop()
fake_subnet = fakes.FakeSubnet.create_one_subnet()
pool_key = 'pool_%s' % self.pool_id
self.ovn_hm_lb.protocol = [protocol]
folbpi.return_value = (pool_key, self.ovn_hm_lb)
uhm.return_value = constants.ONLINE
net_cli.return_value.get_subnet.return_value = {'subnet': fake_subnet}
if not fip:
del self.ovn_hm_lb.external_ids[ovn_const.LB_EXT_IDS_VIP_FIP_KEY]
self._update_external_ids_member_status(self.ovn_hm_lb, self.member_id,
'online')
status = self.helper.hm_create(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.ONLINE)
if members:
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.ONLINE)
vip = (self.ovn_hm_lb.external_ids[ovn_const.LB_EXT_IDS_VIP_KEY] +
':' + str(self.listener['protocol_port']))
if fip:
fip = (self.ovn_hm_lb.external_ids[
ovn_const.LB_EXT_IDS_VIP_FIP_KEY] +
':' + str(self.listener['protocol_port']))
options = {'interval': '6',
'timeout': '7',
'failure_count': '5',
'success_count': '3'}
external_ids = {
ovn_const.LB_EXT_IDS_HM_KEY: self.healthmonitor_id,
ovn_const.LB_EXT_IDS_HM_VIP:
self.ovn_hm_lb.external_ids[ovn_const.LB_EXT_IDS_VIP_KEY],
ovn_const.LB_EXT_IDS_HM_POOL_KEY: self.pool_id}
kwargs = {'vip': vip,
'options': options,
'external_ids': external_ids}
if fip:
external_ids_fips = copy.deepcopy(external_ids)
external_ids_fips[ovn_const.LB_EXT_IDS_HM_VIP] = (
self.ovn_hm_lb.external_ids[ovn_const.LB_EXT_IDS_VIP_FIP_KEY])
fip_kwargs = {'vip': fip,
'options': options,
'external_ids': external_ids_fips}
expected_lbhc_calls = [
mock.call('Load_Balancer_Health_Check', **kwargs)]
if fip:
expected_lbhc_calls.append(
mock.call('Load_Balancer_Health_Check', **fip_kwargs)
)
self.helper.ovn_nbdb_api.db_create.assert_has_calls(
expected_lbhc_calls)
if fip:
self.assertEqual(self.helper.ovn_nbdb_api.db_add.call_count, 2)
else:
self.helper.ovn_nbdb_api.db_add.assert_called_once_with(
'Load_Balancer', self.ovn_hm_lb.uuid, 'health_check', mock.ANY)
def test_hm_create_tcp(self):
self._test_hm_create('tcp', False, True)
def test_hm_create_tcp_no_fip(self):
self._test_hm_create('tcp', False, False)
def test_hm_create_udp(self):
self._test_hm_create('udp', False, True)
def test_hm_create_tcp_pool_members(self):
pool_key = 'pool_%s' % self.pool_id
self.ovn_hm_lb.external_ids[pool_key] = self.member_line
self._test_hm_create('tcp', True, True)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
def test_hm_create_no_vip_port(self, folbpi):
pool_key = 'pool_%s' % self.pool_id
listener_key = 'listener_%s' % self.listener_id
self.ovn_hm_lb.external_ids.pop(listener_key)
folbpi.return_value = (pool_key, self.ovn_hm_lb)
status = self.helper.hm_create(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.ONLINE)
vip = ''
options = {'interval': '6',
'timeout': '7',
'success_count': '3',
'failure_count': '5'}
self.ovn_hm.external_ids.pop(ovn_const.LB_EXT_IDS_HM_KEY)
external_ids_vip = {
ovn_const.LB_EXT_IDS_HM_KEY: self.healthmonitor_id,
ovn_const.LB_EXT_IDS_HM_POOL_KEY: self.pool_id,
ovn_const.LB_EXT_IDS_HM_VIP: self.ovn_hm_lb.external_ids.get(
ovn_const.LB_EXT_IDS_VIP_KEY)}
external_ids_fip = {
ovn_const.LB_EXT_IDS_HM_KEY: self.healthmonitor_id,
ovn_const.LB_EXT_IDS_HM_POOL_KEY: self.pool_id,
ovn_const.LB_EXT_IDS_HM_VIP: self.ovn_hm_lb.external_ids.get(
ovn_const.LB_EXT_IDS_VIP_FIP_KEY)}
kwargs_first = {'vip': vip,
'options': options,
'external_ids': external_ids_vip}
kwargs_second = {'vip': vip,
'options': options,
'external_ids': external_ids_fip}
expected_lbhc_calls = [
mock.call('Load_Balancer_Health_Check', **kwargs_first),
mock.call('Load_Balancer_Health_Check', **kwargs_second)]
self.helper.ovn_nbdb_api.db_create.assert_has_calls(
expected_lbhc_calls)
self.assertEqual(self.helper.ovn_nbdb_api.db_add.call_count, 2)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
def test_hm_create_offline(self, folbpi):
self._get_pool_listeners.stop()
pool_key = 'pool_%s' % self.pool_id
folbpi.return_value = (pool_key, self.ovn_hm_lb)
self.health_monitor['admin_state_up'] = False
self._update_external_ids_member_status(self.ovn_hm_lb, self.member_id,
'online')
status = self.helper.hm_create(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.OFFLINE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.ONLINE)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
def test_hm_create_lb_not_found(self, folbpi):
folbpi.return_value = (None, None)
status = self.helper.hm_create(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.NO_MONITOR)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
def test_hm_create_pool_not_found(self, folbpi):
folbpi.return_value = ('pool_closed', self.ovn_hm_lb)
status = self.helper.hm_create(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.NO_MONITOR)
self.assertEqual(status['pools'][0]['operating_status'],
constants.OFFLINE)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
def test_hm_create_vip_not_found(self, folbpi):
pool_key = 'pool_%s' % self.pool_id
self.ovn_hm_lb.external_ids.pop(ovn_const.LB_EXT_IDS_VIP_KEY)
folbpi.return_value = (pool_key, self.ovn_hm_lb)
status = self.helper.hm_create(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.ERROR)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
def test_hm_create_lsp_not_found(self, folbpi, net_cli):
pool_key = 'pool_%s' % self.pool_id
self.ovn_hm_lb.external_ids[pool_key] = self.member_line
folbpi.return_value = (pool_key, self.ovn_hm_lb)
net_cli.return_value.get_subnet.side_effect = [
openstack.exceptions.ResourceNotFound]
status = self.helper.hm_create(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.ONLINE)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
def test_hm_create_hm_port_not_found(self, folbpi, net_cli):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
fake_port = fakes.FakePort.create_one_port(
attrs={'allowed_address_pairs': ''})
member = {'id': uuidutils.generate_uuid(),
'address': fake_port['fixed_ips'][0]['ip_address'],
'protocol_port': '9999',
'subnet_id': fake_subnet['id'],
'pool_id': self.pool_id,
'admin_state_up': True,
'old_admin_state_up': True}
member_line = ('member_%s_%s:%s_%s' %
(member['id'], member['address'],
member['protocol_port'], member['subnet_id']))
pool_key = 'pool_%s' % self.pool_id
self.ovn_hm_lb.external_ids[pool_key] = member_line
folbpi.return_value = (pool_key, self.ovn_hm_lb)
net_cli.return_value.get_subnet.return_value = fake_subnet
net_cli.return_value.ports.return_value = iter(())
fake_lsp = fakes.FakeOVNPort.from_neutron_port(fake_port)
fake_ls = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {},
'ports': [fake_lsp]})
self.helper.ovn_nbdb_api.lookup.return_value = fake_ls
status = self.helper.hm_create(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.ERROR)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
def test_hm_create_hm_source_ip_not_found(self, folbpi, net_cli):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
fake_port = fakes.FakePort.create_one_port(
attrs={'allowed_address_pairs': ''})
member = {'id': uuidutils.generate_uuid(),
'address': fake_port['fixed_ips'][0]['ip_address'],
'protocol_port': '9999',
'subnet_id': fake_subnet['id'],
'pool_id': self.pool_id,
'admin_state_up': True,
'old_admin_state_up': True}
member_line = (
'member_%s_%s:%s_%s' %
(member['id'], member['address'],
member['protocol_port'], member['subnet_id']))
pool_key = 'pool_%s' % self.pool_id
self.ovn_hm_lb.external_ids[pool_key] = member_line
folbpi.return_value = (pool_key, self.ovn_hm_lb)
net_cli.return_value.get_subnet.return_value = fake_subnet
fake_lsp = fakes.FakeOVNPort.from_neutron_port(fake_port)
fake_ls = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'external_ids': {},
'ports': [fake_lsp]})
self.helper.ovn_nbdb_api.lookup.return_value = fake_ls
status = self.helper.hm_create(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.ERROR)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
def test_hm_create_db_exception(self, folbpi):
pool_key = 'pool_%s' % self.pool_id
folbpi.return_value = (pool_key, self.ovn_hm_lb)
self.helper.ovn_nbdb_api.db_create.side_effect = [RuntimeError]
status = self.helper.hm_create(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.ERROR)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_get_or_create_ovn_lb')
def test_hm_existing_lbhc_update_on_listener_create(self, get_ovn_lb):
vip = (self.ovn_hm_lb.external_ids[ovn_const.LB_EXT_IDS_VIP_KEY] +
':' + str(self.listener['protocol_port']))
fip = (self.ovn_hm_lb.external_ids[ovn_const.LB_EXT_IDS_VIP_FIP_KEY] +
':' + str(self.listener['protocol_port']))
self.ovn_hm.vip = []
self.ovn_hm_fip = copy.deepcopy(self.ovn_hm)
self.ovn_hm_fip.external_ids[ovn_const.LB_EXT_IDS_HM_VIP] = (
self.ovn_hm_lb.external_ids[ovn_const.LB_EXT_IDS_VIP_FIP_KEY])
self.ovn_hm_lb.health_check = [self.ovn_hm, self.ovn_hm_fip]
get_ovn_lb.return_value = self.ovn_hm_lb
self.listener['admin_state_up'] = True
status = self.helper.listener_create(self.listener)
expected_set_external_ids_calls = [
mock.call('Load_Balancer_Health_Check', self.ovn_hm.uuid,
('vip', vip)),
mock.call('Load_Balancer_Health_Check', self.ovn_hm.uuid,
('vip', fip))]
self.helper.ovn_nbdb_api.db_set.assert_has_calls(
expected_set_external_ids_calls)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.ONLINE)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_get_or_create_ovn_lb')
def test_hm_create_then_listener_create_no_fip(self, get_ovn_lb):
vip = (self.ovn_hm_lb.external_ids[ovn_const.LB_EXT_IDS_VIP_KEY] +
':' + str(self.listener['protocol_port']))
self.ovn_hm.vip = []
self.ovn_hm_lb.health_check = [self.ovn_hm]
get_ovn_lb.return_value = self.ovn_hm_lb
self.listener['admin_state_up'] = True
del self.ovn_hm_lb.external_ids[ovn_const.LB_EXT_IDS_VIP_FIP_KEY]
status = self.helper.listener_create(self.listener)
self.helper.ovn_nbdb_api.db_set.assert_called_with(
'Load_Balancer_Health_Check', self.ovn_hm.uuid, ('vip', vip))
self.helper.ovn_nbdb_api.db_create.assert_not_called()
self.helper.ovn_nbdb_api.db_add.assert_not_called()
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.ONLINE)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_refresh_lb_vips')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_lookup_lbhcs_by_hm_id')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_get_or_create_ovn_lb')
def test_hm_create_then_listener_create_no_vip(self, get_ovn_lb,
lookup_hm, refresh_vips):
get_ovn_lb.return_value = self.ovn_hm_lb
lookup_hm.return_value = [self.ovn_hm]
self.ovn_hm_lb.health_check = [self.ovn_hm]
self.ovn_hm_lb.external_ids.pop(ovn_const.LB_EXT_IDS_VIP_KEY)
self.listener['admin_state_up'] = True
status = self.helper.listener_create(self.listener)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['operating_status'],
constants.ONLINE)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_from_hm_id')
def test_hm_update(self, folbfhi):
folbfhi.return_value = ([self.ovn_hm], self.ovn_hm_lb)
status = self.helper.hm_update(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.ONLINE)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_from_hm_id')
def test_hm_update_no_admin_state_up(self, folbfhi):
folbfhi.return_value = ([self.ovn_hm], self.ovn_hm_lb)
self.ovn_hm_lb.pop('admin_state_up')
status = self.helper.hm_update(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.ONLINE)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_from_hm_id')
def test_hm_update_offline(self, folbfhi):
folbfhi.return_value = ([self.ovn_hm], self.ovn_hm_lb)
self.health_monitor['admin_state_up'] = False
status = self.helper.hm_update(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.OFFLINE)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_from_hm_id')
def test_hm_update_hm_not_found(self, folbfhi):
folbfhi.return_value = ([], None)
status = self.helper.hm_update(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.ERROR)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_from_hm_id')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_by_pool_id')
def test_hm_update_lb_not_found(self, folbpi, folbfhi):
folbfhi.return_value = ([self.ovn_hm], None)
folbpi.return_value = (None, None)
status = self.helper.hm_update(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.ERROR)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.ERROR)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_from_hm_id')
def test_hm_update_just_interval(self, folbfhi):
folbfhi.return_value = ([self.ovn_hm], self.ovn_hm_lb)
self.health_monitor['interval'] = 3
self.helper.hm_update(self.health_monitor)
options = {
'interval': str(self.health_monitor['interval']),
'timeout': str(self.health_monitor['timeout']),
'success_count': str(self.health_monitor['success_count']),
'failure_count': str(self.health_monitor['failure_count'])}
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer_Health_Check',
self.ovn_hm.uuid,
('options', options))
@mock.patch.object(ovn_helper.OvnProviderHelper, '_clean_up_hm_port')
def test_hm_delete(self, del_hm_port):
self._get_pool_listeners.stop()
pool_key = 'pool_%s' % self.pool_id
self.ovn_hm_lb.external_ids[pool_key] = self.member_line
self.helper.ovn_nbdb_api.db_list_rows.return_value.\
execute.side_effect = [[self.ovn_hm_lb], [self.ovn_hm]]
status = self.helper.hm_delete(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.NO_MONITOR)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
expected_remove_calls = [
mock.call('Load_Balancer', self.ovn_hm_lb.uuid, 'health_check',
self.ovn_hm.uuid),
mock.call('Load_Balancer', self.ovn_hm_lb.uuid,
'external_ids', ovn_const.LB_EXT_IDS_HMS_KEY)]
expected_destroy_calls = [
mock.call('Load_Balancer_Health_Check', self.ovn_hm.uuid)]
del_hm_port.assert_called_once_with(self.member_subnet_id)
self.helper.ovn_nbdb_api.db_remove.assert_has_calls(
expected_remove_calls)
self.helper.ovn_nbdb_api.db_destroy.assert_has_calls(
expected_destroy_calls)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_clean_up_hm_port')
def test_hm_delete_multiples_pools_sharing_members(self, del_hm_port):
self._get_pool_listeners.stop()
pool_key = 'pool_%s' % self.pool_id
self.ovn_hm_lb.external_ids[pool_key] = self.member_line
self.ovn_hm_lb.external_ids['pool_fake'] = self.member_line
self.helper.ovn_nbdb_api.db_list_rows.return_value.\
execute.side_effect = [[self.ovn_hm_lb], [self.ovn_hm]]
status = self.helper.hm_delete(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.NO_MONITOR)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['id'], self.pool_id)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
expected_remove_calls = [
mock.call('Load_Balancer', self.ovn_hm_lb.uuid, 'health_check',
self.ovn_hm.uuid),
mock.call('Load_Balancer', self.ovn_hm_lb.uuid,
'external_ids', ovn_const.LB_EXT_IDS_HMS_KEY)]
expected_destroy_calls = [
mock.call('Load_Balancer_Health_Check', self.ovn_hm.uuid)]
del_hm_port.assert_called_once_with(self.member_subnet_id)
self.helper.ovn_nbdb_api.db_remove.assert_has_calls(
expected_remove_calls)
self.helper.ovn_nbdb_api.db_destroy.assert_has_calls(
expected_destroy_calls)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_clean_up_hm_port')
def test_hm_delete_without_members_in_pool(self, del_hm_port):
self._get_pool_listeners.stop()
pool_key = 'pool_%s' % self.pool_id
self.ovn_hm_lb.external_ids[pool_key] = ''
self.helper.ovn_nbdb_api.db_list_rows.return_value.\
execute.side_effect = [[self.ovn_hm_lb], [self.ovn_hm]]
status = self.helper.hm_delete(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.NO_MONITOR)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['listeners'][0]['provisioning_status'],
constants.ACTIVE)
expected_remove_calls = [
mock.call('Load_Balancer', self.ovn_hm_lb.uuid, 'health_check',
self.ovn_hm.uuid),
mock.call('Load_Balancer', self.ovn_hm_lb.uuid,
'external_ids', ovn_const.LB_EXT_IDS_HMS_KEY)]
expected_destroy_calls = [
mock.call('Load_Balancer_Health_Check', self.ovn_hm.uuid)]
del_hm_port.assert_not_called()
self.helper.ovn_nbdb_api.db_remove.assert_has_calls(
expected_remove_calls)
self.helper.ovn_nbdb_api.db_destroy.assert_has_calls(
expected_destroy_calls)
def test_hm_delete_row_not_found(self):
self.helper.ovn_nbdb_api.db_list_rows.return_value.\
execute.return_value = [self.ovn_hm]
self.helper.ovn_nbdb_api.db_find_rows.side_effect = (
[idlutils.RowNotFound])
status = self.helper.hm_delete(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.NO_MONITOR)
self.helper.ovn_nbdb_api.db_clear.assert_not_called()
def test_hm_delete_hm_not_found(self):
self.helper.ovn_nbdb_api.db_list_rows.return_value.\
execute.return_value = [self.ovn_hm]
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = [self.ovn_hm_lb]
self.health_monitor['id'] = 'id_not_found'
status = self.helper.hm_delete(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.NO_MONITOR)
self.helper.ovn_nbdb_api.db_clear.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_from_hm_id')
def test_hm_delete_hm_not_found_in_external_ids(self, folbfhi):
folbfhi.return_value = (self.ovn_hm, self.ovn_hm_lb)
self.ovn_hm_lb.external_ids[ovn_const.LB_EXT_IDS_HMS_KEY] = []
status = self.helper.hm_delete(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.NO_MONITOR)
@mock.patch.object(ovn_helper.OvnProviderHelper, '_find_ovn_lb_from_hm_id')
def test_hm_delete_hm_not_match_in_external_ids(self, folbfhi):
folbfhi.return_value = (self.ovn_hm, self.ovn_hm_lb)
self.ovn_hm_lb.external_ids[ovn_const.LB_EXT_IDS_HMS_KEY] = \
'["%s"]' % (uuidutils.generate_uuid())
status = self.helper.hm_delete(self.health_monitor)
self.assertEqual(status['healthmonitors'][0]['provisioning_status'],
constants.DELETED)
self.assertEqual(status['healthmonitors'][0]['operating_status'],
constants.NO_MONITOR)
expected_set_external_ids_calls = [
mock.call('Load_Balancer', self.ovn_hm_lb.uuid,
('external_ids', {
ovn_const.LB_EXT_IDS_HMS_KEY:
self.ovn_hm_lb.external_ids[
ovn_const.LB_EXT_IDS_HMS_KEY]}))]
self.helper.ovn_nbdb_api.db_set.assert_has_calls(
expected_set_external_ids_calls)
def test_hm_update_event_offline(self):
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = [self.ovn_hm_lb]
self.hm_update_event = ovn_event.ServiceMonitorUpdateEvent(
self.helper)
src_ip = '10.22.33.4'
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'ip': self.member_address,
'logical_port': 'a-logical-port',
'src_ip': src_ip,
'port': self.member_port,
'protocol': self.ovn_hm_lb.protocol,
'status': ovn_const.HM_EVENT_MEMBER_PORT_OFFLINE})
self.hm_update_event.run('update', row, mock.ANY)
expected = {
'info':
{'ovn_lbs': [self.ovn_hm_lb],
'ip': self.member_address,
'port': self.member_port,
'status': ovn_const.HM_EVENT_MEMBER_PORT_OFFLINE},
'type': 'hm_update_event'}
self.mock_add_request.assert_called_once_with(expected)
self.helper.ovn_nbdb_api.db_find_rows.assert_called_once_with(
'Load_Balancer',
('ip_port_mappings', '=',
{self.member_address: 'a-logical-port:' + src_ip}),
('protocol', '=', self.ovn_hm_lb.protocol[0]))
def test_hm_update_event_offline_by_delete(self):
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = [self.ovn_hm_lb]
self.hm_update_event = ovn_event.ServiceMonitorUpdateEvent(
self.helper)
src_ip = '10.22.33.4'
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'ip': self.member_address,
'logical_port': 'a-logical-port',
'src_ip': src_ip,
'port': self.member_port,
'protocol': self.ovn_hm_lb.protocol,
'status': ovn_const.HM_EVENT_MEMBER_PORT_ONLINE})
self.hm_update_event.run('delete', row, mock.ANY)
expected = {
'info':
{'ovn_lbs': [self.ovn_hm_lb],
'ip': self.member_address,
'port': self.member_port,
'status': ovn_const.HM_EVENT_MEMBER_PORT_OFFLINE},
'type': 'hm_update_event'}
self.mock_add_request.assert_called_once_with(expected)
self.helper.ovn_nbdb_api.db_find_rows.assert_called_once_with(
'Load_Balancer',
('ip_port_mappings', '=',
{self.member_address: 'a-logical-port:' + src_ip}),
('protocol', '=', self.ovn_hm_lb.protocol[0]))
def test_hm_update_event_lb_not_found(self):
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = []
self.hm_update_event = ovn_event.ServiceMonitorUpdateEvent(
self.helper)
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'ip': self.member_address,
'logical_port': 'a-logical-port',
'src_ip': '10.22.33.4',
'port': self.member_port,
'protocol': self.ovn_hm_lb.protocol,
'status': ovn_const.HM_EVENT_MEMBER_PORT_OFFLINE})
self.hm_update_event.run('update', row, mock.ANY)
self.mock_add_request.assert_not_called()
def test_hm_update_event_lb_row_not_found(self):
self.helper.ovn_nbdb_api.db_find_rows.\
side_effect = [idlutils.RowNotFound]
self.hm_update_event = ovn_event.ServiceMonitorUpdateEvent(
self.helper)
row = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={'ip': self.member_address,
'logical_port': 'a-logical-port',
'src_ip': '10.22.33.4',
'port': self.member_port,
'protocol': self.ovn_hm_lb.protocol,
'status': ovn_const.HM_EVENT_MEMBER_PORT_OFFLINE})
self.hm_update_event.run('update', row, mock.ANY)
self.mock_add_request.assert_not_called()
def _test_hm_update_no_member(self, bad_ip, bad_port):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
fake_port = fakes.FakePort.create_one_port(
attrs={'allowed_address_pairs': ''})
ip = fake_port['fixed_ips'][0]['ip_address']
member = {'id': uuidutils.generate_uuid(),
'address': ip,
'protocol_port': self.member_port,
'subnet_id': fake_subnet['id'],
'pool_id': self.pool_id,
'admin_state_up': True,
'old_admin_state_up': True}
member_line = (
'member_%s_%s:%s_%s' %
(member['id'], member['address'],
member['protocol_port'], member['subnet_id']))
pool_key = 'pool_%s' % self.pool_id
self.ovn_hm_lb.external_ids[pool_key] = member_line
if bad_ip:
ip = 'bad-ip'
port = self.member_port
if bad_port:
port = 'bad-port'
info = {
'ovn_lbs': [self.ovn_hm_lb],
'ip': ip,
'logical_port': 'a-logical-port',
'src_ip': '10.22.33.4',
'port': port,
'protocol': self.ovn_hm_lb.protocol,
'status': ovn_const.HM_EVENT_MEMBER_PORT_OFFLINE}
status = self.helper.hm_update_event(info)
self.assertIsNone(status)
def test_hm_update_event_member_ip_not_found(self):
self._test_hm_update_no_member(True, False)
def test_hm_update_event_member_port_not_found(self):
self._test_hm_update_no_member(False, True)
def _test_hm_update_status(self, ovn_lbs, member_id, ip, port,
mb_status):
info = {
'ovn_lbs': ovn_lbs,
'ip': ip,
'logical_port': 'a-logical-port',
'src_ip': '10.22.33.4',
'port': port,
'protocol': ovn_lbs[0].protocol,
'status': [mb_status]}
mb_status_ovn = 'error' if mb_status == 'offline' else mb_status
self._update_external_ids_member_status(self.ovn_hm_lb, member_id,
mb_status_ovn)
status = self.helper.hm_update_event(info)
return status
@mock.patch.object(ovn_helper.OvnProviderHelper, '_create_hm_port')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test__ensure_hm_ovn_port(self, mock_get_neutron_client,
mock_create_hm_port):
mock_neutron_client = mock_get_neutron_client.return_value
mock_find_port = mock_neutron_client.find_port
mock_find_port.return_value = Port(id='fake_id')
self.helper._ensure_hm_ovn_port('network_id', 'subnet_id',
'project_id')
mock_find_port.assert_called_once_with(
network_id='network_id',
name_or_id='%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
'subnet_id'))
mock_create_hm_port.assert_not_called()
@mock.patch.object(ovn_helper.OvnProviderHelper, '_create_hm_port')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test__ensure_hm_ovn_port_create_port_on_network(
self, mock_get_neutron_client, mock_create_hm_port):
mock_neutron_client = mock_get_neutron_client.return_value
mock_find_port = mock_neutron_client.find_port
mock_find_port.return_value = None
self.helper._ensure_hm_ovn_port('network_id', 'subnet_id',
'project_id')
mock_find_port.assert_called_once_with(
network_id='network_id',
name_or_id='%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
'subnet_id'))
mock_create_hm_port.assert_called_with('network_id', 'subnet_id',
'project_id')
def _update_external_ids_member_status(self, lb, member_id, member_status):
status = constants.ONLINE
if member_status == 'offline':
status = constants.OFFLINE
elif member_status == 'error':
status = constants.ERROR
try:
existing_member_status = lb.external_ids[
ovn_const.OVN_MEMBER_STATUS_KEY]
member_statuses = jsonutils.loads(existing_member_status)
except Exception:
member_statuses = {}
member_statuses[member_id] = status
lb.external_ids[
ovn_const.OVN_MEMBER_STATUS_KEY] = jsonutils.dumps(
member_statuses)
def _add_member(self, lb, subnet, port, pool_id=None, ip=None):
if not pool_id:
pool_id = self.pool_id
if not ip:
fake_port = fakes.FakePort.create_one_port(
attrs={'allowed_address_pairs': ''})
ip = fake_port['fixed_ips'][0]['ip_address']
member = {'id': uuidutils.generate_uuid(),
'address': ip,
'protocol_port': port,
'subnet_id': subnet['id'],
'pool_id': pool_id,
'admin_state_up': True,
'old_admin_state_up': True}
member_line = (
'member_%s_%s:%s_%s' %
(member['id'], member['address'],
member['protocol_port'], member['subnet_id']))
pool_key = 'pool_%s' % pool_id
existing_members = lb.external_ids[pool_key]
existing_member_status = lb.external_ids[
ovn_const.OVN_MEMBER_STATUS_KEY]
try:
member_statuses = jsonutils.loads(existing_member_status)
except Exception:
member_statuses = {}
if existing_members:
existing_members = ','.join([existing_members, member_line])
lb.external_ids[pool_key] = existing_members
member_statuses[member['id']] = constants.ONLINE
lb.external_ids[
ovn_const.OVN_MEMBER_STATUS_KEY] = jsonutils.dumps(
member_statuses)
else:
lb.external_ids[pool_key] = member_line
member_status = '{"%s": "%s"}' % (member['id'],
constants.ONLINE)
lb.external_ids[
ovn_const.OVN_MEMBER_STATUS_KEY] = member_status
return member
def test__create_hm_port(self):
expected_dict = {
'name': '%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']),
'network_id': self.vip_dict['vip_network_id'],
'fixed_ips': [{'subnet_id':
self.vip_dict['vip_subnet_id']}],
'admin_state_up': True,
'port_security_enabled': False,
'device_owner': ovn_const.OVN_LB_HM_PORT_DISTRIBUTED,
'device_id': '%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']),
'project_id': self.project_id
}
with mock.patch.object(clients, 'get_neutron_client') as net_cli:
hm_port = self.helper._create_hm_port(
self.vip_dict['vip_network_id'],
self.vip_dict['vip_subnet_id'],
self.project_id)
expected_call = [
mock.call().create_port(**expected_dict)]
net_cli.assert_has_calls(expected_call)
self.assertIsNotNone(hm_port)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
def test__create_hm_port_neutron_client_exception(
self, net_cli):
net_cli.return_value.create_port.side_effect = [
openstack.exceptions.HttpException]
net_cli.return_value.ports.return_value = []
expected_dict = {
'name': '%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']),
'network_id': self.vip_dict['vip_network_id'],
'fixed_ips': [{'subnet_id':
self.vip_dict['vip_subnet_id']}],
'admin_state_up': True,
'port_security_enabled': False,
'device_owner': ovn_const.OVN_LB_HM_PORT_DISTRIBUTED,
'device_id': '%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']),
'project_id': self.project_id
}
hm_port = self.helper._create_hm_port(
self.vip_dict['vip_network_id'],
self.vip_dict['vip_subnet_id'],
self.project_id)
expected_call = [
mock.call(),
mock.call().create_port(**expected_dict),
mock.call(),
mock.call().ports(
name='%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']))]
net_cli.assert_has_calls(expected_call)
self.assertIsNone(hm_port)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, '_clean_up_hm_port')
def test__create_hm_port_neutron_client_exception_clean_up_hm_port(
self, del_hm_port, net_cli):
net_cli.return_value.create_port.side_effect = [
openstack.exceptions.HttpException]
net_cli.return_value.ports.return_value = [
Port(name='%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']),
id='fake_uuid')]
expected_dict = {
'name': '%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']),
'network_id': self.vip_dict['vip_network_id'],
'fixed_ips': [{
'subnet_id': self.vip_dict['vip_subnet_id']}],
'admin_state_up': True,
'port_security_enabled': False,
'device_owner': ovn_const.OVN_LB_HM_PORT_DISTRIBUTED,
'device_id': '%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']),
'project_id': self.project_id
}
hm_port = self.helper._create_hm_port(
self.vip_dict['vip_network_id'],
self.vip_dict['vip_subnet_id'],
self.project_id)
expected_call = [
mock.call(),
mock.call().create_port(**expected_dict)]
net_cli.assert_has_calls(expected_call)
del_hm_port.assert_called_once_with(self.vip_dict['vip_subnet_id'])
self.assertIsNone(hm_port)
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test__clean_up_hm_port(self, del_port, net_cli):
net_cli.return_value.ports.return_value = [
Port(name='%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']),
id='fake_uuid',
fixed_ips=[{'subnet_id': 'another_subnet_id',
'ip_address': '10.1.2.3'},
{'subnet_id': self.vip_dict['vip_subnet_id'],
'ip_address': '10.0.0.3'}])]
self.helper._clean_up_hm_port(self.vip_dict['vip_subnet_id'])
expected_call = [
mock.call(),
mock.call().ports(
name='%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']))]
net_cli.assert_has_calls(expected_call)
del_port.assert_called_once_with('fake_uuid')
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test__clean_up_hm_port_in_use(self, del_port, net_cli):
net_cli.return_value.ports.return_value = [
Port(name='%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']),
id='fake_uuid',
fixed_ips=[{'subnet_id': 'another_subnet_id',
'ip_address': '10.1.2.3'},
{'subnet_id': self.vip_dict['vip_subnet_id'],
'ip_address': '10.0.0.3'}])]
fake_lb_unrelated = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'ip_port_mappings': {'10.1.2.4': 'fake_member_lgp:10.1.2.3'}})
fake_lb_hm_port_in_use = fakes.FakeOvsdbRow.create_one_ovsdb_row(
attrs={
'ip_port_mappings': {'10.1.2.4': 'fake_member_lgp:10.1.2.3',
'10.0.0.4': 'fake_member_lgp:10.0.0.3'}})
self.helper.ovn_nbdb_api.db_find_rows.return_value.\
execute.return_value = [fake_lb_unrelated, fake_lb_hm_port_in_use]
self.helper._clean_up_hm_port(self.vip_dict['vip_subnet_id'])
expected_call = [
mock.call(),
mock.call().ports(
name='%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']))]
net_cli.assert_has_calls(expected_call)
del_port.assert_not_called()
@mock.patch('ovn_octavia_provider.common.clients.get_neutron_client')
@mock.patch.object(ovn_helper.OvnProviderHelper, 'delete_port')
def test__clean_up_hm_port_not_found(self, del_port, net_cli):
net_cli.return_value.ports.return_value = []
self.helper._clean_up_hm_port(self.vip_dict['vip_subnet_id'])
expected_call = [
mock.call(),
mock.call().ports(
name='%s%s' % (ovn_const.LB_HM_PORT_PREFIX,
self.vip_dict['vip_subnet_id']))]
net_cli.assert_has_calls(expected_call)
del_port.assert_not_called()
def test_hm_update_status_offline(self):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
member = self._add_member(self.ovn_hm_lb, fake_subnet, 8080)
status = self._test_hm_update_status(
[self.ovn_hm_lb], member['id'], member['address'], '8080',
'offline')
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
def test_hm_update_status_offline_two_lbs_affected(self):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
ovn_hm_lb_2 = copy.deepcopy(self.ovn_hm_lb)
ovn_hm_lb_2.uuid = uuidutils.generate_uuid()
member = self._add_member(self.ovn_hm_lb, fake_subnet, 8080)
member_2 = self._add_member(
ovn_hm_lb_2, fake_subnet, 8080, ip=member['address'])
info = {
'ovn_lbs': [self.ovn_hm_lb, ovn_hm_lb_2],
'ip': member['address'],
'logical_port': 'a-logical-port',
'src_ip': '10.22.33.4',
'port': '8080',
'protocol': self.ovn_hm_lb.protocol,
'status': ovn_const.HM_EVENT_MEMBER_PORT_OFFLINE}
self._update_external_ids_member_status(self.ovn_hm_lb, member['id'],
'error')
self._update_external_ids_member_status(ovn_hm_lb_2, member_2['id'],
'error')
status = self.helper.hm_update_event(info)
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['pools'][1]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][1]['operating_status'],
constants.ERROR)
self.assertEqual(status['members'][1]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][1]['operating_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][1]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][1]['operating_status'],
constants.ERROR)
def test_hm_update_status_offline_lb_pool_offline(self):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
member = self._add_member(self.ovn_hm_lb, fake_subnet, 8080)
status = self._test_hm_update_status(
[self.ovn_hm_lb], member['id'], member['address'], '8080',
'offline')
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
def test_hm_update_status_online(self):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
member = self._add_member(self.ovn_hm_lb, fake_subnet, 8080)
status = self._test_hm_update_status(
[self.ovn_hm_lb], member['id'], member['address'], '8080',
'online')
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)
def test_hm_update_status_online_lb_pool_offline(self):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
member = self._add_member(self.ovn_hm_lb, fake_subnet, 8080)
status = self._test_hm_update_status(
[self.ovn_hm_lb], member['id'], member['address'], '8080',
'online')
self.assertEqual(status['pools'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['members'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['members'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['loadbalancers'][0]['provisioning_status'],
constants.ACTIVE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)
def test_hm_update_status_offline_two_members_diff_lbs_port(self):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
ovn_hm_lb2 = mock.MagicMock()
ovn_hm_lb2.uuid = uuidutils.generate_uuid()
listener_id_2 = uuidutils.generate_uuid()
pool_id_2 = uuidutils.generate_uuid()
ovn_hm_lb2.external_ids = {
ovn_const.LB_EXT_IDS_VIP_KEY: '10.22.33.98',
ovn_const.LB_EXT_IDS_VIP_FIP_KEY: '123.123.123.98',
ovn_const.LB_EXT_IDS_VIP_PORT_ID_KEY: 'foo_hm_port_2',
'enabled': True,
'pool_%s' % pool_id_2: [],
'listener_%s' % listener_id_2: '8081:pool_%s' % pool_id_2,
ovn_const.OVN_MEMBER_STATUS_KEY: '{}'}
member_lb1 = self._add_member(self.ovn_hm_lb, fake_subnet, 8080)
ip_member = member_lb1['address']
member_lb2 = self._add_member(ovn_hm_lb2, fake_subnet, 8081,
pool_id=pool_id_2, ip=ip_member)
# member lb2 ERROR, so lb2 operating_status should be ERROR
# for Pool and Loadbalancer, but lb1 should keep ONLINE
self._update_external_ids_member_status(ovn_hm_lb2, member_lb2['id'],
'error')
info = {
'ovn_lbs': [self.ovn_hm_lb, ovn_hm_lb2],
'ip': ip_member,
'logical_port': 'a-logical-port',
'src_ip': '10.22.33.4',
'port': '8081',
'protocol': ovn_hm_lb2.protocol,
'status': ovn_const.HM_EVENT_MEMBER_PORT_OFFLINE}
status = self.helper.hm_update_event(info)
self.assertEqual(status['members'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['members'][0]['id'], member_lb2['id'])
def test_hm_update_status_offline_two_members(self):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
member_1 = self._add_member(self.ovn_hm_lb, fake_subnet, 8080)
ip_1 = member_1['address']
member_2 = self._add_member(self.ovn_hm_lb, fake_subnet, 8081)
ip_2 = member_2['address']
# This is the Octavia API version
fake_member = fakes.FakeMember(
uuid=member_2['id'],
admin_state_up=True,
name='member_2',
project_id=self.project_id,
address=ip_2,
protocol_port=8081)
# Second member ONLINE, operating_status should be DEGRADED
# for Pool and Loadbalancer
fake_member.operating_status = constants.ONLINE
self.octavia_driver_lib.get_member.return_value = fake_member
status = self._test_hm_update_status(
[self.ovn_hm_lb], member_1['id'], ip_1, '8080', 'offline')
self.assertEqual(status['members'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['pools'][0]['operating_status'],
constants.DEGRADED)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.DEGRADED)
# Second member ERROR, operating_status should be ERROR
# for Pool and Loadbalancer
fake_member.operating_status = constants.ERROR
self.octavia_driver_lib.get_member.return_value = fake_member
status = self._test_hm_update_status(
[self.ovn_hm_lb], member_2['id'], ip_2, '8081', 'offline')
self.assertEqual(status['members'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ERROR)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ERROR)
def test_hm_update_status_online_two_members(self):
fake_subnet = fakes.FakeSubnet.create_one_subnet()
member_1 = self._add_member(self.ovn_hm_lb, fake_subnet, 8080)
member_2 = self._add_member(self.ovn_hm_lb, fake_subnet, 8081)
ip_2 = member_2['address']
# This is the Octavia API version
fake_member = fakes.FakeMember(
uuid=member_2['id'],
admin_state_up=True,
name='member_2',
project_id=self.project_id,
address=ip_2,
protocol_port=8081)
# Second member ERROR, operating_status should be DEGRADED
# for Pool and Loadbalancer
status = self._test_hm_update_status(
[self.ovn_hm_lb], member_2['id'], ip_2, '8081', 'offline')
member_status = {
ovn_const.OVN_MEMBER_STATUS_KEY: '{"%s": "%s", "%s": "%s"}'
% (member_1['id'],
constants.ONLINE,
member_2['id'],
constants.ERROR,)}
self.helper.ovn_nbdb_api.db_set.assert_called_once_with(
'Load_Balancer',
self.ovn_hm_lb.uuid,
('external_ids', member_status))
self.assertEqual(status['members'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.DEGRADED)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.DEGRADED)
# Second member ONLINE, operating_status should be ONLINE
# for Pool and Loadbalancer
fake_member.operating_status = constants.ONLINE
self.octavia_driver_lib.get_member.return_value = fake_member
status = self._test_hm_update_status(
[self.ovn_hm_lb], member_2['id'], ip_2, '8081', 'online')
self.assertEqual(status['members'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['pools'][0]['operating_status'],
constants.ONLINE)
self.assertEqual(status['loadbalancers'][0]['operating_status'],
constants.ONLINE)