Allows vip from a different subnet for lbaas resource
This fix allows user to specify a different subnet while adding a vip to a pool resource. If vip subnet is not provided, pool subnet is used by default. Change-Id: I0b7740ca37961ae412866cc15ab439dafbfcf9d9 Closes-Bug: #1286001
This commit is contained in:
parent
b1d5a40b54
commit
c2ec3291ad
|
@ -25,6 +25,7 @@ from heat.engine.resources.neutron import neutron
|
|||
|
||||
if clients.neutronclient is not None:
|
||||
from neutronclient.common.exceptions import NeutronClientException
|
||||
from neutronclient.neutron import v2_0 as neutronV20
|
||||
|
||||
|
||||
class HealthMonitor(neutron.NeutronResource):
|
||||
|
@ -158,11 +159,13 @@ class Pool(neutron.NeutronResource):
|
|||
)
|
||||
|
||||
_VIP_KEYS = (
|
||||
VIP_NAME, VIP_DESCRIPTION, VIP_ADDRESS, VIP_CONNECTION_LIMIT,
|
||||
VIP_PROTOCOL_PORT, VIP_SESSION_PERSISTENCE, VIP_ADMIN_STATE_UP,
|
||||
VIP_NAME, VIP_DESCRIPTION, VIP_SUBNET, VIP_ADDRESS,
|
||||
VIP_CONNECTION_LIMIT, VIP_PROTOCOL_PORT,
|
||||
VIP_SESSION_PERSISTENCE, VIP_ADMIN_STATE_UP,
|
||||
) = (
|
||||
'name', 'description', 'address', 'connection_limit',
|
||||
'protocol_port', 'session_persistence', 'admin_state_up',
|
||||
'name', 'description', 'subnet', 'address',
|
||||
'connection_limit', 'protocol_port',
|
||||
'session_persistence', 'admin_state_up',
|
||||
)
|
||||
|
||||
_VIP_SESSION_PERSISTENCE_KEYS = (
|
||||
|
@ -182,7 +185,8 @@ class Pool(neutron.NeutronResource):
|
|||
),
|
||||
SUBNET_ID: properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
_('The subnet on which the members of the pool will be located.'),
|
||||
_('The subnet for the port on which the members '
|
||||
'of the pool will be connected.'),
|
||||
required=True
|
||||
),
|
||||
LB_METHOD: properties.Schema(
|
||||
|
@ -223,6 +227,10 @@ class Pool(neutron.NeutronResource):
|
|||
properties.Schema.STRING,
|
||||
_('Description of the vip.')
|
||||
),
|
||||
VIP_SUBNET: properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
_('Subnet of the vip.')
|
||||
),
|
||||
VIP_ADDRESS: properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
_('IP address of the vip.')
|
||||
|
@ -279,8 +287,8 @@ class Pool(neutron.NeutronResource):
|
|||
'admin_state_up': _('The administrative state of this pool.'),
|
||||
'name': _('Name of the pool.'),
|
||||
'protocol': _('Protocol to balance.'),
|
||||
'subnet_id': _('The subnet on which the members of the pool '
|
||||
'will be located.'),
|
||||
'subnet_id': _('The subnet for the port on which the members '
|
||||
'of the pool will be connected.'),
|
||||
'lb_method': _('The algorithm used to distribute load between the '
|
||||
'members of the pool.'),
|
||||
'description': _('Description of the pool.'),
|
||||
|
@ -331,7 +339,16 @@ class Pool(neutron.NeutronResource):
|
|||
vip_arguments['session_persistence'] = prepared_props
|
||||
|
||||
vip_arguments['protocol'] = self.properties[self.PROTOCOL]
|
||||
vip_arguments['subnet_id'] = self.properties[self.SUBNET_ID]
|
||||
|
||||
if vip_arguments.get(self.VIP_SUBNET) is None:
|
||||
vip_arguments['subnet_id'] = self.properties[self.SUBNET_ID]
|
||||
else:
|
||||
vip_arguments[
|
||||
'subnet_id'] = neutronV20.find_resourceid_by_name_or_id(
|
||||
self.neutron(),
|
||||
'subnet',
|
||||
vip_arguments.pop(self.VIP_SUBNET))
|
||||
|
||||
vip_arguments['pool_id'] = pool['id']
|
||||
vip = client.create_vip({'vip': vip_arguments})['vip']
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# under the License.
|
||||
|
||||
import copy
|
||||
import mox
|
||||
|
||||
from testtools import skipIf
|
||||
|
||||
|
@ -48,6 +49,27 @@ health_monitor_template = '''
|
|||
}
|
||||
'''
|
||||
|
||||
pool_template_with_vip_subnet = '''
|
||||
{
|
||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
||||
"Description" : "Template to test load balancer resources",
|
||||
"Parameters" : {},
|
||||
"Resources" : {
|
||||
"pool": {
|
||||
"Type": "OS::Neutron::Pool",
|
||||
"Properties": {
|
||||
"protocol": "HTTP",
|
||||
"subnet_id": "sub123",
|
||||
"lb_method": "ROUND_ROBIN",
|
||||
"vip": {
|
||||
"protocol_port": 80,
|
||||
"subnet": "sub9999"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'''
|
||||
pool_template = '''
|
||||
{
|
||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
||||
|
@ -274,12 +296,14 @@ class PoolTest(HeatTestCase):
|
|||
self.m.StubOutWithMock(neutronclient.Client,
|
||||
'disassociate_health_monitor')
|
||||
self.m.StubOutWithMock(neutronclient.Client, 'create_vip')
|
||||
self.m.StubOutWithMock(loadbalancer.neutronV20,
|
||||
'find_resourceid_by_name_or_id')
|
||||
self.m.StubOutWithMock(neutronclient.Client, 'delete_vip')
|
||||
self.m.StubOutWithMock(neutronclient.Client, 'show_vip')
|
||||
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
|
||||
utils.setup_dummy_db()
|
||||
|
||||
def create_pool(self):
|
||||
def create_pool(self, with_vip_subnet=False):
|
||||
clients.OpenStackClients.keystone().AndReturn(
|
||||
fakes.FakeKeystoneClient())
|
||||
neutronclient.Client.create_pool({
|
||||
|
@ -288,18 +312,31 @@ class PoolTest(HeatTestCase):
|
|||
'name': utils.PhysName('test_stack', 'pool'),
|
||||
'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}}
|
||||
).AndReturn({'pool': {'id': '5678'}})
|
||||
neutronclient.Client.create_vip({
|
||||
|
||||
stvipvsn = {
|
||||
'vip': {
|
||||
'protocol': u'HTTP', 'name': 'pool.vip',
|
||||
'admin_state_up': True, 'subnet_id': u'sub123',
|
||||
'pool_id': '5678', 'protocol_port': 80}}
|
||||
).AndReturn({'vip': {'id': 'xyz'}})
|
||||
'admin_state_up': True, 'subnet_id': u'sub9999',
|
||||
'pool_id': '5678', 'protocol_port': 80}
|
||||
}
|
||||
|
||||
stvippsn = copy.deepcopy(stvipvsn)
|
||||
stvippsn['vip']['subnet_id'] = 'sub123'
|
||||
|
||||
if with_vip_subnet:
|
||||
neutronclient.Client.create_vip(stvipvsn
|
||||
).AndReturn({'vip': {'id': 'xyz'}})
|
||||
snippet = template_format.parse(pool_template_with_vip_subnet)
|
||||
else:
|
||||
neutronclient.Client.create_vip(stvippsn
|
||||
).AndReturn({'vip': {'id': 'xyz'}})
|
||||
snippet = template_format.parse(pool_template)
|
||||
|
||||
neutronclient.Client.show_pool('5678').AndReturn(
|
||||
{'pool': {'status': 'ACTIVE'}})
|
||||
neutronclient.Client.show_vip('xyz').AndReturn(
|
||||
{'vip': {'status': 'ACTIVE'}})
|
||||
|
||||
snippet = template_format.parse(pool_template)
|
||||
stack = utils.parse_stack(snippet)
|
||||
return loadbalancer.Pool(
|
||||
'pool', snippet['Resources']['pool'], stack)
|
||||
|
@ -311,6 +348,19 @@ class PoolTest(HeatTestCase):
|
|||
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_create_with_vip_subnet(self):
|
||||
loadbalancer.neutronV20.find_resourceid_by_name_or_id(
|
||||
mox.IsA(neutronclient.Client),
|
||||
'subnet',
|
||||
'sub9999'
|
||||
).AndReturn('sub9999')
|
||||
|
||||
rsrc = self.create_pool(with_vip_subnet=True)
|
||||
self.m.ReplayAll()
|
||||
scheduler.TaskRunner(rsrc.create)()
|
||||
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_create_pending(self):
|
||||
clients.OpenStackClients.keystone().AndReturn(
|
||||
fakes.FakeKeystoneClient())
|
||||
|
@ -472,7 +522,7 @@ class PoolTest(HeatTestCase):
|
|||
pool = snippet['Resources']['pool']
|
||||
persistence = pool['Properties']['vip']['session_persistence']
|
||||
|
||||
#When persistence type is set to APP_COOKIE, cookie_name is required
|
||||
# When persistence type is set to APP_COOKIE, cookie_name is required
|
||||
persistence['type'] = 'APP_COOKIE'
|
||||
persistence['cookie_name'] = None
|
||||
|
||||
|
@ -515,12 +565,12 @@ class PoolTest(HeatTestCase):
|
|||
pool = snippet['Resources']['pool']
|
||||
persistence = pool['Properties']['vip']['session_persistence']
|
||||
|
||||
#change persistence type to HTTP_COOKIE that not require cookie_name
|
||||
# change persistence type to HTTP_COOKIE that not require cookie_name
|
||||
persistence['type'] = 'HTTP_COOKIE'
|
||||
del persistence['cookie_name']
|
||||
resource = loadbalancer.Pool('pool', pool, utils.parse_stack(snippet))
|
||||
|
||||
#assert that properties contain cookie_name property with None value
|
||||
# assert that properties contain cookie_name property with None value
|
||||
persistence = resource.properties['vip']['session_persistence']
|
||||
self.assertIn('cookie_name', persistence)
|
||||
self.assertIsNone(persistence['cookie_name'])
|
||||
|
|
Loading…
Reference in New Issue