Merge "Allow overriding an external URL for virtual media"
This commit is contained in:
commit
8e34aa53ce
@ -87,3 +87,26 @@ An example network data:
|
||||
.. _Glean: https://docs.openstack.org/infra/glean/
|
||||
.. _simple-init: https://docs.openstack.org/diskimage-builder/latest/elements/simple-init/README.html
|
||||
.. _network_data: https://specs.openstack.org/openstack/nova-specs/specs/liberty/implemented/metadata-service-network-info.html
|
||||
|
||||
.. _l3-external-ip:
|
||||
|
||||
Deploying outside of the provisioning network
|
||||
---------------------------------------------
|
||||
|
||||
If you need to combine traditional deployments using a provisioning network
|
||||
with virtual media deployments over L3, you may need to provide an alternative
|
||||
IP address for the remote nodes to connect to:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[deploy]
|
||||
http_url = <HTTP server URL internal to the provisioning network>
|
||||
external_http_url = <HTTP server URL with a routable IP address>
|
||||
|
||||
You may also need to override the callback URL, which is normally fetched from
|
||||
the service catalog or configured in the ``[service_catalog]`` section:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[deploy]
|
||||
external_callback_url = <Bare Metal API URL with a routable IP address>
|
||||
|
@ -71,6 +71,9 @@ ironic configuration file to match the HTTP server configurations.
|
||||
http_url = http://example.com
|
||||
http_root = /httpboot
|
||||
|
||||
.. note::
|
||||
See also: :ref:`l3-external-ip`.
|
||||
|
||||
Each HTTP server should be configured to follow symlinks for images
|
||||
accessible from HTTP service. Please refer to configuration option
|
||||
``FollowSymLinks`` if you are using Apache HTTP server, or
|
||||
|
@ -332,6 +332,8 @@ on the Bare Metal service node(s) where ``ironic-conductor`` is running.
|
||||
# http://192.1.2.3:8080 (string value)
|
||||
http_url=http://192.168.0.2:8080
|
||||
|
||||
See also: :ref:`l3-external-ip`.
|
||||
|
||||
#. Install the iPXE package with the boot images:
|
||||
|
||||
Ubuntu::
|
||||
|
@ -27,6 +27,17 @@ opts = [
|
||||
cfg.StrOpt('http_root',
|
||||
default='/httpboot',
|
||||
help=_("ironic-conductor node's HTTP root path.")),
|
||||
cfg.StrOpt('external_http_url',
|
||||
help=_("URL of the ironic-conductor node's HTTP server for "
|
||||
"boot methods such as virtual media, "
|
||||
"where images could be served outside of the "
|
||||
"provisioning network. Does not apply when Swift is "
|
||||
"used. Defaults to http_url.")),
|
||||
cfg.StrOpt('external_callback_url',
|
||||
help=_("Agent callback URL of the bare metal API for boot "
|
||||
"methods such as virtual media, where images could be "
|
||||
"served outside of the provisioning network. Defaults "
|
||||
"to the configuration from [service_catalog].")),
|
||||
cfg.BoolOpt('enable_ata_secure_erase',
|
||||
default=True,
|
||||
mutable=True,
|
||||
|
@ -622,6 +622,9 @@ def is_software_raid(node):
|
||||
return software_raid
|
||||
|
||||
|
||||
IPA_URL_PARAM_NAME = 'ipa-api-url'
|
||||
|
||||
|
||||
def build_agent_options(node):
|
||||
"""Build the options to be passed to the agent ramdisk.
|
||||
|
||||
@ -630,7 +633,7 @@ def build_agent_options(node):
|
||||
agent ramdisk.
|
||||
"""
|
||||
agent_config_opts = {
|
||||
'ipa-api-url': get_ironic_api_url(),
|
||||
IPA_URL_PARAM_NAME: get_ironic_api_url(),
|
||||
}
|
||||
return agent_config_opts
|
||||
|
||||
|
@ -214,8 +214,8 @@ class ImageHandler(object):
|
||||
shutil.copyfile(image_file, published_file)
|
||||
os.chmod(published_file, self._file_permission)
|
||||
|
||||
image_url = os.path.join(
|
||||
CONF.deploy.http_url, self._image_subdir, object_name)
|
||||
http_url = CONF.deploy.external_http_url or CONF.deploy.http_url
|
||||
image_url = os.path.join(http_url, self._image_subdir, object_name)
|
||||
|
||||
image_url = self._append_filename_param(
|
||||
image_url, os.path.basename(image_file))
|
||||
@ -244,6 +244,16 @@ def cleanup_iso_image(task):
|
||||
suffix='.iso')
|
||||
|
||||
|
||||
def override_api_url(params):
|
||||
if not CONF.deploy.external_callback_url:
|
||||
return params
|
||||
|
||||
params = params or {}
|
||||
params[deploy_utils.IPA_URL_PARAM_NAME] = \
|
||||
CONF.deploy.external_callback_url.rstrip('/')
|
||||
return params
|
||||
|
||||
|
||||
def prepare_floppy_image(task, params=None):
|
||||
"""Prepares the floppy image for passing the parameters.
|
||||
|
||||
@ -264,6 +274,7 @@ def prepare_floppy_image(task, params=None):
|
||||
:returns: image URL for the floppy image.
|
||||
"""
|
||||
object_name = _get_name(task.node, prefix='image')
|
||||
params = override_api_url(params)
|
||||
|
||||
LOG.debug("Trying to create floppy image for node "
|
||||
"%(node)s", {'node': task.node.uuid})
|
||||
@ -533,6 +544,8 @@ def prepare_deploy_iso(task, params, mode, d_info):
|
||||
iso_href = _find_param(iso_str, d_info)
|
||||
bootloader_href = _find_param(bootloader_str, d_info)
|
||||
|
||||
params = override_api_url(params)
|
||||
|
||||
# TODO(TheJulia): At some point we should support something like
|
||||
# boot_iso for the deploy interface, perhaps when we support config
|
||||
# injection.
|
||||
|
@ -121,6 +121,28 @@ class RedfishImageHandlerTestCase(db_base.DbTestCase):
|
||||
'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(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(
|
||||
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)
|
||||
|
||||
url = img_handler_obj.publish_image('file.iso', 'boot.iso')
|
||||
|
||||
self.assertEqual(
|
||||
'http://non-local.host/redfish/boot.iso?filename=file.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(image_utils, 'shutil', autospec=True)
|
||||
@mock.patch.object(os, 'link', autospec=True)
|
||||
@ -248,7 +270,31 @@ class RedfishImageUtilsTestCase(db_base.DbTestCase):
|
||||
mock.ANY, object_name)
|
||||
|
||||
mock_create_vfat_image.assert_called_once_with(
|
||||
mock.ANY, parameters=mock.ANY)
|
||||
mock.ANY, parameters=None)
|
||||
|
||||
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_with_external_ip(
|
||||
self, mock_create_vfat_image, mock_publish_image):
|
||||
self.config(external_callback_url='http://callback/', group='deploy')
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
expected_url = 'https://a.b/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)
|
||||
|
||||
mock_create_vfat_image.assert_called_once_with(
|
||||
mock.ANY, parameters={"ipa-api-url": "http://callback"})
|
||||
|
||||
self.assertEqual(expected_url, url)
|
||||
|
||||
@ -632,6 +678,28 @@ cafile = /etc/ironic-python-agent/ironic.crt
|
||||
task, 'kernel', 'ramdisk', 'bootloader', params={},
|
||||
inject_files=expected_files, base_iso=None)
|
||||
|
||||
@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
|
||||
def test_prepare_deploy_iso_external_ip(self, mock__prepare_iso_image):
|
||||
self.config(external_callback_url='http://callback/', group='deploy')
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
|
||||
d_info = {
|
||||
'ilo_deploy_kernel': 'kernel',
|
||||
'ilo_deploy_ramdisk': 'ramdisk',
|
||||
'ilo_bootloader': 'bootloader'
|
||||
}
|
||||
task.node.driver_info.update(d_info)
|
||||
|
||||
task.node.instance_info.update(deploy_boot_mode='uefi')
|
||||
|
||||
image_utils.prepare_deploy_iso(task, {}, 'deploy', d_info)
|
||||
|
||||
mock__prepare_iso_image.assert_called_once_with(
|
||||
task, 'kernel', 'ramdisk', 'bootloader',
|
||||
params={'ipa-api-url': 'http://callback'},
|
||||
inject_files={}, base_iso=None)
|
||||
|
||||
@mock.patch.object(image_utils, '_find_param', autospec=True)
|
||||
@mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
|
||||
@mock.patch.object(images, 'create_boot_iso', autospec=True)
|
||||
|
13
releasenotes/notes/external-ip-5ec9b7b55a90cec4.yaml
Normal file
13
releasenotes/notes/external-ip-5ec9b7b55a90cec4.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Provides operator ability to override URL settings required for
|
||||
provisioning/cleaning in the event of virtual media based deployment.
|
||||
These scenarios tend to require more delineation than more traditional
|
||||
deployments as they often have a different environmental security
|
||||
requirements. Set these two new configuration options using an IP
|
||||
address that is available to these nodes (both the ramdisk and the BMCs)::
|
||||
|
||||
[deploy]
|
||||
external_http_url = <routable URL of the HTTP server>
|
||||
external_callback_url = <routable URL of bare metal API>
|
Loading…
x
Reference in New Issue
Block a user