Example #1
0
    def update_task(self, newstack, action=UPDATE, event=None):
        if action not in (self.UPDATE, self.ROLLBACK, self.RESTORE):
            LOG.error(_LE("Unexpected action %s passed to update!"), action)
            self.state_set(self.UPDATE, self.FAILED,
                           "Invalid action %s" % action)
            return

        try:
            lifecycle_plugin_utils.do_pre_ops(self.context, self, newstack,
                                              action)
        except Exception as e:
            self.state_set(
                action, self.FAILED,
                e.args[0] if e.args else 'Failed stack pre-ops: %s' %
                six.text_type(e))
            return
        if self.status == self.IN_PROGRESS:
            if action == self.ROLLBACK:
                LOG.debug("Starting update rollback for %s" % self.name)
            else:
                self.state_set(action, self.FAILED,
                               'State invalid for %s' % action)
                return

        self.state_set(action, self.IN_PROGRESS, 'Stack %s started' % action)

        if action == self.UPDATE:
            # Oldstack is useless when the action is not UPDATE , so we don't
            # need to build it, this can avoid some unexpected errors.
            oldstack = Stack(self.context, self.name, copy.deepcopy(self.t),
                             self.env)
        backup_stack = self._backup_stack()
        try:
            update_task = update.StackUpdate(
                self,
                newstack,
                backup_stack,
                rollback=action == self.ROLLBACK,
                error_wait_time=cfg.CONF.error_wait_time)
            updater = scheduler.TaskRunner(update_task)

            self.env = newstack.env
            self.parameters = newstack.parameters
            self.t.files = newstack.t.files
            self.disable_rollback = newstack.disable_rollback
            self.timeout_mins = newstack.timeout_mins
            self._set_param_stackid()

            try:
                updater.start(timeout=self.timeout_secs())
                yield
                while not updater.step():
                    if event is None or not event.ready():
                        yield
                    else:
                        message = event.wait()
                        if message == rpc_api.THREAD_CANCEL:
                            raise ForcedCancel()
            finally:
                self.reset_dependencies()

            if action == self.UPDATE:
                reason = 'Stack successfully updated'
            elif action == self.RESTORE:
                reason = 'Stack successfully restored'
            else:
                reason = 'Stack rollback completed'
            stack_status = self.COMPLETE

        except scheduler.Timeout:
            stack_status = self.FAILED
            reason = 'Timed out'
        except ForcedCancel as e:
            reason = six.text_type(e)

            stack_status = self.FAILED
            if action == self.UPDATE:
                update_task.updater.cancel_all()
                yield self.update_task(oldstack, action=self.ROLLBACK)
                return

        except exception.ResourceFailure as e:
            reason = six.text_type(e)

            stack_status = self.FAILED
            if action == self.UPDATE:
                # If rollback is enabled, we do another update, with the
                # existing template, so we roll back to the original state
                if not self.disable_rollback:
                    yield self.update_task(oldstack, action=self.ROLLBACK)
                    return
        else:
            LOG.debug('Deleting backup stack')
            backup_stack.delete(backup=True)

            # flip the template to the newstack values
            self.t = newstack.t
            template_outputs = self.t[self.t.OUTPUTS]
            self.outputs = self.resolve_static_data(template_outputs)

        # Don't use state_set to do only one update query and avoid race
        # condition with the COMPLETE status
        self.action = action
        self.status = stack_status
        self.status_reason = reason

        self.store()
        lifecycle_plugin_utils.do_post_ops(self.context, self, newstack,
                                           action,
                                           (self.status == self.FAILED))

        notification.send(self)
Example #2
0
    def update_task(self, newstack, action=UPDATE):
        if action not in (self.UPDATE, self.ROLLBACK):
            logger.error(_("Unexpected action %s passed to update!") % action)
            self.state_set(self.UPDATE, self.FAILED,
                           "Invalid action %s" % action)
            return

        if self.status != self.COMPLETE:
            if (action == self.ROLLBACK
                    and self.state == (self.UPDATE, self.IN_PROGRESS)):
                logger.debug(_("Starting update rollback for %s") % self.name)
            else:
                self.state_set(action, self.FAILED,
                               'State invalid for %s' % action)
                return

        self.state_set(self.UPDATE, self.IN_PROGRESS,
                       'Stack %s started' % action)

        oldstack = Stack(self.context, self.name, self.t, self.env)
        backup_stack = self._backup_stack()
        try:
            update_task = update.StackUpdate(self,
                                             newstack,
                                             backup_stack,
                                             rollback=action == self.ROLLBACK)
            updater = scheduler.TaskRunner(update_task)

            self.env = newstack.env
            self.parameters = newstack.parameters
            self.t.files = newstack.t.files
            self._set_param_stackid()

            try:
                updater.start(timeout=self.timeout_secs())
                yield
                while not updater.step():
                    yield
            finally:
                self.reset_dependencies()

            if action == self.UPDATE:
                reason = 'Stack successfully updated'
            else:
                reason = 'Stack rollback completed'
            stack_status = self.COMPLETE

        except scheduler.Timeout:
            stack_status = self.FAILED
            reason = 'Timed out'
        except exception.ResourceFailure as e:
            reason = str(e)

            stack_status = self.FAILED
            if action == self.UPDATE:
                # If rollback is enabled, we do another update, with the
                # existing template, so we roll back to the original state
                if not self.disable_rollback:
                    yield self.update_task(oldstack, action=self.ROLLBACK)
                    return
        else:
            logger.debug(_('Deleting backup stack'))
            backup_stack.delete(backup=True)

        self.state_set(action, stack_status, reason)

        # flip the template to the newstack values
        # Note we do this on success and failure, so the current
        # stack resources are stored, even if one is in a failed
        # state (otherwise we won't remove them on delete)
        self.t = newstack.t
        template_outputs = self.t[self.t.OUTPUTS]
        self.outputs = self.resolve_static_data(template_outputs)
        self.store()
Example #3
0
    def update_task(self, newstack, action=UPDATE):
        if action not in (self.UPDATE, self.ROLLBACK):
            LOG.error(_("Unexpected action %s passed to update!") % action)
            self.state_set(self.UPDATE, self.FAILED,
                           "Invalid action %s" % action)
            return

        if self.status != self.COMPLETE:
            if (action == self.ROLLBACK
                    and self.state == (self.UPDATE, self.IN_PROGRESS)):
                LOG.debug("Starting update rollback for %s" % self.name)
            else:
                self.state_set(action, self.FAILED,
                               'State invalid for %s' % action)
                return

        self.state_set(action, self.IN_PROGRESS, 'Stack %s started' % action)

        oldstack = Stack(self.context, self.name, copy.deepcopy(self.t),
                         self.env)
        backup_stack = self._backup_stack()
        try:
            update_task = update.StackUpdate(self,
                                             newstack,
                                             backup_stack,
                                             rollback=action == self.ROLLBACK)
            updater = scheduler.TaskRunner(update_task)

            self.env = newstack.env
            self.parameters = newstack.parameters
            self.t.files = newstack.t.files
            self.disable_rollback = newstack.disable_rollback
            self.timeout_mins = newstack.timeout_mins
            self._set_param_stackid()

            try:
                updater.start(timeout=self.timeout_secs())
                yield
                while not updater.step():
                    yield
            finally:
                self.reset_dependencies()

            if action == self.UPDATE:
                reason = 'Stack successfully updated'
            else:
                reason = 'Stack rollback completed'
            stack_status = self.COMPLETE

        except scheduler.Timeout:
            stack_status = self.FAILED
            reason = 'Timed out'
        except exception.ResourceFailure as e:
            reason = six.text_type(e)

            stack_status = self.FAILED
            if action == self.UPDATE:
                # If rollback is enabled, we do another update, with the
                # existing template, so we roll back to the original state
                if not self.disable_rollback:
                    yield self.update_task(oldstack, action=self.ROLLBACK)
                    return
        else:
            LOG.debug('Deleting backup stack')
            backup_stack.delete(backup=True)

            # flip the template to the newstack values
            self.t = newstack.t
            template_outputs = self.t[self.t.OUTPUTS]
            self.outputs = self.resolve_static_data(template_outputs)

        # Don't use state_set to do only one update query and avoid race
        # condition with the COMPLETE status
        self.action = action
        self.status = stack_status
        self.status_reason = reason

        self.store()

        notification.send(self)
Example #4
0
    def update(self, newstack, action=UPDATE):
        '''
        Compare the current stack with newstack,
        and where necessary create/update/delete the resources until
        this stack aligns with newstack.

        Note update of existing stack resources depends on update
        being implemented in the underlying resource types

        Update will fail if it exceeds the specified timeout. The default is
        60 minutes, set in the constructor
        '''
        if action not in (self.UPDATE, self.ROLLBACK):
            logger.error("Unexpected action %s passed to update!" % action)
            self.state_set(self.UPDATE, self.FAILED,
                           "Invalid action %s" % action)
            return

        if self.status != self.COMPLETE:
            if (action == self.ROLLBACK
                    and self.state == (self.UPDATE, self.IN_PROGRESS)):
                logger.debug("Starting update rollback for %s" % self.name)
            else:
                self.state_set(action, self.FAILED,
                               'State invalid for %s' % action)
                return

        self.state_set(self.UPDATE, self.IN_PROGRESS,
                       'Stack %s started' % action)

        oldstack = Stack(self.context, self.name, self.t, self.env)
        try:
            update_task = update.StackUpdate(self, newstack, oldstack)
            updater = scheduler.TaskRunner(update_task)

            self.env = newstack.env
            self.parameters = newstack.parameters

            try:
                updater(timeout=self.timeout_secs())
            finally:
                cur_deps = self._get_dependencies(self.resources.itervalues())
                self.dependencies = cur_deps

            if action == self.UPDATE:
                reason = 'Stack successfully updated'
            else:
                reason = 'Stack rollback completed'
            stack_status = self.COMPLETE

        except scheduler.Timeout:
            stack_status = self.FAILED
            reason = 'Timed out'
        except exception.ResourceFailure as e:
            reason = str(e)

            stack_status = self.FAILED
            if action == self.UPDATE:
                # If rollback is enabled, we do another update, with the
                # existing template, so we roll back to the original state
                if not self.disable_rollback:
                    self.update(oldstack, action=self.ROLLBACK)
                    return

        self.state_set(action, stack_status, reason)

        # flip the template to the newstack values
        # Note we do this on success and failure, so the current
        # stack resources are stored, even if one is in a failed
        # state (otherwise we won't remove them on delete)
        self.t = newstack.t
        template_outputs = self.t[template.OUTPUTS]
        self.outputs = self.resolve_static_data(template_outputs)
        self.store()