diff --git a/magnumclient/common/utils.py b/magnumclient/common/utils.py index 7539fd29..4c40bc3f 100644 --- a/magnumclient/common/utils.py +++ b/magnumclient/common/utils.py @@ -80,6 +80,16 @@ def args_array_to_patch(op, attributes): return patch +def handle_labels(labels): + labels = format_labels(labels) + if 'mesos_slave_executor_env_file' in labels: + environment_variables_data = handle_json_from_file( + labels['mesos_slave_executor_env_file']) + labels['mesos_slave_executor_env_variables'] = json.dumps( + environment_variables_data) + return labels + + def format_labels(lbls, parse_comma=True): '''Reformat labels into dict of format expected by the API.''' @@ -111,3 +121,26 @@ def format_labels(lbls, parse_comma=True): def print_list_field(field): return lambda obj: ', '.join(getattr(obj, field)) + + +def handle_json_from_file(json_arg): + """Attempts to read JSON file by the file url. + + :param json_arg: May be a file name containing the JSON. + :returns: A list or dictionary parsed from JSON. + """ + + try: + with open(json_arg, 'r') as f: + json_arg = f.read().strip() + json_arg = json.loads(json_arg) + except IOError as e: + err = _("Cannot get JSON from file '%(file)s'. " + "Error: %(err)s") % {'err': e, 'file': json_arg} + raise exc.InvalidAttribute(err) + except ValueError as e: + err = (_("For JSON: '%(string)s', error: '%(err)s'") % + {'err': e, 'string': json_arg}) + raise exc.InvalidAttribute(err) + + return json_arg diff --git a/magnumclient/tests/test_utils.py b/magnumclient/tests/test_utils.py index dc14f6a1..d2632018 100644 --- a/magnumclient/tests/test_utils.py +++ b/magnumclient/tests/test_utils.py @@ -16,7 +16,11 @@ # under the License. import collections +import mock +from oslo_serialization import jsonutils as json import six +import six.moves.builtins as __builtin__ +import tempfile from magnumclient.common import cliutils from magnumclient.common import utils @@ -230,3 +234,40 @@ class CliUtilsTest(test_utils.BaseTestCase): ('c', dict_out['c'])]) self.assertEqual(six.text_type(dict_exp), six.text_type(dict_act)) + + +class HandleJsonFromFileTest(test_utils.BaseTestCase): + + def test_handle_json_from_file_bad_json(self): + contents = 'foo' + with tempfile.NamedTemporaryFile(mode='w') as f: + f.write(contents) + f.flush() + self.assertRaisesRegex(exc.InvalidAttribute, + 'For JSON', + utils.handle_json_from_file, f.name) + + def test_handle_json_from_file_valid_file(self): + contents = '{"step": "upgrade", "interface": "deploy"}' + + with tempfile.NamedTemporaryFile(mode='w') as f: + f.write(contents) + f.flush() + steps = utils.handle_json_from_file(f.name) + + self.assertEqual(json.loads(contents), steps) + + @mock.patch.object(__builtin__, 'open', autospec=True) + def test_handle_json_from_file_open_fail(self, mock_open): + mock_file_object = mock.MagicMock() + mock_file_handle = mock.MagicMock() + mock_file_handle.__enter__.return_value = mock_file_object + mock_open.return_value = mock_file_handle + mock_file_object.read.side_effect = IOError + + with tempfile.NamedTemporaryFile(mode='w') as f: + self.assertRaisesRegex(exc.InvalidAttribute, + "from file", + utils.handle_json_from_file, f.name) + mock_open.assert_called_once_with(f.name, 'r') + mock_file_object.read.assert_called_once_with() diff --git a/magnumclient/v1/baymodels_shell.py b/magnumclient/v1/baymodels_shell.py index 28d4659b..8642868a 100644 --- a/magnumclient/v1/baymodels_shell.py +++ b/magnumclient/v1/baymodels_shell.py @@ -121,7 +121,7 @@ def do_baymodel_create(cs, args): opts['http_proxy'] = args.http_proxy opts['https_proxy'] = args.https_proxy opts['no_proxy'] = args.no_proxy - opts['labels'] = magnum_utils.format_labels(args.labels) + opts['labels'] = magnum_utils.handle_labels(args.labels) opts['tls_disabled'] = args.tls_disabled opts['public'] = args.public opts['registry_enabled'] = args.registry_enabled