Add Support testing for HttpBootUri
Maps the HttpBootUri to the virtual media functionality, so we can leverage sushy-tools for testing HttpBootUri functionality. Change-Id: I51a7e684bafdb6b3aa9adda35ae438c747c9847a
This commit is contained in:
parent
0246649c06
commit
e14cfe361d
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds support to handle ``HttpBootUri`` being posted to the node, which
|
||||||
|
maps to the virtual media functionality, because there is not a direct
|
||||||
|
analog setting when interacting with libvirt.
|
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds basic functionality for ``HttpBootUri`` to be passed through to
|
||||||
|
the libvirt driver, enabling boot operations utilizing supplied media.
|
||||||
|
This does not influence the default URL to boot from due to a lack of
|
||||||
|
capability in libvirt, but instead treats it similar to virtual media.
|
||||||
|
In this case, an override boot target of ``UefiHttp`` is also re-mapped
|
||||||
|
to ``Cd`` to facilitate testing.
|
@ -392,7 +392,8 @@ def system_resource(identity):
|
|||||||
managers=app.managers.get_managers_for_system(identity),
|
managers=app.managers.get_managers_for_system(identity),
|
||||||
chassis=app.chassis.chassis[:1],
|
chassis=app.chassis.chassis[:1],
|
||||||
indicator_led=app.indicators.get_indicator_state(
|
indicator_led=app.indicators.get_indicator_state(
|
||||||
app.systems.uuid(identity))
|
app.systems.uuid(identity)),
|
||||||
|
http_boot_uri=try_get(app.systems.get_http_boot_uri)
|
||||||
)
|
)
|
||||||
|
|
||||||
elif flask.request.method == 'PATCH':
|
elif flask.request.method == 'PATCH':
|
||||||
@ -405,6 +406,12 @@ def system_resource(identity):
|
|||||||
if boot:
|
if boot:
|
||||||
target = boot.get('BootSourceOverrideTarget')
|
target = boot.get('BootSourceOverrideTarget')
|
||||||
|
|
||||||
|
if target == 'UefiHttp':
|
||||||
|
# Reset to Cd, in our case, since we can't force override
|
||||||
|
# the network boot to a specific URL. This is sort of a hack
|
||||||
|
# but testing functionality overall is a bit more important.
|
||||||
|
target = 'Cd'
|
||||||
|
|
||||||
if target:
|
if target:
|
||||||
# NOTE(lucasagomes): In libvirt we always set the boot
|
# NOTE(lucasagomes): In libvirt we always set the boot
|
||||||
# device frequency to "continuous" so, we are ignoring the
|
# device frequency to "continuous" so, we are ignoring the
|
||||||
@ -423,9 +430,30 @@ def system_resource(identity):
|
|||||||
app.logger.info('Set boot mode to "%s" for system "%s"',
|
app.logger.info('Set boot mode to "%s" for system "%s"',
|
||||||
mode, identity)
|
mode, identity)
|
||||||
|
|
||||||
if not target and not mode:
|
http_uri = boot.get('HttpBootUri')
|
||||||
|
|
||||||
|
if http_uri:
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Download the image
|
||||||
|
image_path = flask.current_app.vmedia.insert_image(
|
||||||
|
identity, 'Cd', http_uri)
|
||||||
|
# Mount it as an ISO
|
||||||
|
flask.current_app.systems.set_boot_image(
|
||||||
|
'Cd', boot_image=image_path,
|
||||||
|
write_protected=True)
|
||||||
|
# Set it for our emulator's API surface to return it
|
||||||
|
# if queried.
|
||||||
|
flask.current_app.systems.set_http_boot_uri(http_uri)
|
||||||
|
except Exception as e:
|
||||||
|
app.logger.error('Unable to load HttpBootUri for boot '
|
||||||
|
'operation. Error: %s', e)
|
||||||
|
return '', 400
|
||||||
|
|
||||||
|
if not target and not mode and not http_uri:
|
||||||
return ('Missing the BootSourceOverrideTarget and/or '
|
return ('Missing the BootSourceOverrideTarget and/or '
|
||||||
'BootSourceOverrideMode element', 400)
|
'BootSourceOverrideMode and/or HttpBootUri '
|
||||||
|
'element', 400)
|
||||||
|
|
||||||
if indicator_led_state:
|
if indicator_led_state:
|
||||||
app.indicators.set_indicator_state(
|
app.indicators.set_indicator_state(
|
||||||
|
@ -233,3 +233,21 @@ class AbstractSystemsDriver(metaclass=abc.ABCMeta):
|
|||||||
:returns: Id of the volume if successfully found/created else None
|
:returns: Id of the volume if successfully found/created else None
|
||||||
"""
|
"""
|
||||||
raise error.NotSupportedError('Not implemented')
|
raise error.NotSupportedError('Not implemented')
|
||||||
|
|
||||||
|
def get_http_boot_uri(self, identity):
|
||||||
|
"""Return the URI stored for the HttpBootUri.
|
||||||
|
|
||||||
|
:param identity: The libvirt identity. Unused, exists for internal
|
||||||
|
sushy-tools compatability.
|
||||||
|
:returns: Stored URI value for HttpBootURI.
|
||||||
|
"""
|
||||||
|
raise error.NotSupportedError('Not implemented')
|
||||||
|
|
||||||
|
def set_http_boot_uri(self, uri):
|
||||||
|
"""Stores the Uri for HttpBootURI.
|
||||||
|
|
||||||
|
:param uri: String to return
|
||||||
|
|
||||||
|
:returns: None
|
||||||
|
"""
|
||||||
|
raise error.NotSupportedError('Not implemented')
|
||||||
|
@ -172,6 +172,7 @@ class LibvirtDriver(AbstractSystemsDriver):
|
|||||||
cls.SECURE_BOOT_DISABLED_NVRAM)
|
cls.SECURE_BOOT_DISABLED_NVRAM)
|
||||||
cls.SUSHY_EMULATOR_IGNORE_BOOT_DEVICE = \
|
cls.SUSHY_EMULATOR_IGNORE_BOOT_DEVICE = \
|
||||||
cls._config.get('SUSHY_EMULATOR_IGNORE_BOOT_DEVICE', False)
|
cls._config.get('SUSHY_EMULATOR_IGNORE_BOOT_DEVICE', False)
|
||||||
|
cls._http_boot_uri = None
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
@memoize.memoize()
|
@memoize.memoize()
|
||||||
@ -1353,3 +1354,21 @@ class LibvirtDriver(AbstractSystemsDriver):
|
|||||||
self._logger.debug(msg)
|
self._logger.debug(msg)
|
||||||
return
|
return
|
||||||
return data['Id']
|
return data['Id']
|
||||||
|
|
||||||
|
def get_http_boot_uri(self, identity):
|
||||||
|
"""Return the URI stored for the HttpBootUri.
|
||||||
|
|
||||||
|
:param identity: The libvirt identity. Unused, exists for internal
|
||||||
|
sushy-tools compatability.
|
||||||
|
:returns: Stored URI value for HttpBootURI.
|
||||||
|
"""
|
||||||
|
return self._http_boot_uri
|
||||||
|
|
||||||
|
def set_http_boot_uri(self, uri):
|
||||||
|
"""Stores the Uri for HttpBootURI.
|
||||||
|
|
||||||
|
:param uri: String to return
|
||||||
|
|
||||||
|
:returns: None
|
||||||
|
"""
|
||||||
|
self._http_boot_uri = uri
|
||||||
|
@ -19,16 +19,21 @@
|
|||||||
"BootSourceOverrideTarget@Redfish.AllowableValues": [
|
"BootSourceOverrideTarget@Redfish.AllowableValues": [
|
||||||
"Pxe",
|
"Pxe",
|
||||||
"Cd",
|
"Cd",
|
||||||
"Hdd"
|
|
||||||
{%- if boot_source_mode %}
|
{%- if boot_source_mode %}
|
||||||
],
|
|
||||||
{%- if 'uefi' in boot_source_mode.lower() %}
|
{%- if 'uefi' in boot_source_mode.lower() %}
|
||||||
|
"Hdd",
|
||||||
|
"UefiHttp"
|
||||||
|
],
|
||||||
"BootSourceOverrideMode": {{ boot_source_mode|string|tojson }},
|
"BootSourceOverrideMode": {{ boot_source_mode|string|tojson }},
|
||||||
"UefiTargetBootSourceOverride": "/0x31/0x33/0x01/0x01"
|
"UefiTargetBootSourceOverride": "/0x31/0x33/0x01/0x01",
|
||||||
|
"HttpBootUri": {{ http_boot_uri|string|tojson }}
|
||||||
{%- else %}
|
{%- else %}
|
||||||
|
"Hdd"
|
||||||
|
],
|
||||||
"BootSourceOverrideMode": {{ boot_source_mode|string|tojson }}
|
"BootSourceOverrideMode": {{ boot_source_mode|string|tojson }}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- else %}
|
{%- else %}
|
||||||
|
"Hdd"
|
||||||
]
|
]
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- else %}
|
{%- else %}
|
||||||
|
@ -1245,3 +1245,17 @@ class LibvirtDriverTestCase(base.BaseTestCase):
|
|||||||
|
|
||||||
self.assertRaises(error.NotSupportedError,
|
self.assertRaises(error.NotSupportedError,
|
||||||
self.test_driver.set_secure_boot, self.uuid, True)
|
self.test_driver.set_secure_boot, self.uuid, True)
|
||||||
|
|
||||||
|
@mock.patch('libvirt.open', autospec=True)
|
||||||
|
@mock.patch('libvirt.openReadOnly', autospec=True)
|
||||||
|
def test_set_get_http_boot_uri(self, libvirt_mock, libvirt_rw_mock):
|
||||||
|
with open('sushy_tools/tests/unit/emulator/domain-q35.xml', 'r') as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
conn_mock = libvirt_mock.return_value
|
||||||
|
domain_mock = conn_mock.lookupByUUID.return_value
|
||||||
|
domain_mock.XMLDesc.return_value = data
|
||||||
|
self.assertIsNone(self.test_driver.get_http_boot_uri(None))
|
||||||
|
uri = 'http://host.path/meow'
|
||||||
|
self.test_driver.set_http_boot_uri(uri)
|
||||||
|
self.assertEqual(uri, self.test_driver.get_http_boot_uri(None))
|
||||||
|
@ -287,3 +287,11 @@ class NovaDriverTestCase(base.BaseTestCase):
|
|||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
error.NotSupportedError, self.test_driver.set_secure_boot,
|
error.NotSupportedError, self.test_driver.set_secure_boot,
|
||||||
self.uuid, True)
|
self.uuid, True)
|
||||||
|
|
||||||
|
def test_set_get_http_boot_uri(self):
|
||||||
|
self.assertRaises(error.NotSupportedError,
|
||||||
|
self.test_driver.get_http_boot_uri,
|
||||||
|
None)
|
||||||
|
self.assertRaises(error.NotSupportedError,
|
||||||
|
self.test_driver.set_http_boot_uri,
|
||||||
|
None)
|
||||||
|
@ -273,6 +273,29 @@ class SystemsTestCase(EmulatorTestCase):
|
|||||||
set_boot_device = systems_mock.return_value.set_boot_device
|
set_boot_device = systems_mock.return_value.set_boot_device
|
||||||
set_boot_device.assert_called_once_with('xxxx-yyyy-zzzz', 'Cd')
|
set_boot_device.assert_called_once_with('xxxx-yyyy-zzzz', 'Cd')
|
||||||
|
|
||||||
|
@patch_resource('vmedia')
|
||||||
|
@patch_resource('systems')
|
||||||
|
def test_system_boot_http_uri(self, systems_mock, vmedia_mock):
|
||||||
|
data = {'Boot': {'BootSourceOverrideMode': 'UEFI',
|
||||||
|
'BootSourceOverrideTarget': 'UefiHttp',
|
||||||
|
'HttpBootUri': 'http://test.url/boot.iso'}}
|
||||||
|
insert_image = vmedia_mock.return_value.insert_image
|
||||||
|
insert_image.return_value = '/path/to/file.iso'
|
||||||
|
response = self.app.patch('/redfish/v1/Systems/xxxx-yyyy-zzzz',
|
||||||
|
json=data)
|
||||||
|
self.assertEqual(204, response.status_code)
|
||||||
|
insert_image.assert_called_once_with('xxxx-yyyy-zzzz', 'Cd',
|
||||||
|
'http://test.url/boot.iso')
|
||||||
|
set_boot_device = systems_mock.return_value.set_boot_device
|
||||||
|
set_boot_image = systems_mock.return_value.set_boot_image
|
||||||
|
set_boot_mode = systems_mock.return_value.set_boot_mode
|
||||||
|
set_http_boot_uri = systems_mock.return_value.set_http_boot_uri
|
||||||
|
set_boot_device.assert_called_once_with('xxxx-yyyy-zzzz', 'Cd')
|
||||||
|
set_boot_image.assert_called_once_with(
|
||||||
|
'Cd', boot_image='/path/to/file.iso', write_protected=True)
|
||||||
|
set_boot_mode.assert_called_once_with('xxxx-yyyy-zzzz', 'UEFI')
|
||||||
|
set_http_boot_uri.assert_called_once_with('http://test.url/boot.iso')
|
||||||
|
|
||||||
@patch_resource('systems')
|
@patch_resource('systems')
|
||||||
def test_system_reset_action(self, systems_mock):
|
def test_system_reset_action(self, systems_mock):
|
||||||
set_power_state = systems_mock.return_value.set_power_state
|
set_power_state = systems_mock.return_value.set_power_state
|
||||||
|
Loading…
x
Reference in New Issue
Block a user