Correct group's updates from a failed state
This patch modifies autoscaling/instance group to handle updates from a failed state. Change-Id: I235b3e97276361022e708266bf06bca6556bcf76 Closes-Bug: #1383618
This commit is contained in:
parent
c16f539c53
commit
1eabdaf45f
@ -14,14 +14,15 @@
|
||||
import six
|
||||
|
||||
|
||||
def get_size(group):
|
||||
def get_size(group, include_failed=False):
|
||||
"""Get number of member resources managed by the specified group.
|
||||
|
||||
The list of members are not sorted or returned.
|
||||
The size exclude failed members default, set include_failed=True
|
||||
to get total size.
|
||||
"""
|
||||
if group.nested():
|
||||
resources = [r for r in six.itervalues(group.nested())
|
||||
if r.status != r.FAILED]
|
||||
if include_failed or r.status != r.FAILED]
|
||||
return len(resources)
|
||||
else:
|
||||
return 0
|
||||
|
@ -230,21 +230,18 @@ class AutoScalingGroup(instgrp.InstanceGroup, cooldown.CooldownMixin):
|
||||
self.context)
|
||||
self.update_policy = up
|
||||
|
||||
self.properties = json_snippet.properties(self.properties_schema,
|
||||
self.context)
|
||||
if prop_diff:
|
||||
self.properties = json_snippet.properties(self.properties_schema,
|
||||
self.context)
|
||||
|
||||
# Replace instances first if launch configuration has changed
|
||||
self._try_rolling_update(prop_diff)
|
||||
|
||||
if (self.DESIRED_CAPACITY in prop_diff and
|
||||
self.properties[self.DESIRED_CAPACITY] is not None):
|
||||
|
||||
self.adjust(self.properties[self.DESIRED_CAPACITY],
|
||||
adjustment_type=EXACT_CAPACITY)
|
||||
else:
|
||||
current_capacity = grouputils.get_size(self)
|
||||
self.adjust(current_capacity, adjustment_type=EXACT_CAPACITY)
|
||||
if self.properties[self.DESIRED_CAPACITY] is not None:
|
||||
self.adjust(self.properties[self.DESIRED_CAPACITY],
|
||||
adjustment_type=EXACT_CAPACITY)
|
||||
else:
|
||||
current_capacity = grouputils.get_size(self)
|
||||
self.adjust(current_capacity, adjustment_type=EXACT_CAPACITY)
|
||||
|
||||
def adjust(self, adjustment, adjustment_type=CHANGE_IN_CAPACITY):
|
||||
"""
|
||||
@ -263,8 +260,9 @@ class AutoScalingGroup(instgrp.InstanceGroup, cooldown.CooldownMixin):
|
||||
|
||||
new_capacity = _calculate_new_capacity(capacity, adjustment,
|
||||
adjustment_type, lower, upper)
|
||||
|
||||
if new_capacity == capacity:
|
||||
total = grouputils.get_size(self, include_failed=True)
|
||||
# if there are failed resources in nested_stack, has to change
|
||||
if new_capacity == total:
|
||||
LOG.debug('no change in capacity %d' % capacity)
|
||||
return
|
||||
|
||||
|
@ -205,19 +205,19 @@ class InstanceGroup(stack_resource.StackResource):
|
||||
self.context)
|
||||
self.update_policy = up
|
||||
|
||||
self.properties = json_snippet.properties(self.properties_schema,
|
||||
self.context)
|
||||
if prop_diff:
|
||||
self.properties = json_snippet.properties(self.properties_schema,
|
||||
self.context)
|
||||
|
||||
# Replace instances first if launch configuration has changed
|
||||
self._try_rolling_update(prop_diff)
|
||||
|
||||
# Get the current capacity, we may need to adjust if
|
||||
# Size has changed
|
||||
if self.SIZE in prop_diff:
|
||||
curr_size = grouputils.get_size(self)
|
||||
if curr_size != self.properties[self.SIZE]:
|
||||
self.resize(self.properties[self.SIZE])
|
||||
# Get the current capacity, we may need to adjust if
|
||||
# Size has changed
|
||||
if self.properties[self.SIZE] is not None:
|
||||
self.resize(self.properties[self.SIZE])
|
||||
else:
|
||||
curr_size = grouputils.get_size(self)
|
||||
self.resize(curr_size)
|
||||
|
||||
def _tags(self):
|
||||
"""
|
||||
|
@ -14,6 +14,7 @@
|
||||
import copy
|
||||
import datetime
|
||||
|
||||
import mock
|
||||
import mox
|
||||
from oslo.config import cfg
|
||||
from oslo.utils import timeutils
|
||||
@ -26,6 +27,7 @@ from heat.common import template_format
|
||||
from heat.engine.notification import autoscaling as notification
|
||||
from heat.engine import parser
|
||||
from heat.engine import resource
|
||||
from heat.engine.resources.aws import autoscaling_group as asg
|
||||
from heat.engine.resources import instance
|
||||
from heat.engine.resources import loadbalancer
|
||||
from heat.engine.resources.neutron import loadbalancer as neutron_lb
|
||||
@ -71,6 +73,16 @@ class AutoScalingTest(common.HeatTestCase):
|
||||
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=self.params)
|
||||
self.defn = rsrc_defn.ResourceDefinition(
|
||||
'asg', 'AWS::AutoScaling::AutoScalingGroup',
|
||||
{'AvailabilityZones': ['nova'],
|
||||
'LaunchConfigurationName': 'config',
|
||||
'MaxSize': 5,
|
||||
'MinSize': 1,
|
||||
'DesiredCapacity': 2})
|
||||
self.asg = asg.AutoScalingGroup('asg', self.defn, stack)
|
||||
|
||||
def create_scaling_group(self, t, stack, resource_name):
|
||||
# create the launch configuration resource
|
||||
@ -490,6 +502,15 @@ class AutoScalingTest(common.HeatTestCase):
|
||||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_update_in_failed(self):
|
||||
self.asg.state_set('CREATE', 'FAILED')
|
||||
# to update the failed asg
|
||||
self.asg.adjust = mock.Mock(return_value=None)
|
||||
|
||||
self.asg.handle_update(self.defn, None, None)
|
||||
self.asg.adjust.assert_called_once_with(
|
||||
2, adjustment_type='ExactCapacity')
|
||||
|
||||
def test_lb_reload_static_resolve(self):
|
||||
t = template_format.parse(as_template)
|
||||
properties = t['Resources']['ElasticLoadBalancer']['Properties']
|
||||
@ -710,7 +731,7 @@ class AutoScalingTest(common.HeatTestCase):
|
||||
up_policy.metadata_get().AndReturn(previous_meta)
|
||||
rsrc.metadata_get().AndReturn(previous_meta)
|
||||
|
||||
#stub for the metadata accesses while creating the two instances
|
||||
# stub for the metadata accesses while creating the two instances
|
||||
resource.Resource.metadata_get()
|
||||
resource.Resource.metadata_get()
|
||||
|
||||
|
@ -33,12 +33,12 @@ class TestInstanceGroup(common.HeatTestCase):
|
||||
super(TestInstanceGroup, self).setUp()
|
||||
t = template_format.parse(inline_templates.as_template)
|
||||
stack = utils.parse_stack(t, params=inline_templates.as_params)
|
||||
defn = rsrc_defn.ResourceDefinition(
|
||||
self.defn = rsrc_defn.ResourceDefinition(
|
||||
'asg', 'OS::Heat::InstanceGroup',
|
||||
{'Size': 2, 'AvailabilityZones': ['zoneb'],
|
||||
'LaunchConfigurationName': 'config'})
|
||||
self.instance_group = instgrp.InstanceGroup('asg',
|
||||
defn, stack)
|
||||
self.defn, stack)
|
||||
|
||||
def test_child_template(self):
|
||||
self.instance_group._create_template = mock.Mock(return_value='tpl')
|
||||
@ -104,6 +104,14 @@ class TestInstanceGroup(common.HeatTestCase):
|
||||
self.instance_group.create_with_template.assert_called_once_with(
|
||||
'{}', expect_env)
|
||||
|
||||
def test_update_in_failed(self):
|
||||
self.instance_group.state_set('CREATE', 'FAILED')
|
||||
# to update the failed instance_group
|
||||
self.instance_group.resize = mock.Mock(return_value=None)
|
||||
|
||||
self.instance_group.handle_update(self.defn, None, None)
|
||||
self.instance_group.resize.assert_called_once_with(2)
|
||||
|
||||
def test_handle_delete(self):
|
||||
self.instance_group.delete_nested = mock.Mock(return_value=None)
|
||||
self.instance_group.handle_delete()
|
||||
@ -112,8 +120,6 @@ class TestInstanceGroup(common.HeatTestCase):
|
||||
def test_handle_update_size(self):
|
||||
self.instance_group._try_rolling_update = mock.Mock(return_value=None)
|
||||
self.instance_group.resize = mock.Mock(return_value=None)
|
||||
get_size = self.patchobject(grouputils, 'get_size')
|
||||
get_size.return_value = 2
|
||||
|
||||
props = {'Size': 5}
|
||||
defn = rsrc_defn.ResourceDefinition(
|
||||
|
Loading…
Reference in New Issue
Block a user