Handle FK error when creating/updating software deployments

Software deployments have FK constraints on software configs.
This change ensures the DBReferenceError caused by the constraints is
properly caught. With this change now heat returns 400 Bad Response,
instead of 500 Internal Server Error when a user tries to create
a software deployment with a non-existing software config.

Also, the stack_user_project_id field is defined as 64-chars-long
string in DB model, so we should ensure that the input value is shorter
than 65 chars. Otherwise it also results in DB error.

Story: 2010001
Task: 45098
Change-Id: I03274dc0cffa226140eb720458cce81e8b5ce187
This commit is contained in:
Ekaterina Chernova 2022-04-19 16:05:30 +03:00 committed by Takashi Kajinami
parent 17ed569181
commit 7860e7acbc
3 changed files with 64 additions and 4 deletions

View File

@ -1244,8 +1244,13 @@ def software_deployment_create(context, values):
obj_ref = models.SoftwareDeployment()
obj_ref.update(values)
with context.session.begin():
obj_ref.save(context.session)
try:
with context.session.begin():
obj_ref.save(context.session)
except db_exception.DBReferenceError:
# NOTE(tkajinam): config_id is the only FK in SoftwareDeployment
err_msg = _('Config with id %s not found') % values['config_id']
raise exception.Invalid(reason=err_msg)
return obj_ref
@ -1278,7 +1283,12 @@ def software_deployment_get_all(context, server_id=None):
def software_deployment_update(context, deployment_id, values):
deployment = software_deployment_get(context, deployment_id)
update_and_save(context, deployment, values)
try:
update_and_save(context, deployment, values)
except db_exception.DBReferenceError:
# NOTE(tkajinam): config_id is the only FK in SoftwareDeployment
err_msg = _('Config with id %s not found') % values['config_id']
raise exception.Invalid(reason=err_msg)
return deployment

View File

@ -268,7 +268,11 @@ class SoftwareConfigService(object):
input_values, action, status,
status_reason, stack_user_project_id,
deployment_id=None):
if stack_user_project_id is not None:
if len(stack_user_project_id) > 64:
raise exception.Invalid(
reason='"stack_user_project_id" '
'should be no more than 64 characters')
if deployment_id is None:
deployment_id = str(uuid.uuid4())
sd = software_deployment_object.SoftwareDeployment.create(cnxt, {

View File

@ -504,6 +504,31 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
self.assertEqual(deployment_id, deployment['id'])
self.assertEqual(kwargs['input_values'], deployment['input_values'])
def test_create_software_deployment_invalid_stack_user_project_id(self):
sc_kwargs = {
'group': 'Heat::Chef',
'name': 'config_heat',
'config': '...',
'inputs': [{'name': 'mode'}],
'outputs': [{'name': 'endpoint'}],
'options': {}
}
config = self._create_software_config(**sc_kwargs)
config_id = config['id']
sd_kwargs = {
'config_id': config_id,
'input_values': {'mode': 'standalone'},
'action': 'INIT',
'status': 'COMPLETE',
'status_reason': '',
# stack_user_project should be no more than 64 characters
'stack_user_project_id': 'a' * 65
}
ex = self.assertRaises(dispatcher.ExpectedException,
self._create_software_deployment,
**sd_kwargs)
self.assertEqual(exception.Invalid, ex.exc_info[0])
@mock.patch.object(service_software_config.SoftwareConfigService,
'_refresh_swift_software_deployment')
def test_show_software_deployment_refresh(
@ -1084,3 +1109,24 @@ class SoftwareConfigIOSchemaTest(common.HeatTestCase):
self.assertEqual({'type': 'Number', 'name': 'baz', 'default': ''},
inp.as_dict())
class SoftwareConfigServiceTestWithConstraint(SoftwareConfigServiceTest):
"""Test cases which require FK constraints"""
def setUp(self):
self.useFixture(utils.ForeignKeyConstraintFixture())
super(SoftwareConfigServiceTestWithConstraint, self).setUp()
def test_create_software_deployment_invalid_config_id(self):
kwargs = {
'config_id': 'this_is_invalid',
'input_values': {'mode': 'standalone'},
'action': 'INIT',
'status': 'COMPLETE',
'status_reason': ''
}
ex = self.assertRaises(dispatcher.ExpectedException,
self._create_software_deployment,
**kwargs)
self.assertEqual(exception.Invalid, ex.exc_info[0])