def test_retry_false(self): """Tests correct behavior when retry is passed as false.""" seq = [ (self.update_call.intent, lambda _: (StubResponse(202, ''), None)), (Log('request-update-stack', ANY), lambda _: None) ] update = UpdateStack(stack=self.stack, stack_config=self.config, retry=False) result = perform_sequence(seq, update.as_effect()) self.assertEqual(result, (StepResult.SUCCESS, []))
def test_retry_default(self): """Tests correct behavior when retry is not specified.""" seq = [ (self.update_call.intent, lambda _: (StubResponse(202, ''), None)), (Log('request-update-stack', ANY), lambda _: None) ] update = UpdateStack(stack=self.stack, stack_config=self.config) reason = 'Waiting for stack to update' result = perform_sequence(seq, update.as_effect()) self.assertEqual(result, (StepResult.RETRY, [ErrorReason.String(reason)]))
def get_fix_steps(scale_down_steps): num_stacks_to_update = len(stacks_check_failed) - len(scale_down_steps) stacks_to_update = (stacks_check_failed[:num_stacks_to_update] if num_stacks_to_update > 0 else []) return [UpdateStack(stack=s, stack_config=config) for s in stacks_to_update]
def converge_launch_stack(desired_state, stacks): """ Create steps that indicate how to transition from the state provided by the given parameters to the :obj:`DesiredStackGroupState` described by ``desired_state``. See note [Converging stacks] for more information. :param DesiredStackGroupState desired_state: The desired group state. :param set stacks: a set of :obj:`HeatStack` instances. This must only contain stacks that are being managed for the specified group. :rtype: :obj:`pbag` of `IStep` """ config = desired_state.stack_config by_state = groupby(lambda stack: stack.get_state(), stacks) stacks_complete = by_state.get(StackState.CREATE_UPDATE_COMPLETE, []) stacks_failed = by_state.get(StackState.CREATE_UPDATE_FAILED, []) stacks_check_complete = by_state.get(StackState.CHECK_COMPLETE, []) stacks_check_failed = by_state.get(StackState.CHECK_FAILED, []) stacks_in_progress = by_state.get(StackState.IN_PROGRESS, []) stacks_delete_in_progress = by_state.get(StackState.DELETE_IN_PROGRESS, []) stacks_delete_failed = by_state.get(StackState.DELETE_FAILED, []) stacks_good = stacks_complete + stacks_check_complete stacks_amiss = (stacks_failed + stacks_check_failed + stacks_in_progress + stacks_delete_in_progress) if stacks_delete_failed: reasons = [ErrorReason.String("Stacks in DELETE_FAILED found.")] return pbag([FailConvergence(reasons)]) # If there are no stacks in CHECK_* or other work to be done, we assume # we're at the beginning of a convergence cycle and need to perform stack # checks. if stacks_complete and not (stacks_check_complete or stacks_amiss): return pbag([CheckStack(stack) for stack in stacks_complete]) # Otherwise, if all stacks are in a good state and we have the right number # of stacks, we call update on the stacks in CHECK_COMPLETE and return # SUCCESS without waiting for it to finish (calling update on a stack in # CREATE_COMPLETE is essentially a no-op) so that there will be no stacks # in CREATE_* the next time otter tries to converge this group. This will # cause all of the stacks to be checked at that time and let otter know # if there are any stacks that have fallen into an error state. elif not stacks_amiss and len(stacks_good) == desired_state.capacity: return pbag([UpdateStack(stack=stack, stack_config=config, retry=False) for stack in stacks_check_complete]) def get_create_steps(): create_stack = CreateStack(stack_config=config) good_or_fixable_stack_count = (len(stacks_good) + len(stacks_in_progress) + len(stacks_check_failed)) return [create_stack] * (desired_state.capacity - good_or_fixable_stack_count) def get_scale_down_steps(): stacks_in_preferred_order = ( stacks_good + stacks_in_progress + stacks_check_failed) unneeded_stacks = stacks_in_preferred_order[desired_state.capacity:] return map(DeleteStack, unneeded_stacks) def get_fix_steps(scale_down_steps): num_stacks_to_update = len(stacks_check_failed) - len(scale_down_steps) stacks_to_update = (stacks_check_failed[:num_stacks_to_update] if num_stacks_to_update > 0 else []) return [UpdateStack(stack=s, stack_config=config) for s in stacks_to_update] create_steps = get_create_steps() scale_down_steps = get_scale_down_steps() fix_steps = get_fix_steps(scale_down_steps) delete_stacks_failed_steps = map(DeleteStack, stacks_failed) converge_later = ( [ConvergeLater([ErrorReason.String("Waiting for stacks to finish.")])] if stacks_delete_in_progress or stacks_in_progress else []) return pbag(create_steps + fix_steps + scale_down_steps + delete_stacks_failed_steps + converge_later)
def test_normal_use(self): """Tests normal usage.""" update = UpdateStack(stack=self.stack, stack_config=self.config) self.assertEqual(update.as_effect().intent, self.update_call.intent)