2
# Licensed under the Apache License, Version 2.0 (the "License"); you may
3
# not use this file except in compliance with the License. You may obtain
4
# a copy of the License at
6
# http://www.apache.org/licenses/LICENSE-2.0
8
# Unless required by applicable law or agreed to in writing, software
9
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
# License for the specific language governing permissions and limitations
19
from oslo.config import cfg
20
from oslo.utils import timeutils
23
from heat.common import exception
24
from heat.common import grouputils
25
from heat.common import short_id
26
from heat.common import template_format
27
from heat.engine.clients.os import nova
28
from heat.engine.notification import autoscaling as notification
29
from heat.engine import parser
30
from heat.engine import resource
31
from heat.engine.resources.aws import autoscaling_group as asg
32
from heat.engine.resources import instance
33
from heat.engine.resources import loadbalancer
34
from heat.engine.resources.neutron import loadbalancer as neutron_lb
35
from heat.engine import rsrc_defn
36
from heat.engine import scheduler
37
from heat.tests.autoscaling import inline_templates
38
from heat.tests import common
39
from heat.tests import utils
42
as_template = inline_templates.as_template
44
as_template_bad_group = '''
46
"AWSTemplateFormatVersion" : "2010-09-09",
48
"ImageId": {"Type": "String"},
49
"KeyName": {"Type": "String"}
52
"WebServerScaleUpPolicy" : {
53
"Type" : "AWS::AutoScaling::ScalingPolicy",
55
"AdjustmentType" : "ChangeInCapacity",
56
"AutoScalingGroupName" : "not a real group",
58
"ScalingAdjustment" : "1"
66
class AutoScalingTest(common.HeatTestCase):
67
dummy_instance_id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
68
params = {'KeyName': 'test', 'ImageId': 'foo'}
69
params_HoT = {'flavor': 'test', 'image': 'foo'}
72
super(AutoScalingTest, self).setUp()
73
cfg.CONF.set_default('heat_waitcondition_server_url',
74
'http://server.test:8000/v1/waitcondition')
75
self.stub_keystoneclient()
76
t = template_format.parse(as_template)
77
stack = utils.parse_stack(t, params=self.params)
78
self.defn = rsrc_defn.ResourceDefinition(
79
'asg', 'AWS::AutoScaling::AutoScalingGroup',
80
{'AvailabilityZones': ['nova'],
81
'LaunchConfigurationName': 'config',
84
'DesiredCapacity': 2})
85
self.asg = asg.AutoScalingGroup('asg', self.defn, stack)
87
def create_scaling_group(self, t, stack, resource_name):
88
# create the launch configuration resource
89
conf = stack['LaunchConfig']
90
self.assertIsNone(conf.validate())
91
scheduler.TaskRunner(conf.create)()
92
self.assertEqual((conf.CREATE, conf.COMPLETE), conf.state)
93
# check bdm in configuration
94
self.assertIsNotNone(conf.properties['BlockDeviceMappings'])
96
# create the group resource
97
rsrc = stack[resource_name]
98
self.assertIsNone(rsrc.validate())
99
scheduler.TaskRunner(rsrc.create)()
100
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
101
# check bdm in instance_definition
102
instance_definition = rsrc._get_instance_definition()
103
self.assertIn('BlockDeviceMappings',
104
instance_definition['Properties'])
108
def create_scaling_policy(self, t, stack, resource_name):
109
rsrc = stack[resource_name]
110
self.assertIsNone(rsrc.validate())
111
scheduler.TaskRunner(rsrc.create)()
112
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
115
def _stub_create(self, num, with_error=None, with_lcn=True):
116
self.m.StubOutWithMock(instance.Instance, 'handle_create')
117
self.m.StubOutWithMock(instance.Instance, 'check_create_complete')
118
self.stub_ImageConstraint_validate()
119
self.stub_FlavorConstraint_validate()
120
# create with launch config name, need to stub snapshot constraint
122
self.stub_SnapshotConstraint_validate()
124
instance.Instance.handle_create().AndRaise(
125
exception.Error(with_error))
129
instance.Instance.handle_create().AndReturn(cookie)
130
instance.Instance.check_create_complete(cookie).AndReturn(False)
131
instance.Instance.check_create_complete(
132
cookie).MultipleTimes().AndReturn(True)
134
def _stub_delete(self, num):
135
self.m.StubOutWithMock(instance.Instance, 'handle_delete')
136
self.m.StubOutWithMock(instance.Instance, 'check_delete_complete')
139
instance.Instance.handle_delete().AndReturn(task)
140
instance.Instance.check_delete_complete(task).AndReturn(False)
141
instance.Instance.check_delete_complete(
142
task).MultipleTimes().AndReturn(True)
144
def _stub_suspend(self, cookies=None, with_error=None):
145
cookies = cookies or []
146
self.m.StubOutWithMock(instance.Instance, 'handle_suspend')
147
self.m.StubOutWithMock(instance.Instance, 'check_suspend_complete')
149
instance.Instance.handle_suspend().AndRaise(
150
exception.Error(with_error))
152
inst_cookies = cookies or [(object(), object(), object())]
153
for cookie in inst_cookies:
154
instance.Instance.handle_suspend().InAnyOrder().AndReturn(cookie)
155
instance.Instance.check_suspend_complete(
156
cookie).InAnyOrder().AndReturn(False)
157
instance.Instance.check_suspend_complete(
158
cookie).InAnyOrder().AndReturn(True)
160
def _stub_resume(self, cookies=None, with_error=None):
161
cookies = cookies or []
162
self.m.StubOutWithMock(instance.Instance, 'handle_resume')
163
self.m.StubOutWithMock(instance.Instance, 'check_resume_complete')
165
instance.Instance.handle_resume().AndRaise(
166
exception.Error(with_error))
168
inst_cookies = cookies or [(object(), object(), object())]
169
for cookie in inst_cookies:
170
instance.Instance.handle_resume().InAnyOrder().AndReturn(cookie)
171
instance.Instance.check_resume_complete(
172
cookie).InAnyOrder().AndReturn(False)
173
instance.Instance.check_resume_complete(
174
cookie).InAnyOrder().AndReturn(True)
176
def _stub_lb_reload(self, num, unset=True, nochange=False):
177
expected_list = [self.dummy_instance_id] * num
182
self.m.StubOutWithMock(instance.Instance, 'FnGetRefId')
183
instance.Instance.FnGetRefId().MultipleTimes().AndReturn(
184
self.dummy_instance_id)
187
self.m.StubOutWithMock(loadbalancer.LoadBalancer, 'handle_update')
188
loadbalancer.LoadBalancer.handle_update(
189
mox.IgnoreArg(), mox.IgnoreArg(),
190
{'Instances': expected_list}).AndReturn(None)
192
def _stub_scale_notification(self,
196
adjust_type='ChangeInCapacity',
200
self.m.StubOutWithMock(notification, 'send')
201
notification.send(stack=mox.IgnoreArg(),
203
adjustment_type=adjust_type,
204
capacity=start_capacity,
205
groupname=mox.IgnoreArg(),
207
message="Start resizing the group %s"
211
notification.send(stack=mox.IgnoreArg(),
213
capacity=start_capacity,
214
adjustment_type=adjust_type,
215
groupname=mox.IgnoreArg(),
216
message='Nested stack update failed:'
217
' Error: %s' % with_error,
221
notification.send(stack=mox.IgnoreArg(),
223
adjustment_type=adjust_type,
224
capacity=end_capacity,
225
groupname=mox.IgnoreArg(),
226
message="End resizing the group %s"
231
def _stub_meta_expected(self, now, data, nmeta=1):
233
timeutils.set_time_override(now)
234
self.addCleanup(timeutils.clear_time_override)
236
# Then set a stub to ensure the metadata update is as
237
# expected based on the timestamp and data
238
self.m.StubOutWithMock(resource.Resource, 'metadata_set')
239
expected = {timeutils.strtime(now): data}
240
# Note for ScalingPolicy, we expect to get a metadata
241
# update for the policy and autoscaling group, so pass nmeta=2
242
for x in range(nmeta):
243
resource.Resource.metadata_set(expected).AndReturn(None)
245
def test_scaling_group_suspend(self):
246
t = template_format.parse(as_template)
247
stack = utils.parse_stack(t, params=self.params)
249
self._stub_lb_reload(1)
250
now = timeutils.utcnow()
251
self._stub_meta_expected(now, 'ExactCapacity : 1')
254
rsrc = self.create_scaling_group(t, stack, 'WebServerGroup')
255
self.assertEqual(utils.PhysName(stack.name, rsrc.name),
257
self.assertEqual(1, len(grouputils.get_member_names(rsrc)))
258
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
266
scheduler.TaskRunner(rsrc.suspend)()
267
self.assertEqual((rsrc.SUSPEND, rsrc.COMPLETE), rsrc.state)
272
def test_scaling_group_resume(self):
273
t = template_format.parse(as_template)
274
stack = utils.parse_stack(t, params=self.params)
276
self._stub_lb_reload(1)
277
now = timeutils.utcnow()
278
self._stub_meta_expected(now, 'ExactCapacity : 1')
281
rsrc = self.create_scaling_group(t, stack, 'WebServerGroup')
282
self.assertEqual(utils.PhysName(stack.name, rsrc.name),
284
self.assertEqual(1, len(grouputils.get_member_names(rsrc)))
285
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
293
rsrc.state_set(rsrc.SUSPEND, rsrc.COMPLETE)
294
for i in rsrc.nested().values():
295
i.state_set(rsrc.SUSPEND, rsrc.COMPLETE)
297
scheduler.TaskRunner(rsrc.resume)()
298
self.assertEqual((rsrc.RESUME, rsrc.COMPLETE), rsrc.state)
303
def test_scaling_group_suspend_multiple(self):
304
t = template_format.parse(as_template)
305
properties = t['Resources']['WebServerGroup']['Properties']
306
properties['DesiredCapacity'] = '2'
307
stack = utils.parse_stack(t, params=self.params)
309
self._stub_lb_reload(2)
310
now = timeutils.utcnow()
311
self._stub_meta_expected(now, 'ExactCapacity : 2')
314
rsrc = self.create_scaling_group(t, stack, 'WebServerGroup')
315
self.assertEqual(utils.PhysName(stack.name, rsrc.name),
317
self.assertEqual(2, len(grouputils.get_member_names(rsrc)))
318
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
323
self._stub_suspend(cookies=[('foo1', 'foo2', 'foo3'),
324
('bar1', 'bar2', 'bar3')])
327
scheduler.TaskRunner(rsrc.suspend)()
328
self.assertEqual((rsrc.SUSPEND, rsrc.COMPLETE), rsrc.state)
333
def test_scaling_group_resume_multiple(self):
334
t = template_format.parse(as_template)
335
properties = t['Resources']['WebServerGroup']['Properties']
336
properties['DesiredCapacity'] = '2'
337
stack = utils.parse_stack(t, params=self.params)
339
self._stub_lb_reload(2)
340
now = timeutils.utcnow()
341
self._stub_meta_expected(now, 'ExactCapacity : 2')
344
rsrc = self.create_scaling_group(t, stack, 'WebServerGroup')
345
self.assertEqual(utils.PhysName(stack.name, rsrc.name),
347
self.assertEqual(2, len(grouputils.get_member_names(rsrc)))
348
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
353
self._stub_resume(cookies=[('foo1', 'foo2', 'foo3'),
354
('bar1', 'bar2', 'bar3')])
357
rsrc.state_set(rsrc.SUSPEND, rsrc.COMPLETE)
358
for i in rsrc.nested().values():
359
i.state_set(rsrc.SUSPEND, rsrc.COMPLETE)
361
scheduler.TaskRunner(rsrc.resume)()
362
self.assertEqual((rsrc.RESUME, rsrc.COMPLETE), rsrc.state)
367
def test_scaling_group_suspend_fail(self):
368
t = template_format.parse(as_template)
369
stack = utils.parse_stack(t, params=self.params)
371
self._stub_lb_reload(1)
372
now = timeutils.utcnow()
373
self._stub_meta_expected(now, 'ExactCapacity : 1')
376
rsrc = self.create_scaling_group(t, stack, 'WebServerGroup')
377
self.assertEqual(utils.PhysName(stack.name, rsrc.name),
379
self.assertEqual(1, len(grouputils.get_member_names(rsrc)))
380
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
385
self._stub_suspend(with_error='oops')
388
sus_task = scheduler.TaskRunner(rsrc.suspend)
389
self.assertRaises(exception.ResourceFailure, sus_task, ())
390
self.assertEqual((rsrc.SUSPEND, rsrc.FAILED), rsrc.state)
391
self.assertEqual('Error: Resource SUSPEND failed: Error: oops',
397
def test_scaling_group_resume_fail(self):
398
t = template_format.parse(as_template)
399
stack = utils.parse_stack(t, params=self.params)
401
self._stub_lb_reload(1)
402
now = timeutils.utcnow()
403
self._stub_meta_expected(now, 'ExactCapacity : 1')
406
rsrc = self.create_scaling_group(t, stack, 'WebServerGroup')
407
self.assertEqual(utils.PhysName(stack.name, rsrc.name),
409
self.assertEqual(1, len(grouputils.get_member_names(rsrc)))
410
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
415
self._stub_resume(with_error='oops')
418
rsrc.state_set(rsrc.SUSPEND, rsrc.COMPLETE)
419
for i in rsrc.nested().values():
420
i.state_set(rsrc.SUSPEND, rsrc.COMPLETE)
422
sus_task = scheduler.TaskRunner(rsrc.resume)
423
self.assertRaises(exception.ResourceFailure, sus_task, ())
424
self.assertEqual((rsrc.RESUME, rsrc.FAILED), rsrc.state)
425
self.assertEqual('Error: Resource RESUME failed: Error: oops',
431
def test_scaling_group_create_error(self):
432
t = template_format.parse(as_template)
433
stack = utils.parse_stack(t, params=self.params)
435
self.m.StubOutWithMock(instance.Instance, 'handle_create')
436
self.m.StubOutWithMock(instance.Instance, 'check_create_complete')
437
instance.Instance.handle_create().AndRaise(Exception)
438
self.stub_ImageConstraint_validate()
439
self.stub_FlavorConstraint_validate()
440
self.stub_SnapshotConstraint_validate()
444
conf = stack['LaunchConfig']
445
self.assertIsNone(conf.validate())
446
scheduler.TaskRunner(conf.create)()
447
self.assertEqual((conf.CREATE, conf.COMPLETE), conf.state)
449
rsrc = stack['WebServerGroup']
450
self.assertIsNone(rsrc.validate())
451
self.assertRaises(exception.ResourceFailure,
452
scheduler.TaskRunner(rsrc.create))
453
self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state)
455
self.assertEqual([], grouputils.get_members(rsrc))
459
def test_update_in_failed(self):
460
self.asg.state_set('CREATE', 'FAILED')
461
# to update the failed asg
462
self.asg.adjust = mock.Mock(return_value=None)
464
self.asg.handle_update(self.defn, None, None)
465
self.asg.adjust.assert_called_once_with(
466
2, adjustment_type='ExactCapacity')
468
def test_lb_reload_static_resolve(self):
469
t = template_format.parse(as_template)
470
properties = t['Resources']['ElasticLoadBalancer']['Properties']
471
properties['AvailabilityZones'] = {'Fn::GetAZs': ''}
473
self.m.StubOutWithMock(parser.Stack, 'get_availability_zones')
474
parser.Stack.get_availability_zones().MultipleTimes().AndReturn(
477
# Check that the Fn::GetAZs is correctly resolved
478
expected = {u'Type': u'AWS::ElasticLoadBalancing::LoadBalancer',
479
u'Properties': {'Instances': ['aaaabbbbcccc'],
480
u'Listeners': [{u'InstancePort': u'80',
481
u'LoadBalancerPort': u'80',
482
u'Protocol': u'HTTP'}],
483
u'AvailabilityZones': ['abc', 'xyz']}}
485
self.m.StubOutWithMock(short_id, 'generate_id')
486
short_id.generate_id().MultipleTimes().AndReturn('aaaabbbbcccc')
488
now = timeutils.utcnow()
489
self._stub_meta_expected(now, 'ExactCapacity : 1')
492
stack = utils.parse_stack(t, params=self.params)
494
lb = stack['ElasticLoadBalancer']
495
self.m.StubOutWithMock(lb, 'handle_update')
496
lb.handle_update(expected,
498
mox.IgnoreArg()).AndReturn(None)
501
rsrc = self.create_scaling_group(t, stack, 'WebServerGroup')
502
self.assertEqual(utils.PhysName(stack.name, rsrc.name),
504
self.assertEqual(1, len(grouputils.get_member_names(rsrc)))
505
props = copy.copy(rsrc.properties.data)
506
props['Cooldown'] = '61'
507
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name,
510
scheduler.TaskRunner(rsrc.update, update_snippet)()
515
def test_lb_reload_members(self):
516
t = template_format.parse(as_template)
517
t['Resources']['ElasticLoadBalancer'] = {
518
'Type': 'OS::Neutron::LoadBalancer',
520
'protocol_port': 8080,
526
'Type': 'OS::Neutron::LoadBalancer',
528
'protocol_port': 8080,
529
'pool_id': 'pool123',
530
'members': [u'aaaabbbbcccc']}
533
self.m.StubOutWithMock(short_id, 'generate_id')
534
short_id.generate_id().MultipleTimes().AndReturn('aaaabbbbcccc')
536
self.m.StubOutWithMock(neutron_lb.LoadBalancer, 'handle_update')
537
neutron_lb.LoadBalancer.handle_update(expected,
539
mox.IgnoreArg()).AndReturn(None)
541
now = timeutils.utcnow()
542
self._stub_meta_expected(now, 'ExactCapacity : 1')
545
stack = utils.parse_stack(t, params=self.params)
546
self.create_scaling_group(t, stack, 'WebServerGroup')
550
def test_scaling_policy_bad_group(self):
551
t = template_format.parse(as_template_bad_group)
552
stack = utils.parse_stack(t, params=self.params)
555
up_policy = self.create_scaling_policy(t, stack,
556
'WebServerScaleUpPolicy')
558
alarm_url = up_policy.FnGetAtt('AlarmUrl')
559
self.assertIsNotNone(alarm_url)
560
ex = self.assertRaises(exception.ResourceFailure, up_policy.signal)
561
self.assertIn('Alarm WebServerScaleUpPolicy could '
562
'not find scaling group', six.text_type(ex))
566
def test_scaling_up_meta_update(self):
567
t = template_format.parse(as_template)
569
# Add CustomLB (just AWS::EC2::Instance) to template
570
t['Resources']['MyCustomLB'] = {
571
'Type': 'AWS::EC2::Instance',
572
'ImageId': {'Ref': 'ImageId'},
573
'InstanceType': 'bar',
575
'IPs': {'Fn::GetAtt': ['WebServerGroup', 'InstanceList']}
578
stack = utils.parse_stack(t, params=self.params)
580
# Create initial group
581
self._stub_lb_reload(1)
582
now = timeutils.utcnow()
583
self._stub_meta_expected(now, 'ExactCapacity : 1')
587
rsrc = self.create_scaling_group(t, stack, 'WebServerGroup')
588
stack.resources['WebServerGroup'] = rsrc
589
self.assertEqual(1, len(grouputils.get_member_names(rsrc)))
592
self._stub_lb_reload(2)
593
self._stub_meta_expected(now, 'ChangeInCapacity : 1', 2)
597
up_policy = self.create_scaling_policy(t, stack,
598
'WebServerScaleUpPolicy')
600
alarm_url = up_policy.FnGetAtt('AlarmUrl')
601
self.assertIsNotNone(alarm_url)
603
self.assertEqual(2, len(grouputils.get_member_names(rsrc)))
605
# Check CustomLB metadata was updated
606
self.m.StubOutWithMock(instance.Instance, '_ipaddress')
607
instance.Instance._ipaddress().MultipleTimes().AndReturn(
611
expected_meta = {'IPs': u'127.0.0.1,127.0.0.1'}
612
self.assertEqual(expected_meta, stack['MyCustomLB'].metadata_get())
617
def test_scaling_policy_update(self):
618
t = template_format.parse(as_template)
619
stack = utils.parse_stack(t, params=self.params)
621
# Create initial group
622
self._stub_lb_reload(1)
623
now = timeutils.utcnow()
624
self._stub_meta_expected(now, 'ExactCapacity : 1')
628
rsrc = self.create_scaling_group(t, stack, 'WebServerGroup')
629
stack.resources['WebServerGroup'] = rsrc
630
self.assertEqual(1, len(grouputils.get_member_names(rsrc)))
632
# Create initial scaling policy
633
up_policy = self.create_scaling_policy(t, stack,
634
'WebServerScaleUpPolicy')
637
self._stub_lb_reload(2)
638
self._stub_meta_expected(now, 'ChangeInCapacity : 1', 2)
645
self.assertEqual(2, len(grouputils.get_member_names(rsrc)))
647
# Update scaling policy
648
props = copy.copy(up_policy.properties.data)
649
props['ScalingAdjustment'] = '2'
650
update_snippet = rsrc_defn.ResourceDefinition(up_policy.name,
653
scheduler.TaskRunner(up_policy.update, update_snippet)()
654
self.assertEqual(2, up_policy.properties['ScalingAdjustment'])
656
# Now move time on 61 seconds - Cooldown in template is 60
657
# so this should trigger a scale-up
658
previous_meta = {timeutils.strtime(now): 'ChangeInCapacity : 1'}
662
self.m.StubOutWithMock(resource.Resource, 'metadata_get')
663
up_policy.metadata_get().AndReturn(previous_meta)
664
rsrc.metadata_get().AndReturn(previous_meta)
666
# stub for the metadata accesses while creating the two instances
667
resource.Resource.metadata_get()
668
resource.Resource.metadata_get()
670
now = now + datetime.timedelta(seconds=61)
672
self._stub_lb_reload(4, unset=False)
673
self._stub_meta_expected(now, 'ChangeInCapacity : 2', 2)
679
self.assertEqual(4, len(grouputils.get_member_names(rsrc)))
684
def _stub_nova_server_get(self, not_found=False):
685
mock_server = mock.MagicMock()
686
mock_server.image = {'id': 'dd619705-468a-4f7d-8a06-b84794b3561a'}
687
mock_server.flavor = {'id': '1'}
688
mock_server.key_name = 'test'
689
mock_server.security_groups = [{u'name': u'hth_test'}]
691
self.patchobject(nova.NovaClientPlugin, 'get_server',
692
side_effect=exception.ServerNotFound(
695
self.patchobject(nova.NovaClientPlugin, 'get_server',
696
return_value=mock_server)
698
def test_validate_without_InstanceId_and_LaunchConfigurationName(self):
699
t = template_format.parse(as_template)
700
agp = t['Resources']['WebServerGroup']['Properties']
701
agp.pop('LaunchConfigurationName')
702
agp.pop('LoadBalancerNames')
703
stack = utils.parse_stack(t, params=self.params)
704
rsrc = stack['WebServerGroup']
705
error_msg = ("Either 'InstanceId' or 'LaunchConfigurationName' "
707
exc = self.assertRaises(exception.StackValidationFailed,
709
self.assertIn(error_msg, six.text_type(exc))
711
def test_validate_with_InstanceId_and_LaunchConfigurationName(self):
712
t = template_format.parse(as_template)
713
agp = t['Resources']['WebServerGroup']['Properties']
714
agp['InstanceId'] = '5678'
715
stack = utils.parse_stack(t, params=self.params)
716
rsrc = stack['WebServerGroup']
717
error_msg = ("Either 'InstanceId' or 'LaunchConfigurationName' "
719
exc = self.assertRaises(exception.StackValidationFailed,
721
self.assertIn(error_msg, six.text_type(exc))
723
def test_scaling_group_create_with_instanceid(self):
724
t = template_format.parse(as_template)
725
agp = t['Resources']['WebServerGroup']['Properties']
726
agp['InstanceId'] = '5678'
727
agp.pop('LaunchConfigurationName')
728
agp.pop('LoadBalancerNames')
729
stack = utils.parse_stack(t, params=self.params)
730
rsrc = stack['WebServerGroup']
731
self.stub_KeypairConstraint_validate()
732
self._stub_nova_server_get()
733
self._stub_create(1, with_lcn=False)
736
scheduler.TaskRunner(rsrc.create)()
737
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
738
instance_definition = rsrc._get_instance_definition()
739
ins_props = instance_definition['Properties']
740
self.assertEqual('dd619705-468a-4f7d-8a06-b84794b3561a',
741
ins_props['ImageId'])
742
self.assertEqual('test', ins_props['KeyName'])
743
self.assertEqual(['hth_test'], ins_props['SecurityGroups'])
744
self.assertEqual('1', ins_props['InstanceType'])
748
def test_scaling_group_create_with_instanceid_not_found(self):
749
t = template_format.parse(as_template)
750
agp = t['Resources']['WebServerGroup']['Properties']
751
agp.pop('LaunchConfigurationName')
752
agp['InstanceId'] = '5678'
753
stack = utils.parse_stack(t, params=self.params)
754
rsrc = stack['WebServerGroup']
755
self._stub_nova_server_get(not_found=True)
757
msg = ("Property error : WebServerGroup: InstanceId Error validating "
758
"value '5678': The server (5678) could not be found")
759
exc = self.assertRaises(exception.StackValidationFailed,
761
self.assertIn(msg, six.text_type(exc))