heat/heat/tests/autoscaling/test_scaling_group.py

241 lines
9.4 KiB
Python

#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from oslo.config import cfg
import six
from heat.common import exception
from heat.common import template_format
from heat.engine import scheduler
from heat.tests.autoscaling import inline_templates
from heat.tests import common
from heat.tests import utils
as_template = inline_templates.as_template
class TestAutoScalingGroupValidation(common.HeatTestCase):
def setUp(self):
super(TestAutoScalingGroupValidation, self).setUp()
cfg.CONF.set_default('heat_waitcondition_server_url',
'http://server.test:8000/v1/waitcondition')
self.stub_keystoneclient()
def validate_scaling_group(self, t, stack, resource_name):
# create the launch configuration resource
conf = stack['LaunchConfig']
self.assertIsNone(conf.validate())
scheduler.TaskRunner(conf.create)()
self.assertEqual((conf.CREATE, conf.COMPLETE), conf.state)
# create the group resource
rsrc = stack[resource_name]
self.assertIsNone(rsrc.validate())
return rsrc
def test_toomany_vpc_zone_identifier(self):
t = template_format.parse(as_template)
properties = t['Resources']['WebServerGroup']['Properties']
properties['VPCZoneIdentifier'] = ['xxxx', 'yyyy']
stack = utils.parse_stack(t, params=inline_templates.as_params)
self.stub_ImageConstraint_validate()
self.m.ReplayAll()
self.assertRaises(exception.NotSupported,
self.validate_scaling_group, t,
stack, 'WebServerGroup')
self.m.VerifyAll()
def test_invalid_min_size(self):
t = template_format.parse(as_template)
properties = t['Resources']['WebServerGroup']['Properties']
properties['MinSize'] = '-1'
properties['MaxSize'] = '2'
stack = utils.parse_stack(t, params=inline_templates.as_params)
self.stub_ImageConstraint_validate()
self.m.ReplayAll()
e = self.assertRaises(exception.StackValidationFailed,
self.validate_scaling_group, t,
stack, 'WebServerGroup')
expected_msg = "The size of AutoScalingGroup can not be less than zero"
self.assertEqual(expected_msg, six.text_type(e))
self.m.VerifyAll()
def test_invalid_max_size(self):
t = template_format.parse(as_template)
properties = t['Resources']['WebServerGroup']['Properties']
properties['MinSize'] = '3'
properties['MaxSize'] = '1'
stack = utils.parse_stack(t, params=inline_templates.as_params)
self.stub_ImageConstraint_validate()
self.m.ReplayAll()
e = self.assertRaises(exception.StackValidationFailed,
self.validate_scaling_group, t,
stack, 'WebServerGroup')
expected_msg = "MinSize can not be greater than MaxSize"
self.assertEqual(expected_msg, six.text_type(e))
self.m.VerifyAll()
def test_invalid_desiredcapacity(self):
t = template_format.parse(as_template)
properties = t['Resources']['WebServerGroup']['Properties']
properties['MinSize'] = '1'
properties['MaxSize'] = '3'
properties['DesiredCapacity'] = '4'
stack = utils.parse_stack(t, params=inline_templates.as_params)
self.stub_ImageConstraint_validate()
self.m.ReplayAll()
e = self.assertRaises(exception.StackValidationFailed,
self.validate_scaling_group, t,
stack, 'WebServerGroup')
expected_msg = "DesiredCapacity must be between MinSize and MaxSize"
self.assertEqual(expected_msg, six.text_type(e))
self.m.VerifyAll()
def test_invalid_desiredcapacity_zero(self):
t = template_format.parse(as_template)
properties = t['Resources']['WebServerGroup']['Properties']
properties['MinSize'] = '1'
properties['MaxSize'] = '3'
properties['DesiredCapacity'] = '0'
stack = utils.parse_stack(t, params=inline_templates.as_params)
self.stub_ImageConstraint_validate()
self.m.ReplayAll()
e = self.assertRaises(exception.StackValidationFailed,
self.validate_scaling_group, t,
stack, 'WebServerGroup')
expected_msg = "DesiredCapacity must be between MinSize and MaxSize"
self.assertEqual(expected_msg, six.text_type(e))
self.m.VerifyAll()
class TestInitialGroupSize(common.HeatTestCase):
scenarios = [
('000', dict(mins=0, maxs=0, desired=0, expected=0)),
('040', dict(mins=0, maxs=4, desired=0, expected=0)),
('253', dict(mins=2, maxs=5, desired=3, expected=3)),
('14n', dict(mins=1, maxs=4, desired=None, expected=1)),
]
def setUp(self):
super(TestInitialGroupSize, self).setUp()
cfg.CONF.set_default('heat_waitcondition_server_url',
'http://server.test:8000/v1/waitcondition')
self.stub_keystoneclient()
def test_initial_size(self):
t = template_format.parse(as_template)
properties = t['Resources']['WebServerGroup']['Properties']
properties['MinSize'] = self.mins
properties['MaxSize'] = self.maxs
properties['DesiredCapacity'] = self.desired
stack = utils.parse_stack(t, params=inline_templates.as_params)
group = stack['WebServerGroup']
with mock.patch.object(group, '_create_template') as mock_cre_temp:
group.child_template()
mock_cre_temp.assert_called_once_with(self.expected)
class TestGroupAdjust(common.HeatTestCase):
def setUp(self):
super(TestGroupAdjust, self).setUp()
cfg.CONF.set_default('heat_waitcondition_server_url',
'http://server.test:8000/v1/waitcondition')
self.stub_keystoneclient()
t = template_format.parse(as_template)
stack = utils.parse_stack(t, params=inline_templates.as_params)
self.group = stack['WebServerGroup']
self.assertIsNone(self.group.validate())
def test_scaling_policy_cooldown_toosoon(self):
"""If _cooldown_inprogress() returns True don't progress."""
dont_call = self.patchobject(self.group, 'get_instances')
with mock.patch.object(self.group, '_cooldown_inprogress',
return_value=True):
self.group.adjust(1)
self.assertEqual([], dont_call.call_args_list)
def test_scaling_policy_cooldown_ok(self):
self.patchobject(self.group, 'get_instances', return_value=[])
resize = self.patchobject(self.group, 'resize')
cd_stamp = self.patchobject(self.group, '_cooldown_timestamp')
notify = self.patch('heat.engine.notification.autoscaling.send')
self.patchobject(self.group, '_cooldown_inprogress',
return_value=False)
self.group.adjust(1)
expected_notifies = [
mock.call(
capacity=0, suffix='start', adjustment_type='ChangeInCapacity',
groupname=u'WebServerGroup',
message=u'Start resizing the group WebServerGroup',
adjustment=1,
stack=self.group.stack),
mock.call(
capacity=1, suffix='end',
adjustment_type='ChangeInCapacity',
groupname=u'WebServerGroup',
message=u'End resizing the group WebServerGroup',
adjustment=1,
stack=self.group.stack)]
self.assertEqual(expected_notifies, notify.call_args_list)
resize.assert_called_once_with(1)
cd_stamp.assert_called_once_with('ChangeInCapacity : 1')
def test_scaling_policy_resize_fail(self):
self.patchobject(self.group, 'get_instances', return_value=[])
self.patchobject(self.group, 'resize',
side_effect=ValueError('test error'))
notify = self.patch('heat.engine.notification.autoscaling.send')
self.patchobject(self.group, '_cooldown_inprogress',
return_value=False)
self.assertRaises(ValueError, self.group.adjust, 1)
expected_notifies = [
mock.call(
capacity=0, suffix='start',
adjustment_type='ChangeInCapacity',
groupname=u'WebServerGroup',
message=u'Start resizing the group WebServerGroup',
adjustment=1,
stack=self.group.stack),
mock.call(
capacity=0, suffix='error',
adjustment_type='ChangeInCapacity',
groupname=u'WebServerGroup',
message=u'test error',
adjustment=1,
stack=self.group.stack)]
self.assertEqual(expected_notifies, notify.call_args_list)