Fix provider driver utils

The provider driver utils module converts Octavia data model objects
to provider driver objects.
This module had some bugs in the conversion that led to errors and
incomplete data.
Specifically the following conversions were fixed:
flavor_id in load balancer conversion
sni_refs and L7 policies in listener conversion
health monitors in pool conversion

This patch corrects those and updates the tests.

Story: 2006306
Task: 36022

Change-Id: Ia2570b929be1c9d89ca971fb37f036f104fb32f2
This commit is contained in:
Michael Johnson 2019-07-27 16:19:23 -07:00
parent 36afa82d0c
commit 6af536ec29
5 changed files with 173 additions and 67 deletions

View File

@ -16,17 +16,19 @@ import copy
import six
from octavia_lib.api.drivers import data_models as driver_dm
from octavia_lib.api.drivers import exceptions as lib_exceptions
from oslo_config import cfg
from oslo_context import context as oslo_context
from oslo_log import log as logging
from stevedore import driver as stevedore_driver
from octavia.api.drivers import data_models as driver_dm
from octavia.api.drivers import exceptions as driver_exceptions
from octavia.common import data_models
from octavia.common import exceptions
from octavia.common.tls_utils import cert_parser
from octavia.db import api as db_api
from octavia.db import repositories
from octavia.i18n import _
LOG = logging.getLogger(__name__)
@ -105,6 +107,18 @@ def _base_to_provider_dict(current_dict, include_project_id=False):
del new_dict['flavor_id']
if 'topology' in new_dict:
del new_dict['topology']
if 'vrrp_group' in new_dict:
del new_dict['vrrp_group']
if 'amphorae' in new_dict:
del new_dict['amphorae']
if 'vip' in new_dict:
del new_dict['vip']
if 'listeners' in new_dict:
del new_dict['listeners']
if 'pools' in new_dict:
del new_dict['pools']
if 'server_group_id' in new_dict:
del new_dict['server_group_id']
return new_dict
@ -120,7 +134,10 @@ def lb_dict_to_provider_dict(lb_dict, vip=None,
new_lb_dict['vip_port_id'] = vip.port_id
new_lb_dict['vip_subnet_id'] = vip.subnet_id
new_lb_dict['vip_qos_policy_id'] = vip.qos_policy_id
if 'flavor_id' in lb_dict and lb_dict['flavor_id']:
flavor_repo = repositories.FlavorRepository()
new_lb_dict['flavor'] = flavor_repo.get_flavor_metadata_dict(
db_api.get_session(), lb_dict['flavor_id'])
if db_pools:
new_lb_dict['pools'] = db_pools_to_provider_pools(db_pools)
if db_listeners:
@ -189,8 +206,15 @@ def listener_dict_to_provider_dict(listener_dict):
new_listener_dict['default_tls_container_ref'] = new_listener_dict.pop(
'tls_certificate_id')
if 'sni_containers' in new_listener_dict:
new_listener_dict['sni_container_refs'] = new_listener_dict.pop(
'sni_containers')
sni_refs = []
sni_containers = new_listener_dict.pop('sni_containers')
for sni in sni_containers:
if 'tls_container_id' in sni:
sni_refs.append(sni['tls_container_id'])
else:
raise exceptions.ValidationException(
detail=_('Invalid SNI container on listener'))
new_listener_dict['sni_container_refs'] = sni_refs
if 'sni_container_refs' in listener_dict:
listener_dict['sni_containers'] = listener_dict.pop(
'sni_container_refs')
@ -206,6 +230,8 @@ def listener_dict_to_provider_dict(listener_dict):
SNI_objs = []
for sni in listener_obj.sni_containers:
if isinstance(sni, dict):
if 'listener' in sni:
del sni['listener']
sni_obj = data_models.SNI(**sni)
SNI_objs.append(sni_obj)
elif isinstance(sni, six.string_types):
@ -256,7 +282,7 @@ def listener_dict_to_provider_dict(listener_dict):
new_listener_dict['default_pool'] = pool_dict_to_provider_dict(pool)
provider_l7policies = []
if 'l7policies' in new_listener_dict:
l7policies = new_listener_dict.pop('l7policies')
l7policies = new_listener_dict.pop('l7policies') or []
for l7policy in l7policies:
provider_l7policy = l7policy_dict_to_provider_dict(l7policy)
provider_l7policies.append(provider_l7policy)
@ -346,9 +372,12 @@ def pool_dict_to_provider_dict(pool_dict):
if 'load_balancer_id' in new_pool_dict:
new_pool_dict['loadbalancer_id'] = new_pool_dict.pop(
'load_balancer_id')
if 'health_monitor' in new_pool_dict and new_pool_dict['health_monitor']:
if 'health_monitor' in new_pool_dict:
hm = new_pool_dict.pop('health_monitor')
new_pool_dict['healthmonitor'] = hm_dict_to_provider_dict(hm)
if hm:
new_pool_dict['healthmonitor'] = hm_dict_to_provider_dict(hm)
else:
new_pool_dict['healthmonitor'] = None
if 'members' in new_pool_dict and new_pool_dict['members']:
members = new_pool_dict.pop('members')
provider_members = []

View File

@ -13,11 +13,11 @@
# under the License.
import mock
from octavia_lib.api.drivers import data_models as driver_dm
from oslo_config import cfg
from oslo_config import fixture as oslo_fixture
from oslo_utils import uuidutils
from octavia.api.drivers import data_models as driver_dm
from octavia.api.drivers import utils as driver_utils
from octavia.common import constants
import octavia.common.context

View File

@ -13,10 +13,12 @@
# under the License.
import copy
import datetime
from octavia_lib.api.drivers import data_models as driver_dm
from octavia_lib.common import constants as lib_consts
from oslo_utils import uuidutils
from octavia.api.drivers import data_models as driver_dm
from octavia.common import constants
from octavia.common import data_models
@ -31,6 +33,10 @@ class SampleDriverDataModels(object):
self.network_id = uuidutils.generate_uuid()
self.subnet_id = uuidutils.generate_uuid()
self.qos_policy_id = uuidutils.generate_uuid()
self.lb_name = uuidutils.generate_uuid()
self.lb_description = uuidutils.generate_uuid()
self.flavor_id = uuidutils.generate_uuid()
self.flavor_profile_id = uuidutils.generate_uuid()
self.listener1_id = uuidutils.generate_uuid()
self.listener2_id = uuidutils.generate_uuid()
@ -60,11 +66,15 @@ class SampleDriverDataModels(object):
self.l7rule1_id = uuidutils.generate_uuid()
self.l7rule2_id = uuidutils.generate_uuid()
self.created_at = datetime.datetime.now()
self.updated_at = (datetime.datetime.now() +
datetime.timedelta(minutes=1))
self._common_test_dict = {'provisioning_status': constants.ACTIVE,
'operating_status': constants.ONLINE,
'project_id': self.project_id,
'created_at': 'then',
'updated_at': 'now',
'created_at': self.created_at,
'updated_at': self.updated_at,
'enabled': True}
# Setup Health Monitors
@ -119,9 +129,13 @@ class SampleDriverDataModels(object):
'protocol_port': 80, 'weight': 0,
'backup': False,
'subnet_id': self.subnet_id,
'pool': None,
'project_id': self.project_id,
'name': 'member1',
'operating_status': lib_consts.ONLINE,
'provisioning_status': lib_consts.ACTIVE,
'enabled': True,
'created_at': self.created_at,
'updated_at': self.updated_at,
'monitor_address': '192.0.2.26',
'monitor_port': 81}
@ -214,11 +228,11 @@ class SampleDriverDataModels(object):
'name': 'pool1', 'description': 'Pool 1',
'load_balancer_id': self.lb_id,
'project_id': self.project_id,
'protocol': 'avian',
'lb_algorithm': 'round_robin',
'protocol': 'TCP',
'lb_algorithm': 'ROUND_ROBIN',
'members': self.test_pool1_members_dict,
'health_monitor': self.test_hm1_dict,
'session_persistence': {'type': 'SOURCE'},
'session_persistence': {'type': 'SOURCE_IP'},
'listeners': [],
'l7policies': [],
'tls_certificate_id':
@ -258,14 +272,14 @@ class SampleDriverDataModels(object):
'admin_state_up': True,
'description': 'Pool 1',
'healthmonitor': self.provider_hm1_dict,
'lb_algorithm': 'round_robin',
'lb_algorithm': 'ROUND_ROBIN',
'loadbalancer_id': self.lb_id,
'members': self.provider_pool1_members_dict,
'name': 'pool1',
'pool_id': self.pool1_id,
'project_id': self.project_id,
'protocol': 'avian',
'session_persistence': {'type': 'SOURCE'},
'protocol': 'TCP',
'session_persistence': {'type': 'SOURCE_IP'},
'tls_container_ref': self.pool_sni_container_ref,
'tls_container_data': pool_cert.to_dict(),
'ca_tls_container_ref': self.pool_ca_container_ref,
@ -298,15 +312,16 @@ class SampleDriverDataModels(object):
self.provider_pools = [self.provider_pool1, self.provider_pool2]
# Setup L7Rules
self.test_l7rule1_dict = {'id': self.l7rule1_id,
'l7policy_id': self.l7policy1_id,
'type': 'o',
'compare_type': 'fake_type',
'key': 'fake_key',
'value': 'fake_value',
'project_id': self.project_id,
'l7policy': None,
'invert': False}
self.test_l7rule1_dict = {
'id': self.l7rule1_id,
'l7policy_id': self.l7policy1_id,
'type': lib_consts.L7RULE_TYPE_PATH,
'compare_type': lib_consts.L7RULE_COMPARE_TYPE_EQUAL_TO,
'key': 'fake_key',
'value': 'fake_value',
'project_id': self.project_id,
'l7policy': None,
'invert': False}
self.test_l7rule1_dict.update(self._common_test_dict)
@ -320,15 +335,16 @@ class SampleDriverDataModels(object):
self.db_l7Rules = [self.db_l7Rule1, self.db_l7Rule2]
self.provider_l7rule1_dict = {'admin_state_up': True,
'compare_type': 'fake_type',
'invert': False,
'key': 'fake_key',
'l7policy_id': self.l7policy1_id,
'l7rule_id': self.l7rule1_id,
'type': 'o',
'project_id': self.project_id,
'value': 'fake_value'}
self.provider_l7rule1_dict = {
'admin_state_up': True,
'compare_type': lib_consts.L7RULE_COMPARE_TYPE_EQUAL_TO,
'invert': False,
'key': 'fake_key',
'l7policy_id': self.l7policy1_id,
'l7rule_id': self.l7rule1_id,
'type': lib_consts.L7RULE_TYPE_PATH,
'project_id': self.project_id,
'value': 'fake_value'}
self.provider_l7rule2_dict = copy.deepcopy(self.provider_l7rule1_dict)
self.provider_l7rule2_dict['l7rule_id'] = self.l7rule2_id
@ -341,20 +357,21 @@ class SampleDriverDataModels(object):
self.provider_rules = [self.provider_l7rule1, self.provider_l7rule2]
# Setup L7Policies
self.test_l7policy1_dict = {'id': self.l7policy1_id,
'name': 'l7policy_1',
'description': 'L7policy 1',
'listener_id': self.listener1_id,
'action': 'go',
'redirect_pool_id': self.pool1_id,
'redirect_url': '/index.html',
'redirect_prefix': 'https://example.com/',
'project_id': self.project_id,
'position': 1,
'listener': None,
'redirect_pool': None,
'l7rules': self.test_l7rules,
'redirect_http_code': 302}
self.test_l7policy1_dict = {
'id': self.l7policy1_id,
'name': 'l7policy_1',
'description': 'L7policy 1',
'listener_id': self.listener1_id,
'action': lib_consts.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_pool_id': None,
'redirect_url': 'http://example.com/index.html',
'redirect_prefix': None,
'project_id': self.project_id,
'position': 1,
'listener': None,
'redirect_pool': None,
'l7rules': self.test_l7rules,
'redirect_http_code': 302}
self.test_l7policy1_dict.update(self._common_test_dict)
@ -374,7 +391,7 @@ class SampleDriverDataModels(object):
self.db_l7policies = [self.db_l7policy1, self.db_l7policy2]
self.provider_l7policy1_dict = {
'action': 'go',
'action': lib_consts.L7POLICY_ACTION_REDIRECT_TO_URL,
'admin_state_up': True,
'description': 'L7policy 1',
'l7policy_id': self.l7policy1_id,
@ -382,9 +399,9 @@ class SampleDriverDataModels(object):
'name': 'l7policy_1',
'position': 1,
'project_id': self.project_id,
'redirect_pool_id': self.pool1_id,
'redirect_url': '/index.html',
'redirect_prefix': 'https://example.com/',
'redirect_pool_id': None,
'redirect_url': 'http://example.com/index.html',
'redirect_prefix': None,
'rules': self.provider_l7rules_dicts,
'redirect_http_code': 302
}
@ -416,19 +433,16 @@ class SampleDriverDataModels(object):
'default_pool_id': self.pool1_id,
'load_balancer_id': self.lb_id,
'project_id': self.project_id,
'protocol': 'avian',
'protocol': 'TCP',
'protocol_port': 90,
'connection_limit': 10000,
'tls_certificate_id': self.default_tls_container_ref,
'stats': None,
'default_pool': self.test_pool1_dict,
'load_balancer': None,
'sni_containers': [self.sni_container_ref_1,
self.sni_container_ref_2],
'sni_containers': [{'tls_container_id': self.sni_container_ref_1},
{'tls_container_id': self.sni_container_ref_2}],
'peer_port': 55,
'l7policies': self.test_l7policies,
'insert_headers': {},
'pools': None,
'timeout_client_data': 1000,
'timeout_member_connect': 2000,
'timeout_member_data': 3000,
@ -485,7 +499,7 @@ class SampleDriverDataModels(object):
'loadbalancer_id': self.lb_id,
'name': 'listener_1',
'project_id': self.project_id,
'protocol': 'avian',
'protocol': 'TCP',
'protocol_port': 90,
'sni_container_data': [cert2.to_dict(), cert3.to_dict()],
'sni_container_refs': [self.sni_container_ref_1,
@ -546,3 +560,48 @@ class SampleDriverDataModels(object):
port_id=self.port_id,
subnet_id=self.subnet_id,
qos_policy_id=self.qos_policy_id)
self.test_loadbalancer1_dict = {
'name': self.lb_name, 'description': self.lb_description,
'enabled': True,
'provisioning_status': lib_consts.PENDING_UPDATE,
'operating_status': lib_consts.OFFLINE,
'topology': constants.TOPOLOGY_ACTIVE_STANDBY,
'vrrp_group': None,
'provider': 'amphora',
'server_group_id': uuidutils.generate_uuid(),
'project_id': self.project_id,
'id': self.lb_id, 'flavor_id': self.flavor_id,
'tags': ['test_tag']}
self.provider_loadbalancer_dict = {
'additional_vips': None,
'admin_state_up': True,
'description': self.lb_description,
'flavor': {"something": "else"},
'listeners': None,
'loadbalancer_id': self.lb_id,
'name': self.lb_name,
'pools': None,
'project_id': self.project_id,
'vip_address': self.ip_address,
'vip_network_id': self.network_id,
'vip_port_id': self.port_id,
'vip_qos_policy_id': self.qos_policy_id,
'vip_subnet_id': self.subnet_id}
self.provider_loadbalancer_tree_dict = {
'additional_vips': None,
'admin_state_up': True,
'description': self.lb_description,
'flavor': {"something": "else"},
'listeners': None,
'loadbalancer_id': self.lb_id,
'name': self.lb_name,
'pools': None,
'project_id': self.project_id,
'vip_address': self.ip_address,
'vip_network_id': self.network_id,
'vip_port_id': self.port_id,
'vip_qos_policy_id': self.qos_policy_id,
'vip_subnet_id': self.subnet_id}

View File

@ -16,9 +16,9 @@ import copy
import mock
from octavia_lib.api.drivers import data_models as driver_dm
from octavia_lib.api.drivers import exceptions as lib_exceptions
from octavia.api.drivers import data_models as driver_dm
from octavia.api.drivers import exceptions as driver_exceptions
from octavia.api.drivers import utils
from octavia.common import constants
@ -103,9 +103,13 @@ class TestUtils(base.TestCase):
self.assertEqual({'admin_state_up': True},
result_dict)
@mock.patch('octavia.db.repositories.FlavorRepository.'
'get_flavor_metadata_dict')
@mock.patch('octavia.db.api.get_session')
@mock.patch('octavia.api.drivers.utils._get_secret_data')
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
def test_lb_dict_to_provider_dict(self, mock_load_cert, mock_secret):
def test_lb_dict_to_provider_dict(self, mock_load_cert, mock_secret,
mock_get_session, mock_get_flavor):
cert1 = data_models.TLSContainer(certificate='cert 1')
cert2 = data_models.TLSContainer(certificate='cert 2')
cert3 = data_models.TLSContainer(certificate='cert 3')
@ -120,6 +124,7 @@ class TestUtils(base.TestCase):
mock_load_cert.side_effect = [pool_certs, listener_certs,
listener_certs, listener_certs,
listener_certs]
mock_get_flavor.return_value = {'shaved_ice': 'cherry'}
test_lb_dict = {'name': 'lb1',
'project_id': self.sample_data.project_id,
'vip_subnet_id': self.sample_data.subnet_id,
@ -133,7 +138,7 @@ class TestUtils(base.TestCase):
'description': '', 'admin_state_up': True,
'provisioning_status': constants.PENDING_CREATE,
'operating_status': constants.OFFLINE,
'flavor_id': '',
'flavor_id': 'flavor_id',
'provider': 'noop_driver'}
ref_prov_lb_dict = {
'vip_address': self.sample_data.ip_address,
@ -147,6 +152,7 @@ class TestUtils(base.TestCase):
'vip_qos_policy_id': self.sample_data.qos_policy_id,
'vip_network_id': self.sample_data.network_id,
'pools': self.sample_data.provider_pools,
'flavor': {'shaved_ice': 'cherry'},
'name': 'lb1'}
vip = data_models.Vip(ip_address=self.sample_data.ip_address,
network_id=self.sample_data.network_id,
@ -160,16 +166,22 @@ class TestUtils(base.TestCase):
self.assertEqual(ref_prov_lb_dict, provider_lb_dict)
def test_db_loadbalancer_to_provider_loadbalancer(self):
@mock.patch('octavia.db.repositories.FlavorRepository.'
'get_flavor_metadata_dict')
@mock.patch('octavia.db.api.get_session')
def test_db_loadbalancer_to_provider_loadbalancer(self, mock_get_session,
mock_get_flavor):
mock_get_flavor.return_value = {'shaved_ice': 'cherry'}
vip = data_models.Vip(ip_address=self.sample_data.ip_address,
network_id=self.sample_data.network_id,
port_id=self.sample_data.port_id,
subnet_id=self.sample_data.subnet_id)
test_db_lb = data_models.LoadBalancer(id=1, vip=vip)
test_db_lb = data_models.LoadBalancer(id=1, flavor_id='2', vip=vip)
provider_lb = utils.db_loadbalancer_to_provider_loadbalancer(
test_db_lb)
ref_provider_lb = driver_dm.LoadBalancer(
loadbalancer_id=1,
flavor={'shaved_ice': 'cherry'},
vip_address=self.sample_data.ip_address,
vip_network_id=self.sample_data.network_id,
vip_port_id=self.sample_data.port_id,
@ -240,7 +252,7 @@ class TestUtils(base.TestCase):
'sni_certs': [cert2, cert3]}
# Test with bad SNI content
test_listener = copy.deepcopy(self.sample_data.test_listener1_dict)
test_listener['sni_containers'] = [[]]
test_listener['sni_containers'] = [{}]
self.assertRaises(exceptions.ValidationException,
utils.listener_dict_to_provider_dict,
test_listener)

View File

@ -0,0 +1,6 @@
---
fixes:
- |
Fixes the provider driver utils conversion of flavor_id in load balancer
conversion, sni_refs and L7 policies in listener conversion, and health
monitor in pool conversions.