示例#1
0
    def acquire(self, retry=True):
        """Acquire a lock on the stack.

        :param retry: When True, retry if lock was released while stealing.
        :type retry: boolean
        """
        lock_engine_id = stack_lock_object.StackLock.create(self.context,
                                                            self.stack_id,
                                                            self.engine_id)
        if lock_engine_id is None:
            LOG.debug("Engine %(engine)s acquired lock on stack "
                      "%(stack)s" % {'engine': self.engine_id,
                                     'stack': self.stack_id})
            return

        stack = stack_object.Stack.get_by_id(self.context, self.stack_id,
                                             show_deleted=True,
                                             eager_load=False)
        if (lock_engine_id == self.engine_id or
                service_utils.engine_alive(self.context, lock_engine_id)):
            LOG.debug("Lock on stack %(stack)s is owned by engine "
                      "%(engine)s" % {'stack': self.stack_id,
                                      'engine': lock_engine_id})
            raise exception.ActionInProgress(stack_name=stack.name,
                                             action=stack.action)
        else:
            LOG.info("Stale lock detected on stack %(stack)s.  Engine "
                     "%(engine)s will attempt to steal the lock",
                     {'stack': self.stack_id, 'engine': self.engine_id})

            result = stack_lock_object.StackLock.steal(self.context,
                                                       self.stack_id,
                                                       lock_engine_id,
                                                       self.engine_id)

            if result is None:
                LOG.info("Engine %(engine)s successfully stole the lock "
                         "on stack %(stack)s",
                         {'engine': self.engine_id,
                          'stack': self.stack_id})
                return
            elif result is True:
                if retry:
                    LOG.info("The lock on stack %(stack)s was released "
                             "while engine %(engine)s was stealing it. "
                             "Trying again", {'stack': self.stack_id,
                                              'engine': self.engine_id})
                    return self.acquire(retry=False)
            else:
                new_lock_engine_id = result
                LOG.info("Failed to steal lock on stack %(stack)s. "
                         "Engine %(engine)s stole the lock first",
                         {'stack': self.stack_id,
                          'engine': new_lock_engine_id})

            raise exception.ActionInProgress(
                stack_name=stack.name, action=stack.action)
示例#2
0
    def acquire(self, retry=True):
        """
        Acquire a lock on the stack.

        :param retry: When True, retry if lock was released while stealing.
        :type retry: boolean
        """
        lock_engine_id = db_api.stack_lock_create(self.stack.id,
                                                  self.engine_id)
        if lock_engine_id is None:
            logger.debug(_("Engine %(engine)s acquired lock on stack "
                           "%(stack)s") % {'engine': self.engine_id,
                                           'stack': self.stack.id})
            return

        if lock_engine_id == self.engine_id or \
           self.engine_alive(self.context, lock_engine_id):
            logger.debug(_("Lock on stack %(stack)s is owned by engine "
                           "%(engine)s") % {'stack': self.stack.id,
                                            'engine': lock_engine_id})
            raise exception.ActionInProgress(stack_name=self.stack.name,
                                             action=self.stack.action)
        else:
            logger.info(_("Stale lock detected on stack %(stack)s.  Engine "
                          "%(engine)s will attempt to steal the lock")
                        % {'stack': self.stack.id, 'engine': self.engine_id})

            result = db_api.stack_lock_steal(self.stack.id, lock_engine_id,
                                             self.engine_id)

            if result is None:
                logger.info(_("Engine %(engine)s successfully stole the lock "
                              "on stack %(stack)s")
                            % {'engine': self.engine_id,
                               'stack': self.stack.id})
                return
            elif result is True:
                if retry:
                    logger.info(_("The lock on stack %(stack)s was released "
                                  "while engine %(engine)s was stealing it. "
                                  "Trying again") % {'stack': self.stack.id,
                                                     'engine': self.engine_id})
                    return self.acquire(retry=False)
            else:
                new_lock_engine_id = result
                logger.info(_("Failed to steal lock on stack %(stack)s. "
                              "Engine %(engine)s stole the lock first")
                            % {'stack': self.stack.id,
                               'engine': new_lock_engine_id})

            raise exception.ActionInProgress(
                stack_name=self.stack.name, action=self.stack.action)
示例#3
0
    def abandon_stack(self, cnxt, stack_identity):
        """
        The abandon_stack method abandons a given stack.
        :param cnxt: RPC context.
        :param stack_identity: Name of the stack you want to abandon.
        """
        st = self._get_stack(cnxt, stack_identity)
        logger.info(_('abandoning stack %s') % st.name)
        stack = parser.Stack.load(cnxt, stack=st)
        lock = stack_lock.StackLock(cnxt, stack, self.engine_id)
        acquire_result = lock.try_acquire()

        # If an action is in progress, 'try_acquire' returns engine UUID. If
        # the returned engine is alive, then throw ActionInProgress exception
        if (acquire_result and
            (acquire_result == self.engine_id
             or stack_lock.StackLock.engine_alive(cnxt, acquire_result))):
            raise exception.ActionInProgress(stack_name=stack.name,
                                             action=stack.action)

        try:
            # Get stack details before deleting it.
            stack_info = stack.prepare_abandon()
        except:
            with excutils.save_and_reraise_exception():
                lock.release(stack.id)

        self.thread_group_mgr.start_with_acquired_lock(stack, lock,
                                                       stack.delete)
        return stack_info
示例#4
0
 def test_mark_unhealthy_stack_lock_exc_no_convergence(self):
     self.patchobject(stack_lock.StackLock,
                      'acquire',
                      return_value=None,
                      side_effect=exception.ActionInProgress(
                          stack_name=self.stack.name,
                          action=self.stack.action))
     ex = self.assertRaises(dispatcher.ExpectedException,
                            self.eng.resource_mark_unhealthy,
                            self.ctx,
                            self.stack.identifier(),
                            'WebServer',
                            True,
                            resource_status_reason="")
     self.assertEqual(exception.ActionInProgress, ex.exc_info[0])
示例#5
0
    def update_stack(self, cnxt, stack_identity, template, params, files,
                     args):
        """
        The update_stack method updates an existing stack based on the
        provided template and parameters.
        Note that at this stage the template has already been fetched from the
        heat-api process if using a template-url.
        arg1 -> RPC context.
        arg2 -> Name of the stack you want to create.
        arg3 -> Template of stack you want to create.
        arg4 -> Stack Input Params
        arg4 -> Request parameters/args passed from API
        """
        logger.info('template is %s' % template)

        self._validate_mandatory_credentials(cnxt)

        # Get the database representation of the existing stack
        db_stack = self._get_stack(cnxt, stack_identity)

        if db_stack.status != parser.Stack.COMPLETE:
            raise exception.ActionInProgress(stack_name=db_stack.name,
                                             action=db_stack.action)

        current_stack = parser.Stack.load(cnxt, stack=db_stack)

        # Now parse the template and any parameters for the updated
        # stack definition.
        tmpl = parser.Template(template, files=files)
        stack_name = current_stack.name
        common_params = api.extract_args(args)
        env = environment.Environment(params)
        updated_stack = parser.Stack(cnxt, stack_name, tmpl, env,
                                     **common_params)

        updated_stack.validate()

        self._start_in_thread(db_stack.id, current_stack.update, updated_stack)

        return dict(current_stack.identifier())
示例#6
0
    def delete_stack(self, cnxt, stack_identity):
        """
        The delete_stack method deletes a given stack.
        arg1 -> RPC context.
        arg2 -> Name of the stack you want to delete.
        """
        st = self._get_stack(cnxt, stack_identity)

        if st.status not in (parser.Stack.COMPLETE, parser.Stack.FAILED):
            raise exception.ActionInProgress(stack_name=st.name,
                                             action=st.action)

        logger.info('deleting stack %s' % st.name)
        stack = parser.Stack.load(cnxt, stack=st)

        # Kill any pending threads by calling ThreadGroup.stop()
        if st.id in self.stg:
            self.stg[st.id].stop()
            del self.stg[st.id]
        # use the service ThreadGroup for deletes
        self.tg.add_thread(stack.delete)
        return None
示例#7
0
 def test_map_remote_error_invalid_action_error(self):
     ex = common_exception.ActionInProgress(stack_name="teststack",
                                            action="testing")
     expected = aws_exception.HeatActionInProgressError
     self.assertIsInstance(aws_exception.map_remote_error(ex), expected)