Add support for launch_stack launchConfiguration type

Rackspace AutoScale Groups now support a "launch_stack"
launchConfiguration type.  This adds support to the
Rackspace::AutoScale::Group resource.

Change-Id: I20d2d9d4f317d726ccbb21275984f096ba300767
This commit is contained in:
Jason Dunsmore 2016-01-29 11:43:19 -06:00
parent 681df8eb00
commit 268e6a10d6
2 changed files with 567 additions and 15 deletions

View File

@ -14,6 +14,7 @@
"""Resources for Rackspace Auto Scale.""" """Resources for Rackspace Auto Scale."""
import copy import copy
import six
from heat.common import exception from heat.common import exception
from heat.common.i18n import _ from heat.common.i18n import _
@ -22,6 +23,7 @@ from heat.engine import constraints
from heat.engine import properties from heat.engine import properties
from heat.engine import resource from heat.engine import resource
from heat.engine import support from heat.engine import support
from heat.engine import template as templatem
try: try:
from pyrax.exceptions import Forbidden from pyrax.exceptions import Forbidden
@ -74,9 +76,11 @@ class Group(resource.Resource):
_LAUNCH_CONFIG_ARGS_KEYS = ( _LAUNCH_CONFIG_ARGS_KEYS = (
LAUNCH_CONFIG_ARGS_LOAD_BALANCERS, LAUNCH_CONFIG_ARGS_LOAD_BALANCERS,
LAUNCH_CONFIG_ARGS_SERVER, LAUNCH_CONFIG_ARGS_SERVER,
LAUNCH_CONFIG_ARGS_STACK,
) = ( ) = (
'loadBalancers', 'loadBalancers',
'server', 'server',
'stack',
) )
_LAUNCH_CONFIG_ARGS_LOAD_BALANCER_KEYS = ( _LAUNCH_CONFIG_ARGS_LOAD_BALANCER_KEYS = (
@ -115,6 +119,24 @@ class Group(resource.Resource):
'uuid', 'uuid',
) )
_LAUNCH_CONFIG_ARGS_STACK_KEYS = (
LAUNCH_CONFIG_ARGS_STACK_TEMPLATE,
LAUNCH_CONFIG_ARGS_STACK_TEMPLATE_URL,
LAUNCH_CONFIG_ARGS_STACK_DISABLE_ROLLBACK,
LAUNCH_CONFIG_ARGS_STACK_ENVIRONMENT,
LAUNCH_CONFIG_ARGS_STACK_FILES,
LAUNCH_CONFIG_ARGS_STACK_PARAMETERS,
LAUNCH_CONFIG_ARGS_STACK_TIMEOUT_MINS
) = (
'template',
'template_url',
'disable_rollback',
'environment',
'files',
'parameters',
'timeout_mins'
)
_launch_configuration_args_schema = { _launch_configuration_args_schema = {
LAUNCH_CONFIG_ARGS_LOAD_BALANCERS: properties.Schema( LAUNCH_CONFIG_ARGS_LOAD_BALANCERS: properties.Schema(
properties.Schema.LIST, properties.Schema.LIST,
@ -141,6 +163,7 @@ class Group(resource.Resource):
properties.Schema.MAP, properties.Schema.MAP,
_('Server creation arguments, as accepted by the Cloud Servers ' _('Server creation arguments, as accepted by the Cloud Servers '
'server creation API.'), 'server creation API.'),
required=False,
schema={ schema={
LAUNCH_CONFIG_ARGS_SERVER_NAME: properties.Schema( LAUNCH_CONFIG_ARGS_SERVER_NAME: properties.Schema(
properties.Schema.STRING, properties.Schema.STRING,
@ -211,8 +234,49 @@ class Group(resource.Resource):
'key-based authentication to the server.') 'key-based authentication to the server.')
), ),
}, },
required=True
), ),
LAUNCH_CONFIG_ARGS_STACK: properties.Schema(
properties.Schema.MAP,
_('The attributes that Auto Scale uses to create a new stack. The '
'attributes that you specify for the stack entity apply to all '
'new stacks in the scaling group. Note the stack arguments are '
'directly passed to Heat when creating a stack.'),
schema={
LAUNCH_CONFIG_ARGS_STACK_TEMPLATE: properties.Schema(
properties.Schema.MAP,
_('The template that describes the stack. Either the '
'template or template_url property must be specified.'),
),
LAUNCH_CONFIG_ARGS_STACK_TEMPLATE_URL: properties.Schema(
properties.Schema.STRING,
_('A URI to a template. Either the template or '
'template_url property must be specified.')
),
LAUNCH_CONFIG_ARGS_STACK_DISABLE_ROLLBACK: properties.Schema(
properties.Schema.BOOLEAN,
_('Keep the resources that have been created if the stack '
'fails to create. Defaults to True.'),
default=True
),
LAUNCH_CONFIG_ARGS_STACK_ENVIRONMENT: properties.Schema(
properties.Schema.MAP,
_('The environment for the stack.'),
),
LAUNCH_CONFIG_ARGS_STACK_FILES: properties.Schema(
properties.Schema.MAP,
_('The contents of files that the template references.')
),
LAUNCH_CONFIG_ARGS_STACK_PARAMETERS: properties.Schema(
properties.Schema.MAP,
_('Key/value pairs of the parameters and their values to '
'pass to the parameters in the template.')
),
LAUNCH_CONFIG_ARGS_STACK_TIMEOUT_MINS: properties.Schema(
properties.Schema.INTEGER,
_('The stack creation timeout in minutes.')
)
}
)
} }
properties_schema = { properties_schema = {
@ -256,17 +320,18 @@ class Group(resource.Resource):
schema={ schema={
LAUNCH_CONFIG_ARGS: properties.Schema( LAUNCH_CONFIG_ARGS: properties.Schema(
properties.Schema.MAP, properties.Schema.MAP,
_('Type-specific server launching arguments.'), _('Type-specific launch arguments.'),
schema=_launch_configuration_args_schema, schema=_launch_configuration_args_schema,
required=True required=True
), ),
LAUNCH_CONFIG_TYPE: properties.Schema( LAUNCH_CONFIG_TYPE: properties.Schema(
properties.Schema.STRING, properties.Schema.STRING,
_('Launch configuration method. Only launch_server ' _('Launch configuration method. Only launch_server and '
'is currently supported.'), 'launch_stack are currently supported.'),
required=True, required=True,
constraints=[ constraints=[
constraints.AllowedValues(['launch_server']), constraints.AllowedValues(['launch_server',
'launch_stack']),
] ]
), ),
}, },
@ -287,8 +352,7 @@ class Group(resource.Resource):
max_entities=groupconf[self.GROUP_CONFIGURATION_MAX_ENTITIES], max_entities=groupconf[self.GROUP_CONFIGURATION_MAX_ENTITIES],
metadata=groupconf.get(self.GROUP_CONFIGURATION_METADATA, None)) metadata=groupconf.get(self.GROUP_CONFIGURATION_METADATA, None))
def _get_launch_config_args(self, launchconf): def _get_launch_config_server_args(self, launchconf):
"""Get the launchConfiguration-related pyrax arguments."""
lcargs = launchconf[self.LAUNCH_CONFIG_ARGS] lcargs = launchconf[self.LAUNCH_CONFIG_ARGS]
server_args = lcargs[self.LAUNCH_CONFIG_ARGS_SERVER] server_args = lcargs[self.LAUNCH_CONFIG_ARGS_SERVER]
lb_args = lcargs.get(self.LAUNCH_CONFIG_ARGS_LOAD_BALANCERS) lb_args = lcargs.get(self.LAUNCH_CONFIG_ARGS_LOAD_BALANCERS)
@ -330,6 +394,30 @@ class Group(resource.Resource):
key_name=server_args.get(self.LAUNCH_CONFIG_ARGS_SERVER_KEY_NAME), key_name=server_args.get(self.LAUNCH_CONFIG_ARGS_SERVER_KEY_NAME),
) )
def _get_launch_config_stack_args(self, launchconf):
lcargs = launchconf[self.LAUNCH_CONFIG_ARGS]
stack_args = lcargs[self.LAUNCH_CONFIG_ARGS_STACK]
return dict(
launch_config_type=launchconf[self.LAUNCH_CONFIG_TYPE],
template=stack_args[self.LAUNCH_CONFIG_ARGS_STACK_TEMPLATE],
template_url=stack_args[
self.LAUNCH_CONFIG_ARGS_STACK_TEMPLATE_URL],
disable_rollback=stack_args[
self.LAUNCH_CONFIG_ARGS_STACK_DISABLE_ROLLBACK],
environment=stack_args[self.LAUNCH_CONFIG_ARGS_STACK_ENVIRONMENT],
files=stack_args[self.LAUNCH_CONFIG_ARGS_STACK_FILES],
parameters=stack_args[self.LAUNCH_CONFIG_ARGS_STACK_PARAMETERS],
timeout_mins=stack_args[self.LAUNCH_CONFIG_ARGS_STACK_TIMEOUT_MINS]
)
def _get_launch_config_args(self, launchconf):
"""Get the launchConfiguration-related pyrax arguments."""
if launchconf[self.LAUNCH_CONFIG_ARGS].get(
self.LAUNCH_CONFIG_ARGS_SERVER):
return self._get_launch_config_server_args(launchconf)
else:
return self._get_launch_config_stack_args(launchconf)
def _get_create_args(self): def _get_create_args(self):
"""Get pyrax-style arguments for creating a scaling group.""" """Get pyrax-style arguments for creating a scaling group."""
args = self._get_group_config_args( args = self._get_group_config_args(
@ -406,6 +494,19 @@ class Group(resource.Resource):
super(Group, self).validate() super(Group, self).validate()
launchconf = self.properties[self.LAUNCH_CONFIGURATION] launchconf = self.properties[self.LAUNCH_CONFIGURATION]
lcargs = launchconf[self.LAUNCH_CONFIG_ARGS] lcargs = launchconf[self.LAUNCH_CONFIG_ARGS]
server_args = lcargs.get(self.LAUNCH_CONFIG_ARGS_SERVER)
st_args = lcargs.get(self.LAUNCH_CONFIG_ARGS_STACK)
# launch_server and launch_stack are required and mutually exclusive.
if ((not server_args and not st_args) or
(server_args and st_args)):
msg = (_('Must provide one of %(server)s or %(stack)s in %(conf)s')
% {'server': self.LAUNCH_CONFIG_ARGS_SERVER,
'stack': self.LAUNCH_CONFIG_ARGS_STACK,
'conf': self.LAUNCH_CONFIGURATION})
raise exception.StackValidationFailed(msg)
lb_args = lcargs.get(self.LAUNCH_CONFIG_ARGS_LOAD_BALANCERS) lb_args = lcargs.get(self.LAUNCH_CONFIG_ARGS_LOAD_BALANCERS)
lbs = copy.deepcopy(lb_args) lbs = copy.deepcopy(lb_args)
for lb in lbs: for lb in lbs:
@ -418,6 +519,26 @@ class Group(resource.Resource):
'with id %s') % (lb_id) 'with id %s') % (lb_id)
raise exception.StackValidationFailed(msg) raise exception.StackValidationFailed(msg)
if st_args:
st_tmpl = st_args.get(self.LAUNCH_CONFIG_ARGS_STACK_TEMPLATE)
st_tmpl_url = st_args.get(
self.LAUNCH_CONFIG_ARGS_STACK_TEMPLATE_URL)
st_env = st_args.get(self.LAUNCH_CONFIG_ARGS_STACK_ENVIRONMENT)
# template and template_url are required and mutually exclusive.
if ((not st_tmpl and not st_tmpl_url) or
(st_tmpl and st_tmpl_url)):
msg = _('Must provide one of template or template_url.')
raise exception.StackValidationFailed(msg)
if st_tmpl:
st_files = st_args.get(self.LAUNCH_CONFIG_ARGS_STACK_FILES)
try:
templatem.Template(st_tmpl, files=st_files, env=st_env)
except Exception as exc:
msg = (_('Encountered error while loading template: %s') %
six.text_type(exc))
raise exception.StackValidationFailed(msg)
def auto_scale(self): def auto_scale(self):
return self.client('auto_scale') return self.client('auto_scale')

View File

@ -102,9 +102,15 @@ class FakeAutoScale(object):
def replace_launch_config(self, group_id, **kwargs): def replace_launch_config(self, group_id, **kwargs):
"""Update the launch configuration on a scaling group.""" """Update the launch configuration on a scaling group."""
if kwargs.get('launch_config_type') == 'launch_server':
allowed = ['launch_config_type', 'server_name', 'image', 'flavor', allowed = ['launch_config_type', 'server_name', 'image', 'flavor',
'disk_config', 'metadata', 'personality', 'networks', 'disk_config', 'metadata', 'personality', 'networks',
'load_balancers', 'key_name', 'user_data', 'config_drive'] 'load_balancers', 'key_name', 'user_data',
'config_drive']
elif kwargs.get('launch_config_type') == 'launch_stack':
allowed = ['launch_config_type', 'template', 'template_url',
'disable_rollback', 'environment', 'files',
'parameters', 'timeout_mins']
self._check_args(kwargs, allowed) self._check_args(kwargs, allowed)
self._get_group(group_id).kwargs = kwargs self._get_group(group_id).kwargs = kwargs
@ -171,7 +177,7 @@ class FakeAutoScale(object):
class ScalingGroupTest(common.HeatTestCase): class ScalingGroupTest(common.HeatTestCase):
group_template = template_format.parse(''' server_template = template_format.parse('''
HeatTemplateFormatVersion: "2012-12-12" HeatTemplateFormatVersion: "2012-12-12"
Description: "Rackspace Auto Scale" Description: "Rackspace Auto Scale"
Parameters: {} Parameters: {}
@ -207,6 +213,53 @@ class ScalingGroupTest(common.HeatTestCase):
''') ''')
stack_template = template_format.parse('''
HeatTemplateFormatVersion: "2012-12-12"
Description: "Rackspace Auto Scale"
Parameters: {}
Resources:
my_group:
Type: Rackspace::AutoScale::Group
Properties:
groupConfiguration:
name: "My Group"
cooldown: 60
minEntities: 1
maxEntities: 25
metadata:
group: metadata
launchConfiguration:
type: launch_stack
args:
stack:
template:
heat_template_version: 2015-10-15
description: This is a Heat template
parameters:
image:
default: cirros-0.3.4-x86_64-uec
type: string
flavor:
default: m1.tiny
type: string
resources:
rand:
type: OS::Heat::RandomString
disable_rollback: False
environment:
parameters:
image: Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)
resource_registry:
Heat::InstallConfigAgent:
https://myhost.com/bootconfig.yaml
files:
fileA.yaml: Contents of the file
file:///usr/fileB.template: Contents of the file
parameters:
flavor: 4 GB Performance
timeout_mins: 30
''')
def setUp(self): def setUp(self):
super(ScalingGroupTest, self).setUp() super(ScalingGroupTest, self).setUp()
for res_name, res_class in auto_scale.resource_mapping().items(): for res_name, res_class in auto_scale.resource_mapping().items():
@ -222,14 +275,16 @@ class ScalingGroupTest(common.HeatTestCase):
'find_flavor_by_name_or_id') 'find_flavor_by_name_or_id')
mock_fl.return_value = 'flavor-ref' mock_fl.return_value = 'flavor-ref'
def _setup_test_stack(self): def _setup_test_stack(self, template=None):
self.stack = utils.parse_stack(self.group_template) if template is None:
template = self.server_template
self.stack = utils.parse_stack(template)
self.stack.create() self.stack.create()
self.assertEqual( self.assertEqual(
('CREATE', 'COMPLETE'), self.stack.state, ('CREATE', 'COMPLETE'), self.stack.state,
self.stack.status_reason) self.stack.status_reason)
def test_group_create(self): def test_group_create_server(self):
"""Creating a group passes all the correct arguments to pyrax. """Creating a group passes all the correct arguments to pyrax.
Also saves the group ID as the resource ID. Also saves the group ID as the resource ID.
@ -266,6 +321,62 @@ class ScalingGroupTest(common.HeatTestCase):
resource = self.stack['my_group'] resource = self.stack['my_group']
self.assertEqual('0', resource.FnGetRefId()) self.assertEqual('0', resource.FnGetRefId())
def test_group_create_stack(self):
"""Creating a group passes all the correct arguments to pyrax.
Also saves the group ID as the resource ID.
"""
self._setup_test_stack(self.stack_template)
self.assertEqual(1, len(self.fake_auto_scale.groups))
self.assertEqual(
{
'cooldown': 60,
'min_entities': 1,
'max_entities': 25,
'group_metadata': {'group': 'metadata'},
'name': 'My Group',
'launch_config_type': u'launch_stack',
'template': {
'heat_template_version': '2015-10-15',
'description': 'This is a Heat template',
'parameters': {
'flavor': {
'default': 'm1.tiny',
'type': 'string'},
'image': {
'default': 'cirros-0.3.4-x86_64-uec',
'type': 'string'}},
'resources': {
'rand': {'type': u'OS::Heat::RandomString'}
}
},
'template_url': None,
'disable_rollback': False,
'environment': {
'parameters': {
'image':
'Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)',
},
'resource_registry': {
'Heat::InstallConfigAgent': ('https://myhost.com/'
'bootconfig.yaml')
}
},
'files': {
'fileA.yaml': 'Contents of the file',
'file:///usr/fileB.template': 'Contents of the file'
},
'parameters': {
'flavor': '4 GB Performance',
},
'timeout_mins': 30,
},
self.fake_auto_scale.groups['0'].kwargs
)
resource = self.stack['my_group']
self.assertEqual('0', resource.FnGetRefId())
def test_group_create_no_personality(self): def test_group_create_no_personality(self):
template = template_format.parse(''' template = template_format.parse('''
@ -366,7 +477,7 @@ Resources:
self.assertEqual( self.assertEqual(
5, self.fake_auto_scale.groups['0'].kwargs['min_entities']) 5, self.fake_auto_scale.groups['0'].kwargs['min_entities'])
def test_update_launch_config(self): def test_update_launch_config_server(self):
"""Updates the launchConfigresults section. """Updates the launchConfigresults section.
Updates the launchConfigresults section in a template results in a Updates the launchConfigresults section in a template results in a
@ -389,6 +500,24 @@ Resources:
[{'loadBalancerId': 1, 'port': 80}], [{'loadBalancerId': 1, 'port': 80}],
self.fake_auto_scale.groups['0'].kwargs['load_balancers']) self.fake_auto_scale.groups['0'].kwargs['load_balancers'])
def test_update_launch_config_stack(self):
self._setup_test_stack(self.stack_template)
resource = self.stack['my_group']
uprops = copy.deepcopy(dict(resource.properties.data))
lcargs = uprops['launchConfiguration']['args']
lcargs['stack']['timeout_mins'] = 60
new_template = rsrc_defn.ResourceDefinition(resource.name,
resource.type(),
uprops)
scheduler.TaskRunner(resource.update, new_template)()
self.assertEqual(1, len(self.fake_auto_scale.groups))
self.assertEqual(
60,
self.fake_auto_scale.groups['0'].kwargs['timeout_mins'])
def test_delete(self): def test_delete(self):
"""Deleting a ScalingGroup resource invokes pyrax API to delete it.""" """Deleting a ScalingGroup resource invokes pyrax API to delete it."""
self._setup_test_stack() self._setup_test_stack()
@ -786,3 +915,305 @@ class AutoScaleGroupValidationTests(common.HeatTestCase):
asg = auto_scale.Group("test", rsrcdef, self.mockstack) asg = auto_scale.Group("test", rsrcdef, self.mockstack)
self.assertIsNone(asg.validate()) self.assertIsNone(asg.validate())
def test_validate_launch_stack(self, mock_client, mock_plugin):
asg_properties = {
"groupConfiguration": {
"name": "My Group",
"cooldown": 60,
"minEntities": 1,
"maxEntities": 25,
"metadata": {
"group": "metadata",
},
},
"launchConfiguration": {
"type": "launch_stack",
"args": {
"stack": {
'template': {
'heat_template_version': '2015-10-15',
'description': 'This is a Heat template',
'parameters': {
'flavor': {
'default': 'm1.tiny',
'type': 'string'},
'image': {
'default': 'cirros-0.3.4-x86_64-uec',
'type': 'string'}},
'resources': {
'rand': {'type': u'OS::Heat::RandomString'}
}
},
'template_url': None,
'disable_rollback': False,
'environment': {
'parameters': {
'image':
'Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)',
},
'resource_registry': {
'Heat::InstallConfigAgent': (
'https://myhost.com/bootconfig.yaml')
}
},
'files': {
'fileA.yaml': 'Contents of the file',
'file:///usr/fileB.yaml': 'Contents of the file'
},
'parameters': {
'flavor': '4 GB Performance',
},
'timeout_mins': 30,
}
}
}
}
rsrcdef = rsrc_defn.ResourceDefinition(
"test", auto_scale.Group, properties=asg_properties)
asg = auto_scale.Group("test", rsrcdef, self.mockstack)
self.assertIsNone(asg.validate())
def test_validate_launch_server_and_stack(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": {
"server": {
"name": "sdfsdf",
"flavorRef": "ffdgdf",
"imageRef": "image-ref",
},
"stack": {
'template': {
'heat_template_version': '2015-10-15',
'description': 'This is a Heat template',
'parameters': {
'flavor': {
'default': 'm1.tiny',
'type': 'string'},
'image': {
'default': 'cirros-0.3.4-x86_64-uec',
'type': 'string'}},
'resources': {
'rand': {'type': u'OS::Heat::RandomString'}
}
},
'template_url': None,
'disable_rollback': False,
'environment': {
'parameters': {
'image':
'Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)',
},
'resource_registry': {
'Heat::InstallConfigAgent': (
'https://myhost.com/bootconfig.yaml')
}
},
'files': {
'fileA.yaml': 'Contents of the file',
'file:///usr/fileB.yaml': 'Contents of the file'
},
'parameters': {
'flavor': '4 GB Performance',
},
'timeout_mins': 30,
}
}
}
}
rsrcdef = rsrc_defn.ResourceDefinition(
"test", auto_scale.Group, properties=asg_properties)
asg = auto_scale.Group("test", rsrcdef, self.mockstack)
error = self.assertRaises(
exception.StackValidationFailed, asg.validate)
self.assertIn(
'Must provide one of server or stack in launchConfiguration',
six.text_type(error))
def test_validate_no_launch_server_or_stack(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": {}
}
}
rsrcdef = rsrc_defn.ResourceDefinition(
"test", auto_scale.Group, properties=asg_properties)
asg = auto_scale.Group("test", rsrcdef, self.mockstack)
error = self.assertRaises(
exception.StackValidationFailed, asg.validate)
self.assertIn(
'Must provide one of server or stack in launchConfiguration',
six.text_type(error))
def test_validate_stack_template_and_template_url(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": {
"stack": {
'template': {
'heat_template_version': '2015-10-15',
'description': 'This is a Heat template',
'parameters': {
'flavor': {
'default': 'm1.tiny',
'type': 'string'},
'image': {
'default': 'cirros-0.3.4-x86_64-uec',
'type': 'string'}},
'resources': {
'rand': {'type': 'OS::Heat::RandomString'}
}
},
'template_url': 'https://myhost.com/template.yaml',
}
}
}
}
rsrcdef = rsrc_defn.ResourceDefinition(
"test", auto_scale.Group, properties=asg_properties)
asg = auto_scale.Group("test", rsrcdef, self.mockstack)
error = self.assertRaises(
exception.StackValidationFailed, asg.validate)
self.assertIn(
'Must provide one of template or template_url',
six.text_type(error))
def test_validate_stack_no_template_or_template_url(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": {
"stack": {
'disable_rollback': False,
'environment': {
'parameters': {
'image':
'Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)',
},
'resource_registry': {
'Heat::InstallConfigAgent': (
'https://myhost.com/bootconfig.yaml')
}
},
'files': {
'fileA.yaml': 'Contents of the file',
'file:///usr/fileB.yaml': 'Contents of the file'
},
'parameters': {
'flavor': '4 GB Performance',
},
'timeout_mins': 30,
}
}
}
}
rsrcdef = rsrc_defn.ResourceDefinition(
"test", auto_scale.Group, properties=asg_properties)
asg = auto_scale.Group("test", rsrcdef, self.mockstack)
error = self.assertRaises(
exception.StackValidationFailed, asg.validate)
self.assertIn(
'Must provide one of template or template_url',
six.text_type(error))
def test_validate_invalid_template(self, mock_client, mock_plugin):
asg_properties = {
"groupConfiguration": {
"name": "My Group",
"cooldown": 60,
"minEntities": 1,
"maxEntities": 25,
"metadata": {
"group": "metadata",
},
},
"launchConfiguration": {
"type": "launch_stack",
"args": {
"stack": {
'template': {
'SJDADKJAJKLSheat_template_version': '2015-10-15',
'description': 'This is a Heat template',
'parameters': {
'flavor': {
'default': 'm1.tiny',
'type': 'string'},
'image': {
'default': 'cirros-0.3.4-x86_64-uec',
'type': 'string'}},
'resources': {
'rand': {'type': u'OS::Heat::RandomString'}
}
},
'template_url': None,
'disable_rollback': False,
'environment': {'Foo': 'Bar'},
'files': {
'fileA.yaml': 'Contents of the file',
'file:///usr/fileB.yaml': 'Contents of the file'
},
'parameters': {
'flavor': '4 GB Performance',
},
'timeout_mins': 30,
}
}
}
}
rsrcdef = rsrc_defn.ResourceDefinition(
"test", auto_scale.Group, properties=asg_properties)
asg = auto_scale.Group("test", rsrcdef, self.mockstack)
error = self.assertRaises(
exception.StackValidationFailed, asg.validate)
self.assertIn(
'Encountered error while loading template:',
six.text_type(error))