Support passing a dictionary for configdrive

API version 1.56 introduces support for building configdrive on the
server side. In this case configdrive is a dictionary, this changes
adds support for it.

Change-Id: I2b870fc89aa31c13b33f76b14acd6ee959800554
Depends-On: https://review.openstack.org/639050
Story: #2005083
Task: #29841
This commit is contained in:
Dmitry Tantsur 2019-03-05 16:45:01 +01:00
parent cc37253428
commit 595db83ddc
6 changed files with 60 additions and 11 deletions

View File

@ -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__)

View File

@ -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(

View File

@ -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 = [

View File

@ -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'

View File

@ -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:

View File

@ -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).