summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2019-03-07 03:30:54 +0000
committerGerrit Code Review <review@openstack.org>2019-03-07 03:30:54 +0000
commit7ed696e5ded4776093c7e50316a13d6481c7e71b (patch)
treeb2d87cf2bef75639e94523cca77f0b83a5e4a1db
parentaa2c7fc9ac0b9c094db0f09bb3b75a09fa92063f (diff)
parent595db83ddcbed667c6d1abdb1e697e3397df3a3b (diff)
downloadpython-ironicclient-7ed696e5ded4776093c7e50316a13d6481c7e71b.tar.gz
Merge "Support passing a dictionary for configdrive"
-rw-r--r--ironicclient/common/http.py2
-rwxr-xr-xironicclient/osc/v1/baremetal_node.py16
-rw-r--r--ironicclient/tests/unit/osc/v1/test_baremetal_node.py19
-rw-r--r--ironicclient/tests/unit/v1/test_node.py10
-rw-r--r--ironicclient/v1/node.py19
-rw-r--r--releasenotes/notes/configdrive-7bd2b67830691b2e.yaml5
6 files changed, 60 insertions, 11 deletions
diff --git a/ironicclient/common/http.py b/ironicclient/common/http.py
index f930e21..0144e98 100644
--- a/ironicclient/common/http.py
+++ b/ironicclient/common/http.py
@@ -43,7 +43,7 @@ from ironicclient import exc
# http://specs.openstack.org/openstack/ironic-specs/specs/kilo/api-microversions.html # noqa
# for full details.
DEFAULT_VER = '1.9'
-LAST_KNOWN_API_VERSION = 55
+LAST_KNOWN_API_VERSION = 56
LATEST_VERSION = '1.{}'.format(LAST_KNOWN_API_VERSION)
LOG = logging.getLogger(__name__)
diff --git a/ironicclient/osc/v1/baremetal_node.py b/ironicclient/osc/v1/baremetal_node.py
index 718e12a..e940731 100755
--- a/ironicclient/osc/v1/baremetal_node.py
+++ b/ironicclient/osc/v1/baremetal_node.py
@@ -16,6 +16,7 @@
import argparse
import itertools
+import json
import logging
from osc_lib.command import command
@@ -30,8 +31,10 @@ from ironicclient.v1 import utils as v1_utils
CONFIG_DRIVE_ARG_HELP = _(
"A gzipped, base64-encoded configuration drive string OR "
"the path to the configuration drive file OR the path to a "
- "directory containing the config drive files. In case it's "
- "a directory, a config drive will be generated from it.")
+ "directory containing the config drive files OR a JSON object to build "
+ "config drive from. In case it's a directory, a config drive will be "
+ "generated from it. In case it's a JSON object, a config drive will "
+ "be generated on the server side.")
SUPPORTED_INTERFACES = ['bios', 'boot', 'console', 'deploy', 'inspect',
@@ -69,6 +72,15 @@ class ProvisionStateBaremetalNode(command.Command):
clean_steps = utils.handle_json_arg(clean_steps, 'clean steps')
config_drive = getattr(parsed_args, 'config_drive', None)
+ if config_drive:
+ try:
+ config_drive_dict = json.loads(config_drive)
+ except (ValueError, TypeError):
+ pass
+ else:
+ if isinstance(config_drive_dict, dict):
+ config_drive = config_drive_dict
+
rescue_password = getattr(parsed_args, 'rescue_password', None)
baremetal_client.node.set_provision_state(
diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_node.py b/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
index ad45fac..887e763 100644
--- a/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
+++ b/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
@@ -1390,6 +1390,25 @@ class TestDeployBaremetalProvisionState(TestBaremetal):
'node_uuid', 'active',
cleansteps=None, configdrive='path/to/drive', rescue_password=None)
+ def test_deploy_baremetal_provision_state_active_and_configdrive_dict(
+ self):
+ arglist = ['node_uuid',
+ '--config-drive', '{"meta_data": {}}']
+ verifylist = [
+ ('node', 'node_uuid'),
+ ('provision_state', 'active'),
+ ('config_drive', '{"meta_data": {}}'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.baremetal_mock.node.set_provision_state.assert_called_once_with(
+ 'node_uuid', 'active',
+ cleansteps=None, configdrive={'meta_data': {}},
+ rescue_password=None)
+
def test_deploy_no_wait(self):
arglist = ['node_uuid']
verifylist = [
diff --git a/ironicclient/tests/unit/v1/test_node.py b/ironicclient/tests/unit/v1/test_node.py
index 6afe1e2..baba5ea 100644
--- a/ironicclient/tests/unit/v1/test_node.py
+++ b/ironicclient/tests/unit/v1/test_node.py
@@ -1388,6 +1388,16 @@ class NodeManagerTest(testtools.TestCase):
]
self.assertEqual(expect, self.api.calls)
+ def test_node_set_provision_state_with_configdrive_as_dict(self):
+ target_state = 'active'
+ self.mgr.set_provision_state(NODE1['uuid'], target_state,
+ configdrive={'user_data': ''})
+ body = {'target': target_state, 'configdrive': {'user_data': ''}}
+ expect = [
+ ('PUT', '/v1/nodes/%s/states/provision' % NODE1['uuid'], {}, body),
+ ]
+ self.assertEqual(expect, self.api.calls)
+
def test_node_set_provision_state_with_configdrive_file(self):
target_state = 'active'
file_content = b'foo bar cat meow dog bark'
diff --git a/ironicclient/v1/node.py b/ironicclient/v1/node.py
index 8e5747b..d525eed 100644
--- a/ironicclient/v1/node.py
+++ b/ironicclient/v1/node.py
@@ -515,9 +515,11 @@ class NodeManager(base.CreateManager):
'rescue', 'unrescue'.
:param configdrive: A gzipped, base64-encoded configuration drive
string OR the path to the configuration drive file OR the path to
- a directory containing the config drive files. In case it's a
- directory, a config drive will be generated from it. This is only
- valid when setting state to 'active'.
+ a directory containing the config drive files OR a dictionary to
+ build config drive from. In case it's a directory, a config drive
+ will be generated from it. In case it's a dictionary, a config
+ drive will be generated on the server side (requires API version
+ 1.56). This is only valid when setting state to 'active'.
:param cleansteps: The clean steps as a list of clean-step
dictionaries; each dictionary should have keys 'interface' and
'step', and optional key 'args'. This must be specified (and is
@@ -534,11 +536,12 @@ class NodeManager(base.CreateManager):
path = "%s/states/provision" % node_uuid
body = {'target': state}
if configdrive:
- if os.path.isfile(configdrive):
- with open(configdrive, 'rb') as f:
- configdrive = f.read()
- if os.path.isdir(configdrive):
- configdrive = utils.make_configdrive(configdrive)
+ if not isinstance(configdrive, dict):
+ if os.path.isfile(configdrive):
+ with open(configdrive, 'rb') as f:
+ configdrive = f.read()
+ if os.path.isdir(configdrive):
+ configdrive = utils.make_configdrive(configdrive)
body['configdrive'] = configdrive
elif cleansteps:
diff --git a/releasenotes/notes/configdrive-7bd2b67830691b2e.yaml b/releasenotes/notes/configdrive-7bd2b67830691b2e.yaml
new file mode 100644
index 0000000..b7dbed3
--- /dev/null
+++ b/releasenotes/notes/configdrive-7bd2b67830691b2e.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Supports passing a JSON object to ``--config-drive`` to build the config
+ drive on the server side (requires API version 1.56).