Merge "Follow-up for ramdisk deploy configdrive support"
This commit is contained in:
commit
5640860c81
@ -272,8 +272,7 @@ parameter injection, as such the ``[instance_info]/kernel_append_params``
|
||||
setting is ignored.
|
||||
|
||||
Configuration drives are supported starting with the Wallaby release
|
||||
for nodes that have a free virtual USB slot. The configuration option
|
||||
``[deploy]configdrive_use_object_store`` must be set to ``False`` for now.
|
||||
for nodes that have a free virtual USB slot.
|
||||
|
||||
Layer 3 or DHCP-less ramdisk booting
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -346,7 +346,7 @@ def create_esp_image_for_uefi(
|
||||
raise exception.ImageCreationFailed(image_type='iso', error=e)
|
||||
|
||||
|
||||
def fetch(context, image_href, path, force_raw=False):
|
||||
def fetch_into(context, image_href, image_file):
|
||||
# TODO(vish): Improve context handling and add owner and auth data
|
||||
# when it is added to glance. Right now there is no
|
||||
# auth checking in glance, so we assume that access was
|
||||
@ -357,9 +357,13 @@ def fetch(context, image_href, path, force_raw=False):
|
||||
{'image_service': image_service.__class__,
|
||||
'image_href': image_href})
|
||||
|
||||
image_service.download(image_href, image_file)
|
||||
|
||||
|
||||
def fetch(context, image_href, path, force_raw=False):
|
||||
with fileutils.remove_path_on_error(path):
|
||||
with open(path, "wb") as image_file:
|
||||
image_service.download(image_href, image_file)
|
||||
fetch_into(context, image_href, image_file)
|
||||
|
||||
if force_raw:
|
||||
image_to_raw(image_href, path, "%s.part" % path)
|
||||
|
@ -299,20 +299,26 @@ def cleanup_floppy_image(task):
|
||||
def prepare_configdrive_image(task, content):
|
||||
"""Prepare an image with configdrive.
|
||||
|
||||
Decodes base64 contents and writes it into a disk image that can be
|
||||
attached e.g. to a virtual USB device. Images stored in Swift are
|
||||
downloaded first.
|
||||
|
||||
:param task: a TaskManager instance containing the node to act on.
|
||||
:param content: Config drive as a base64-encoded string.
|
||||
:raises: ImageCreationFailed, if it failed while creating the image.
|
||||
:raises: SwiftOperationError, if any operation with Swift fails.
|
||||
:returns: image URL for the image.
|
||||
"""
|
||||
# FIXME(dtantsur): download and convert?
|
||||
if '://' in content:
|
||||
raise exception.ImageCreationFailed(
|
||||
_('URLs are not supported for configdrive images yet'))
|
||||
|
||||
with tempfile.TemporaryFile(dir=CONF.tempdir) as comp_tmpfile_obj:
|
||||
if '://' in content:
|
||||
with tempfile.TemporaryFile(dir=CONF.tempdir) as tmpfile2:
|
||||
images.fetch_into(task.context, content, tmpfile2)
|
||||
tmpfile2.seek(0)
|
||||
base64.decode(tmpfile2, comp_tmpfile_obj)
|
||||
else:
|
||||
comp_tmpfile_obj.write(base64.b64decode(content))
|
||||
comp_tmpfile_obj.seek(0)
|
||||
|
||||
gz = gzip.GzipFile(fileobj=comp_tmpfile_obj, mode='rb')
|
||||
with tempfile.NamedTemporaryFile(
|
||||
dir=CONF.tempdir, suffix='.img') as image_tmpfile_obj:
|
||||
|
@ -58,12 +58,15 @@ class PXERamdiskDeploy(agent_base.AgentBaseMixin, agent_base.HeartbeatMixin,
|
||||
@base.deploy_step(priority=100)
|
||||
@task_manager.require_exclusive_lock
|
||||
def deploy(self, task):
|
||||
if 'configdrive' in task.node.instance_info:
|
||||
LOG.warning('A configuration drive is present with '
|
||||
'in the deployment request of node %(node)s. '
|
||||
'The configuration drive will be ignored for '
|
||||
'this deployment.',
|
||||
{'node': task.node})
|
||||
if ('configdrive' in task.node.instance_info
|
||||
and 'ramdisk_boot_configdrive' not in
|
||||
task.driver.boot.capabilities):
|
||||
# TODO(dtantsur): make it an actual error?
|
||||
LOG.warning('A configuration drive is present in the ramdisk '
|
||||
'deployment request of node %(node)s with boot '
|
||||
'interface %(drv)s. The configuration drive will be '
|
||||
'ignored for this deployment.',
|
||||
{'node': task.node, 'drv': task.node.boot_interface})
|
||||
manager_utils.node_power_action(task, states.POWER_OFF)
|
||||
# Tenant neworks must enable connectivity to the boot
|
||||
# location, as reboot() can otherwise be very problematic.
|
||||
|
@ -308,7 +308,8 @@ class RedfishVirtualMediaBoot(base.BootInterface):
|
||||
`[instance_info]image_source` node property.
|
||||
"""
|
||||
|
||||
capabilities = ['iscsi_volume_boot', 'ramdisk_boot']
|
||||
capabilities = ['iscsi_volume_boot', 'ramdisk_boot',
|
||||
'ramdisk_boot_configdrive']
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the Redfish virtual media boot interface.
|
||||
|
@ -304,6 +304,30 @@ class RedfishImageUtilsTestCase(db_base.DbTestCase):
|
||||
result = image_utils.prepare_configdrive_image(task, encoded)
|
||||
self.assertEqual(expected_url, result)
|
||||
|
||||
@mock.patch.object(images, 'fetch_into', autospec=True)
|
||||
@mock.patch.object(image_utils, 'prepare_disk_image', autospec=True)
|
||||
def test_prepare_configdrive_image_url(self, mock_prepare, mock_fetch):
|
||||
content = 'https://swift/path'
|
||||
expected_url = 'https://a.b/c.f?e=f'
|
||||
encoded = b'H4sIAPJ8418C/0vOzytJzSsBAKkwxf4HAAAA'
|
||||
|
||||
def _fetch(context, image_href, image_file):
|
||||
self.assertEqual(content, image_href)
|
||||
image_file.write(encoded)
|
||||
|
||||
def _prepare(task, content, prefix):
|
||||
with open(content, 'rb') as fp:
|
||||
self.assertEqual(b'content', fp.read())
|
||||
return expected_url
|
||||
|
||||
mock_fetch.side_effect = _fetch
|
||||
mock_prepare.side_effect = _prepare
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
result = image_utils.prepare_configdrive_image(task, content)
|
||||
self.assertEqual(expected_url, result)
|
||||
|
||||
@mock.patch.object(image_utils.ImageHandler, 'unpublish_image',
|
||||
autospec=True)
|
||||
def test_cleanup_iso_image(self, mock_unpublish):
|
||||
|
@ -3,5 +3,4 @@ features:
|
||||
- |
|
||||
Supports attaching configdrives when doing ``ramdisk`` deploy with the
|
||||
``redfish-virtual-media`` boot. A configdrive is attached to a free USB
|
||||
slot. Swift must not be used for configdrive storage (this limitation will
|
||||
be fixed later).
|
||||
slot.
|
||||
|
Loading…
Reference in New Issue
Block a user