Spec validation for LB policy

This patch adds spec validation for the LB policy. The properties need
to be validated are the subnets used for LB pool and LB VIP.

Change-Id: I28ddf4e7b0f474af3a8d97c29261b703f6c9ef8b
This commit is contained in:
tengqm 2016-08-30 22:53:40 -04:00
parent e14a174293
commit 91c21f05f7
2 changed files with 85 additions and 16 deletions

View File

@ -23,6 +23,7 @@ from oslo_log import log as logging
from senlin.common import constraints
from senlin.common import consts
from senlin.common import exception as exc
from senlin.common.i18n import _
from senlin.common.i18n import _LW
from senlin.common import scaleutils
@ -278,10 +279,29 @@ class LoadBalancingPolicy(base.Policy):
def validate(self, context, validate_props=False):
super(LoadBalancingPolicy, self).validate(context, validate_props)
# TODO(elynn): Check if subnet exists
if validate_props:
pass
# subnet = self.nc.subnet_get(vip[self.VIP_SUBNET])
if not validate_props:
return True
params = self._build_conn_params(context.user, context.project)
nc = driver_base.SenlinDriver().network(params)
# validate pool subnet
name_or_id = self.pool_spec.get(self.POOL_SUBNET)
try:
nc.subnet_get(name_or_id)
except exc.InternalError:
msg = _("The specified %(key)s '%(value)s' could not be found."
) % {'key': self.POOL_SUBNET, 'value': name_or_id}
raise exc.InvalidSpec(message=msg)
# validate VIP subnet
name_or_id = self.vip_spec.get(self.VIP_SUBNET)
try:
nc.subnet_get(name_or_id)
except exc.InternalError:
msg = _("The specified %(key)s '%(value)s' could not be found."
) % {'key': self.VIP_SUBNET, 'value': name_or_id}
raise exc.InvalidSpec(message=msg)
def attach(self, cluster):
"""Routine to be invoked when policy is to be attached to a cluster.

View File

@ -12,8 +12,10 @@
import mock
from oslo_context import context as oslo_context
import six
from senlin.common import consts
from senlin.common import exception as exc
from senlin.common import scaleutils
from senlin.drivers import base as driver_base
from senlin.engine import cluster_policy
@ -38,7 +40,7 @@ class TestLoadBalancingPolicy(base.SenlinTestCase):
'pool': {
'protocol': 'HTTP',
'protocol_port': 80,
'subnet': 'test-subnet',
'subnet': 'internal-subnet',
'lb_method': 'ROUND_ROBIN',
'admin_state_up': True,
'session_persistence': {
@ -48,7 +50,7 @@ class TestLoadBalancingPolicy(base.SenlinTestCase):
},
'vip': {
'address': '192.168.1.100',
'subnet': 'test-subnet',
'subnet': 'external-subnet',
'connection_limit': 500,
'protocol': 'HTTP',
'protocol_port': 80,
@ -67,10 +69,12 @@ class TestLoadBalancingPolicy(base.SenlinTestCase):
'lb_status_timeout': 600
}
}
sd = mock.Mock()
self.patchobject(driver_base, 'SenlinDriver', return_value=sd)
self.sd = mock.Mock()
self.patchobject(driver_base, 'SenlinDriver', return_value=self.sd)
self.lb_driver = mock.Mock()
sd.loadbalancing.return_value = self.lb_driver
self.net_driver = mock.Mock()
self.sd.loadbalancing.return_value = self.lb_driver
self.sd.network.return_value = self.net_driver
@mock.patch.object(lb_policy.LoadBalancingPolicy, 'validate')
def test_init(self, mock_validate):
@ -88,8 +92,8 @@ class TestLoadBalancingPolicy(base.SenlinTestCase):
'type': 'senlin.policy.loadbalance',
'version': '1.0',
'properties': {
'pool': {'subnet': 'test-subnet'},
'vip': {'subnet': 'test-subnet'}
'pool': {'subnet': 'internal-subnet'},
'vip': {'subnet': 'external-subnet'}
}
}
default_spec = {
@ -99,14 +103,14 @@ class TestLoadBalancingPolicy(base.SenlinTestCase):
'pool': {
'protocol': 'HTTP',
'protocol_port': 80,
'subnet': 'test-subnet',
'subnet': 'internal-subnet',
'lb_method': 'ROUND_ROBIN',
'admin_state_up': True,
'session_persistence': {},
},
'vip': {
'address': None,
'subnet': 'test-subnet',
'subnet': 'external-subnet',
'connection_limit': -1,
'protocol': 'HTTP',
'protocol_port': 80,
@ -132,9 +136,54 @@ class TestLoadBalancingPolicy(base.SenlinTestCase):
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
ctx = mock.Mock()
policy.validate(ctx, True)
res = policy.validate(ctx, False)
self.assertTrue(res)
mock_validate.assert_called_with(ctx, False)
@mock.patch.object(policy_base.Policy, '_build_conn_params')
@mock.patch.object(policy_base.Policy, 'validate')
def test_validate_pool_subnet_notfound(self, mock_validate, mock_params):
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
ctx = mock.Mock(user='user1', project='project1')
x_params = mock.Mock()
mock_params.return_value = x_params
self.net_driver.subnet_get = mock.Mock(
side_effect=exc.InternalError(code='404', message='not found'))
ex = self.assertRaises(exc.InvalidSpec, policy.validate, ctx, True)
mock_validate.assert_called_with(ctx, True)
mock_params.assert_called_once_with('user1', 'project1')
self.sd.network.assert_called_once_with(x_params)
self.net_driver.subnet_get.assert_called_once_with('internal-subnet')
self.assertEqual("The specified subnet 'internal-subnet' could not "
"be found.", six.text_type(ex))
@mock.patch.object(policy_base.Policy, '_build_conn_params')
@mock.patch.object(policy_base.Policy, 'validate')
def test_validate_vip_subnet_notfound(self, mock_validate, mock_params):
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
ctx = mock.Mock(user='user1', project='project1')
x_params = mock.Mock()
mock_params.return_value = x_params
self.net_driver.subnet_get = mock.Mock(
side_effect=[
mock.Mock(), # for the internal (pool) one
exc.InternalError(code='404', message='not found')
]
)
ex = self.assertRaises(exc.InvalidSpec, policy.validate, ctx, True)
mock_validate.assert_called_with(ctx, True)
mock_params.assert_called_once_with('user1', 'project1')
self.sd.network.assert_called_once_with(x_params)
self.net_driver.subnet_get.assert_has_calls([
mock.call('internal-subnet'), mock.call('external-subnet')
])
self.assertEqual("The specified subnet 'external-subnet' could not "
"be found.", six.text_type(ex))
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_build_policy_data')
@mock.patch.object(node_mod.Node, 'load_all')
@ -168,8 +217,8 @@ class TestLoadBalancingPolicy(base.SenlinTestCase):
policy.hm_spec)
m_load.assert_called_once_with(mock.ANY, cluster_id=cluster.id)
member_add_calls = [
mock.call(node1, 'LB_ID', 'POOL_ID', 80, 'test-subnet'),
mock.call(node2, 'LB_ID', 'POOL_ID', 80, 'test-subnet')
mock.call(node1, 'LB_ID', 'POOL_ID', 80, 'internal-subnet'),
mock.call(node2, 'LB_ID', 'POOL_ID', 80, 'internal-subnet')
]
self.lb_driver.member_add.assert_has_calls(member_add_calls)
node1.data.update.assert_called_once_with({'lb_member': 'MEMBER1_ID'})