Handles the creating or updating of a stack in CloudFormation.

        Also makes sure that we don't try to create or update a stack while
        it is already updating or creating.

def _launch_stack(self, stack, **kwargs):
        """Handles the creating or updating of a stack in CloudFormation.

        Also makes sure that we don't try to create or update a stack while
        it is already updating or creating.

        """
        old_status = kwargs.get("status")
        wait_time = 0 if old_status is PENDING else STACK_POLL_TIME
        if self.cancel.wait(wait_time):
            return INTERRUPTED

        if not should_submit(stack):
            return NotSubmittedStatus()

        provider = self.build_provider(stack)

        try:
            provider_stack = provider.get_stack(stack.fqn)
        except StackDoesNotExist:
            provider_stack = None

        if provider_stack and not should_update(stack):
            stack.set_outputs(
                self.provider.get_output_dict(provider_stack))
            return NotUpdatedStatus()

        recreate = False
        if provider_stack and old_status == SUBMITTED:
            logger.debug(
                "Stack %s provider status: %s",
                stack.fqn,
                provider.get_stack_status(provider_stack),
            )

            if provider.is_stack_rolling_back(provider_stack):
                if 'rolling back' in old_status.reason:
                    return old_status

                logger.debug("Stack %s entered a roll back", stack.fqn)
                if 'updating' in old_status.reason:
                    reason = 'rolling back update'
                else:
                    reason = 'rolling back new stack'

                return SubmittedStatus(reason)
            elif provider.is_stack_in_progress(provider_stack):
                logger.debug("Stack %s in progress.", stack.fqn)
                return old_status
            elif provider.is_stack_destroyed(provider_stack):
                logger.debug("Stack %s finished deleting", stack.fqn)
                recreate = True
                # Continue with creation afterwards
            # Failure must be checked *before* completion, as both will be true
            # when completing a rollback, and we don't want to consider it as
            # a successful update.
            elif provider.is_stack_failed(provider_stack):
                reason = old_status.reason
                if 'rolling' in reason:
                    reason = reason.replace('rolling', 'rolled')
                status_reason = provider.get_rollback_status_reason(stack.fqn)
                logger.info(
                    "%s Stack Roll Back Reason: " + status_reason, stack.fqn)
                return FailedStatus(reason)

            elif provider.is_stack_completed(provider_stack):
                stack.set_outputs(
                    provider.get_output_dict(provider_stack))
                return CompleteStatus(old_status.reason)
            else:
                return old_status

        logger.debug("Resolving stack %s", stack.fqn)
        stack.resolve(self.context, self.provider)

        logger.debug("Launching stack %s now.", stack.fqn)
        template = self._template(stack.blueprint)
        stack_policy = self._stack_policy(stack)
        tags = build_stack_tags(stack)
        parameters = self.build_parameters(stack, provider_stack)
        force_change_set = stack.blueprint.requires_change_set

        if recreate:
            logger.debug("Re-creating stack: %s", stack.fqn)
            provider.create_stack(stack.fqn, template, parameters,
                                  tags, stack_policy=stack_policy)
            return SubmittedStatus("re-creating stack")
        elif not provider_stack:
            logger.debug("Creating new stack: %s", stack.fqn)
            provider.create_stack(stack.fqn, template, parameters, tags,
                                  force_change_set,
                                  stack_policy=stack_policy)
            return SubmittedStatus("creating new stack")

        try:
            wait = stack.in_progress_behavior == "wait"
            if wait and provider.is_stack_in_progress(provider_stack):
                return WAITING
            if provider.prepare_stack_for_update(provider_stack, tags):
                existing_params = provider_stack.get('Parameters', [])
                provider.update_stack(
                    stack.fqn,
                    template,
                    existing_params,
                    parameters,
                    tags,
                    force_interactive=stack.protected,
                    force_change_set=force_change_set,
                    stack_policy=stack_policy,
                )

                logger.debug("Updating existing stack: %s", stack.fqn)
                return SubmittedStatus("updating existing stack")
            else:
                return SubmittedStatus("destroying stack for re-creation")
        except CancelExecution:
            stack.set_outputs(provider.get_output_dict(provider_stack))
            return SkippedStatus(reason="canceled execution")
        except StackDidNotChange:
            stack.set_outputs(provider.get_output_dict(provider_stack))
            return DidNotChangeStatus()