Merge "Add command to reset one stack status"
This commit is contained in:
commit
9d5038da88
|
@ -98,6 +98,18 @@ def do_resource_data_list():
|
|||
print(print_format % (k, data[k]))
|
||||
|
||||
|
||||
def do_reset_stack_status():
|
||||
print(_("Warning: this command is potentially destructive and only "
|
||||
"intended to recover from specific crashes."))
|
||||
print(_("It is advised to shutdown all Heat engines beforehand."))
|
||||
print(_("Continue ? [y/N]"))
|
||||
data = raw_input()
|
||||
if not data.lower().startswith('y'):
|
||||
return
|
||||
ctxt = context.get_admin_context()
|
||||
db_api.reset_stack_status(ctxt, CONF.command.stack_id)
|
||||
|
||||
|
||||
def purge_deleted():
|
||||
"""Remove database records that have been previously soft deleted."""
|
||||
utils.purge_deleted(CONF.command.age, CONF.command.granularity)
|
||||
|
@ -157,6 +169,11 @@ def add_command_parsers(subparsers):
|
|||
parser.add_argument('resource_id',
|
||||
help=_('Stack resource id'))
|
||||
|
||||
parser = subparsers.add_parser('reset_stack_status')
|
||||
parser.set_defaults(func=do_reset_stack_status)
|
||||
parser.add_argument('stack_id',
|
||||
help=_('Stack id'))
|
||||
|
||||
ServiceManageCommand.add_service_parsers(subparsers)
|
||||
|
||||
command_opt = cfg.SubCommandOpt('command',
|
||||
|
|
|
@ -425,3 +425,7 @@ def db_sync(engine, version=None):
|
|||
def db_version(engine):
|
||||
"""Display the current database version."""
|
||||
return IMPL.db_version(engine)
|
||||
|
||||
|
||||
def reset_stack_status(context, stack_id):
|
||||
return IMPL.reset_stack_status(context, stack_id)
|
||||
|
|
|
@ -39,6 +39,7 @@ from heat.db.sqlalchemy import filters as db_filters
|
|||
from heat.db.sqlalchemy import migration
|
||||
from heat.db.sqlalchemy import models
|
||||
from heat.db.sqlalchemy import utils as db_utils
|
||||
from heat.engine import environment as heat_environment
|
||||
from heat.rpc import api as rpc_api
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -1385,3 +1386,43 @@ def _get_batch(session, ctxt, query, model, batch_size=50):
|
|||
for result in results:
|
||||
yield result
|
||||
last_batch_marker = results[-1].id
|
||||
|
||||
|
||||
def reset_stack_status(context, stack_id, stack=None):
|
||||
if stack is None:
|
||||
stack = model_query(context, models.Stack).get(stack_id)
|
||||
|
||||
if stack is None:
|
||||
raise exception.NotFound(_('Stack with id %s not found') % stack_id)
|
||||
|
||||
session = _session(context)
|
||||
with session.begin():
|
||||
query = model_query(context, models.Resource).filter_by(
|
||||
status='IN_PROGRESS', stack_id=stack_id)
|
||||
query.update({'status': 'FAILED',
|
||||
'status_reason': 'Stack status manually reset'})
|
||||
|
||||
query = model_query(context, models.ResourceData)
|
||||
query = query.join(models.Resource)
|
||||
query = query.filter_by(stack_id=stack_id)
|
||||
query = query.filter(
|
||||
models.ResourceData.key.in_(heat_environment.HOOK_TYPES))
|
||||
data_ids = [data.id for data in query]
|
||||
|
||||
if data_ids:
|
||||
query = model_query(context, models.ResourceData)
|
||||
query = query.filter(models.ResourceData.id.in_(data_ids))
|
||||
query.delete(synchronize_session='fetch')
|
||||
|
||||
query = model_query(context, models.Stack).filter_by(owner_id=stack_id)
|
||||
for child in query:
|
||||
reset_stack_status(context, child.id, child)
|
||||
|
||||
with session.begin():
|
||||
if stack.status == 'IN_PROGRESS':
|
||||
stack.status = 'FAILED'
|
||||
stack.status_reason = 'Stack status manually reset'
|
||||
|
||||
session.query(
|
||||
models.StackLock
|
||||
).filter_by(stack_id=stack_id).delete()
|
||||
|
|
|
@ -3249,3 +3249,52 @@ class DBAPICryptParamsPropsTest(common.HeatTestCase):
|
|||
self.assertNotEqual(enc_params['param3'], dec_params['param3'])
|
||||
self.assertEqual('bar', dec_params['param2'])
|
||||
self.assertEqual('12345', dec_params['param3'])
|
||||
|
||||
|
||||
class ResetStackStatusTests(common.HeatTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ResetStackStatusTests, self).setUp()
|
||||
self.ctx = utils.dummy_context()
|
||||
self.template = create_raw_template(self.ctx)
|
||||
self.user_creds = create_user_creds(self.ctx)
|
||||
self.stack = create_stack(self.ctx, self.template, self.user_creds)
|
||||
|
||||
def test_status_reset(self):
|
||||
db_api.stack_update(self.ctx, self.stack.id, {'status': 'IN_PROGRESS'})
|
||||
db_api.stack_lock_create(self.stack.id, UUID1)
|
||||
db_api.reset_stack_status(self.ctx, self.stack.id)
|
||||
self.assertEqual('FAILED', self.stack.status)
|
||||
self.assertEqual('Stack status manually reset',
|
||||
self.stack.status_reason)
|
||||
self.assertEqual(True, db_api.stack_lock_release(self.stack.id, UUID1))
|
||||
|
||||
def test_resource_reset(self):
|
||||
resource_progress = create_resource(self.ctx, self.stack,
|
||||
status='IN_PROGRESS')
|
||||
resource_complete = create_resource(self.ctx, self.stack)
|
||||
db_api.reset_stack_status(self.ctx, self.stack.id)
|
||||
self.assertEqual('complete', resource_complete.status)
|
||||
self.assertEqual('FAILED', resource_progress.status)
|
||||
|
||||
def test_hook_reset(self):
|
||||
resource = create_resource(self.ctx, self.stack)
|
||||
resource.context = self.ctx
|
||||
create_resource_data(self.ctx, resource, key="pre-create")
|
||||
create_resource_data(self.ctx, resource)
|
||||
db_api.reset_stack_status(self.ctx, self.stack.id)
|
||||
|
||||
vals = db_api.resource_data_get_all(self.ctx, resource.id)
|
||||
self.assertEqual({'test_resource_key': 'test_value'}, vals)
|
||||
|
||||
def test_nested_stack(self):
|
||||
db_api.stack_update(self.ctx, self.stack.id, {'status': 'IN_PROGRESS'})
|
||||
child = create_stack(self.ctx, self.template, self.user_creds,
|
||||
owner_id=self.stack.id)
|
||||
grandchild = create_stack(self.ctx, self.template, self.user_creds,
|
||||
owner_id=child.id, status='IN_PROGRESS')
|
||||
resource = create_resource(self.ctx, grandchild, status='IN_PROGRESS')
|
||||
db_api.reset_stack_status(self.ctx, self.stack.id)
|
||||
self.assertEqual('FAILED', grandchild.status)
|
||||
self.assertEqual('FAILED', resource.status)
|
||||
self.assertEqual('FAILED', self.stack.status)
|
||||
|
|
Loading…
Reference in New Issue