Always commit after deployment db operations

This should eliminate a potential race where a depolyment
create doesn't get commited before another engine calls
SoftwareConfigService._refresh_software_deployment

This change also adds a functional test which creates
4 parallel deployments to a server and assert that all 4 end
up in the server metadata.

Change-Id: Iab26aa10bddf3ea569e3ed83a973bcf968964b62
Related-Bug: #1477329
This commit is contained in:
Steve Baker 2015-07-23 10:21:02 +12:00
parent bd7895c555
commit 95e7389f9d
2 changed files with 83 additions and 6 deletions

View File

@ -877,7 +877,10 @@ def software_config_delete(context, config_id):
def software_deployment_create(context, values): def software_deployment_create(context, values):
obj_ref = models.SoftwareDeployment() obj_ref = models.SoftwareDeployment()
obj_ref.update(values) obj_ref.update(values)
obj_ref.save(_session(context)) session = _session(context)
session.begin()
obj_ref.save(session)
session.commit()
return obj_ref return obj_ref
@ -909,16 +912,13 @@ def software_deployment_get_all(context, server_id=None):
def software_deployment_update(context, deployment_id, values): def software_deployment_update(context, deployment_id, values):
deployment = software_deployment_get(context, deployment_id) deployment = software_deployment_get(context, deployment_id)
deployment.update(values) deployment.update_and_save(values)
deployment.save(_session(context))
return deployment return deployment
def software_deployment_delete(context, deployment_id): def software_deployment_delete(context, deployment_id):
deployment = software_deployment_get(context, deployment_id) deployment = software_deployment_get(context, deployment_id)
session = orm_session.Session.object_session(deployment) deployment.delete()
session.delete(deployment)
session.flush()
def snapshot_create(context, values): def snapshot_create(context, values):

View File

@ -0,0 +1,77 @@
# 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 heat_integrationtests.common import test
class ParallelDeploymentsTest(test.HeatIntegrationTest):
template = '''
heat_template_version: "2013-05-23"
parameters:
flavor:
type: string
image:
type: string
network:
type: string
resources:
server:
type: OS::Nova::Server
properties:
image: {get_param: image}
flavor: {get_param: flavor}
user_data_format: SOFTWARE_CONFIG
networks: [{network: {get_param: network} }]
config:
type: OS::Heat::SoftwareConfig
properties:
config: hi!
dep1:
type: OS::Heat::SoftwareDeployment
properties:
config: {get_resource: config}
server: {get_resource: server}
signal_transport: NO_SIGNAL
dep2:
type: OS::Heat::SoftwareDeployment
properties:
config: {get_resource: config}
server: {get_resource: server}
signal_transport: NO_SIGNAL
dep3:
type: OS::Heat::SoftwareDeployment
properties:
config: {get_resource: config}
server: {get_resource: server}
signal_transport: NO_SIGNAL
dep4:
type: OS::Heat::SoftwareDeployment
properties:
config: {get_resource: config}
server: {get_resource: server}
signal_transport: NO_SIGNAL
'''
def setUp(self):
super(ParallelDeploymentsTest, self).setUp()
self.client = self.orchestration_client
def test_fail(self):
parms = {'flavor': self.conf.minimal_instance_type,
'network': self.conf.fixed_network_name,
'image': self.conf.minimal_image_ref}
stack_identifier = self.stack_create(
parameters=parms,
template=self.template)
stack = self.client.stacks.get(stack_identifier)
server_metadata = self.client.resources.metadata(stack.id, 'server')
self.assertEqual(4, len(server_metadata['deployments']))