Convert Events to separate action/status
First step in decoupling action/status in Resource This adjusts the Event DB columns, model and class to split action/status, but in order to be backwards compatible we set the action to None, which means we can do the right thing in the CFN API, and resource_status still maps correctly to what is expected in python-heatclient (which will need to change after the Resource action/status split happens) Change-Id: I261d47d2a3fdb3cdc2a8aaf6c159763f4636f633
This commit is contained in:
parent
a234b3a3d0
commit
5206990f9a
|
@ -469,6 +469,12 @@ class StackController(object):
|
|||
}
|
||||
|
||||
result = api_utils.reformat_dict_keys(keymap, e)
|
||||
action = e[engine_api.EVENT_RES_ACTION]
|
||||
status = e[engine_api.EVENT_RES_STATUS]
|
||||
if action and status:
|
||||
result['ResourceStatus'] = '_'.join((action, status))
|
||||
else:
|
||||
result['ResourceStatus'] = status
|
||||
result['ResourceProperties'] = json.dumps(result[
|
||||
'ResourceProperties'])
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ summary_keys = [
|
|||
engine_api.EVENT_ID,
|
||||
engine_api.EVENT_TIMESTAMP,
|
||||
engine_api.EVENT_RES_NAME,
|
||||
engine_api.EVENT_RES_ACTION,
|
||||
engine_api.EVENT_RES_STATUS,
|
||||
engine_api.EVENT_RES_STATUS_DATA,
|
||||
engine_api.EVENT_RES_PHYSICAL_ID,
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from sqlalchemy import *
|
||||
from migrate import *
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
meta = MetaData()
|
||||
meta.bind = migrate_engine
|
||||
|
||||
event = Table('event', meta, autoload=True)
|
||||
# Currently there is a 'name' column which really holds the
|
||||
# resource status, so rename it and add a separate action column
|
||||
# action is e.g "CREATE" and status is e.g "IN_PROGRESS"
|
||||
event.c.name.alter(name='resource_status')
|
||||
Column('resource_action', String(255)).create(event)
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta = MetaData()
|
||||
meta.bind = migrate_engine
|
||||
|
||||
event = Table('event', meta, autoload=True)
|
||||
event.c.resource_status.alter(name='name')
|
||||
event.c.resource_action.drop()
|
|
@ -197,7 +197,8 @@ class Event(BASE, HeatBase):
|
|||
stack_id = Column(String, ForeignKey('stack.id'), nullable=False)
|
||||
stack = relationship(Stack, backref=backref('events'))
|
||||
|
||||
name = Column(String)
|
||||
resource_action = Column(String)
|
||||
resource_status = Column(String)
|
||||
logical_resource_id = Column(String)
|
||||
physical_resource_id = Column(String)
|
||||
resource_status_reason = Column(String)
|
||||
|
|
|
@ -126,7 +126,8 @@ def format_event(event):
|
|||
EVENT_TIMESTAMP: timeutils.isotime(event.timestamp),
|
||||
EVENT_RES_NAME: event.resource.name,
|
||||
EVENT_RES_PHYSICAL_ID: event.physical_resource_id,
|
||||
EVENT_RES_STATUS: event.new_state,
|
||||
EVENT_RES_ACTION: event.action,
|
||||
EVENT_RES_STATUS: event.status,
|
||||
EVENT_RES_STATUS_DATA: event.reason,
|
||||
EVENT_RES_TYPE: event.resource.type(),
|
||||
EVENT_RES_PROPERTIES: event.resource_properties,
|
||||
|
|
|
@ -25,7 +25,7 @@ class Event(object):
|
|||
'''Class representing a Resource state change.'''
|
||||
|
||||
def __init__(self, context, stack, resource,
|
||||
new_state, reason,
|
||||
action, status, reason,
|
||||
physical_resource_id, resource_properties,
|
||||
timestamp=None, id=None):
|
||||
'''
|
||||
|
@ -36,7 +36,8 @@ class Event(object):
|
|||
self.context = context
|
||||
self.resource = resource
|
||||
self.stack = stack
|
||||
self.new_state = new_state
|
||||
self.action = action
|
||||
self.status = status
|
||||
self.reason = reason
|
||||
self.physical_resource_id = physical_resource_id
|
||||
try:
|
||||
|
@ -60,7 +61,8 @@ class Event(object):
|
|||
resource = stack[ev.logical_resource_id]
|
||||
|
||||
event = cls(context, stack, resource,
|
||||
ev.name, ev.resource_status_reason,
|
||||
ev.resource_action, ev.resource_status,
|
||||
ev.resource_status_reason,
|
||||
ev.physical_resource_id, ev.resource_properties,
|
||||
ev.created_at, ev.id)
|
||||
|
||||
|
@ -72,9 +74,8 @@ class Event(object):
|
|||
'logical_resource_id': self.resource.name,
|
||||
'physical_resource_id': self.physical_resource_id,
|
||||
'stack_id': self.stack.id,
|
||||
'stack_name': self.stack.name,
|
||||
'resource_status': self.new_state,
|
||||
'name': self.new_state,
|
||||
'resource_action': self.action,
|
||||
'resource_status': self.status,
|
||||
'resource_status_reason': self.reason,
|
||||
'resource_type': self.resource.type(),
|
||||
'resource_properties': self.resource_properties,
|
||||
|
|
|
@ -505,7 +505,7 @@ class Resource(object):
|
|||
def _add_event(self, new_state, reason):
|
||||
'''Add a state change event to the database.'''
|
||||
ev = event.Event(self.context, self.stack, self,
|
||||
new_state, reason,
|
||||
None, new_state, reason,
|
||||
self.resource_id, self.properties)
|
||||
|
||||
try:
|
||||
|
|
|
@ -48,28 +48,28 @@ STACK_OUTPUT_KEYS = (
|
|||
|
||||
RES_KEYS = (
|
||||
RES_DESCRIPTION, RES_UPDATED_TIME,
|
||||
RES_NAME, RES_PHYSICAL_ID, RES_METADATA,
|
||||
RES_NAME, RES_PHYSICAL_ID, RES_METADATA, RES_ACTION,
|
||||
RES_STATUS, RES_STATUS_DATA, RES_TYPE,
|
||||
RES_ID, RES_STACK_ID, RES_STACK_NAME,
|
||||
) = (
|
||||
'description', 'updated_time',
|
||||
'logical_resource_id', 'physical_resource_id', 'metadata',
|
||||
'resource_status', 'resource_status_reason', 'resource_type',
|
||||
'resource_identity', STACK_ID, STACK_NAME,
|
||||
'resource_action', 'resource_status', 'resource_status_reason',
|
||||
'resource_type', 'resource_identity', STACK_ID, STACK_NAME,
|
||||
)
|
||||
|
||||
EVENT_KEYS = (
|
||||
EVENT_ID,
|
||||
EVENT_STACK_ID, EVENT_STACK_NAME,
|
||||
EVENT_TIMESTAMP,
|
||||
EVENT_RES_NAME, EVENT_RES_PHYSICAL_ID,
|
||||
EVENT_RES_NAME, EVENT_RES_PHYSICAL_ID, EVENT_RES_ACTION,
|
||||
EVENT_RES_STATUS, EVENT_RES_STATUS_DATA, EVENT_RES_TYPE,
|
||||
EVENT_RES_PROPERTIES,
|
||||
) = (
|
||||
'event_identity',
|
||||
STACK_ID, STACK_NAME,
|
||||
"event_time",
|
||||
RES_NAME, RES_PHYSICAL_ID,
|
||||
RES_NAME, RES_PHYSICAL_ID, RES_ACTION,
|
||||
RES_STATUS, RES_STATUS_DATA, RES_TYPE,
|
||||
'resource_properties',
|
||||
)
|
||||
|
|
|
@ -957,6 +957,7 @@ class CfnStackControllerTest(HeatTestCase):
|
|||
u'stack_name': u'wordpress',
|
||||
u'stack_id': u'6',
|
||||
u'path': u'/resources/WikiDatabase/events/42'},
|
||||
u'resource_action': u'TEST',
|
||||
u'resource_status': u'IN_PROGRESS',
|
||||
u'physical_resource_id': None,
|
||||
u'resource_properties': {u'UserData': u'blah'},
|
||||
|
@ -983,7 +984,68 @@ class CfnStackControllerTest(HeatTestCase):
|
|||
{'StackEvents':
|
||||
[{'EventId': u'42',
|
||||
'StackId': u'arn:openstack:heat::t:stacks/wordpress/6',
|
||||
'ResourceStatus': u'IN_PROGRESS',
|
||||
'ResourceStatus': u'TEST_IN_PROGRESS',
|
||||
'ResourceType': u'AWS::EC2::Instance',
|
||||
'Timestamp': u'2012-07-23T13:05:39Z',
|
||||
'StackName': u'wordpress',
|
||||
'ResourceProperties':
|
||||
json.dumps({u'UserData': u'blah'}),
|
||||
'PhysicalResourceId': None,
|
||||
'ResourceStatusReason': u'state changed',
|
||||
'LogicalResourceId': u'WikiDatabase'}]}}}
|
||||
|
||||
self.assertEqual(response, expected)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_events_list_onlystatus(self):
|
||||
# Format a dummy request
|
||||
stack_name = "wordpress"
|
||||
identity = dict(identifier.HeatIdentifier('t', stack_name, '6'))
|
||||
params = {'Action': 'DescribeStackEvents', 'StackName': stack_name}
|
||||
dummy_req = self._dummy_GET_request(params)
|
||||
|
||||
# Stub out the RPC call to the engine with a pre-canned response
|
||||
engine_resp = [{u'stack_name': u'wordpress',
|
||||
u'event_time': u'2012-07-23T13:05:39Z',
|
||||
u'stack_identity': {u'tenant': u't',
|
||||
u'stack_name': u'wordpress',
|
||||
u'stack_id': u'6',
|
||||
u'path': u''},
|
||||
u'logical_resource_id': u'WikiDatabase',
|
||||
u'resource_status_reason': u'state changed',
|
||||
u'event_identity':
|
||||
{u'tenant': u't',
|
||||
u'stack_name': u'wordpress',
|
||||
u'stack_id': u'6',
|
||||
u'path': u'/resources/WikiDatabase/events/42'},
|
||||
u'resource_action': None,
|
||||
u'resource_status': u'TEST_IN_PROGRESS',
|
||||
u'physical_resource_id': None,
|
||||
u'resource_properties': {u'UserData': u'blah'},
|
||||
u'resource_type': u'AWS::EC2::Instance'}]
|
||||
|
||||
self.m.StubOutWithMock(rpc, 'call')
|
||||
rpc.call(dummy_req.context, self.topic,
|
||||
{'namespace': None,
|
||||
'method': 'identify_stack',
|
||||
'args': {'stack_name': stack_name},
|
||||
'version': self.api_version}, None).AndReturn(identity)
|
||||
rpc.call(dummy_req.context, self.topic,
|
||||
{'namespace': None,
|
||||
'method': 'list_events',
|
||||
'args': {'stack_identity': identity},
|
||||
'version': self.api_version}, None).AndReturn(engine_resp)
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
||||
response = self.controller.events_list(dummy_req)
|
||||
|
||||
expected = {'DescribeStackEventsResponse':
|
||||
{'DescribeStackEventsResult':
|
||||
{'StackEvents':
|
||||
[{'EventId': u'42',
|
||||
'StackId': u'arn:openstack:heat::t:stacks/wordpress/6',
|
||||
'ResourceStatus': u'TEST_IN_PROGRESS',
|
||||
'ResourceType': u'AWS::EC2::Instance',
|
||||
'Timestamp': u'2012-07-23T13:05:39Z',
|
||||
'StackName': u'wordpress',
|
||||
|
|
|
@ -557,7 +557,7 @@ class stackServiceTest(HeatTestCase):
|
|||
self.assertEqual(ev['resource_properties']['InstanceType'],
|
||||
'm1.large')
|
||||
|
||||
self.assertTrue('resource_status' in ev)
|
||||
self.assertTrue('resource_action' in ev)
|
||||
self.assertTrue(ev['resource_status'] in ('IN_PROGRESS',
|
||||
'CREATE_COMPLETE'))
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ class EventTest(HeatTestCase):
|
|||
self.resource.resource_id_set('resource_physical_id')
|
||||
|
||||
e = event.Event(self.ctx, self.stack, self.resource,
|
||||
'TEST_IN_PROGRESS', 'Testing',
|
||||
'TEST', 'IN_PROGRESS', 'Testing',
|
||||
'wibble', self.resource.properties)
|
||||
|
||||
e.store()
|
||||
|
@ -79,14 +79,15 @@ class EventTest(HeatTestCase):
|
|||
self.assertEqual(loaded_e.resource.name, self.resource.name)
|
||||
self.assertEqual(loaded_e.resource.id, self.resource.id)
|
||||
self.assertEqual(loaded_e.physical_resource_id, 'wibble')
|
||||
self.assertEqual(loaded_e.new_state, 'TEST_IN_PROGRESS')
|
||||
self.assertEqual(loaded_e.action, 'TEST')
|
||||
self.assertEqual(loaded_e.status, 'IN_PROGRESS')
|
||||
self.assertEqual(loaded_e.reason, 'Testing')
|
||||
self.assertNotEqual(loaded_e.timestamp, None)
|
||||
self.assertEqual(loaded_e.resource_properties, {'foo': True})
|
||||
|
||||
def test_identifier(self):
|
||||
e = event.Event(self.ctx, self.stack, self.resource,
|
||||
'TEST_IN_PROGRESS', 'Testing',
|
||||
'TEST', 'IN_PROGRESS', 'Testing',
|
||||
'wibble', self.resource.properties)
|
||||
|
||||
eid = e.store()
|
||||
|
@ -103,6 +104,6 @@ class EventTest(HeatTestCase):
|
|||
rname = 'bad_resource'
|
||||
res = generic_rsrc.GenericResource(rname, tmpl, self.stack)
|
||||
e = event.Event(self.ctx, self.stack, res,
|
||||
'TEST_IN_PROGRESS', 'Testing',
|
||||
'TEST', 'IN_PROGRESS', 'Testing',
|
||||
'wibble', res.properties)
|
||||
self.assertTrue('Error' in e.resource_properties)
|
||||
|
|
Loading…
Reference in New Issue