Support setting non-string fields

Some attributes in Ironic support multiple types of data, before the
CLI was treating everything as a string this patch is changing that by
making the CLI to JSON deserialize the values before sending it to Ironic.

Change-Id: I7d53b31ad401bc7c36841e0ece28e818cdc8976d
Closes-Bug: #1403491
This commit is contained in:
Lucas Alvares Gomes 2014-12-17 16:35:10 +00:00
parent 8a07fdffb2
commit 8910d45955
2 changed files with 63 additions and 22 deletions
ironicclient

@ -18,6 +18,7 @@
from __future__ import print_function
import argparse
import json
from ironicclient import exc
from ironicclient.openstack.common import importutils
@ -70,16 +71,32 @@ def import_versioned_module(version, submodule=None):
return importutils.import_module(module)
def split_and_deserialize(string):
"""Split and try to JSON deserialize a string.
Gets a string with the KEY=VALUE format, split it (using '=' as the
separator) and try to JSON deserialize the VALUE.
:returns: A tuple of (key, value).
"""
try:
key, value = string.split("=", 1)
except ValueError:
raise exc.CommandError(_('Attributes must be a list of '
'PATH=VALUE not "%s"') % string)
try:
value = json.loads(value)
except ValueError:
pass
return (key, value)
def args_array_to_dict(kwargs, key_to_convert):
values_to_convert = kwargs.get(key_to_convert)
if values_to_convert:
try:
kwargs[key_to_convert] = dict(v.split("=", 1)
for v in values_to_convert)
except ValueError:
raise exc.CommandError(
_('%(key)s must be a list of KEY=VALUE not "%(values)s"') %
{'key': key_to_convert, 'values': values_to_convert})
kwargs[key_to_convert] = dict(split_and_deserialize(v)
for v in values_to_convert)
return kwargs
@ -91,12 +108,9 @@ def args_array_to_patch(op, attributes):
attr = '/' + attr
if op in ['add', 'replace']:
try:
path, value = attr.split("=", 1)
patch.append({'op': op, 'path': path, 'value': value})
except ValueError:
raise exc.CommandError(_('Attributes must be a list of '
'PATH=VALUE not "%s"') % attr)
path, value = split_and_deserialize(attr)
patch.append({'op': op, 'path': path, 'value': value})
elif op == "remove":
# For remove only the key is needed
patch.append({'op': op, 'path': attr})

@ -23,31 +23,35 @@ from ironicclient.tests import utils as test_utils
class UtilsTest(test_utils.BaseTestCase):
def test_args_array_to_dict(self):
my_args = {
'matching_metadata': ['metadata.key=metadata_value'],
'matching_metadata': ['str=foo', 'int=1', 'bool=true',
'list=[1, 2, 3]', 'dict={"foo": "bar"}'],
'other': 'value'
}
cleaned_dict = utils.args_array_to_dict(my_args,
"matching_metadata")
self.assertEqual({
'matching_metadata': {'metadata.key': 'metadata_value'},
'matching_metadata': {'str': 'foo', 'int': 1, 'bool': True,
'list': [1, 2, 3], 'dict': {'foo': 'bar'}},
'other': 'value'
}, cleaned_dict)
def test_args_array_to_patch(self):
my_args = {
'attributes': ['foo=bar', '/extra/bar=baz'],
'attributes': ['str=foo', 'int=1', 'bool=true',
'list=[1, 2, 3]', 'dict={"foo": "bar"}'],
'op': 'add',
}
patch = utils.args_array_to_patch(my_args['op'],
my_args['attributes'])
self.assertEqual([{'op': 'add',
'value': 'bar',
'path': '/foo'},
{'op': 'add',
'value': 'baz',
'path': '/extra/bar'}], patch)
self.assertEqual([{'op': 'add', 'value': 'foo', 'path': '/str'},
{'op': 'add', 'value': 1, 'path': '/int'},
{'op': 'add', 'value': True, 'path': '/bool'},
{'op': 'add', 'value': [1, 2, 3], 'path': '/list'},
{'op': 'add', 'value': {"foo": "bar"},
'path': '/dict'}], patch)
def test_args_array_to_patch_format_error(self):
my_args = {
@ -67,6 +71,29 @@ class UtilsTest(test_utils.BaseTestCase):
self.assertEqual([{'op': 'remove', 'path': '/foo'},
{'op': 'remove', 'path': '/extra/bar'}], patch)
def test_split_and_deserialize(self):
ret = utils.split_and_deserialize('str=foo')
self.assertEqual(('str', 'foo'), ret)
ret = utils.split_and_deserialize('int=1')
self.assertEqual(('int', 1), ret)
ret = utils.split_and_deserialize('bool=false')
self.assertEqual(('bool', False), ret)
ret = utils.split_and_deserialize('list=[1, "foo", 2]')
self.assertEqual(('list', [1, "foo", 2]), ret)
ret = utils.split_and_deserialize('dict={"foo": 1}')
self.assertEqual(('dict', {"foo": 1}), ret)
ret = utils.split_and_deserialize('str_int="1"')
self.assertEqual(('str_int', "1"), ret)
def test_split_and_deserialize_fail(self):
self.assertRaises(exc.CommandError,
utils.split_and_deserialize, 'foo:bar')
class CommonParamsForListTest(test_utils.BaseTestCase):
def setUp(self):