Merge "Allow lists and strings for Json parameters via provider resources"
This commit is contained in:
commit
32aa3aac2b
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from heat.common import exception
|
from heat.common import exception
|
||||||
@ -58,13 +59,15 @@ class Schema(constr.Schema):
|
|||||||
implemented=True,
|
implemented=True,
|
||||||
update_allowed=False,
|
update_allowed=False,
|
||||||
immutable=False,
|
immutable=False,
|
||||||
support_status=support.SupportStatus()):
|
support_status=support.SupportStatus(),
|
||||||
|
allow_conversion=False):
|
||||||
super(Schema, self).__init__(data_type, description, default,
|
super(Schema, self).__init__(data_type, description, default,
|
||||||
schema, required, constraints)
|
schema, required, constraints)
|
||||||
self.implemented = implemented
|
self.implemented = implemented
|
||||||
self.update_allowed = update_allowed
|
self.update_allowed = update_allowed
|
||||||
self.immutable = immutable
|
self.immutable = immutable
|
||||||
self.support_status = support_status
|
self.support_status = support_status
|
||||||
|
self.allow_conversion = allow_conversion
|
||||||
# validate structural correctness of schema itself
|
# validate structural correctness of schema itself
|
||||||
self.validate()
|
self.validate()
|
||||||
|
|
||||||
@ -146,6 +149,13 @@ class Schema(constr.Schema):
|
|||||||
param.BOOLEAN: cls.BOOLEAN
|
param.BOOLEAN: cls.BOOLEAN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# allow_conversion allows slightly more flexible type conversion
|
||||||
|
# where property->parameter types don't align, primarily when
|
||||||
|
# a json parameter value is passed via a Map property, which requires
|
||||||
|
# some coercion to pass strings or lists (which are both valid for
|
||||||
|
# Json parameters but not for Map properties).
|
||||||
|
allow_conversion = param.type == param.MAP
|
||||||
|
|
||||||
# make update_allowed true by default on TemplateResources
|
# make update_allowed true by default on TemplateResources
|
||||||
# as the template should deal with this.
|
# as the template should deal with this.
|
||||||
return cls(data_type=param_type_map.get(param.type, cls.MAP),
|
return cls(data_type=param_type_map.get(param.type, cls.MAP),
|
||||||
@ -153,7 +163,8 @@ class Schema(constr.Schema):
|
|||||||
required=param.required,
|
required=param.required,
|
||||||
constraints=param.constraints,
|
constraints=param.constraints,
|
||||||
update_allowed=True,
|
update_allowed=True,
|
||||||
immutable=False)
|
immutable=False,
|
||||||
|
allow_conversion=allow_conversion)
|
||||||
|
|
||||||
def allowed_param_prop_type(self):
|
def allowed_param_prop_type(self):
|
||||||
"""
|
"""
|
||||||
@ -269,6 +280,14 @@ class Property(object):
|
|||||||
if value is None:
|
if value is None:
|
||||||
value = self.has_default() and self.default() or {}
|
value = self.has_default() and self.default() or {}
|
||||||
if not isinstance(value, collections.Mapping):
|
if not isinstance(value, collections.Mapping):
|
||||||
|
# This is to handle passing Lists via Json parameters exposed
|
||||||
|
# via a provider resource, in particular lists-of-dicts which
|
||||||
|
# cannot be handled correctly via comma_delimited_list
|
||||||
|
if self.schema.allow_conversion:
|
||||||
|
if isinstance(value, six.string_types):
|
||||||
|
return value
|
||||||
|
elif isinstance(value, collections.Sequence):
|
||||||
|
return jsonutils.dumps(value)
|
||||||
raise TypeError(_('"%s" is not a map') % value)
|
raise TypeError(_('"%s" is not a map') % value)
|
||||||
|
|
||||||
return dict(self._get_children(six.iteritems(value),
|
return dict(self._get_children(six.iteritems(value),
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
import six
|
import six
|
||||||
import testtools
|
import testtools
|
||||||
|
|
||||||
@ -468,6 +469,7 @@ class PropertySchemaTest(testtools.TestCase):
|
|||||||
self.assertTrue(schema.required)
|
self.assertTrue(schema.required)
|
||||||
self.assertIsNone(schema.default)
|
self.assertIsNone(schema.default)
|
||||||
self.assertEqual(0, len(schema.constraints))
|
self.assertEqual(0, len(schema.constraints))
|
||||||
|
self.assertFalse(schema.allow_conversion)
|
||||||
|
|
||||||
def test_from_number_param_min(self):
|
def test_from_number_param_min(self):
|
||||||
default = "42"
|
default = "42"
|
||||||
@ -546,6 +548,7 @@ class PropertySchemaTest(testtools.TestCase):
|
|||||||
self.assertIsNone(schema.default)
|
self.assertIsNone(schema.default)
|
||||||
self.assertFalse(schema.required)
|
self.assertFalse(schema.required)
|
||||||
self.assertEqual(1, len(schema.constraints))
|
self.assertEqual(1, len(schema.constraints))
|
||||||
|
self.assertFalse(schema.allow_conversion)
|
||||||
|
|
||||||
allowed_constraint = schema.constraints[0]
|
allowed_constraint = schema.constraints[0]
|
||||||
|
|
||||||
@ -563,6 +566,7 @@ class PropertySchemaTest(testtools.TestCase):
|
|||||||
self.assertEqual(properties.Schema.LIST, schema.type)
|
self.assertEqual(properties.Schema.LIST, schema.type)
|
||||||
self.assertIsNone(schema.default)
|
self.assertIsNone(schema.default)
|
||||||
self.assertFalse(schema.required)
|
self.assertFalse(schema.required)
|
||||||
|
self.assertFalse(schema.allow_conversion)
|
||||||
|
|
||||||
def test_from_json_param(self):
|
def test_from_json_param(self):
|
||||||
param = parameters.Schema.from_dict('name', {
|
param = parameters.Schema.from_dict('name', {
|
||||||
@ -575,6 +579,7 @@ class PropertySchemaTest(testtools.TestCase):
|
|||||||
self.assertEqual(properties.Schema.MAP, schema.type)
|
self.assertEqual(properties.Schema.MAP, schema.type)
|
||||||
self.assertIsNone(schema.default)
|
self.assertIsNone(schema.default)
|
||||||
self.assertFalse(schema.required)
|
self.assertFalse(schema.required)
|
||||||
|
self.assertTrue(schema.allow_conversion)
|
||||||
|
|
||||||
|
|
||||||
class PropertyTest(testtools.TestCase):
|
class PropertyTest(testtools.TestCase):
|
||||||
@ -862,6 +867,12 @@ class PropertyTest(testtools.TestCase):
|
|||||||
p = properties.Property({'Type': 'Map'})
|
p = properties.Property({'Type': 'Map'})
|
||||||
self.assertRaises(TypeError, p.get_value, ['foo'])
|
self.assertRaises(TypeError, p.get_value, ['foo'])
|
||||||
|
|
||||||
|
def test_map_allow_conversion(self):
|
||||||
|
p = properties.Property({'Type': 'Map'})
|
||||||
|
p.schema.allow_conversion = True
|
||||||
|
self.assertEqual('foo', p.get_value('foo'))
|
||||||
|
self.assertEqual(jsonutils.dumps(['foo']), p.get_value(['foo']))
|
||||||
|
|
||||||
def test_map_schema_good(self):
|
def test_map_schema_good(self):
|
||||||
map_schema = {'valid': {'Type': 'Boolean'}}
|
map_schema = {'valid': {'Type': 'Boolean'}}
|
||||||
p = properties.Property({'Type': 'Map', 'Schema': map_schema})
|
p = properties.Property({'Type': 'Map', 'Schema': map_schema})
|
||||||
|
Loading…
Reference in New Issue
Block a user