Override external_http_url at node level
This patch adds support to specify the URL to be used to publish the node image when using virtual media. The option is available under `driver_info['external_http_url']`, if set this value has priority over the values in the configuration file ([deploy]/external_http_url and [deploy]/http_url) Story: 2010221 Task: 45970 Change-Id: If6a117a756b7d2a04251792f88c2ee412a040b28
This commit is contained in:
parent
45c9c3029f
commit
c197a2d8b2
@ -169,7 +169,7 @@ class ImageHandler(object):
|
|||||||
|
|
||||||
return urlparse.urlunparse(parsed_url)
|
return urlparse.urlunparse(parsed_url)
|
||||||
|
|
||||||
def publish_image(self, image_file, object_name):
|
def publish_image(self, image_file, object_name, node_http_url=None):
|
||||||
"""Make image file downloadable.
|
"""Make image file downloadable.
|
||||||
|
|
||||||
Depending on ironic settings, pushes given file into Swift or copies
|
Depending on ironic settings, pushes given file into Swift or copies
|
||||||
@ -178,6 +178,9 @@ class ImageHandler(object):
|
|||||||
|
|
||||||
:param image_file: path to file to publish
|
:param image_file: path to file to publish
|
||||||
:param object_name: name of the published file
|
:param object_name: name of the published file
|
||||||
|
:param node_http_url: a url to be used to publish the image. If set,
|
||||||
|
the values from external_http_url and http_url
|
||||||
|
from CONF.deploy won't be used.
|
||||||
:return: a URL to download published file
|
:return: a URL to download published file
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -220,7 +223,8 @@ class ImageHandler(object):
|
|||||||
shutil.copyfile(image_file, published_file)
|
shutil.copyfile(image_file, published_file)
|
||||||
os.chmod(published_file, self._file_permission)
|
os.chmod(published_file, self._file_permission)
|
||||||
|
|
||||||
http_url = CONF.deploy.external_http_url or CONF.deploy.http_url
|
http_url = (node_http_url or CONF.deploy.external_http_url
|
||||||
|
or CONF.deploy.http_url)
|
||||||
image_url = os.path.join(http_url, self._image_subdir, object_name)
|
image_url = os.path.join(http_url, self._image_subdir, object_name)
|
||||||
|
|
||||||
return image_url
|
return image_url
|
||||||
@ -302,8 +306,9 @@ def prepare_floppy_image(task, params=None):
|
|||||||
images.create_vfat_image(vfat_image_tmpfile, parameters=params)
|
images.create_vfat_image(vfat_image_tmpfile, parameters=params)
|
||||||
|
|
||||||
img_handler = ImageHandler(task.node.driver)
|
img_handler = ImageHandler(task.node.driver)
|
||||||
|
node_http_url = task.node.driver_info.get("external_http_url")
|
||||||
image_url = img_handler.publish_image(vfat_image_tmpfile, object_name)
|
image_url = img_handler.publish_image(vfat_image_tmpfile, object_name,
|
||||||
|
node_http_url)
|
||||||
|
|
||||||
LOG.debug("Created floppy image %(name)s in Swift for node %(node)s, "
|
LOG.debug("Created floppy image %(name)s in Swift for node %(node)s, "
|
||||||
"exposed as temporary URL "
|
"exposed as temporary URL "
|
||||||
|
@ -53,7 +53,11 @@ OPTIONAL_PROPERTIES = {
|
|||||||
"used by ironic when building UEFI-bootable ISO "
|
"used by ironic when building UEFI-bootable ISO "
|
||||||
"out of kernel and ramdisk. Required for UEFI "
|
"out of kernel and ramdisk. Required for UEFI "
|
||||||
"when deploy_iso is not provided."),
|
"when deploy_iso is not provided."),
|
||||||
|
'external_http_url': _("External URL that is used when the image could "
|
||||||
|
"be served outside of the provisioning network. "
|
||||||
|
"If set it will have priority over the following "
|
||||||
|
"configs: CONF.deploy.external_http_url and "
|
||||||
|
"CONF.deploy.http_url. Defaults to None.")
|
||||||
}
|
}
|
||||||
|
|
||||||
RESCUE_PROPERTIES = {
|
RESCUE_PROPERTIES = {
|
||||||
|
@ -147,6 +147,32 @@ class RedfishImageHandlerTestCase(db_base.DbTestCase):
|
|||||||
'file.iso', '/httpboot/redfish/boot.iso')
|
'file.iso', '/httpboot/redfish/boot.iso')
|
||||||
mock_chmod.assert_called_once_with('file.iso', 0o644)
|
mock_chmod.assert_called_once_with('file.iso', 0o644)
|
||||||
|
|
||||||
|
@mock.patch.object(os, 'chmod', autospec=True)
|
||||||
|
@mock.patch.object(image_utils, 'shutil', autospec=True)
|
||||||
|
@mock.patch.object(os, 'link', autospec=True)
|
||||||
|
@mock.patch.object(os, 'mkdir', autospec=True)
|
||||||
|
def test_publish_image_external_ip_node_override(
|
||||||
|
self, mock_mkdir, mock_link, mock_shutil, mock_chmod):
|
||||||
|
self.config(use_swift=False, group='redfish')
|
||||||
|
self.config(http_url='http://localhost',
|
||||||
|
external_http_url='http://non-local.host',
|
||||||
|
group='deploy')
|
||||||
|
img_handler_obj = image_utils.ImageHandler(self.node.driver)
|
||||||
|
self.node.driver_info["external_http_url"] = "http://node.override.url"
|
||||||
|
|
||||||
|
override_url = self.node.driver_info.get("external_http_url")
|
||||||
|
|
||||||
|
url = img_handler_obj.publish_image('file.iso', 'boot.iso',
|
||||||
|
override_url)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
'http://node.override.url/redfish/boot.iso', url)
|
||||||
|
|
||||||
|
mock_mkdir.assert_called_once_with('/httpboot/redfish', 0o755)
|
||||||
|
mock_link.assert_called_once_with(
|
||||||
|
'file.iso', '/httpboot/redfish/boot.iso')
|
||||||
|
mock_chmod.assert_called_once_with('file.iso', 0o644)
|
||||||
|
|
||||||
@mock.patch.object(os, 'chmod', autospec=True)
|
@mock.patch.object(os, 'chmod', autospec=True)
|
||||||
@mock.patch.object(image_utils, 'shutil', autospec=True)
|
@mock.patch.object(image_utils, 'shutil', autospec=True)
|
||||||
@mock.patch.object(os, 'link', autospec=True)
|
@mock.patch.object(os, 'link', autospec=True)
|
||||||
@ -271,8 +297,8 @@ class RedfishImageUtilsTestCase(db_base.DbTestCase):
|
|||||||
|
|
||||||
object_name = 'image-%s' % task.node.uuid
|
object_name = 'image-%s' % task.node.uuid
|
||||||
|
|
||||||
mock_publish_image.assert_called_once_with(mock.ANY,
|
mock_publish_image.assert_called_once_with(mock.ANY, mock.ANY,
|
||||||
mock.ANY, object_name)
|
object_name, None)
|
||||||
|
|
||||||
mock_create_vfat_image.assert_called_once_with(
|
mock_create_vfat_image.assert_called_once_with(
|
||||||
mock.ANY, parameters=None)
|
mock.ANY, parameters=None)
|
||||||
@ -295,8 +321,63 @@ class RedfishImageUtilsTestCase(db_base.DbTestCase):
|
|||||||
|
|
||||||
object_name = 'image-%s' % task.node.uuid
|
object_name = 'image-%s' % task.node.uuid
|
||||||
|
|
||||||
mock_publish_image.assert_called_once_with(mock.ANY,
|
mock_publish_image.assert_called_once_with(mock.ANY, mock.ANY,
|
||||||
mock.ANY, object_name)
|
object_name, None)
|
||||||
|
|
||||||
|
mock_create_vfat_image.assert_called_once_with(
|
||||||
|
mock.ANY, parameters={"ipa-api-url": "http://callback"})
|
||||||
|
|
||||||
|
self.assertEqual(expected_url, url)
|
||||||
|
|
||||||
|
@mock.patch.object(image_utils.ImageHandler, 'publish_image',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch.object(images, 'create_vfat_image', autospec=True)
|
||||||
|
def test_prepare_floppy_image_publish_with_config_external_http_url(
|
||||||
|
self, mock_create_vfat_image, mock_publish_image):
|
||||||
|
self.config(external_callback_url='http://callback/',
|
||||||
|
external_http_url='http://config.external.url',
|
||||||
|
group='deploy')
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
expected_url = 'https://config.external.url/c.f?e=f'
|
||||||
|
|
||||||
|
mock_publish_image.return_value = expected_url
|
||||||
|
|
||||||
|
url = image_utils.prepare_floppy_image(task)
|
||||||
|
|
||||||
|
object_name = 'image-%s' % task.node.uuid
|
||||||
|
|
||||||
|
mock_publish_image.assert_called_once_with(mock.ANY, mock.ANY,
|
||||||
|
object_name, None)
|
||||||
|
|
||||||
|
mock_create_vfat_image.assert_called_once_with(
|
||||||
|
mock.ANY, parameters={"ipa-api-url": "http://callback"})
|
||||||
|
|
||||||
|
self.assertEqual(expected_url, url)
|
||||||
|
|
||||||
|
@mock.patch.object(image_utils.ImageHandler, 'publish_image',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch.object(images, 'create_vfat_image', autospec=True)
|
||||||
|
def test_prepare_floppy_image_publish_with_node_external_http_url(
|
||||||
|
self, mock_create_vfat_image, mock_publish_image):
|
||||||
|
self.config(external_callback_url='http://callback/',
|
||||||
|
external_http_url='http://config.external.url',
|
||||||
|
group='deploy')
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
task.node.driver_info["external_http_url"] = \
|
||||||
|
"https://node.external"
|
||||||
|
override_url = task.node.driver_info.get("external_http_url")
|
||||||
|
expected_url = '"https://node.external/c.f?e=f'
|
||||||
|
|
||||||
|
mock_publish_image.return_value = expected_url
|
||||||
|
|
||||||
|
url = image_utils.prepare_floppy_image(task)
|
||||||
|
|
||||||
|
object_name = 'image-%s' % task.node.uuid
|
||||||
|
|
||||||
|
mock_publish_image.assert_called_once_with(
|
||||||
|
mock.ANY, mock.ANY, object_name, override_url)
|
||||||
|
|
||||||
mock_create_vfat_image.assert_called_once_with(
|
mock_create_vfat_image.assert_called_once_with(
|
||||||
mock.ANY, parameters={"ipa-api-url": "http://callback"})
|
mock.ANY, parameters={"ipa-api-url": "http://callback"})
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Nodes using virtual media can now specify their own external URL.
|
||||||
|
This setting can be leveraged via the ``driver_info\external_http_url``
|
||||||
|
node setting.
|
||||||
|
When used, this setting overrides the ``[deploy]http_url`` and
|
||||||
|
``[deploy]external_http_url`` settings in the configuration file.
|
Loading…
x
Reference in New Issue
Block a user