summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZane Bitter <zbitter@redhat.com>2015-03-18 21:30:31 -0400
committerZane Bitter <zbitter@redhat.com>2015-03-19 00:15:59 -0400
commit073a9d34048a29fab099c2886c274eacf94301dd (patch)
tree8b7e8c0ea12f47a5009e78dd45bd15a1bdb89012
parent740dc88dcce832990e98198d0b6574d38b624489 (diff)
downloadheat-073a9d34048a29fab099c2886c274eacf94301dd.tar.gz
Store Resources before they are created
Store all Resources in an initial INIT_COMPLETE state prior to creating a stack, rather than waiting until each Resource is create()d. When updating a stack, store each new Resource just prior to create()ing it. Change-Id: Ifeee8213c1962cbf45fd0dd59f1832b0eeff1a47 Closes-Bug: #1319813
-rw-r--r--heat/engine/resource.py57
-rw-r--r--heat/engine/service.py3
-rwxr-xr-xheat/engine/stack.py9
-rw-r--r--heat/tests/test_nested_stack.py1
-rw-r--r--heat/tests/test_provider_template.py1
-rw-r--r--heat/tests/test_software_deployment.py1
6 files changed, 46 insertions, 26 deletions
diff --git a/heat/engine/resource.py b/heat/engine/resource.py
index 2f4ff6775..35cb8ab78 100644
--- a/heat/engine/resource.py
+++ b/heat/engine/resource.py
@@ -249,7 +249,7 @@ class Resource(object):
def metadata_get(self, refresh=False):
if refresh:
self._rsrc_metadata = None
- if self.id is None:
+ if self.id is None or self.action == self.INIT:
return self.t.metadata()
if self._rsrc_metadata is not None:
return self._rsrc_metadata
@@ -259,7 +259,7 @@ class Resource(object):
return rs.rsrc_metadata
def metadata_set(self, metadata):
- if self.id is None:
+ if self.id is None or self.action == self.INIT:
raise exception.ResourceNotAvailable(resource_name=self.name)
rs = resource_objects.Resource.get_obj(self.stack.context, self.id)
rs.update_and_save({'rsrc_metadata': metadata})
@@ -790,7 +790,7 @@ class Resource(object):
yield self.action_handler_task('delete_snapshot', args=[data])
def physical_resource_name(self):
- if self.id is None:
+ if self.id is None or self.action == self.INIT:
return None
name = '%s-%s-%s' % (self.stack.name,
@@ -904,9 +904,8 @@ class Resource(object):
except Exception as ex:
LOG.warn(_LW('db error %s'), ex)
- def _store(self):
+ def _store(self, metadata=None):
'''Create the resource in the database.'''
- metadata = self.metadata_get()
try:
rs = {'action': self.action,
'status': self.status,
@@ -940,35 +939,43 @@ class Resource(object):
ev.store()
def _store_or_update(self, action, status, reason):
+ prev_action = self.action
self.action = action
self.status = status
self.status_reason = reason
+ data = {
+ 'action': self.action,
+ 'status': self.status,
+ 'status_reason': reason,
+ 'stack_id': self.stack.id,
+ 'updated_at': self.updated_time,
+ 'properties_data': self._stored_properties_data,
+ 'needed_by': self.needed_by,
+ 'requires': self.requires,
+ 'replaces': self.replaces,
+ 'replaced_by': self.replaced_by,
+ 'current_template_id': self.current_template_id,
+ 'nova_instance': self.resource_id
+ }
+ if prev_action == self.INIT:
+ metadata = self.t.metadata()
+ data['rsrc_metadata'] = metadata
+ else:
+ metadata = self._rsrc_metadata
+
if self.id is not None:
try:
rs = resource_objects.Resource.get_obj(self.context, self.id)
- rs.update_and_save({
- 'action': self.action,
- 'status': self.status,
- 'status_reason': reason,
- 'stack_id': self.stack.id,
- 'updated_at': self.updated_time,
- 'properties_data': self._stored_properties_data,
- 'needed_by': self.needed_by,
- 'requires': self.requires,
- 'replaces': self.replaces,
- 'replaced_by': self.replaced_by,
- 'current_template_id': self.current_template_id,
- 'nova_instance': self.resource_id})
+ rs.update_and_save(data)
except Exception as ex:
LOG.error(_LE('DB error %s'), ex)
-
- # store resource in DB on transition to CREATE_IN_PROGRESS
- # all other transitions (other than to DELETE_COMPLETE)
- # should be handled by the update_and_save above..
- elif (action, status) in [(self.CREATE, self.IN_PROGRESS),
- (self.ADOPT, self.IN_PROGRESS)]:
- self._store()
+ else:
+ self._rsrc_metadata = metadata
+ else:
+ # This should only happen in unit tests
+ LOG.warning(_LW('Resource "%s" not pre-stored in DB'), self)
+ self._store(metadata)
def _resolve_attribute(self, name):
"""
diff --git a/heat/engine/service.py b/heat/engine/service.py
index 8740431bf..41a07d3b2 100644
--- a/heat/engine/service.py
+++ b/heat/engine/service.py
@@ -1115,7 +1115,8 @@ class EngineService(service.Service):
# when signalling a WaitConditionHandle resource, and other
# resources may refer to WaitCondition Fn::GetAtt Data
for r in stack.dependencies:
- if r.name != rsrc.name and r.id is not None:
+ if (r.name != rsrc.name and r.id is not None and
+ r.action != r.INIT):
r.metadata_update()
s = self._get_stack(cnxt, stack_identity)
diff --git a/heat/engine/stack.py b/heat/engine/stack.py
index dbb02b6ff..e2bcfebd2 100755
--- a/heat/engine/stack.py
+++ b/heat/engine/stack.py
@@ -430,6 +430,8 @@ class Stack(collections.Mapping):
self.t.add_resource(definition)
if self.t.id is not None:
self.t.store(self.context)
+ if resource.action == resource.INIT:
+ resource._store()
def remove_resource(self, resource_name):
'''Remove the resource with the specified name.'''
@@ -618,6 +620,11 @@ class Stack(collections.Mapping):
return [resource.preview()
for resource in self.resources.itervalues()]
+ def _store_resources(self):
+ for r in reversed(self.dependencies):
+ if r.action == r.INIT:
+ r._store()
+
@profiler.trace('Stack.create', hide_args=False)
def create(self):
'''
@@ -628,6 +635,8 @@ class Stack(collections.Mapping):
self.FAILED):
self.delete(action=self.ROLLBACK)
+ self._store_resources()
+
creator = scheduler.TaskRunner(
self.stack_task, action=self.CREATE,
reverse=False, post_func=rollback,
diff --git a/heat/tests/test_nested_stack.py b/heat/tests/test_nested_stack.py
index d87f5b42a..b20a7e904 100644
--- a/heat/tests/test_nested_stack.py
+++ b/heat/tests/test_nested_stack.py
@@ -353,6 +353,7 @@ Outputs:
def test_handle_delete(self):
self.res.rpc_client = mock.MagicMock()
+ self.res.action = self.res.CREATE
stack_identity = identifier.HeatIdentifier(
self.ctx.tenant_id,
self.res.physical_resource_name(),
diff --git a/heat/tests/test_provider_template.py b/heat/tests/test_provider_template.py
index e368ed277..f6a97c342 100644
--- a/heat/tests/test_provider_template.py
+++ b/heat/tests/test_provider_template.py
@@ -878,6 +878,7 @@ class TemplateResourceCrudTest(common.HeatTestCase):
self.res.id = 55
self.res.uuid = six.text_type(uuid.uuid4())
self.res.resource_id = six.text_type(uuid.uuid4())
+ self.res.action = self.res.CREATE
ident = identifier.HeatIdentifier(self.ctx.tenant_id,
self.res.physical_resource_name(),
self.res.resource_id)
diff --git a/heat/tests/test_software_deployment.py b/heat/tests/test_software_deployment.py
index 124f6e453..dc624bf19 100644
--- a/heat/tests/test_software_deployment.py
+++ b/heat/tests/test_software_deployment.py
@@ -869,6 +869,7 @@ class SoftwareDeploymentTest(common.HeatTestCase):
self.deployment.id = 23
self.deployment.uuid = str(uuid.uuid4())
+ self.deployment.action = self.deployment.CREATE
container = self.deployment.physical_resource_name()
temp_url = self.deployment._get_temp_url()