def delete_stack(self, cnxt, stack_identity): """ The delete_stack method deletes a given stack. :param cnxt: RPC context. :param stack_identity: Name of the stack you want to delete. """ def remote_stop(lock_engine_id): rpc = proxy.RpcProxy(lock_engine_id, "1.0") msg = rpc.make_msg("stop_stack", stack_identity=stack_identity) timeout = cfg.CONF.engine_life_check_timeout try: rpc.call(cnxt, msg, topic=lock_engine_id, timeout=timeout) except rpc_common.Timeout: return False st = self._get_stack(cnxt, stack_identity) logger.info(_('Deleting 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() # Successfully acquired lock if acquire_result is None: self.thread_group_mgr.start_with_acquired_lock(stack, lock, stack.delete) return # Current engine has the lock elif acquire_result == self.engine_id: self.thread_group_mgr.stop(stack.id) # Another active engine has the lock elif stack_lock.StackLock.engine_alive(cnxt, acquire_result): stop_result = remote_stop(acquire_result) if stop_result is None: logger.debug(_("Successfully stopped remote task on engine %s") % acquire_result) else: raise exception.StopActionFailed(stack_name=stack.name, engine_id=acquire_result) # If the lock isn't released here, then the call to # start_with_lock below will raise an ActionInProgress # exception. Ideally, we wouldn't be calling another # release() here, since it should be called as soon as the # ThreadGroup is stopped. But apparently there's a race # between release() the next call to lock.acquire(). db_api.stack_lock_release(stack.id, acquire_result) # There may be additional resources that we don't know about # if an update was in-progress when the stack was stopped, so # reload the stack from the database. st = self._get_stack(cnxt, stack_identity) stack = parser.Stack.load(cnxt, stack=st) self.thread_group_mgr.start_with_lock(cnxt, stack, self.engine_id, stack.delete) return None
def delete_stack(self, cnxt, stack_identity): """ The delete_stack method deletes a given stack. :param cnxt: RPC context. :param stack_identity: Name of the stack you want to delete. """ def remote_stop(lock_engine_id): timeout = cfg.CONF.engine_life_check_timeout self.cctxt = self._client.prepare(version='1.0', timeout=timeout, topic=lock_engine_id) try: self.cctxt.call(cnxt, 'stop_stack', stack_identity=stack_identity) except messaging.MessagingTimeout: return False st = self._get_stack(cnxt, stack_identity) LOG.info(_('Deleting stack %s') % st.name) stack = parser.Stack.load(cnxt, stack=st) lock = stack_lock.StackLock(cnxt, stack, self.engine_id) with lock.try_thread_lock(stack.id) as acquire_result: # Successfully acquired lock if acquire_result is None: self.thread_group_mgr.stop_timers(stack.id) self.thread_group_mgr.start_with_acquired_lock( stack, lock, stack.delete) return # Current engine has the lock if acquire_result == self.engine_id: # give threads which are almost complete an opportunity to # finish naturally before force stopping them eventlet.sleep(0.2) self.thread_group_mgr.stop(stack.id) # Another active engine has the lock elif stack_lock.StackLock.engine_alive(cnxt, acquire_result): stop_result = remote_stop(acquire_result) if stop_result is None: LOG.debug("Successfully stopped remote task on engine %s" % acquire_result) else: raise exception.StopActionFailed(stack_name=stack.name, engine_id=acquire_result) # There may be additional resources that we don't know about # if an update was in-progress when the stack was stopped, so # reload the stack from the database. st = self._get_stack(cnxt, stack_identity) stack = parser.Stack.load(cnxt, stack=st) self.thread_group_mgr.start_with_lock(cnxt, stack, self.engine_id, stack.delete) return None