def _assemble_for_rolling_update( self, total_capacity, max_updates, include_all=False, template_version=("heat_template_version", "2015-04-30") ): names = list(self._resource_names(total_capacity)) name_blacklist = self._name_blacklist() valid_resources = [(n, d) for n, d in grouputils.get_member_definitions(self) if n not in name_blacklist] targ_cap = self.get_size() def replace_priority(res_item): name, defn = res_item try: index = names.index(name) except ValueError: # High priority - delete immediately return 0 else: if index < targ_cap: # Update higher indices first return targ_cap - index else: # Low priority - don't update return total_capacity old_resources = sorted(valid_resources, key=replace_priority) existing_names = set(n for n, d in valid_resources) new_names = six.moves.filterfalse(lambda n: n in existing_names, names) res_def = self.get_resource_def(include_all) definitions = scl_template.member_definitions( old_resources, res_def, total_capacity, max_updates, lambda: next(new_names), self.build_resource_definition ) return scl_template.make_template(definitions, version=template_version)
def _create_template(self, num_instances, num_replace=0, template_version=('HeatTemplateFormatVersion', '2012-12-12')): """ Create a template to represent autoscaled instances. Also see heat.scaling.template.member_definitions. """ instance_definition = self._get_resource_definition() old_resources = self._get_instance_templates() definitions = template.member_definitions(old_resources, instance_definition, num_instances, num_replace, short_id.generate_id) child_env = environment.get_child_environment( self.stack.env, self.child_params(), item_to_remove=self.resource_info) return template.make_template(definitions, version=template_version, child_env=child_env)
def _create_template(self, num_instances, num_replace=0, template_version=('HeatTemplateFormatVersion', '2012-12-12')): """Create a template to represent autoscaled instances. Also see heat.scaling.template.member_definitions. """ instance_definition = self._get_resource_definition() old_resources = grouputils.get_member_definitions(self, include_failed=True) definitions = list(template.member_definitions( old_resources, instance_definition, num_instances, num_replace, short_id.generate_id)) child_env = environment.get_child_environment( self.stack.env, self.child_params(), item_to_remove=self.resource_info) tmpl = template.make_template(definitions, version=template_version, child_env=child_env) # Subclasses use HOT templates att_func, res_func = 'get_attr', 'get_resource' if att_func not in tmpl.functions or res_func not in tmpl.functions: att_func, res_func = 'Fn::GetAtt', 'Ref' get_attr = functools.partial(tmpl.functions[att_func], None, att_func) get_res = functools.partial(tmpl.functions[res_func], None, res_func) for odefn in self._nested_output_defns([k for k, d in definitions], get_attr, get_res): tmpl.add_output(odefn) return tmpl
def _create_template(self, num_instances, num_replace=0, template_version=('HeatTemplateFormatVersion', '2012-12-12')): """Create a template to represent autoscaled instances. Also see heat.scaling.template.member_definitions. """ instance_definition = self._get_resource_definition() old_resources = grouputils.get_member_definitions(self, include_failed=True) definitions = list(template.member_definitions( old_resources, instance_definition, num_instances, num_replace, short_id.generate_id)) child_env = environment.get_child_environment( self.stack.env, self.child_params(), item_to_remove=self.resource_info) tmpl = template.make_template(definitions, version=template_version, child_env=child_env) # Subclasses use HOT templates att_func = 'get_attr' if att_func not in tmpl.functions: att_func = 'Fn::GetAtt' get_attr = functools.partial(tmpl.functions[att_func], None, att_func) for odefn in self._nested_output_defns([k for k, d in definitions], get_attr): tmpl.add_output(odefn) return tmpl
def test_create_template(self): """ When creating a template from scratch, an empty list is accepted as the "old" resources and new resources are created up to num_resource. """ templates = template.member_definitions([], {'type': 'Foo'}, 2, 0, self.next_id) expected = [ ('stubbed-id-0', {'type': 'Foo'}), ('stubbed-id-1', {'type': 'Foo'})] self.assertEqual(expected, list(templates))
def test_replace_template(self): """ If num_replace is the number of old resources, then all of the resources will be replaced. """ old_resources = [ ('old-id-0', {'type': 'Foo'}), ('old-id-1', {'type': 'Foo'})] templates = template.member_definitions(old_resources, {'type': 'Bar'}, 1, 2, self.next_id) expected = [('old-id-1', {'type': 'Bar'})] self.assertEqual(expected, list(templates))
def test_replace_some_units(self): """ If the resource definition changes, only the number of replacements specified will be made; beyond that, the original templates are used. """ old_resources = [ ('old-id-0', {'type': 'Foo'}), ('old-id-1', {'type': 'Foo'})] new_spec = {'type': 'Bar'} templates = template.member_definitions(old_resources, new_spec, 2, 1, self.next_id) expected = [ ('old-id-0', {'type': 'Bar'}), ('old-id-1', {'type': 'Foo'})] self.assertEqual(expected, list(templates))
def test_replace_units_some_already_up_to_date(self): """ If some of the old resources already have the new resource definition, then they won't be considered for replacement, and the next resource that is out-of-date will be replaced. """ old_resources = [ ('old-id-0', {'type': 'Bar'}), ('old-id-1', {'type': 'Foo'})] new_spec = {'type': 'Bar'} templates = template.member_definitions(old_resources, new_spec, 2, 1, self.next_id) second_batch_expected = [ ('old-id-0', {'type': 'Bar'}), ('old-id-1', {'type': 'Bar'})] self.assertEqual(second_batch_expected, list(templates))
def _create_template( self, num_instances, num_replace=0, template_version=("HeatTemplateFormatVersion", "2012-12-12") ): """Create a template to represent autoscaled instances. Also see heat.scaling.template.member_definitions. """ instance_definition = self._get_resource_definition() old_resources = grouputils.get_member_definitions(self, include_failed=True) definitions = template.member_definitions( old_resources, instance_definition, num_instances, num_replace, short_id.generate_id ) child_env = environment.get_child_environment( self.stack.env, self.child_params(), item_to_remove=self.resource_info ) return template.make_template(definitions, version=template_version, child_env=child_env)
def _assemble_for_rolling_update(self, total_capacity, max_updates, include_all=False, template_version=('heat_template_version', '2015-04-30')): names = list(self._resource_names(total_capacity)) name_blacklist = self._name_blacklist() valid_resources = [(n, d) for n, d in grouputils.get_member_definitions(self) if n not in name_blacklist] targ_cap = self.get_size() def replace_priority(res_item): name, defn = res_item try: index = names.index(name) except ValueError: # High priority - delete immediately return 0 else: if index < targ_cap: # Update higher indices first return targ_cap - index else: # Low priority - don't update return total_capacity old_resources = sorted(valid_resources, key=replace_priority) existing_names = set(n for n, d in valid_resources) new_names = six.moves.filterfalse(lambda n: n in existing_names, names) res_def = self.get_resource_def(include_all) definitions = scl_template.member_definitions( old_resources, res_def, total_capacity, max_updates, lambda: next(new_names), self.build_resource_definition) tmpl = scl_template.make_template(definitions, version=template_version) self._add_output_defns_to_template(tmpl, names) return tmpl
def test_growth_counts_as_replacement(self): """ If we grow the template and replace some elements at the same time, the number of replacements to perform is reduced by the number of new resources to be created. """ spec = {'type': 'Foo'} old_resources = [ ('old-id-0', spec), ('old-id-1', spec)] new_spec = {'type': 'Bar'} templates = template.member_definitions(old_resources, new_spec, 4, 2, self.next_id) expected = [ ('old-id-0', spec), ('old-id-1', spec), ('stubbed-id-0', new_spec), ('stubbed-id-1', new_spec)] self.assertEqual(expected, list(templates))
def _create_template(self, num_instances, num_replace=0, template_version=('HeatTemplateFormatVersion', '2012-12-12')): """Create a template to represent autoscaled instances. Also see heat.scaling.template.member_definitions. """ instance_definition = self._get_resource_definition() old_resources = grouputils.get_member_definitions(self, include_failed=True) # WRS: Detect a scale down. Issue a vote # If any vote is rejected, set new_resources to be same size as old existing = grouputils.get_members(self) if num_instances < len(existing): LOG.info("WRS downscale detected, vote initiated") for i in range(num_instances, len(existing)): if existing[i].wrs_vote() is False: LOG.info("WRS downscale blocked by vote") num_instances = len(existing) break definitions = list(template.member_definitions( old_resources, instance_definition, num_instances, num_replace, short_id.generate_id, delete_oldest=False)) child_env = environment.get_child_environment( self.stack.env, self.child_params(), item_to_remove=self.resource_info) tmpl = template.make_template(definitions, version=template_version, child_env=child_env) # Subclasses use HOT templates att_func = 'get_attr' if att_func not in tmpl.functions: att_func = 'Fn::GetAtt' get_attr = functools.partial(tmpl.functions[att_func], None, att_func) for odefn in self._nested_output_defns([k for k, d in definitions], get_attr): tmpl.add_output(odefn) return tmpl
def _assemble_for_rolling_update(self, total_capacity, max_updates, include_all=False): names = list(self._resource_names(total_capacity)) name_blacklist = self._name_blacklist() valid_resources = [(n, d) for n, d in self._get_resources() if n not in name_blacklist] targ_cap = self.get_size() def replace_priority(res_item): name, defn = res_item try: index = names.index(name) except ValueError: # High priority - delete immediately return 0 else: if index < targ_cap: # Update higher indices first return targ_cap - index else: # Low priority - don't update return total_capacity old_resources = sorted(valid_resources, key=replace_priority) existing_names = set(n for n, d in valid_resources) new_names = six.moves.filterfalse(lambda n: n in existing_names, names) res_def = self._build_resource_definition(include_all) resources = scale_template.member_definitions(old_resources, res_def, total_capacity, max_updates, lambda: next(new_names), self._do_prop_replace) child_template = copy.deepcopy(template_template) child_template['resources'] = dict(resources) return child_template
def _assemble_for_rolling_update(self, total_capacity, max_updates, include_all=False): names = list(self._resource_names(total_capacity)) name_blacklist = self._name_blacklist() valid_resources = [(n, d) for n, d in self._get_resources() if n not in name_blacklist] num_creating = max(total_capacity - len(valid_resources), 0) new_names = iter(names[total_capacity - num_creating:]) targ_cap = self.get_size() def replace_priority(res_item): name, defn = res_item try: index = names.index(name) except ValueError: # High priority - delete immediately return 0 else: if index < targ_cap: # Update higher indices first return targ_cap - index else: # Low priority - don't update return total_capacity old_resources = sorted(valid_resources, key=replace_priority) res_def = self._build_resource_definition(include_all) resources = scale_template.member_definitions(old_resources, res_def, total_capacity, max_updates, lambda: next(new_names), self._do_prop_replace) child_template = copy.deepcopy(template_template) child_template['resources'] = dict(resources) return child_template