Handle requirements set to empty strings

If hypervisor_properties or resource_properties are set to empty strings
by the API client, they are persisted as empty strings in the database.
However, in convert_requirements(), the code assumes they are JSON
strings and tries to parse them, which raises a MalformedRequirements
exception.

This can be triggered by an operator when updating an extra capability
on a node that is reserved with resource_properties set to an empty
string, as is_updatable_extra_capability() calls convert_requirements().
Blazar would return a 400 Client Error to them.

Ideally, only valid JSON should be persisted to the database. However,
this will require an Alembic migration to change existing empty strings
to empty JSON arrays. In the meantime, this simpler patch can be
backported to stable branches.

Change-Id: Ic6d18418a2515cd37bbeed25ee3ab8c360624ca3
Closes-Bug: #1792245
This commit is contained in:
Pierre Riteau 2018-09-13 11:35:55 -06:00
parent 9bcb976a72
commit 77c1a2b683
2 changed files with 13 additions and 0 deletions

View File

@ -29,6 +29,13 @@ class TestPluginsUtils(tests.TestCase):
result = plugins_utils.convert_requirements(request)
self.assertEqual([], result)
def test_convert_requirements_empty_string(self):
# NOTE(priteau): Currently, empty requirements can be persisted in the
# database as empty strings, which are not valid JSON objects.
request = ''
result = plugins_utils.convert_requirements(request)
self.assertEqual([], result)
def test_convert_requirements_small(self):
request = '["=", "$memory", "4096"]'
result = plugins_utils.convert_requirements(request)

View File

@ -28,6 +28,12 @@ def convert_requirements(requirements):
# TODO(frossigneux) Support the "or" operator
# Convert text to json
if isinstance(requirements, six.string_types):
# Treat empty string as an empty JSON array, to avoid raising a
# ValueError exception while loading JSON
#
# TODO(priteau): Only persist valid JSON to the database
if requirements == '':
requirements = '[]'
try:
requirements = jsonutils.loads(requirements)
except ValueError: