Support RackConnect V3 LB in Rackspace AutoScaleGroup Resource

Currently, only Rackspace CloudLoadBalancers are supported by
the ASG resource.

Also update the requirements to use fork of pyrax that is
maintained by the Rackspace heat team.

Closes-Bug: #1525391
Change-Id: Iabb52b2a34f1c2a434e724b9a70e4b948e4d0d37
This commit is contained in:
Pratik Mallya 2015-12-11 14:37:14 -06:00
parent d069bd6245
commit 58624d4f1c
3 changed files with 120 additions and 5 deletions

View File

@ -15,6 +15,7 @@
import copy
from heat.common import exception
from heat.common.i18n import _
from heat.engine import attributes
from heat.engine import constraints
@ -130,8 +131,7 @@ class Group(resource.Resource):
),
LAUNCH_CONFIG_ARGS_LOAD_BALANCER_PORT: properties.Schema(
properties.Schema.INTEGER,
_('Server port to connect the load balancer to.'),
required=True
_('Server port to connect the load balancer to.')
),
},
)
@ -294,6 +294,11 @@ class Group(resource.Resource):
lbs = copy.deepcopy(lb_args)
if lbs:
for lb in lbs:
# if the port is not specified, the lbid must be that of a
# RackConnectV3 lb pool.
if not lb[self.LAUNCH_CONFIG_ARGS_LOAD_BALANCER_PORT]:
del lb[self.LAUNCH_CONFIG_ARGS_LOAD_BALANCER_PORT]
continue
lbid = int(lb[self.LAUNCH_CONFIG_ARGS_LOAD_BALANCER_ID])
lb[self.LAUNCH_CONFIG_ARGS_LOAD_BALANCER_ID] = lbid
personality = server_args.get(
@ -391,6 +396,28 @@ class Group(resource.Resource):
else:
return True
def _check_rackconnect_v3_pool_exists(self, pool_id):
pools = self.client("rackconnect").list_load_balancer_pools()
if pool_id in (p.id for p in pools):
return True
return False
def validate(self):
super(Group, self).validate()
launchconf = self.properties[self.LAUNCH_CONFIGURATION]
lcargs = launchconf[self.LAUNCH_CONFIG_ARGS]
lb_args = lcargs.get(self.LAUNCH_CONFIG_ARGS_LOAD_BALANCERS)
lbs = copy.deepcopy(lb_args)
for lb in lbs:
lb_port = lb.get(self.LAUNCH_CONFIG_ARGS_LOAD_BALANCER_PORT)
lb_id = lb[self.LAUNCH_CONFIG_ARGS_LOAD_BALANCER_ID]
if not lb_port:
# check if lb id is a valid RCV3 pool id
if not self._check_rackconnect_v3_pool_exists(lb_id):
msg = _('Could not find RackConnectV3 pool '
'with id %s') % (lb_id)
raise exception.StackValidationFailed(msg)
def auto_scale(self):
return self.client('auto_scale')

View File

@ -15,6 +15,7 @@ import copy
import itertools
import mock
import six
from heat.common import exception
from heat.common import template_format
@ -200,6 +201,10 @@ class ScalingGroupTest(common.HeatTestCase):
networks:
- uuid: "00000000-0000-0000-0000-000000000000"
- uuid: "11111111-1111-1111-1111-111111111111"
loadBalancers:
- loadBalancerId: 234
port: 80
''')
def setUp(self):
@ -237,9 +242,12 @@ class ScalingGroupTest(common.HeatTestCase):
'disk_config': None,
'flavor': 'flavor-ref',
'image': 'image-ref',
'launch_config_type': 'launch_server',
'load_balancers': None,
'load_balancers': [{
'loadBalancerId': 234,
'port': 80,
}],
'key_name': "my-key",
'launch_config_type': u'launch_server',
'max_entities': 25,
'group_metadata': {'group': 'metadata'},
'metadata': {'server': 'metadata'},
@ -668,3 +676,83 @@ class WebHookTest(common.HeatTestCase):
del self.fake_auto_scale.webhooks['0']
scheduler.TaskRunner(resource.delete)()
self.assertEqual({}, self.fake_auto_scale.webhooks)
@mock.patch.object(resource.Resource, "client_plugin")
@mock.patch.object(resource.Resource, "client")
class AutoScaleGroupValidationTests(common.HeatTestCase):
def setUp(self):
super(AutoScaleGroupValidationTests, self).setUp()
self.mockstack = mock.Mock()
self.mockstack.has_cache_data.return_value = False
self.mockstack.db_resource_get.return_value = None
def test_validate_no_rcv3_pool(self, mock_client, mock_plugin):
asg_properties = {
"groupConfiguration": {
"name": "My Group",
"cooldown": 60,
"minEntities": 1,
"maxEntities": 25,
"metadata": {
"group": "metadata",
},
},
"launchConfiguration": {
"type": "launch_server",
"args": {
"loadBalancers": [{
"loadBalancerId": 'not integer!',
}],
"server": {
"name": "sdfsdf",
"flavorRef": "ffdgdf",
"imageRef": "image-ref",
},
},
},
}
rsrcdef = rsrc_defn.ResourceDefinition(
"test", auto_scale.Group, properties=asg_properties)
asg = auto_scale.Group("test", rsrcdef, self.mockstack)
mock_client().list_load_balancer_pools.return_value = []
error = self.assertRaises(
exception.StackValidationFailed, asg.validate)
self.assertEqual(
'Could not find RackConnectV3 pool with id not integer!: ',
six.text_type(error))
def test_validate_rcv3_pool_found(self, mock_client, mock_plugin):
asg_properties = {
"groupConfiguration": {
"name": "My Group",
"cooldown": 60,
"minEntities": 1,
"maxEntities": 25,
"metadata": {
"group": "metadata",
},
},
"launchConfiguration": {
"type": "launch_server",
"args": {
"loadBalancers": [{
"loadBalancerId": 'pool_exists',
}],
"server": {
"name": "sdfsdf",
"flavorRef": "ffdgdf",
"imageRef": "image-ref",
},
},
},
}
rsrcdef = rsrc_defn.ResourceDefinition(
"test", auto_scale.Group, properties=asg_properties)
asg = auto_scale.Group("test", rsrcdef, self.mockstack)
mock_client().list_load_balancer_pools.return_value = [
mock.Mock(id='pool_exists'),
]
self.assertIsNone(asg.validate())

View File

@ -1 +1 @@
pyrax>=1.9.2
-e git+https://github.com/rackerlabs/heat-pyrax.git#egg=pyrax