Add rolling update for SDG
This patch adds rolling_update/batch_create support for SoftwareDeploymentGroup. Change-Id: I336e66b62a7beddb306b8a61af26e12759e1b490
This commit is contained in:
parent
0272577c9e
commit
5465579bdf
|
@ -390,6 +390,9 @@ class ResourceGroup(stack_resource.StackResource):
|
|||
return False
|
||||
return True
|
||||
|
||||
def res_def_changed(self, prop_diff):
|
||||
return self.RESOURCE_DEF in prop_diff
|
||||
|
||||
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
||||
if tmpl_diff:
|
||||
# parse update policy
|
||||
|
@ -401,7 +404,7 @@ class ResourceGroup(stack_resource.StackResource):
|
|||
checkers = []
|
||||
self.properties = json_snippet.properties(self.properties_schema,
|
||||
self.context)
|
||||
if prop_diff and self.RESOURCE_DEF in prop_diff:
|
||||
if prop_diff and self.res_def_changed(prop_diff):
|
||||
updaters = self._try_rolling_update()
|
||||
if updaters:
|
||||
checkers.extend(updaters)
|
||||
|
|
|
@ -17,6 +17,7 @@ import uuid
|
|||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import timeutils
|
||||
from six import itertools
|
||||
|
||||
from heat.common import exception
|
||||
from heat.common.i18n import _
|
||||
|
@ -574,6 +575,14 @@ class SoftwareDeploymentGroup(resource_group.ResourceGroup):
|
|||
'deploy_stdouts', 'deploy_stderrs', 'deploy_status_codes'
|
||||
)
|
||||
|
||||
_ROLLING_UPDATES_SCHEMA_KEYS = (
|
||||
MAX_BATCH_SIZE,
|
||||
PAUSE_TIME,
|
||||
) = (
|
||||
resource_group.ResourceGroup.MAX_BATCH_SIZE,
|
||||
resource_group.ResourceGroup.PAUSE_TIME,
|
||||
)
|
||||
|
||||
_sd_ps = SoftwareDeployment.properties_schema
|
||||
_rg_ps = resource_group.ResourceGroup.properties_schema
|
||||
|
||||
|
@ -611,13 +620,34 @@ class SoftwareDeploymentGroup(resource_group.ResourceGroup):
|
|||
),
|
||||
}
|
||||
|
||||
update_policy_schema = {}
|
||||
rolling_update_schema = {
|
||||
MAX_BATCH_SIZE: properties.Schema(
|
||||
properties.Schema.INTEGER,
|
||||
_('The maximum number of deployments to replace at once.'),
|
||||
constraints=[constraints.Range(min=1)],
|
||||
default=1),
|
||||
PAUSE_TIME: properties.Schema(
|
||||
properties.Schema.NUMBER,
|
||||
_('The number of seconds to wait between batches of '
|
||||
'updates.'),
|
||||
constraints=[constraints.Range(min=0)],
|
||||
default=0),
|
||||
}
|
||||
|
||||
def get_size(self):
|
||||
return len(self.properties[self.SERVERS])
|
||||
|
||||
def _resource_names(self):
|
||||
return iter(self.properties[self.SERVERS])
|
||||
def _resource_names(self, size=None):
|
||||
candidates = self.properties[self.SERVERS]
|
||||
if size is None:
|
||||
return iter(candidates)
|
||||
return itertools.islice(candidates, size)
|
||||
|
||||
def res_def_changed(self, prop_diff):
|
||||
return True
|
||||
|
||||
def _name_blacklist(self):
|
||||
return set()
|
||||
|
||||
def get_resource_def(self, include_all=False):
|
||||
return dict(self.properties)
|
||||
|
@ -646,6 +676,13 @@ class SoftwareDeploymentGroup(resource_group.ResourceGroup):
|
|||
rg_attr = rg.get_attribute(rg.ATTR_ATTRIBUTES, n_attr)
|
||||
return attributes.select_from_attribute(rg_attr, path)
|
||||
|
||||
def _try_rolling_update(self):
|
||||
if self.update_policy[self.ROLLING_UPDATE]:
|
||||
policy = self.update_policy[self.ROLLING_UPDATE]
|
||||
return self._replace(0,
|
||||
policy[self.MAX_BATCH_SIZE],
|
||||
policy[self.PAUSE_TIME])
|
||||
|
||||
|
||||
class SoftwareDeployments(SoftwareDeploymentGroup):
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ from oslo_serialization import jsonutils
|
|||
|
||||
from heat.common import exception as exc
|
||||
from heat.common.i18n import _
|
||||
from heat.common import template_format
|
||||
from heat.engine.clients.os import nova
|
||||
from heat.engine.clients.os import swift
|
||||
from heat.engine.clients.os import zaqar
|
||||
|
@ -1488,3 +1489,79 @@ class SoftwareDeploymentGroupTest(common.HeatTestCase):
|
|||
snip = stack.t.resource_definitions(stack)['deploy_mysql']
|
||||
resg = sd.SoftwareDeploymentGroup('deploy_mysql', snip, stack)
|
||||
self.assertIsNone(resg.validate())
|
||||
|
||||
|
||||
class SDGReplaceTest(common.HeatTestCase):
|
||||
template = {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'resources': {
|
||||
'deploy_mysql': {
|
||||
'type': 'OS::Heat::SoftwareDeploymentGroup',
|
||||
'properties': {
|
||||
'config': 'config_uuid',
|
||||
'servers': {'server1': 'uuid1', 'server2': 'uuid2'},
|
||||
'input_values': {'foo': 'bar'},
|
||||
'name': '10_config'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 1. existing > batch_size
|
||||
# 2. existing < batch_size
|
||||
# 3. count > existing
|
||||
# 4. count < exiting
|
||||
# 5. with pause_sec
|
||||
|
||||
scenarios = [
|
||||
('1', dict(count=2,
|
||||
existing=['0', '1'], batch_size=1,
|
||||
pause_sec=0, tasks=2)),
|
||||
('2', dict(count=4,
|
||||
existing=['0', '1'], batch_size=3,
|
||||
pause_sec=0, tasks=2)),
|
||||
('3', dict(count=3,
|
||||
existing=['0', '1'], batch_size=2,
|
||||
pause_sec=0, tasks=2)),
|
||||
('4', dict(count=2,
|
||||
existing=['0', '1', '2'], batch_size=2,
|
||||
pause_sec=0, tasks=1)),
|
||||
('5', dict(count=2,
|
||||
existing=['0', '1'], batch_size=1,
|
||||
pause_sec=1, tasks=3))]
|
||||
|
||||
def get_fake_nested_stack(self, names):
|
||||
nested_t = '''
|
||||
heat_template_version: 2015-04-30
|
||||
description: Resource Group
|
||||
resources:
|
||||
'''
|
||||
resource_snip = '''
|
||||
'%s':
|
||||
type: SoftwareDeployment
|
||||
properties:
|
||||
foo: bar
|
||||
'''
|
||||
resources = [nested_t]
|
||||
for res_name in names:
|
||||
resources.extend([resource_snip % res_name])
|
||||
|
||||
nested_t = ''.join(resources)
|
||||
return utils.parse_stack(template_format.parse(nested_t))
|
||||
|
||||
def setUp(self):
|
||||
super(SDGReplaceTest, self).setUp()
|
||||
self.stack = utils.parse_stack(self.template)
|
||||
snip = self.stack.t.resource_definitions(self.stack)['deploy_mysql']
|
||||
self.group = sd.SoftwareDeploymentGroup('deploy_mysql',
|
||||
snip, self.stack)
|
||||
self.group.update_with_template = mock.Mock()
|
||||
self.group.check_update_complete = mock.Mock()
|
||||
|
||||
def test_rolling_updates(self):
|
||||
self.group._nested = self.get_fake_nested_stack(self.existing)
|
||||
self.group.get_size = mock.Mock(return_value=self.count)
|
||||
tasks = self.group._replace(0, self.batch_size,
|
||||
self.pause_sec)
|
||||
self.assertEqual(self.tasks,
|
||||
len(tasks))
|
||||
|
|
Loading…
Reference in New Issue