Check swift deployments before update

Before making a software deployments update in the Swift backend, check
the data content to operate as a transaction.

Change-Id: I58d3af3d1de481b3d314313c9f39255504792634
Closes-Bug: #1731032
This commit is contained in:
Thomas Herve 2017-11-20 10:51:13 +01:00
parent 121627bce7
commit 746a122d81
2 changed files with 33 additions and 8 deletions

View File

@ -108,22 +108,37 @@ class SoftwareConfigService(object):
deployments = self.metadata_software_deployments(cnxt, server_id)
md = rs.rsrc_metadata or {}
md['deployments'] = deployments
rows_updated = db_api.resource_update(
cnxt, rs.id, {'rsrc_metadata': md}, rs.atomic_key)
if not rows_updated:
action = _('deployments of server %s') % server_id
raise exception.ConcurrentTransaction(action=action)
metadata_put_url = None
metadata_queue_id = None
metadata_headers = None
for rd in rs.data:
if rd.key == 'metadata_put_url':
metadata_put_url = rd.value
if rd.key == 'metadata_queue_id':
metadata_queue_id = rd.value
if metadata_put_url:
data = requests.head(metadata_put_url)
etag = data.headers.get('etag')
if etag:
metadata_headers = {'if-match': etag}
else:
LOG.warning('Couldn\'t find existing Swift metadata')
rows_updated = db_api.resource_update(
cnxt, rs.id, {'rsrc_metadata': md}, rs.atomic_key)
if not rows_updated:
LOG.debug('Conflict on database deployment update, retrying')
action = _('deployments of server %s') % server_id
raise exception.ConcurrentTransaction(action=action)
if metadata_put_url:
json_md = jsonutils.dumps(md)
requests.put(metadata_put_url, json_md)
resp = requests.put(metadata_put_url, json_md,
headers=metadata_headers)
if resp.status_code == 412:
LOG.debug('Conflict on Swift deployment update, retrying')
action = _('deployments of server %s') % server_id
raise exception.ConcurrentTransaction(action=action)
if metadata_queue_id:
project = stack_user_project_id
queue = self._get_zaqar_queue(cnxt, rs, project, metadata_queue_id)

View File

@ -692,8 +692,9 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
@mock.patch.object(db_api, 'resource_update')
@mock.patch.object(db_api, 'resource_get_by_physical_resource_id')
@mock.patch.object(service_software_config.requests, 'put')
@mock.patch.object(service_software_config.requests, 'head')
def test_push_metadata_software_deployments_temp_url(
self, put, res_get, res_upd, md_sd):
self, head, put, res_get, res_upd, md_sd):
rs = mock.Mock()
rs.rsrc_metadata = {'original': 'metadata'}
rs.id = '1234'
@ -705,6 +706,14 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
res_get.return_value = rs
res_upd.return_value = 1
head_response = mock.Mock()
head_response.headers = {'etag': '1234'}
head_response.status_code = 200
head.return_value = head_response
put_response = mock.Mock()
put_response.status_code = 201
deployments = {'deploy': 'this'}
md_sd.return_value = deployments
@ -719,7 +728,8 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
self.ctx, '1234', {'rsrc_metadata': result_metadata}, 1)
put.assert_called_once_with(
'http://192.168.2.2/foo/bar', json.dumps(result_metadata))
'http://192.168.2.2/foo/bar', json.dumps(result_metadata),
headers={'if-match': '1234'})
@mock.patch.object(service_software_config.SoftwareConfigService,
'metadata_software_deployments')