DB: add stack status & reason, resource metadata
Change-Id: I369aa688fa9890a5484de417a9995e7f04f34ad2 Signed-off-by: Angus Salkeld <asalkeld@redhat.com>
This commit is contained in:
parent
b85bdc2d6c
commit
66fb2054fb
|
@ -0,0 +1,32 @@
|
|||
from sqlalchemy import *
|
||||
from migrate import *
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
meta = MetaData(bind=migrate_engine)
|
||||
|
||||
resource = Table('resource', meta, autoload=True)
|
||||
Column('rsrc_metadata', Text()).create(resource)
|
||||
|
||||
stack = Table('stack', meta, autoload=True)
|
||||
Column('status', String(length=255,
|
||||
convert_unicode=False,
|
||||
assert_unicode=None,
|
||||
unicode_error=None,
|
||||
_warn_on_bytestring=False)).create(stack)
|
||||
Column('status_reason', String(length=255,
|
||||
convert_unicode=False,
|
||||
assert_unicode=None,
|
||||
unicode_error=None,
|
||||
_warn_on_bytestring=False)).create(stack)
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta = MetaData(bind=migrate_engine)
|
||||
|
||||
resource = Table('resource', meta, autoload=True)
|
||||
resource.c.rsrc_metadata.drop()
|
||||
|
||||
stack = Table('stack', meta, autoload=True)
|
||||
stack.c.status.drop()
|
||||
stack.c.status_reason.drop()
|
|
@ -142,6 +142,8 @@ class Stack(BASE, HeatBase):
|
|||
raw_template = relationship(RawTemplate,
|
||||
backref=backref('stack'))
|
||||
username = Column(String)
|
||||
status = Column('status', String)
|
||||
status_reason = Column('status_reason', String)
|
||||
user_creds_id = Column(Integer, ForeignKey('user_creds.id'),
|
||||
nullable=False)
|
||||
owner_id = Column(Integer, nullable=True)
|
||||
|
@ -196,6 +198,8 @@ class Resource(BASE, HeatBase):
|
|||
name = Column('name', String, nullable=False)
|
||||
nova_instance = Column('nova_instance', String)
|
||||
state_description = Column('state_description', String)
|
||||
# odd name as "metadata" is reserved
|
||||
rsrc_metadata = Column('rsrc_metadata', Json)
|
||||
parsed_template_id = Column(Integer, ForeignKey('parsed_template.id'),
|
||||
nullable=True)
|
||||
parsed_template = relationship(ParsedTemplate,
|
||||
|
|
|
@ -155,7 +155,7 @@ class EngineManager(manager.Manager):
|
|||
mem['CreationTime'] = heat_utils.strtime(s.created_at)
|
||||
mem['TemplateDescription'] = ps.t.get('Description',
|
||||
'No description')
|
||||
mem['StackStatus'] = ps.t.get('stack_status', 'unknown')
|
||||
mem['StackStatus'] = s.status
|
||||
res['stacks'].append(mem)
|
||||
|
||||
return res
|
||||
|
@ -185,12 +185,11 @@ class EngineManager(manager.Manager):
|
|||
mem['TimeoutInMinutes'] = ps.t.get('Timeout', '60')
|
||||
mem['TemplateDescription'] = ps.t.get('Description',
|
||||
'No description')
|
||||
mem['StackStatus'] = ps.t.get('stack_status', 'unknown')
|
||||
mem['StackStatusReason'] = ps.t.get('stack_status_reason',
|
||||
'State changed')
|
||||
mem['StackStatus'] = s.status
|
||||
mem['StackStatusReason'] = s.status_reason
|
||||
|
||||
# only show the outputs on a completely created stack
|
||||
if ps.t['stack_status'] == ps.CREATE_COMPLETE:
|
||||
if s.state == ps.CREATE_COMPLETE:
|
||||
mem['Outputs'] = ps.get_outputs()
|
||||
|
||||
res['stacks'].append(mem)
|
||||
|
@ -481,12 +480,11 @@ class EngineManager(manager.Manager):
|
|||
if not s:
|
||||
return ['stack', None]
|
||||
|
||||
template = s.raw_template.parsed_template.template
|
||||
if not resource_id in template.get('Resources', {}):
|
||||
r = db_api.resource_get_by_name_and_stack(None, resource_id, s.id)
|
||||
if r is None:
|
||||
return ['resource', None]
|
||||
|
||||
metadata = template['Resources'][resource_id].get('Metadata', {})
|
||||
return [None, metadata]
|
||||
return [None, r.rsrc_metadata]
|
||||
|
||||
def metadata_update(self, context, stack_name, resource_id, metadata):
|
||||
"""
|
||||
|
@ -495,21 +493,14 @@ class EngineManager(manager.Manager):
|
|||
s = db_api.stack_get_by_name(None, stack_name)
|
||||
if not s:
|
||||
return ['stack', None]
|
||||
pt_id = s.raw_template.parsed_template.id
|
||||
|
||||
pt = db_api.parsed_template_get(None, pt_id)
|
||||
if not resource_id in pt.template.get('Resources', {}):
|
||||
r = db_api.resource_get_by_name_and_stack(None, resource_id, s.id)
|
||||
if r is None:
|
||||
logger.warn("Resource not found %s:%s." % (stack_name,
|
||||
resource_id))
|
||||
return ['resource', None]
|
||||
|
||||
# TODO(shadower) deep copy of the template is required here. Without
|
||||
# it, we directly modify parsed_template.template by assigning the new
|
||||
# metadata. When we then call parsed_template.update_and_save, the
|
||||
# session will detect no changes and thus not update the database.
|
||||
# Just updating the values and calling save didn't seem to work either.
|
||||
# There's probably an idiomatic way I'm missing right now.
|
||||
t = deepcopy(pt.template)
|
||||
t['Resources'][resource_id]['Metadata'] = metadata
|
||||
pt.update_and_save({'template': t})
|
||||
r.update_and_save({'rsrc_metadata': metadata})
|
||||
return [None, metadata]
|
||||
|
||||
@manager.periodic_task
|
||||
|
|
|
@ -178,9 +178,17 @@ class Stack(object):
|
|||
self.parsed_template_id)
|
||||
|
||||
def state_set(self, new_status, reason='change in resource state'):
|
||||
self.t['stack_status'] = new_status
|
||||
self.t['stack_status_reason'] = reason
|
||||
self.update_parsed_template()
|
||||
if self.id != 0:
|
||||
stack = db_api.stack_get(self.context, self.id)
|
||||
else:
|
||||
stack = db_api.stack_get_by_name(self.context, self.name)
|
||||
|
||||
if stack is None:
|
||||
return
|
||||
|
||||
self.id = stack.id
|
||||
stack.update_and_save({'status': new_status,
|
||||
'status_reason': reason})
|
||||
|
||||
def _timeout(self):
|
||||
'''Return the stack creation timeout in seconds'''
|
||||
|
|
|
@ -64,6 +64,10 @@ class Resource(object):
|
|||
# make a dummy entry to prevent having to check all over the
|
||||
# place for it.
|
||||
self.t['Properties'] = {}
|
||||
if 'Metadata' not in self.t:
|
||||
# make a dummy entry to prevent having to check all over the
|
||||
# place for it.
|
||||
self.t['Metadata'] = {}
|
||||
|
||||
resource = db_api.resource_get_by_name_and_stack(self.stack.context,
|
||||
name, stack.id)
|
||||
|
@ -146,11 +150,10 @@ class Resource(object):
|
|||
|
||||
logger.info('creating %s' % str(self))
|
||||
|
||||
self.state_set(self.CREATE_IN_PROGRESS)
|
||||
|
||||
try:
|
||||
self.calculate_properties()
|
||||
self.properties.validate()
|
||||
self.state_set(self.CREATE_IN_PROGRESS)
|
||||
if callable(getattr(self, 'handle_create', None)):
|
||||
self.handle_create()
|
||||
except Exception as ex:
|
||||
|
@ -207,7 +210,7 @@ class Resource(object):
|
|||
def instance_id_set(self, inst):
|
||||
self.instance_id = inst
|
||||
|
||||
def _create_db(self):
|
||||
def _create_db(self, metadata=None):
|
||||
'''Create the resource in the database'''
|
||||
try:
|
||||
rs = {'state': self.state,
|
||||
|
@ -215,6 +218,7 @@ class Resource(object):
|
|||
'parsed_template_id': self.stack.parsed_template_id,
|
||||
'nova_instance': self.instance_id,
|
||||
'name': self.name,
|
||||
'rsrc_metadata': metadata,
|
||||
'stack_name': self.stack.name}
|
||||
|
||||
new_rs = db_api.resource_create(self.stack.context, rs)
|
||||
|
@ -259,7 +263,7 @@ class Resource(object):
|
|||
logger.error('DB error %s' % str(ex))
|
||||
|
||||
elif new_state in (self.CREATE_COMPLETE, self.CREATE_FAILED):
|
||||
self._create_db()
|
||||
self._create_db(metadata=self.parsed_template()['Metadata'])
|
||||
|
||||
if new_state != old_state:
|
||||
self._add_event(new_state, reason)
|
||||
|
|
|
@ -75,11 +75,11 @@ class WaitCondition(Resource):
|
|||
tmo = eventlet.Timeout(self.timeout)
|
||||
status = 'WAITING'
|
||||
reason = ''
|
||||
res = None
|
||||
try:
|
||||
while status == 'WAITING':
|
||||
pt = None
|
||||
try:
|
||||
pt = self.stack.parsed_template_get()
|
||||
res = db_api.resource_get(self.stack.context, self.id)
|
||||
except Exception as ex:
|
||||
if 'not found' in ex:
|
||||
# it has been deleted
|
||||
|
@ -87,9 +87,9 @@ class WaitCondition(Resource):
|
|||
else:
|
||||
pass
|
||||
|
||||
if pt:
|
||||
res = pt.template['Resources'][self.resource_id]
|
||||
metadata = res.get('Metadata', {})
|
||||
if res and res.rsrc_metadata:
|
||||
metadata = res.rsrc_metadata
|
||||
if metadata:
|
||||
status = metadata.get('Status', 'WAITING')
|
||||
reason = metadata.get('Reason', 'Reason not provided')
|
||||
logger.debug('got %s' % json.dumps(metadata))
|
||||
|
@ -111,10 +111,14 @@ class WaitCondition(Resource):
|
|||
|
||||
def FnGetAtt(self, key):
|
||||
res = None
|
||||
self._get_handle_resource_id()
|
||||
if key == 'Data':
|
||||
resource = self.stack.t['Resources'][self.resource_id]
|
||||
res = resource['Metadata']['Data']
|
||||
try:
|
||||
r = db_api.resource_get(self.stack.context, self.id)
|
||||
if r.rsrc_metadata and 'Data' in r.rsrc_metadata:
|
||||
res = r.rsrc_metadata['Data']
|
||||
except Exception as ex:
|
||||
pass
|
||||
|
||||
else:
|
||||
raise exception.InvalidTemplateAttribute(resource=self.name,
|
||||
key=key)
|
||||
|
|
|
@ -90,7 +90,7 @@ class stacksTest(unittest.TestCase):
|
|||
assert(stack.resources['WebServer'].instance_id > 0)
|
||||
stack.delete()
|
||||
assert(stack.resources['WebServer'].state == 'DELETE_COMPLETE')
|
||||
assert(stack.t['stack_status'] == 'DELETE_COMPLETE')
|
||||
assert(new_s.status == 'DELETE_COMPLETE')
|
||||
|
||||
def test_stack_event_list(self):
|
||||
stack = self.start_wordpress_stack('test_event_list_stack')
|
||||
|
|
Loading…
Reference in New Issue