Add BIOS resource support
Emulates BIOS support for libvirt driver by storing custom XML with BIOS attributes in libvirt Domain XML. For now it supports getting attributes, updating attributes, resetting to default. This does not support changing password yet, but can be added later. This does not support getting attribute update status, because this is not implemented in sushy library yet. Can be added after this is implemented in sushy. Test structure depends and is based on other patches to be merged: I02725332df886fdf6b13c98cb6d80ab3650575b9 and I82032fd13a74d9aa77616dac3802d506b4a9c1cf. Change-Id: I3b9e7683934e4448bedf3933f1a2fe222d70c208 Story: 2001791 Task: 22264
This commit is contained in:
parent
f5450bb8c6
commit
acd170e61e
@ -119,3 +119,28 @@ class AbstractDriver(object):
|
||||
:returns: available CPU count as `int` or `None` if CPU count
|
||||
can't be determined
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_bios(self, identity):
|
||||
"""Get BIOS attributes for the system
|
||||
|
||||
:returns: key-value pairs of BIOS attributes
|
||||
|
||||
:raises: `FishyError` if BIOS attributes cannot be processed
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_bios(self, identity, attributes):
|
||||
"""Update BIOS attributes
|
||||
|
||||
:param attributes: key-value pairs of attributes to update
|
||||
|
||||
:raises: `FishyError` if BIOS attributes cannot be processed
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def reset_bios(self, identity):
|
||||
"""Reset BIOS attributes to default
|
||||
|
||||
:raises: `FishyError` if BIOS attributes cannot be processed
|
||||
"""
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from collections import namedtuple
|
||||
from sushy_tools.emulator.drivers.base import AbstractDriver
|
||||
from sushy_tools.error import FishyError
|
||||
|
||||
@ -66,6 +67,11 @@ class LibvirtDriver(AbstractDriver):
|
||||
|
||||
BOOT_MODE_MAP_REV = {v: k for k, v in BOOT_MODE_MAP.items()}
|
||||
|
||||
DEFAULT_BIOS_ATTRIBUTES = {"BootMode": "Uefi",
|
||||
"EmbeddedSata": "Raid",
|
||||
"NicBoot1": "NetworkBoot",
|
||||
"ProcTurboMode": "Enabled"}
|
||||
|
||||
def __init__(self, uri=None):
|
||||
self._uri = uri or self.LIBVIRT_URI
|
||||
|
||||
@ -324,3 +330,143 @@ class LibvirtDriver(AbstractDriver):
|
||||
total_cpus = int(vcpu_element.text)
|
||||
|
||||
return total_cpus or None
|
||||
|
||||
def _process_bios_attributes(self,
|
||||
domain_xml,
|
||||
bios_attributes=DEFAULT_BIOS_ATTRIBUTES,
|
||||
update_existing_attributes=False):
|
||||
"""Process Libvirt domain XML for BIOS attributes
|
||||
|
||||
This method supports adding default BIOS attributes,
|
||||
retrieving existing BIOS attributes and
|
||||
updating existing BIOS attributes.
|
||||
|
||||
This method is introduced to make XML testable otherwise have to
|
||||
compare XML strings to test if XML saved to libvirt is as expected.
|
||||
|
||||
Sample of custom XML:
|
||||
<domain type="kvm">
|
||||
[...]
|
||||
<metadata xmlns:sushy="http://openstack.org/xmlns/libvirt/sushy">
|
||||
<sushy:bios>
|
||||
<sushy:attributes>
|
||||
<sushy:attribute name="ProcTurboMode" value="Enabled"/>
|
||||
<sushy:attribute name="BootMode" value="Uefi"/>
|
||||
<sushy:attribute name="NicBoot1" value="NetworkBoot"/>
|
||||
<sushy:attribute name="EmbeddedSata" value="Raid"/>
|
||||
</sushy:attributes>
|
||||
</sushy:bios>
|
||||
</metadata>
|
||||
[...]
|
||||
|
||||
:param domain_xml: Libvirt domain XML to process
|
||||
:param bios_attributes: BIOS attributes for updates or default
|
||||
values if not specified
|
||||
:param update_existing_attributes: Update existing BIOS attributes
|
||||
|
||||
:returns: namedtuple of tree: processed XML element tree,
|
||||
attributes_written: if changes were made to XML,
|
||||
bios_attributes: dict of BIOS attributes
|
||||
"""
|
||||
namespace = 'http://openstack.org/xmlns/libvirt/sushy'
|
||||
ET.register_namespace('sushy', namespace)
|
||||
ns = {'sushy': namespace}
|
||||
|
||||
tree = ET.fromstring(domain_xml)
|
||||
metadata = tree.find('metadata')
|
||||
|
||||
if metadata is None:
|
||||
metadata = ET.SubElement(tree, 'metadata')
|
||||
bios = metadata.find('sushy:bios', ns)
|
||||
|
||||
attributes_written = False
|
||||
if bios is not None and update_existing_attributes:
|
||||
metadata.remove(bios)
|
||||
bios = None
|
||||
if bios is None:
|
||||
bios = ET.SubElement(metadata, '{%s}bios' % (namespace))
|
||||
attributes = ET.SubElement(bios, '{%s}attributes' % (namespace))
|
||||
for key, value in sorted(bios_attributes.items()):
|
||||
ET.SubElement(attributes,
|
||||
'{%s}attribute' % (namespace),
|
||||
name=key,
|
||||
value=value)
|
||||
attributes_written = True
|
||||
|
||||
bios_attributes = {atr.attrib['name']: atr.attrib['value']
|
||||
for atr in tree.find('.//sushy:attributes', ns)}
|
||||
|
||||
BiosProcessResult = namedtuple('BiosProcessResult',
|
||||
'tree, attributes_written,'
|
||||
'bios_attributes')
|
||||
return BiosProcessResult(tree, attributes_written, bios_attributes)
|
||||
|
||||
def _process_bios(self, identity,
|
||||
bios_attributes=DEFAULT_BIOS_ATTRIBUTES,
|
||||
update_existing_attributes=False):
|
||||
"""Process Libvirt domain XML for BIOS attributes and update it if necessary
|
||||
|
||||
:param identity: libvirt domain name or ID
|
||||
:param bios_attributes: Full list of BIOS attributes to use if
|
||||
they are missing or update necessary
|
||||
:param update: Update existing BIOS attributes
|
||||
|
||||
:returns: New or existing dict of BIOS attributes
|
||||
|
||||
:raises: `FishyError` if BIOS attributes cannot be saved
|
||||
"""
|
||||
with libvirt_open(self._uri) as conn:
|
||||
libvirt_domain = conn.lookupByName(identity)
|
||||
result = self._process_bios_attributes(libvirt_domain.XMLDesc(),
|
||||
bios_attributes,
|
||||
update_existing_attributes)
|
||||
|
||||
if result.attributes_written:
|
||||
try:
|
||||
conn.defineXML(ET.tostring(result.tree).decode('utf-8'))
|
||||
except libvirt.libvirtError as e:
|
||||
msg = ('Error updating BIOS attributes'
|
||||
' at libvirt URI "%(uri)s": '
|
||||
'%(error)s' % {'uri': self._uri, 'error': e})
|
||||
raise FishyError(msg)
|
||||
return result.bios_attributes
|
||||
|
||||
def get_bios(self, identity):
|
||||
"""Get BIOS section
|
||||
|
||||
If there are no BIOS attributes, domain is updated with default values.
|
||||
|
||||
:param identity: libvirt domain name or ID
|
||||
:returns: dict of BIOS attributes
|
||||
"""
|
||||
return self._process_bios(identity)
|
||||
|
||||
def set_bios(self, identity, attributes):
|
||||
"""Update BIOS attributes
|
||||
|
||||
These values do not have any effect on VM. This is a workaround
|
||||
because there is no libvirt API to manage BIOS settings.
|
||||
By storing fake BIOS attributes they are attached to VM and are
|
||||
persisted through VM lifecycle.
|
||||
|
||||
Updates to attributes are immediate unlike in real BIOS that
|
||||
would require system reboot.
|
||||
|
||||
:param identity: libvirt domain name or ID
|
||||
:param attributes: dict of BIOS attributes to update. Can pass only
|
||||
attributes that need update, not all
|
||||
"""
|
||||
bios_attributes = self.get_bios(identity)
|
||||
|
||||
bios_attributes.update(attributes)
|
||||
|
||||
self._process_bios(identity, bios_attributes,
|
||||
update_existing_attributes=True)
|
||||
|
||||
def reset_bios(self, identity):
|
||||
"""Reset BIOS attributes to default
|
||||
|
||||
:param identity: libvirt domain name or ID
|
||||
"""
|
||||
self._process_bios(identity, self.DEFAULT_BIOS_ATTRIBUTES,
|
||||
update_existing_attributes=True)
|
||||
|
@ -272,3 +272,15 @@ class OpenStackDriver(AbstractDriver):
|
||||
return
|
||||
|
||||
return flavor.vcpus
|
||||
|
||||
def get_bios(self, identity):
|
||||
"""Not supported as Openstack SDK does not expose API for BIOS"""
|
||||
raise NotImplementedError
|
||||
|
||||
def set_bios(self, identity, attributes):
|
||||
"""Not supported as Openstack SDK does not expose API for BIOS"""
|
||||
raise NotImplementedError
|
||||
|
||||
def reset_bios(self, identity):
|
||||
"""Not supported as Openstack SDK does not expose API for BIOS"""
|
||||
raise NotImplementedError
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
import argparse
|
||||
import functools
|
||||
import json
|
||||
import os
|
||||
import ssl
|
||||
import sys
|
||||
@ -178,6 +179,56 @@ def system_reset_action(identity):
|
||||
return '', 204
|
||||
|
||||
|
||||
@app.route('/redfish/v1/Systems/<identity>/BIOS', methods=['GET'])
|
||||
@init_virt_driver
|
||||
@returns_json
|
||||
def bios(identity):
|
||||
bios = driver.get_bios(identity)
|
||||
|
||||
app.logger.debug('Serving BIOS for system "%s"', identity)
|
||||
|
||||
return flask.render_template(
|
||||
'bios.json',
|
||||
identity=identity,
|
||||
bios_current_attributes=json.dumps(bios, sort_keys=True, indent=6))
|
||||
|
||||
|
||||
@app.route('/redfish/v1/Systems/<identity>/BIOS/Settings',
|
||||
methods=['GET', 'PATCH'])
|
||||
@init_virt_driver
|
||||
@returns_json
|
||||
def bios_settings(identity):
|
||||
|
||||
if flask.request.method == 'GET':
|
||||
bios = driver.get_bios(identity)
|
||||
|
||||
app.logger.debug('Serving BIOS Settings for system "%s"', identity)
|
||||
|
||||
return flask.render_template(
|
||||
'bios_settings.json',
|
||||
identity=identity,
|
||||
bios_pending_attributes=json.dumps(bios, sort_keys=True, indent=6))
|
||||
|
||||
elif flask.request.method == 'PATCH':
|
||||
attributes = flask.request.json.get('Attributes')
|
||||
|
||||
driver.set_bios(identity, attributes)
|
||||
app.logger.info('System "%s" BIOS attributes "%s" updated',
|
||||
identity, attributes)
|
||||
return '', 204
|
||||
|
||||
|
||||
@app.route('/redfish/v1/Systems/<identity>/BIOS/Actions/Bios.ResetBios',
|
||||
methods=['POST'])
|
||||
@init_virt_driver
|
||||
@returns_json
|
||||
def system_reset_bios(identity):
|
||||
|
||||
driver.reset_bios(identity)
|
||||
app.logger.info('BIOS for system "%s" reset', identity)
|
||||
return '', 204
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser('sushy-emulator')
|
||||
parser.add_argument('-i', '--interface',
|
||||
|
23
sushy_tools/emulator/templates/bios.json
Normal file
23
sushy_tools/emulator/templates/bios.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"@odata.type": "#Bios.v1_0_0.Bios",
|
||||
"Id": "BIOS",
|
||||
"Name": "BIOS Configuration Current Settings",
|
||||
"AttributeRegistry": "BiosAttributeRegistryP89.v1_0_0",
|
||||
"Attributes": {{ bios_current_attributes }},
|
||||
"@Redfish.Settings": {
|
||||
"@odata.type": "#Settings.v1_0_0.Settings",
|
||||
"SettingsObject": {
|
||||
"@odata.id": "/redfish/v1/Systems/{{ identity }}/BIOS/Settings"
|
||||
}
|
||||
},
|
||||
"Actions": {
|
||||
"#Bios.ResetBios": {
|
||||
"target": "/redfish/v1/Systems/{{ identity }}/BIOS/Actions/Bios.ResetBios"
|
||||
},
|
||||
"#Bios.ChangePassword": {
|
||||
"target": "/redfish/v1/Systems/{{ identity }}/BIOS/Actions/Bios.ChangePassword"
|
||||
}
|
||||
},
|
||||
"@odata.context": "/redfish/v1/$metadata#Bios.Bios",
|
||||
"@odata.id": "/redfish/v1/Systems/{{ identity }}/BIOS"
|
||||
}
|
10
sushy_tools/emulator/templates/bios_settings.json
Normal file
10
sushy_tools/emulator/templates/bios_settings.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"@odata.type": "#Bios.v1_0_0.Bios",
|
||||
"Id": "Settings",
|
||||
"Name": "BIOS Configuration Pending Settings",
|
||||
"AttributeRegistry": "BiosAttributeRegistryP89.v1_0_0",
|
||||
"Attributes": {{ bios_pending_attributes }},
|
||||
"@odata.context": "/redfish/v1/$metadata#Bios.Bios",
|
||||
"@odata.id": "/redfish/v1/Systems/{{ identity }}/BIOS/Settings",
|
||||
"@Redfish.Copyright": "Copyright 2014-2016 Distributed Management Task Force, Inc. (DMTF). For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright."
|
||||
}
|
29
sushy_tools/tests/unit/emulator/domain_bios.xml
Normal file
29
sushy_tools/tests/unit/emulator/domain_bios.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<domain type='qemu'
|
||||
xmlns:sushy="http://openstack.org/xmlns/libvirt/sushy">
|
||||
<name>QEmu-fedora-i686</name>
|
||||
<uuid>c7a5fdbd-cdaf-9455-926a-d65c16db1809</uuid>
|
||||
<memory>219200</memory>
|
||||
<currentMemory>219200</currentMemory>
|
||||
<vcpu>2</vcpu>
|
||||
<os>
|
||||
<type arch='i686' machine='pc'>hvm</type>
|
||||
<boot dev='cdrom'/>
|
||||
<loader type='rom'/>
|
||||
</os>
|
||||
<devices>
|
||||
<emulator>/usr/bin/qemu-system-x86_64</emulator>
|
||||
<disk type='file' device='cdrom'>
|
||||
<source file='/home/user/boot.iso'/>
|
||||
<target dev='hdc'/>
|
||||
<readonly/>
|
||||
</disk>
|
||||
<disk type='file' device='disk'>
|
||||
<source file='/home/user/fedora.img'/>
|
||||
<target dev='hda'/>
|
||||
</disk>
|
||||
<interface type='network'>
|
||||
<source network='default'/>
|
||||
</interface>
|
||||
<graphics type='vnc' port='-1'/>
|
||||
</devices>
|
||||
<metadata><sushy:bios><sushy:attributes><sushy:attribute name="BootMode" value="Bios" /><sushy:attribute name="EmbeddedSata" value="Raid" /><sushy:attribute name="NicBoot1" value="NetworkBoot" /><sushy:attribute name="ProcTurboMode" value="Disabled" /></sushy:attributes></sushy:bios></metadata></domain>
|
29
sushy_tools/tests/unit/emulator/domain_metadata.xml
Normal file
29
sushy_tools/tests/unit/emulator/domain_metadata.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<domain type='qemu'>
|
||||
<name>QEmu-fedora-i686</name>
|
||||
<uuid>c7a5fdbd-cdaf-9455-926a-d65c16db1809</uuid>
|
||||
<memory>219200</memory>
|
||||
<currentMemory>219200</currentMemory>
|
||||
<vcpu>2</vcpu>
|
||||
<os>
|
||||
<type arch='i686' machine='pc'>hvm</type>
|
||||
<boot dev='cdrom'/>
|
||||
<loader type='rom'/>
|
||||
</os>
|
||||
<devices>
|
||||
<emulator>/usr/bin/qemu-system-x86_64</emulator>
|
||||
<disk type='file' device='cdrom'>
|
||||
<source file='/home/user/boot.iso'/>
|
||||
<target dev='hdc'/>
|
||||
<readonly/>
|
||||
</disk>
|
||||
<disk type='file' device='disk'>
|
||||
<source file='/home/user/fedora.img'/>
|
||||
<target dev='hda'/>
|
||||
</disk>
|
||||
<interface type='network'>
|
||||
<source network='default'/>
|
||||
</interface>
|
||||
<graphics type='vnc' port='-1'/>
|
||||
</devices>
|
||||
<metadata /></domain>
|
||||
|
@ -11,11 +11,14 @@
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import libvirt
|
||||
|
||||
from oslotest import base
|
||||
from six.moves import mock
|
||||
|
||||
from sushy_tools.emulator.drivers.libvirtdriver import LibvirtDriver
|
||||
from sushy_tools.emulator import main
|
||||
from sushy_tools.error import FishyError
|
||||
|
||||
|
||||
class EmulatorTestCase(base.BaseTestCase):
|
||||
@ -25,7 +28,7 @@ class EmulatorTestCase(base.BaseTestCase):
|
||||
|
||||
# This enables libvirt driver
|
||||
main.driver = None
|
||||
|
||||
self.test_driver = LibvirtDriver()
|
||||
super(EmulatorTestCase, self).setUp()
|
||||
|
||||
def test_root_resource(self):
|
||||
@ -186,3 +189,131 @@ class EmulatorTestCase(base.BaseTestCase):
|
||||
data=data, content_type='application/json')
|
||||
self.assertEqual(response.status, '204 NO CONTENT')
|
||||
domain_mock.injectNMI.assert_called_once_with()
|
||||
|
||||
@mock.patch('libvirt.open', autospec=True)
|
||||
def test_get_bios(self, libvirt_mock):
|
||||
with open('sushy_tools/tests/unit/emulator/domain.xml') as f:
|
||||
domain_xml = f.read()
|
||||
|
||||
conn_mock = libvirt_mock.return_value
|
||||
domain_mock = conn_mock.lookupByName.return_value
|
||||
domain_mock.XMLDesc.return_value = domain_xml
|
||||
|
||||
bios_attributes = self.test_driver.get_bios('xxx-yyy-zzz')
|
||||
self.assertEqual(LibvirtDriver.DEFAULT_BIOS_ATTRIBUTES,
|
||||
bios_attributes)
|
||||
self.assertEqual(1, conn_mock.defineXML.call_count)
|
||||
|
||||
@mock.patch('libvirt.open', autospec=True)
|
||||
def test_get_bios_existing(self, libvirt_mock):
|
||||
with open('sushy_tools/tests/unit/emulator/domain_bios.xml') as f:
|
||||
domain_xml = f.read()
|
||||
|
||||
conn_mock = libvirt_mock.return_value
|
||||
domain_mock = conn_mock.lookupByName.return_value
|
||||
domain_mock.XMLDesc.return_value = domain_xml
|
||||
|
||||
bios_attributes = self.test_driver.get_bios('xxx-yyy-zzz')
|
||||
self.assertEqual({"BootMode": "Bios",
|
||||
"EmbeddedSata": "Raid",
|
||||
"NicBoot1": "NetworkBoot",
|
||||
"ProcTurboMode": "Disabled"},
|
||||
bios_attributes)
|
||||
conn_mock.defineXML.assert_not_called()
|
||||
|
||||
@mock.patch('libvirt.open', autospec=True)
|
||||
def test_set_bios(self, libvirt_mock):
|
||||
with open('sushy_tools/tests/unit/emulator/domain_bios.xml') as f:
|
||||
domain_xml = f.read()
|
||||
|
||||
conn_mock = libvirt_mock.return_value
|
||||
domain_mock = conn_mock.lookupByName.return_value
|
||||
domain_mock.XMLDesc.return_value = domain_xml
|
||||
|
||||
self.test_driver.set_bios('xxx-yyy-zzz',
|
||||
{"BootMode": "Uefi",
|
||||
"ProcTurboMode": "Enabled"})
|
||||
self.assertEqual(1, conn_mock.defineXML.call_count)
|
||||
|
||||
@mock.patch('libvirt.open', autospec=True)
|
||||
def test_reset_bios(self, libvirt_mock):
|
||||
with open('sushy_tools/tests/unit/emulator/domain_bios.xml') as f:
|
||||
domain_xml = f.read()
|
||||
|
||||
conn_mock = libvirt_mock.return_value
|
||||
domain_mock = conn_mock.lookupByName.return_value
|
||||
domain_mock.XMLDesc.return_value = domain_xml
|
||||
|
||||
self.test_driver.reset_bios('xxx-yyy-zzz')
|
||||
self.assertEqual(1, conn_mock.defineXML.call_count)
|
||||
|
||||
def test__process_bios_attributes_get_default(self):
|
||||
with open('sushy_tools/tests/unit/emulator/domain.xml') as f:
|
||||
domain_xml = f.read()
|
||||
|
||||
result = self.test_driver._process_bios_attributes(domain_xml)
|
||||
self.assertTrue(result.attributes_written)
|
||||
self.assertEqual(LibvirtDriver.DEFAULT_BIOS_ATTRIBUTES,
|
||||
result.bios_attributes)
|
||||
self._assert_bios_xml(result.tree)
|
||||
|
||||
def test__process_bios_attributes_get_default_metadata_exists(self):
|
||||
with open('sushy_tools/tests/unit/emulator/'
|
||||
'domain_metadata.xml') as f:
|
||||
domain_xml = f.read()
|
||||
|
||||
result = self.test_driver._process_bios_attributes(domain_xml)
|
||||
self.assertTrue(result.attributes_written)
|
||||
self.assertEqual(LibvirtDriver.DEFAULT_BIOS_ATTRIBUTES,
|
||||
result.bios_attributes)
|
||||
self._assert_bios_xml(result.tree)
|
||||
|
||||
def test__process_bios_attributes_get_existing(self):
|
||||
with open('sushy_tools/tests/unit/emulator/domain_bios.xml') as f:
|
||||
domain_xml = f.read()
|
||||
|
||||
result = self.test_driver._process_bios_attributes(domain_xml)
|
||||
self.assertFalse(result.attributes_written)
|
||||
self.assertEqual({"BootMode": "Bios",
|
||||
"EmbeddedSata": "Raid",
|
||||
"NicBoot1": "NetworkBoot",
|
||||
"ProcTurboMode": "Disabled"},
|
||||
result.bios_attributes)
|
||||
self._assert_bios_xml(result.tree)
|
||||
|
||||
def test__process_bios_attributes_update(self):
|
||||
with open('sushy_tools/tests/unit/emulator/domain_bios.xml') as f:
|
||||
domain_xml = f.read()
|
||||
result = self.test_driver._process_bios_attributes(
|
||||
domain_xml,
|
||||
{"BootMode": "Uefi",
|
||||
"ProcTurboMode": "Enabled"},
|
||||
True)
|
||||
self.assertTrue(result.attributes_written)
|
||||
self.assertEqual({"BootMode": "Uefi",
|
||||
"ProcTurboMode": "Enabled"},
|
||||
result.bios_attributes)
|
||||
self._assert_bios_xml(result.tree)
|
||||
|
||||
def _assert_bios_xml(self, tree):
|
||||
ns = {'sushy': 'http://openstack.org/xmlns/libvirt/sushy'}
|
||||
self.assertIsNotNone(tree.find('metadata')
|
||||
.find('sushy:bios', ns)
|
||||
.find('sushy:attributes', ns))
|
||||
|
||||
@mock.patch('libvirt.open', autospec=True)
|
||||
def test__process_bios_error(self, libvirt_mock):
|
||||
with open('sushy_tools/tests/unit/emulator/domain.xml') as f:
|
||||
domain_xml = f.read()
|
||||
|
||||
conn_mock = libvirt_mock.return_value
|
||||
domain_mock = conn_mock.lookupByName.return_value
|
||||
domain_mock.XMLDesc.return_value = domain_xml
|
||||
conn_mock.defineXML.side_effect = libvirt.libvirtError(
|
||||
'because I can')
|
||||
|
||||
self.assertRaises(FishyError,
|
||||
self.test_driver._process_bios,
|
||||
'xxx-yyy-zzz',
|
||||
{"BootMode": "Uefi",
|
||||
"ProcTurboMode": "Enabled"})
|
||||
|
70
sushy_tools/tests/unit/emulator/test_main.py
Normal file
70
sushy_tools/tests/unit/emulator/test_main.py
Normal file
@ -0,0 +1,70 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
|
||||
from oslotest import base
|
||||
from six.moves import mock
|
||||
|
||||
from sushy_tools.emulator import main
|
||||
|
||||
|
||||
@mock.patch('sushy_tools.emulator.main.driver', autospec=True)
|
||||
class EmulatorTestCase(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
main.driver = None
|
||||
self.app = main.app.test_client()
|
||||
|
||||
super(EmulatorTestCase, self).setUp()
|
||||
|
||||
def test_bios(self, driver_mock):
|
||||
driver_mock.get_bios.return_value = {"attribute 1": "value 1",
|
||||
"attribute 2": "value 2"}
|
||||
response = self.app.get('/redfish/v1/Systems/xxxx-yyyy-zzzz/BIOS')
|
||||
|
||||
self.assertEqual('200 OK', response.status)
|
||||
self.assertEqual('BIOS', response.json['Id'])
|
||||
self.assertEqual({"attribute 1": "value 1",
|
||||
"attribute 2": "value 2"},
|
||||
response.json['Attributes'])
|
||||
|
||||
def test_bios_settings(self, driver_mock):
|
||||
driver_mock.get_bios.return_value = {"attribute 1": "value 1",
|
||||
"attribute 2": "value 2"}
|
||||
response = self.app.get(
|
||||
'/redfish/v1/Systems/xxxx-yyyy-zzzz/BIOS/Settings')
|
||||
|
||||
self.assertEqual('200 OK', response.status)
|
||||
self.assertEqual('Settings', response.json['Id'])
|
||||
self.assertEqual({"attribute 1": "value 1",
|
||||
"attribute 2": "value 2"},
|
||||
response.json['Attributes'])
|
||||
|
||||
def test_bios_settings_patch(self, driver_mock):
|
||||
self.app.driver = driver_mock
|
||||
response = self.app.patch(
|
||||
'/redfish/v1/Systems/xxxx-yyyy-zzzz/BIOS/Settings',
|
||||
data=json.dumps({'Attributes': {'key': 'value'}}),
|
||||
content_type='application/json')
|
||||
|
||||
self.assertEqual('204 NO CONTENT', response.status)
|
||||
driver_mock.set_bios.assert_called_once_with('xxxx-yyyy-zzzz',
|
||||
{'key': 'value'})
|
||||
|
||||
def test_reset_bios(self, driver_mock):
|
||||
self.app.driver = driver_mock
|
||||
response = self.app.post('/redfish/v1/Systems/xxxx-yyyy-zzzz/'
|
||||
'BIOS/Actions/Bios.ResetBios')
|
||||
|
||||
self.assertEqual('204 NO CONTENT', response.status)
|
||||
driver_mock.reset_bios.assert_called_once_with('xxxx-yyyy-zzzz')
|
@ -18,6 +18,7 @@ import os
|
||||
from oslotest import base
|
||||
from six.moves import mock
|
||||
|
||||
from sushy_tools.emulator.drivers.novadriver import OpenStackDriver
|
||||
from sushy_tools.emulator import main
|
||||
|
||||
|
||||
@ -157,3 +158,27 @@ class EmulatorTestCase(base.BaseTestCase):
|
||||
json=data)
|
||||
self.assertEqual(response.status_code, 204)
|
||||
server.compute.reboot_server.called_once()
|
||||
|
||||
@mock.patch('openstack.connect', autospec=True)
|
||||
def test_get_bios(self, nova_mock):
|
||||
test_driver = OpenStackDriver('fake-cloud')
|
||||
self.assertRaises(
|
||||
NotImplementedError,
|
||||
test_driver.get_bios, 'xxx-yyy-zzz')
|
||||
|
||||
@mock.patch('openstack.connect', autospec=True)
|
||||
def test_set_bios(self, nova_mock):
|
||||
test_driver = OpenStackDriver('fake-cloud')
|
||||
self.assertRaises(
|
||||
NotImplementedError,
|
||||
test_driver.set_bios,
|
||||
'xxx-yyy-zzz',
|
||||
{'attribute 1': 'value 1'})
|
||||
|
||||
@mock.patch('openstack.connect', autospec=True)
|
||||
def test_reset_bios(self, nova_mock):
|
||||
test_driver = OpenStackDriver('fake-cloud')
|
||||
self.assertRaises(
|
||||
NotImplementedError,
|
||||
test_driver.reset_bios,
|
||||
'xxx-yyy-zzz')
|
||||
|
Loading…
Reference in New Issue
Block a user