Exemple #1
0
    def _delete_credentials(self, stack_status, reason, abandon):
        # Cleanup stored user_creds so they aren't accessible via
        # the soft-deleted stack which remains in the DB
        # The stack_status and reason passed in are current values, which
        # may get rewritten and returned from this method
        if self.user_creds_id:
            user_creds = db_api.user_creds_get(self.user_creds_id)
            # If we created a trust, delete it
            if user_creds is not None:
                trust_id = user_creds.get('trust_id')
                if trust_id:
                    try:
                        # If the trustor doesn't match the context user the
                        # we have to use the stored context to cleanup the
                        # trust, as although the user evidently has
                        # permission to delete the stack, they don't have
                        # rights to delete the trust unless an admin
                        trustor_id = user_creds.get('trustor_user_id')
                        if self.context.user_id != trustor_id:
                            LOG.debug('Context user_id doesn\'t match '
                                      'trustor, using stored context')
                            sc = self.stored_context()
                            sc.clients.client('keystone').delete_trust(
                                trust_id)
                        else:
                            self.clients.client('keystone').delete_trust(
                                trust_id)
                    except Exception as ex:
                        LOG.exception(ex)
                        stack_status = self.FAILED
                        reason = ("Error deleting trust: %s" %
                                  six.text_type(ex))

            # Delete the stored credentials
            try:
                db_api.user_creds_delete(self.context, self.user_creds_id)
            except exception.NotFound:
                LOG.info(_LI("Tried to delete user_creds that do not exist "
                             "(stack=%(stack)s user_creds_id=%(uc)s)"),
                         {'stack': self.id, 'uc': self.user_creds_id})

            try:
                self.user_creds_id = None
                self.store()
            except exception.NotFound:
                LOG.info(_LI("Tried to store a stack that does not exist %s"),
                         self.id)

        # If the stack has a domain project, delete it
        if self.stack_user_project_id and not abandon:
            try:
                keystone = self.clients.client('keystone')
                keystone.delete_stack_domain_project(
                    project_id=self.stack_user_project_id)
            except Exception as ex:
                LOG.exception(ex)
                stack_status = self.FAILED
                reason = "Error deleting project: %s" % six.text_type(ex)

        return stack_status, reason
Exemple #2
0
    def _delete_credentials(self, stack_status, reason, abandon):
        # Cleanup stored user_creds so they aren't accessible via
        # the soft-deleted stack which remains in the DB
        # The stack_status and reason passed in are current values, which
        # may get rewritten and returned from this method
        if self.user_creds_id:
            user_creds = self._try_get_user_creds(self.user_creds_id)
            # If we created a trust, delete it
            if user_creds is not None:
                trust_id = user_creds.get('trust_id')
                if trust_id:
                    try:
                        # If the trustor doesn't match the context user the
                        # we have to use the stored context to cleanup the
                        # trust, as although the user evidently has
                        # permission to delete the stack, they don't have
                        # rights to delete the trust unless an admin
                        trustor_id = user_creds.get('trustor_user_id')
                        if self.context.user_id != trustor_id:
                            LOG.debug("Context user_id doesn't match "
                                      "trustor, using stored context")
                            sc = self.stored_context()
                            sc.clients.client('keystone').delete_trust(
                                trust_id)
                        else:
                            self.clients.client('keystone').delete_trust(
                                trust_id)
                    except Exception as ex:
                        LOG.exception(ex)
                        stack_status = self.FAILED
                        reason = ("Error deleting trust: %s" %
                                  six.text_type(ex))

            # Delete the stored credentials
            try:
                db_api.user_creds_delete(self.context, self.user_creds_id)
            except exception.NotFound:
                LOG.info(_LI("Tried to delete user_creds that do not exist "
                             "(stack=%(stack)s user_creds_id=%(uc)s)"),
                         {'stack': self.id, 'uc': self.user_creds_id})

            try:
                self.user_creds_id = None
                self.store()
            except exception.NotFound:
                LOG.info(_LI("Tried to store a stack that does not exist %s"),
                         self.id)

        # If the stack has a domain project, delete it
        if self.stack_user_project_id and not abandon:
            try:
                keystone = self.clients.client('keystone')
                keystone.delete_stack_domain_project(
                    project_id=self.stack_user_project_id)
            except Exception as ex:
                LOG.exception(ex)
                stack_status = self.FAILED
                reason = "Error deleting project: %s" % six.text_type(ex)

        return stack_status, reason
 def delete(cls, context, user_creds_id):
     db_api.user_creds_delete(context, user_creds_id)
Exemple #4
0
    def delete(self, action=DELETE, backup=False):
        '''
        Delete all of the resources, and then the stack itself.
        The action parameter is used to differentiate between a user
        initiated delete and an automatic stack rollback after a failed
        create, which amount to the same thing, but the states are recorded
        differently.
        '''
        if action not in (self.DELETE, self.ROLLBACK):
            LOG.error(_("Unexpected action %s passed to delete!") % action)
            self.state_set(self.DELETE, self.FAILED,
                           "Invalid action %s" % action)
            return

        stack_status = self.COMPLETE
        reason = 'Stack %s completed successfully' % action
        self.state_set(action, self.IN_PROGRESS, 'Stack %s started' % action)

        backup_stack = self._backup_stack(False)
        if backup_stack:
            for key, backup_resource in backup_stack.resources.items():
                # If UpdateReplace is failed, we must restore backup_resource
                # to existing_stack in case of it may have dependencies in
                # these stacks. current_resource is the resource that just
                # created and failed, so put into the backup_stack to delete
                # anyway.
                backup_resource_id = backup_resource.resource_id
                current_resource = self.resources[key]
                current_resource_id = current_resource.resource_id
                if backup_resource_id:
                    child_failed = False
                    for child in self.dependencies[current_resource]:
                        # If child resource failed to update, current_resource
                        # should be replaced to resolve dependencies. But this
                        # is not fundamental solution. If there are update
                        # failer and success resources in the children, cannot
                        # delete the stack.
                        if (child.status == child.FAILED
                                and child.action == child.CREATE):
                            child_failed = True
                    if (current_resource.status == current_resource.FAILED
                            or child_failed):
                        # Stack class owns dependencies as set of resource's
                        # objects, so we switch members of the resource that is
                        # needed to delete it.
                        self.resources[key].resource_id = backup_resource_id
                        self.resources[
                            key].properties = backup_resource.properties
                        backup_stack.resources[
                            key].resource_id = current_resource_id
                        backup_stack.resources[
                            key].properties = current_resource.properties

            backup_stack.delete(backup=True)
            if backup_stack.status != backup_stack.COMPLETE:
                errs = backup_stack.status_reason
                failure = 'Error deleting backup resources: %s' % errs
                self.state_set(action, self.FAILED,
                               'Failed to %s : %s' % (action, failure))
                return

        action_task = scheduler.DependencyTaskGroup(self.dependencies,
                                                    resource.Resource.destroy,
                                                    reverse=True)
        try:
            scheduler.TaskRunner(action_task)(timeout=self.timeout_secs())
        except exception.ResourceFailure as ex:
            stack_status = self.FAILED
            reason = 'Resource %s failed: %s' % (action, six.text_type(ex))
        except scheduler.Timeout:
            stack_status = self.FAILED
            reason = '%s timed out' % action.title()

        if stack_status != self.FAILED and not backup:
            # Cleanup stored user_creds so they aren't accessible via
            # the soft-deleted stack which remains in the DB
            if self.user_creds_id:
                user_creds = db_api.user_creds_get(self.user_creds_id)
                # If we created a trust, delete it
                if user_creds is not None:
                    trust_id = user_creds.get('trust_id')
                    if trust_id:
                        try:
                            self.clients.client('keystone').delete_trust(
                                trust_id)
                        except Exception as ex:
                            LOG.exception(ex)
                            stack_status = self.FAILED
                            reason = ("Error deleting trust: %s" %
                                      six.text_type(ex))

                # Delete the stored credentials
                try:
                    db_api.user_creds_delete(self.context, self.user_creds_id)
                except exception.NotFound:
                    LOG.info(
                        _("Tried to delete user_creds that do not exist "
                          "(stack=%(stack)s user_creds_id=%(uc)s)") % {
                              'stack': self.id,
                              'uc': self.user_creds_id
                          })

                try:
                    self.user_creds_id = None
                    self.store()
                except exception.NotFound:
                    LOG.info(
                        _("Tried to store a stack that does not exist "
                          "%s ") % self.id)

            # If the stack has a domain project, delete it
            if self.stack_user_project_id:
                try:
                    keystone = self.clients.client('keystone')
                    keystone.delete_stack_domain_project(
                        project_id=self.stack_user_project_id)
                except Exception as ex:
                    LOG.exception(ex)
                    stack_status = self.FAILED
                    reason = "Error deleting project: %s" % six.text_type(ex)

        try:
            self.state_set(action, stack_status, reason)
        except exception.NotFound:
            LOG.info(
                _("Tried to delete stack that does not exist "
                  "%s ") % self.id)

        if stack_status != self.FAILED:
            # delete the stack
            try:
                db_api.stack_delete(self.context, self.id)
            except exception.NotFound:
                LOG.info(
                    _("Tried to delete stack that does not exist "
                      "%s ") % self.id)
            self.id = None
Exemple #5
0
    def delete(self, action=DELETE, backup=False):
        '''
        Delete all of the resources, and then the stack itself.
        The action parameter is used to differentiate between a user
        initiated delete and an automatic stack rollback after a failed
        create, which amount to the same thing, but the states are recorded
        differently.
        '''
        if action not in (self.DELETE, self.ROLLBACK):
            LOG.error(_("Unexpected action %s passed to delete!") % action)
            self.state_set(self.DELETE, self.FAILED,
                           "Invalid action %s" % action)
            return

        stack_status = self.COMPLETE
        reason = 'Stack %s completed successfully' % action
        self.state_set(action, self.IN_PROGRESS, 'Stack %s started' %
                       action)

        backup_stack = self._backup_stack(False)
        if backup_stack:
            for key, backup_resource in backup_stack.resources.items():
                # If UpdateReplace is failed, we must restore backup_resource
                # to existing_stack in case of it may have dependencies in
                # these stacks. current_resource is the resource that just
                # created and failed, so put into the backup_stack to delete
                # anyway.
                backup_resource_id = backup_resource.resource_id
                current_resource = self.resources[key]
                current_resource_id = current_resource.resource_id
                if backup_resource_id:
                    child_failed = False
                    for child in self.dependencies[current_resource]:
                        # If child resource failed to update, current_resource
                        # should be replaced to resolve dependencies. But this
                        # is not fundamental solution. If there are update
                        # failer and success resources in the children, cannot
                        # delete the stack.
                        if (child.status == child.FAILED and child.action ==
                                child.CREATE):
                            child_failed = True
                    if (current_resource.status == current_resource.FAILED or
                            child_failed):
                        # Stack class owns dependencies as set of resource's
                        # objects, so we switch members of the resource that is
                        # needed to delete it.
                        self.resources[key].resource_id = backup_resource_id
                        self.resources[
                            key].properties = backup_resource.properties
                        backup_stack.resources[
                            key].resource_id = current_resource_id
                        backup_stack.resources[
                            key].properties = current_resource.properties

            backup_stack.delete(backup=True)
            if backup_stack.status != backup_stack.COMPLETE:
                errs = backup_stack.status_reason
                failure = 'Error deleting backup resources: %s' % errs
                self.state_set(action, self.FAILED,
                               'Failed to %s : %s' % (action, failure))
                return

        action_task = scheduler.DependencyTaskGroup(self.dependencies,
                                                    resource.Resource.destroy,
                                                    reverse=True)
        try:
            scheduler.TaskRunner(action_task)(timeout=self.timeout_secs())
        except exception.ResourceFailure as ex:
            stack_status = self.FAILED
            reason = 'Resource %s failed: %s' % (action, six.text_type(ex))
        except scheduler.Timeout:
            stack_status = self.FAILED
            reason = '%s timed out' % action.title()

        if stack_status != self.FAILED and not backup:
            # Cleanup stored user_creds so they aren't accessible via
            # the soft-deleted stack which remains in the DB
            if self.user_creds_id:
                user_creds = db_api.user_creds_get(self.user_creds_id)
                # If we created a trust, delete it
                if user_creds is not None:
                    trust_id = user_creds.get('trust_id')
                    if trust_id:
                        try:
                            self.clients.keystone().delete_trust(trust_id)
                        except Exception as ex:
                            LOG.exception(ex)
                            stack_status = self.FAILED
                            reason = ("Error deleting trust: %s" %
                                      six.text_type(ex))

                # Delete the stored credentials
                try:
                    db_api.user_creds_delete(self.context, self.user_creds_id)
                except exception.NotFound:
                    LOG.info(_("Tried to delete user_creds that do not exist "
                               "(stack=%(stack)s user_creds_id=%(uc)s)") %
                             {'stack': self.id, 'uc': self.user_creds_id})
                self.user_creds_id = None
                self.store()

            # If the stack has a domain project, delete it
            if self.stack_user_project_id:
                try:
                    self.clients.keystone().delete_stack_domain_project(
                        project_id=self.stack_user_project_id)
                except Exception as ex:
                    LOG.exception(ex)
                    stack_status = self.FAILED
                    reason = "Error deleting project: %s" % six.text_type(ex)

        self.state_set(action, stack_status, reason)

        if stack_status != self.FAILED:
            # delete the stack
            db_api.stack_delete(self.context, self.id)
            self.id = None
Exemple #6
0
    def delete(self, action=DELETE, backup=False):
        '''
        Delete all of the resources, and then the stack itself.
        The action parameter is used to differentiate between a user
        initiated delete and an automatic stack rollback after a failed
        create, which amount to the same thing, but the states are recorded
        differently.
        '''
        if action not in (self.DELETE, self.ROLLBACK):
            logger.error(_("Unexpected action %s passed to delete!") % action)
            self.state_set(self.DELETE, self.FAILED,
                           "Invalid action %s" % action)
            return

        stack_status = self.COMPLETE
        reason = 'Stack %s completed successfully' % action
        self.state_set(action, self.IN_PROGRESS, 'Stack %s started' %
                       action)

        backup_stack = self._backup_stack(False)
        if backup_stack is not None:
            backup_stack.delete(backup=True)
            if backup_stack.status != backup_stack.COMPLETE:
                errs = backup_stack.status_reason
                failure = 'Error deleting backup resources: %s' % errs
                self.state_set(action, self.FAILED,
                               'Failed to %s : %s' % (action, failure))
                return

        action_task = scheduler.DependencyTaskGroup(self.dependencies,
                                                    resource.Resource.destroy,
                                                    reverse=True)
        try:
            scheduler.TaskRunner(action_task)(timeout=self.timeout_secs())
        except exception.ResourceFailure as ex:
            stack_status = self.FAILED
            reason = 'Resource %s failed: %s' % (action, six.text_type(ex))
        except scheduler.Timeout:
            stack_status = self.FAILED
            reason = '%s timed out' % action.title()

        if stack_status != self.FAILED and not backup:
            # Cleanup stored user_creds so they aren't accessible via
            # the soft-deleted stack which remains in the DB
            if self.user_creds_id:
                user_creds = db_api.user_creds_get(self.user_creds_id)
                # If we created a trust, delete it
                trust_id = user_creds.get('trust_id')
                if trust_id:
                    try:
                        self.clients.keystone().delete_trust(trust_id)
                    except Exception as ex:
                        logger.exception(ex)
                        stack_status = self.FAILED
                        reason = "Error deleting trust: %s" % six.text_type(ex)

                # Delete the stored credentials
                db_api.user_creds_delete(self.context, self.user_creds_id)
                self.user_creds_id = None
                self.store()

            # If the stack has a domain project, delete it
            if self.stack_user_project_id:
                try:
                    self.clients.keystone().delete_stack_domain_project(
                        project_id=self.stack_user_project_id)
                except Exception as ex:
                    logger.exception(ex)
                    stack_status = self.FAILED
                    reason = "Error deleting project: %s" % six.text_type(ex)

        self.state_set(action, stack_status, reason)

        if stack_status != self.FAILED:
            # delete the stack
            db_api.stack_delete(self.context, self.id)
            self.id = None
Exemple #7
0
    def delete(self, action=DELETE, backup=False):
        '''
        Delete all of the resources, and then the stack itself.
        The action parameter is used to differentiate between a user
        initiated delete and an automatic stack rollback after a failed
        create, which amount to the same thing, but the states are recorded
        differently.
        '''
        if action not in (self.DELETE, self.ROLLBACK):
            logger.error(_("Unexpected action %s passed to delete!") % action)
            self.state_set(self.DELETE, self.FAILED,
                           "Invalid action %s" % action)
            return

        stack_status = self.COMPLETE
        reason = 'Stack %s completed successfully' % action
        self.state_set(action, self.IN_PROGRESS, 'Stack %s started' % action)

        backup_stack = self._backup_stack(False)
        if backup_stack is not None:
            backup_stack.delete(backup=True)
            if backup_stack.status != backup_stack.COMPLETE:
                errs = backup_stack.status_reason
                failure = 'Error deleting backup resources: %s' % errs
                self.state_set(action, self.FAILED,
                               'Failed to %s : %s' % (action, failure))
                return

        action_task = scheduler.DependencyTaskGroup(self.dependencies,
                                                    resource.Resource.destroy,
                                                    reverse=True)
        try:
            scheduler.TaskRunner(action_task)(timeout=self.timeout_secs())
        except exception.ResourceFailure as ex:
            stack_status = self.FAILED
            reason = 'Resource %s failed: %s' % (action, str(ex))
        except scheduler.Timeout:
            stack_status = self.FAILED
            reason = '%s timed out' % action.title()

        if stack_status != self.FAILED and not backup:
            # Cleanup stored user_creds so they aren't accessible via
            # the soft-deleted stack which remains in the DB
            if self.user_creds_id:
                user_creds = db_api.user_creds_get(self.user_creds_id)
                # If we created a trust, delete it
                trust_id = user_creds.get('trust_id')
                if trust_id:
                    try:
                        self.clients.keystone().delete_trust(trust_id)
                    except Exception as ex:
                        logger.exception(ex)
                        stack_status = self.FAILED
                        reason = "Error deleting trust: %s" % str(ex)

                # Delete the stored credentials
                db_api.user_creds_delete(self.context, self.user_creds_id)
                self.user_creds_id = None
                self.store()

            # If the stack has a domain project, delete it
            if self.stack_user_project_id:
                try:
                    self.clients.keystone().delete_stack_domain_project(
                        project_id=self.stack_user_project_id)
                except Exception as ex:
                    logger.exception(ex)
                    stack_status = self.FAILED
                    reason = "Error deleting project: %s" % str(ex)

        self.state_set(action, stack_status, reason)

        if stack_status != self.FAILED:
            # delete the stack
            db_api.stack_delete(self.context, self.id)
            self.id = None
Exemple #8
0
    def delete(self, action=DELETE, backup=False, abandon=False):
        '''
        Delete all of the resources, and then the stack itself.
        The action parameter is used to differentiate between a user
        initiated delete and an automatic stack rollback after a failed
        create, which amount to the same thing, but the states are recorded
        differently.

        Note abandon is a delete where all resources have been set to a
        RETAIN deletion policy, but we also don't want to delete anything
        required for those resources, e.g the stack_user_project.
        '''
        if action not in (self.DELETE, self.ROLLBACK):
            LOG.error(_("Unexpected action %s passed to delete!") % action)
            self.state_set(self.DELETE, self.FAILED,
                           "Invalid action %s" % action)
            return

        stack_status = self.COMPLETE
        reason = 'Stack %s completed successfully' % action
        self.state_set(action, self.IN_PROGRESS, 'Stack %s started' %
                       action)

        backup_stack = self._backup_stack(False)
        if backup_stack:
            def failed(child):
                return (child.action == child.CREATE and
                        child.status in (child.FAILED, child.IN_PROGRESS))

            for key, backup_resource in backup_stack.resources.items():
                # If UpdateReplace is failed, we must restore backup_resource
                # to existing_stack in case of it may have dependencies in
                # these stacks. current_resource is the resource that just
                # created and failed, so put into the backup_stack to delete
                # anyway.
                backup_resource_id = backup_resource.resource_id
                current_resource = self.resources[key]
                current_resource_id = current_resource.resource_id
                if backup_resource_id:
                    if (any(failed(child) for child in
                            self.dependencies[current_resource]) or
                            current_resource.status in
                            (current_resource.FAILED,
                             current_resource.IN_PROGRESS)):
                        # If child resource failed to update, current_resource
                        # should be replaced to resolve dependencies. But this
                        # is not fundamental solution. If there are update
                        # failer and success resources in the children, cannot
                        # delete the stack.
                        # Stack class owns dependencies as set of resource's
                        # objects, so we switch members of the resource that is
                        # needed to delete it.
                        self.resources[key].resource_id = backup_resource_id
                        self.resources[
                            key].properties = backup_resource.properties
                        backup_stack.resources[
                            key].resource_id = current_resource_id
                        backup_stack.resources[
                            key].properties = current_resource.properties

            backup_stack.delete(backup=True)
            if backup_stack.status != backup_stack.COMPLETE:
                errs = backup_stack.status_reason
                failure = 'Error deleting backup resources: %s' % errs
                self.state_set(action, self.FAILED,
                               'Failed to %s : %s' % (action, failure))
                return

        snapshots = db_api.snapshot_get_all(self.context, self.id)
        for snapshot in snapshots:
            self.delete_snapshot(snapshot)

        if not backup:
            try:
                lifecycle_plugin_utils.do_pre_ops(self.context, self,
                                                  None, 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
        action_task = scheduler.DependencyTaskGroup(self.dependencies,
                                                    resource.Resource.destroy,
                                                    reverse=True)
        try:
            scheduler.TaskRunner(action_task)(timeout=self.timeout_secs())
        except exception.ResourceFailure as ex:
            stack_status = self.FAILED
            reason = 'Resource %s failed: %s' % (action, six.text_type(ex))
        except scheduler.Timeout:
            stack_status = self.FAILED
            reason = '%s timed out' % action.title()

        # If the stack delete succeeded, this is not a backup stack and it's
        # not a nested stack, we should delete the credentials
        if stack_status != self.FAILED and not backup and not self.owner_id:
            # Cleanup stored user_creds so they aren't accessible via
            # the soft-deleted stack which remains in the DB
            if self.user_creds_id:
                user_creds = db_api.user_creds_get(self.user_creds_id)
                # If we created a trust, delete it
                if user_creds is not None:
                    trust_id = user_creds.get('trust_id')
                    if trust_id:
                        try:
                            # If the trustor doesn't match the context user the
                            # we have to use the stored context to cleanup the
                            # trust, as although the user evidently has
                            # permission to delete the stack, they don't have
                            # rights to delete the trust unless an admin
                            trustor_id = user_creds.get('trustor_user_id')
                            if self.context.user_id != trustor_id:
                                LOG.debug('Context user_id doesn\'t match '
                                          'trustor, using stored context')
                                sc = self.stored_context()
                                sc.clients.client('keystone').delete_trust(
                                    trust_id)
                            else:
                                self.clients.client('keystone').delete_trust(
                                    trust_id)
                        except Exception as ex:
                            LOG.exception(ex)
                            stack_status = self.FAILED
                            reason = ("Error deleting trust: %s" %
                                      six.text_type(ex))

                # Delete the stored credentials
                try:
                    db_api.user_creds_delete(self.context, self.user_creds_id)
                except exception.NotFound:
                    LOG.info(_("Tried to delete user_creds that do not exist "
                               "(stack=%(stack)s user_creds_id=%(uc)s)") %
                             {'stack': self.id, 'uc': self.user_creds_id})

                try:
                    self.user_creds_id = None
                    self.store()
                except exception.NotFound:
                    LOG.info(_("Tried to store a stack that does not exist "
                               "%s ") % self.id)

            # If the stack has a domain project, delete it
            if self.stack_user_project_id and not abandon:
                try:
                    keystone = self.clients.client('keystone')
                    keystone.delete_stack_domain_project(
                        project_id=self.stack_user_project_id)
                except Exception as ex:
                    LOG.exception(ex)
                    stack_status = self.FAILED
                    reason = "Error deleting project: %s" % six.text_type(ex)

        try:
            self.state_set(action, stack_status, reason)
        except exception.NotFound:
            LOG.info(_("Tried to delete stack that does not exist "
                       "%s ") % self.id)

        if not backup:
            lifecycle_plugin_utils.do_post_ops(self.context, self,
                                               None, action,
                                               (self.status == self.FAILED))
        if stack_status != self.FAILED:
            # delete the stack
            try:
                db_api.stack_delete(self.context, self.id)
            except exception.NotFound:
                LOG.info(_("Tried to delete stack that does not exist "
                           "%s ") % self.id)
            self.id = None
 def delete(cls, context, user_creds_id):
     db_api.user_creds_delete(context, user_creds_id)
Exemple #10
0
    def delete(self, action=DELETE, backup=False, abandon=False):
        '''
        Delete all of the resources, and then the stack itself.
        The action parameter is used to differentiate between a user
        initiated delete and an automatic stack rollback after a failed
        create, which amount to the same thing, but the states are recorded
        differently.

        Note abandon is a delete where all resources have been set to a
        RETAIN deletion policy, but we also don't want to delete anything
        required for those resources, e.g the stack_user_project.
        '''
        if action not in (self.DELETE, self.ROLLBACK):
            LOG.error(_("Unexpected action %s passed to delete!") % action)
            self.state_set(self.DELETE, self.FAILED,
                           "Invalid action %s" % action)
            return

        stack_status = self.COMPLETE
        reason = 'Stack %s completed successfully' % action
        self.state_set(action, self.IN_PROGRESS, 'Stack %s started' % action)

        backup_stack = self._backup_stack(False)
        if backup_stack:

            def failed(child):
                return (child.action == child.CREATE
                        and child.status in (child.FAILED, child.IN_PROGRESS))

            for key, backup_resource in backup_stack.resources.items():
                # If UpdateReplace is failed, we must restore backup_resource
                # to existing_stack in case of it may have dependencies in
                # these stacks. current_resource is the resource that just
                # created and failed, so put into the backup_stack to delete
                # anyway.
                backup_resource_id = backup_resource.resource_id
                current_resource = self.resources[key]
                current_resource_id = current_resource.resource_id
                if backup_resource_id:
                    if (any(
                            failed(child)
                            for child in self.dependencies[current_resource])
                            or current_resource.status
                            in (current_resource.FAILED,
                                current_resource.IN_PROGRESS)):
                        # If child resource failed to update, current_resource
                        # should be replaced to resolve dependencies. But this
                        # is not fundamental solution. If there are update
                        # failer and success resources in the children, cannot
                        # delete the stack.
                        # Stack class owns dependencies as set of resource's
                        # objects, so we switch members of the resource that is
                        # needed to delete it.
                        self.resources[key].resource_id = backup_resource_id
                        self.resources[
                            key].properties = backup_resource.properties
                        backup_stack.resources[
                            key].resource_id = current_resource_id
                        backup_stack.resources[
                            key].properties = current_resource.properties

            backup_stack.delete(backup=True)
            if backup_stack.status != backup_stack.COMPLETE:
                errs = backup_stack.status_reason
                failure = 'Error deleting backup resources: %s' % errs
                self.state_set(action, self.FAILED,
                               'Failed to %s : %s' % (action, failure))
                return

        snapshots = db_api.snapshot_get_all(self.context, self.id)
        for snapshot in snapshots:
            self.delete_snapshot(snapshot)

        if not backup:
            try:
                lifecycle_plugin_utils.do_pre_ops(self.context, self, None,
                                                  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
        action_task = scheduler.DependencyTaskGroup(self.dependencies,
                                                    resource.Resource.destroy,
                                                    reverse=True)
        try:
            scheduler.TaskRunner(action_task)(timeout=self.timeout_secs())
        except exception.ResourceFailure as ex:
            stack_status = self.FAILED
            reason = 'Resource %s failed: %s' % (action, six.text_type(ex))
        except scheduler.Timeout:
            stack_status = self.FAILED
            reason = '%s timed out' % action.title()

        # If the stack delete succeeded, this is not a backup stack and it's
        # not a nested stack, we should delete the credentials
        if stack_status != self.FAILED and not backup and not self.owner_id:
            # Cleanup stored user_creds so they aren't accessible via
            # the soft-deleted stack which remains in the DB
            if self.user_creds_id:
                user_creds = db_api.user_creds_get(self.user_creds_id)
                # If we created a trust, delete it
                if user_creds is not None:
                    trust_id = user_creds.get('trust_id')
                    if trust_id:
                        try:
                            # If the trustor doesn't match the context user the
                            # we have to use the stored context to cleanup the
                            # trust, as although the user evidently has
                            # permission to delete the stack, they don't have
                            # rights to delete the trust unless an admin
                            trustor_id = user_creds.get('trustor_user_id')
                            if self.context.user_id != trustor_id:
                                LOG.debug('Context user_id doesn\'t match '
                                          'trustor, using stored context')
                                sc = self.stored_context()
                                sc.clients.client('keystone').delete_trust(
                                    trust_id)
                            else:
                                self.clients.client('keystone').delete_trust(
                                    trust_id)
                        except Exception as ex:
                            LOG.exception(ex)
                            stack_status = self.FAILED
                            reason = ("Error deleting trust: %s" %
                                      six.text_type(ex))

                # Delete the stored credentials
                try:
                    db_api.user_creds_delete(self.context, self.user_creds_id)
                except exception.NotFound:
                    LOG.info(
                        _("Tried to delete user_creds that do not exist "
                          "(stack=%(stack)s user_creds_id=%(uc)s)") % {
                              'stack': self.id,
                              'uc': self.user_creds_id
                          })

                try:
                    self.user_creds_id = None
                    self.store()
                except exception.NotFound:
                    LOG.info(
                        _("Tried to store a stack that does not exist "
                          "%s ") % self.id)

            # If the stack has a domain project, delete it
            if self.stack_user_project_id and not abandon:
                try:
                    keystone = self.clients.client('keystone')
                    keystone.delete_stack_domain_project(
                        project_id=self.stack_user_project_id)
                except Exception as ex:
                    LOG.exception(ex)
                    stack_status = self.FAILED
                    reason = "Error deleting project: %s" % six.text_type(ex)

        try:
            self.state_set(action, stack_status, reason)
        except exception.NotFound:
            LOG.info(
                _("Tried to delete stack that does not exist "
                  "%s ") % self.id)

        if not backup:
            lifecycle_plugin_utils.do_post_ops(self.context, self, None,
                                               action,
                                               (self.status == self.FAILED))
        if stack_status != self.FAILED:
            # delete the stack
            try:
                db_api.stack_delete(self.context, self.id)
            except exception.NotFound:
                LOG.info(
                    _("Tried to delete stack that does not exist "
                      "%s ") % self.id)
            self.id = None