Merge "Support YAML files wherever JSON files are accepted"
This commit is contained in:
commit
891192ca2b
@ -26,6 +26,7 @@ import tempfile
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from oslo_utils import strutils
|
from oslo_utils import strutils
|
||||||
|
import yaml
|
||||||
|
|
||||||
from ironicclient.common.i18n import _
|
from ironicclient.common.i18n import _
|
||||||
from ironicclient import exc
|
from ironicclient import exc
|
||||||
@ -366,7 +367,7 @@ def get_from_stdin(info_desc):
|
|||||||
def handle_json_or_file_arg(json_arg):
|
def handle_json_or_file_arg(json_arg):
|
||||||
"""Attempts to read JSON argument from file or string.
|
"""Attempts to read JSON argument from file or string.
|
||||||
|
|
||||||
:param json_arg: May be a file name containing the JSON, or
|
:param json_arg: May be a file name containing the YAML or JSON, or
|
||||||
a JSON string.
|
a JSON string.
|
||||||
:returns: A list or dictionary parsed from JSON.
|
:returns: A list or dictionary parsed from JSON.
|
||||||
:raises: InvalidAttribute if the argument cannot be parsed.
|
:raises: InvalidAttribute if the argument cannot be parsed.
|
||||||
@ -375,9 +376,9 @@ def handle_json_or_file_arg(json_arg):
|
|||||||
if os.path.isfile(json_arg):
|
if os.path.isfile(json_arg):
|
||||||
try:
|
try:
|
||||||
with open(json_arg, 'r') as f:
|
with open(json_arg, 'r') as f:
|
||||||
json_arg = f.read().strip()
|
return yaml.safe_load(f)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
err = _("Cannot get JSON from file '%(file)s'. "
|
err = _("Cannot get JSON/YAML from file '%(file)s'. "
|
||||||
"Error: %(err)s") % {'err': e, 'file': json_arg}
|
"Error: %(err)s") % {'err': e, 'file': json_arg}
|
||||||
raise exc.InvalidAttribute(err)
|
raise exc.InvalidAttribute(err)
|
||||||
try:
|
try:
|
||||||
|
@ -25,9 +25,9 @@ from ironicclient.v1 import resource_fields as res_fields
|
|||||||
|
|
||||||
|
|
||||||
_DEPLOY_STEPS_HELP = _(
|
_DEPLOY_STEPS_HELP = _(
|
||||||
"The deploy steps in JSON format. May be the path to a file containing "
|
"The deploy steps. May be the path to a YAML file containing the deploy "
|
||||||
"the deploy steps; OR '-', with the deploy steps being read from standard "
|
"steps; OR '-', with the deploy steps being read from standard "
|
||||||
"input; OR a string. The value should be a list of deploy-step "
|
"input; OR a JSON string. The value should be a list of deploy-step "
|
||||||
"dictionaries; each dictionary should have keys 'interface', 'step', "
|
"dictionaries; each dictionary should have keys 'interface', 'step', "
|
||||||
"'args' and 'priority'.")
|
"'args' and 'priority'.")
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ CONFIG_DRIVE_ARG_HELP = _(
|
|||||||
|
|
||||||
|
|
||||||
NETWORK_DATA_ARG_HELP = _(
|
NETWORK_DATA_ARG_HELP = _(
|
||||||
"JSON string or a file or '-' for stdin to read static network "
|
"JSON string or a YAML file or '-' for stdin to read static network "
|
||||||
"configuration for the baremetal node associated with this ironic node. "
|
"configuration for the baremetal node associated with this ironic node. "
|
||||||
"Format of this file should comply with Nova network data metadata "
|
"Format of this file should comply with Nova network data metadata "
|
||||||
"(network_data.json). Depending on ironic boot interface capabilities "
|
"(network_data.json). Depending on ironic boot interface capabilities "
|
||||||
@ -256,10 +256,10 @@ class CleanBaremetalNode(ProvisionStateWithWait):
|
|||||||
metavar='<clean-steps>',
|
metavar='<clean-steps>',
|
||||||
required=True,
|
required=True,
|
||||||
default=None,
|
default=None,
|
||||||
help=_("The clean steps in JSON format. May be the path to a file "
|
help=_("The clean steps. May be the path to a YAML file "
|
||||||
"containing the clean steps; OR '-', with the clean steps "
|
"containing the clean steps; OR '-', with the clean steps "
|
||||||
"being read from standard input; OR a string. The value "
|
"being read from standard input; OR a JSON string. The "
|
||||||
"should be a list of clean-step dictionaries; each "
|
"value should be a list of clean-step dictionaries; each "
|
||||||
"dictionary should have keys 'interface' and 'step', and "
|
"dictionary should have keys 'interface' and 'step', and "
|
||||||
"optional key 'args'."))
|
"optional key 'args'."))
|
||||||
return parser
|
return parser
|
||||||
@ -571,12 +571,12 @@ class DeployBaremetalNode(ProvisionStateWithWait):
|
|||||||
metavar='<deploy-steps>',
|
metavar='<deploy-steps>',
|
||||||
required=False,
|
required=False,
|
||||||
default=None,
|
default=None,
|
||||||
help=_("The deploy steps in JSON format. May be the path to a "
|
help=_("The deploy steps. May be the path to a YAML file "
|
||||||
"file containing the deploy steps; OR '-', with the deploy "
|
"containing the deploy steps; OR '-', with the deploy "
|
||||||
"steps being read from standard input; OR a string. The "
|
"steps being read from standard input; OR a JSON string. "
|
||||||
"value should be a list of deploy-step dictionaries; each "
|
"The value should be a list of deploy-step dictionaries; "
|
||||||
"dictionary should have keys 'interface', 'step', "
|
"each dictionary should have keys 'interface' and 'step', "
|
||||||
"'priority' and optional key 'args'."))
|
"and optional key 'args'."))
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -1262,7 +1262,7 @@ class SetBaremetalNode(command.Command):
|
|||||||
'--target-raid-config',
|
'--target-raid-config',
|
||||||
metavar='<target_raid_config>',
|
metavar='<target_raid_config>',
|
||||||
help=_('Set the target RAID configuration (JSON) for the node. '
|
help=_('Set the target RAID configuration (JSON) for the node. '
|
||||||
'This can be one of: 1. a file containing JSON data of the '
|
'This can be one of: 1. a file containing YAML data of the '
|
||||||
'RAID configuration; 2. "-" to read the contents from '
|
'RAID configuration; 2. "-" to read the contents from '
|
||||||
'standard input; or 3. a valid JSON string.'),
|
'standard input; or 3. a valid JSON string.'),
|
||||||
)
|
)
|
||||||
|
@ -355,17 +355,24 @@ class HandleJsonFileTest(test_utils.BaseTestCase):
|
|||||||
|
|
||||||
self.assertEqual(json.loads(contents), steps)
|
self.assertEqual(json.loads(contents), steps)
|
||||||
|
|
||||||
|
def test_handle_yaml_or_file_arg_file(self):
|
||||||
|
contents = '''---
|
||||||
|
- step: upgrade
|
||||||
|
interface: deploy'''
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(mode='w') as f:
|
||||||
|
f.write(contents)
|
||||||
|
f.flush()
|
||||||
|
steps = utils.handle_json_or_file_arg(f.name)
|
||||||
|
|
||||||
|
self.assertEqual([{"step": "upgrade", "interface": "deploy"}], steps)
|
||||||
|
|
||||||
@mock.patch.object(builtins, 'open', autospec=True)
|
@mock.patch.object(builtins, 'open', autospec=True)
|
||||||
def test_handle_json_or_file_arg_file_fail(self, mock_open):
|
def test_handle_json_or_file_arg_file_fail(self, mock_open):
|
||||||
mock_file_object = mock.MagicMock()
|
mock_open.return_value.__enter__.side_effect = IOError
|
||||||
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:
|
with tempfile.NamedTemporaryFile(mode='w') as f:
|
||||||
self.assertRaisesRegex(exc.InvalidAttribute,
|
self.assertRaisesRegex(exc.InvalidAttribute,
|
||||||
"from file",
|
"from file",
|
||||||
utils.handle_json_or_file_arg, f.name)
|
utils.handle_json_or_file_arg, f.name)
|
||||||
mock_open.assert_called_once_with(f.name, 'r')
|
mock_open.assert_called_once_with(f.name, 'r')
|
||||||
mock_file_object.read.assert_called_once_with()
|
|
||||||
|
7
releasenotes/notes/yaml-files-79cd8367d7a4c2f2.yaml
Normal file
7
releasenotes/notes/yaml-files-79cd8367d7a4c2f2.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
YAML files are now supported for the ``--network-data``,
|
||||||
|
``--deploy-steps``, ``--clean-steps`` and ``--target-raid-config``
|
||||||
|
arguments, as well as for the ``--steps`` argument of deploy template
|
||||||
|
commands.
|
Loading…
x
Reference in New Issue
Block a user