Redirect to UUID URLs

Redfish ComputerSystem is addressed by Redfish resource `Id`,
while the resource can also carry the `name` and/or `uuid`
properties.

Technically, Redfish emulator could respond to queries performed
against `uuid` and `name`. This change makes Redfish emulator
HTTP redirecting all queries performed against `name` to the same
REST endpoint addressing the same ComputerSystem by its `uuid`
as a more canonical.

Also, when listing ComputerSystems, `uuid` is now universally used.
Prior to this change the libvirt driver advertised ComputerSystems
names while nova driver advertised UUIDs.

Story: 2004306
Task: 27867
Change-Id: Ic5dab0a5642d65d832f66092b7bf178ec58a3655
This commit is contained in:
Ilya Etingof 2018-10-31 11:06:36 +01:00
parent a7d8302a5e
commit 499536afcb
9 changed files with 252 additions and 191 deletions

View File

@ -32,7 +32,7 @@ class AbstractDriver(object):
def systems(self):
"""Return available computer systems
:returns: list of computer systems names.
:returns: list of UUIDs representing the systems
"""
@abc.abstractmethod
@ -43,11 +43,24 @@ class AbstractDriver(object):
in place of system name if there are duplicates.
If virtualization backend does not support non-unique system identity,
this property may just return the `identity`.
this method may just return the `identity`.
:returns: computer system UUID
"""
@abc.abstractmethod
def name(self, identity):
"""Get computer system name by UUID
The universal unique identifier (UUID) for this system. Can be used
in place of system name if there are duplicates.
If virtualization backend does not support system names
this method may just return the `identity`.
:returns: computer system name
"""
@abc.abstractmethod
def get_power_state(self, identity):
"""Get computer system power state

View File

@ -19,7 +19,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
from sushy_tools import error
try:
import libvirt
@ -57,7 +57,7 @@ class libvirt_open(object):
except libvirt.libvirtError as e:
msg = ('Error when connecting to the libvirt URI "%(uri)s": '
'%(error)s' % {'uri': self._uri, 'error': e})
raise FishyError(msg)
raise error.FishyError(msg)
def __exit__(self, type, value, traceback):
self._conn.close()
@ -108,15 +108,15 @@ class LibvirtDriver(AbstractDriver):
def _get_domain(self, identity, readonly=False):
with libvirt_open(self._uri, readonly=readonly) as conn:
try:
return conn.lookupByName(identity)
uu_identity = uuid.UUID(identity)
except libvirt.libvirtError as ex:
return conn.lookupByUUID(uu_identity.bytes)
except (ValueError, libvirt.libvirtError):
try:
uu_identity = uuid.UUID(identity)
domain = conn.lookupByName(identity)
return conn.lookupByUUID(uu_identity.bytes)
except (ValueError, libvirt.libvirtError):
except libvirt.libvirtError as ex:
msg = ('Error finding domain by name/UUID "%(identity)s" '
'at libvirt URI %(uri)s": %(err)s' %
{'identity': identity,
@ -124,7 +124,9 @@ class LibvirtDriver(AbstractDriver):
logger.debug(msg)
raise FishyError(msg)
raise error.FishyError(msg)
raise error.AliasAccessError(domain.UUIDString())
@property
def driver(self):
@ -138,10 +140,11 @@ class LibvirtDriver(AbstractDriver):
def systems(self):
"""Return available computer systems
:returns: list of computer systems names.
:returns: list of UUIDs representing the systems
"""
with libvirt_open(self._uri, readonly=True) as conn:
return conn.listDefinedDomains()
return [domain.UUIDString()
for domain in conn.listDefinedDomains()]
def uuid(self, identity):
"""Get computer system UUID
@ -156,6 +159,16 @@ class LibvirtDriver(AbstractDriver):
domain = self._get_domain(identity, readonly=True)
return domain.UUIDString()
def name(self, identity):
"""Get computer system name by name
:param identity: libvirt domain name or UUID
:returns: computer system name
"""
domain = self._get_domain(identity, readonly=True)
return domain.name()
def get_power_state(self, identity):
"""Get computer system power state
@ -176,7 +189,7 @@ class LibvirtDriver(AbstractDriver):
Valid values are: *On*, *ForceOn*, *ForceOff*, *GracefulShutdown*,
*GracefulRestart*, *ForceRestart*, *Nmi*.
:raises: `FishyError` if power state can't be set
:raises: `error.FishyError` if power state can't be set
"""
domain = self._get_domain(identity)
@ -204,7 +217,7 @@ class LibvirtDriver(AbstractDriver):
msg = ('Error changing power state at libvirt URI "%(uri)s": '
'%(error)s' % {'uri': self._uri, 'error': e})
raise FishyError(msg)
raise error.FishyError(msg)
def get_boot_device(self, identity):
"""Get computer system boot device name
@ -234,7 +247,7 @@ class LibvirtDriver(AbstractDriver):
change on the system. If not specified, current boot device is
returned. Valid values are: *Pxe*, *Hdd*, *Cd*.
:raises: `FishyError` if boot device can't be set
:raises: `error.FishyError` if boot device can't be set
"""
domain = self._get_domain(identity)
@ -248,7 +261,7 @@ class LibvirtDriver(AbstractDriver):
msg = ('Unknown power state requested: '
'%(boot_source)s' % {'boot_source': boot_source})
raise FishyError(msg)
raise error.FishyError(msg)
for os_element in tree.findall('os'):
# Remove all "boot" elements
@ -267,7 +280,7 @@ class LibvirtDriver(AbstractDriver):
msg = ('Error changing boot device at libvirt URI "%(uri)s": '
'%(error)s' % {'uri': self._uri, 'error': e})
raise FishyError(msg)
raise error.FishyError(msg)
def get_boot_mode(self, identity):
"""Get computer system boot mode.
@ -296,7 +309,7 @@ class LibvirtDriver(AbstractDriver):
change on the system. If not specified, current boot mode is
returned. Valid values are: *Uefi*, *Legacy*.
:raises: `FishyError` if boot mode can't be set
:raises: `error.FishyError` if boot mode can't be set
"""
domain = self._get_domain(identity, readonly=True)
@ -310,7 +323,7 @@ class LibvirtDriver(AbstractDriver):
msg = ('Unknown boot mode requested: '
'%(boot_mode)s' % {'boot_mode': boot_mode})
raise FishyError(msg)
raise error.FishyError(msg)
for os_element in tree.findall('os'):
type_element = os_element.find('type')
@ -346,7 +359,7 @@ class LibvirtDriver(AbstractDriver):
'"%(uri)s": %(error)s' % {'uri': self._uri,
'error': e})
raise FishyError(msg)
raise error.FishyError(msg)
def get_total_memory(self, identity):
"""Get computer system total memory
@ -464,7 +477,7 @@ class LibvirtDriver(AbstractDriver):
:returns: New or existing dict of BIOS attributes
:raises: `FishyError` if BIOS attributes cannot be saved
:raises: `error.FishyError` if BIOS attributes cannot be saved
"""
domain = self._get_domain(identity)
@ -481,7 +494,7 @@ class LibvirtDriver(AbstractDriver):
msg = ('Error updating BIOS attributes'
' at libvirt URI "%(uri)s": '
'%(error)s' % {'uri': self._uri, 'error': e})
raise FishyError(msg)
raise error.FishyError(msg)
return result.bios_attributes

View File

@ -17,7 +17,7 @@ import logging
import math
from sushy_tools.emulator.drivers.base import AbstractDriver
from sushy_tools.error import FishyError
from sushy_tools import error
try:
import openstack
@ -56,9 +56,12 @@ class OpenStackDriver(AbstractDriver):
self._os_cloud = os_cloud
def _get_instance(self, identity):
server = self._cc.get_server(identity)
if server:
return server
instance = self._cc.get_server(identity)
if instance:
if identity != instance.id:
raise error.AliasAccessError(instance.id)
return instance
msg = ('Error finding instance by UUID "%(identity)s" at OS '
'cloud %(os_cloud)s"' % {'identity': identity,
@ -66,7 +69,7 @@ class OpenStackDriver(AbstractDriver):
logger.debug(msg)
raise FishyError(msg)
raise error.FishyError(msg)
def _get_flavor(self, identity):
instance = self._get_instance(identity)
@ -85,7 +88,7 @@ class OpenStackDriver(AbstractDriver):
def systems(self):
"""Return available computer systems
:returns: list of computer systems names.
:returns: list of UUIDs representing the systems
"""
return [server.id for server in self._cc.list_servers()]
@ -99,6 +102,16 @@ class OpenStackDriver(AbstractDriver):
instance = self._get_instance(identity)
return instance.id
def name(self, identity):
"""Get computer system name by name
:param identity: OpenStack instance name or ID
:returns: computer system name
"""
instance = self._get_instance(identity)
return instance.name
def get_power_state(self, identity):
"""Get computer system power state
@ -110,7 +123,7 @@ class OpenStackDriver(AbstractDriver):
try:
instance = self._get_instance(identity)
except FishyError:
except error.FishyError:
return
if instance.power_state == self.NOVA_POWER_STATE_ON:
@ -127,7 +140,7 @@ class OpenStackDriver(AbstractDriver):
returned. Valid values are: *On*, *ForceOn*, *ForceOff*,
*GracefulShutdown*, *GracefulRestart*, *ForceRestart*, *Nmi*.
:raises: `FishyError` if power state can't be set
:raises: `error.FishyError` if power state can't be set
"""
instance = self._get_instance(identity)
@ -159,8 +172,8 @@ class OpenStackDriver(AbstractDriver):
# NOTE(etingof) can't support `state == "Nmi"` as
# openstacksdk does not seem to support that
else:
raise FishyError('Unknown ResetType '
'"%(state)s"' % {'state': state})
raise error.FishyError(
'Unknown ResetType "%(state)s"' % {'state': state})
def get_boot_device(self, identity):
"""Get computer system boot device name
@ -173,7 +186,7 @@ class OpenStackDriver(AbstractDriver):
try:
instance = self._get_instance(identity)
except FishyError:
except error.FishyError:
return
metadata = self._cc.compute.get_server_metadata(instance.id).to_dict()
@ -195,7 +208,7 @@ class OpenStackDriver(AbstractDriver):
change on the system. If not specified, current boot device is
returned. Valid values are: *Pxe*, *Hdd*, *Cd*.
:raises: `FishyError` if boot device can't be set
:raises: `error.FishyError` if boot device can't be set
"""
instance = self._get_instance(identity)
@ -206,7 +219,7 @@ class OpenStackDriver(AbstractDriver):
msg = ('Unknown power state requested: '
'%(boot_source)s' % {'boot_source': boot_source})
raise FishyError(msg)
raise error.FishyError(msg)
# NOTE(etingof): the following probably only works with
# libvirt-backed compute nodes
@ -237,7 +250,7 @@ class OpenStackDriver(AbstractDriver):
change on the system. If not specified, current boot mode is
returned. Valid values are: *Uefi*, *Legacy*.
:raises: `FishyError` if boot mode can't be set
:raises: `error.FishyError` if boot mode can't be set
"""
# just to make sure passed identity exists
self._get_instance(identity)
@ -245,7 +258,7 @@ class OpenStackDriver(AbstractDriver):
msg = ('The cloud driver %(driver)s does not allow changing boot '
'mode through Redfish' % {'driver': self.driver})
raise FishyError(msg)
raise error.FishyError(msg)
def get_total_memory(self, identity):
"""Get computer system total memory
@ -258,7 +271,7 @@ class OpenStackDriver(AbstractDriver):
try:
flavor = self._get_flavor(identity)
except FishyError:
except error.FishyError:
return
return int(math.ceil(flavor.ram / 1024.))
@ -274,24 +287,24 @@ class OpenStackDriver(AbstractDriver):
try:
flavor = self._get_flavor(identity)
except FishyError:
except error.FishyError:
return
return flavor.vcpus
def get_bios(self, identity):
"""Not supported as Openstack SDK does not expose API for BIOS"""
raise FishyError(
raise error.FishyError(
'Operation not supported by the virtualization driver')
def set_bios(self, identity, attributes):
"""Not supported as Openstack SDK does not expose API for BIOS"""
raise FishyError(
raise error.FishyError(
'Operation not supported by the virtualization driver')
def reset_bios(self, identity):
"""Not supported as Openstack SDK does not expose API for BIOS"""
raise FishyError(
raise error.FishyError(
'Operation not supported by the virtualization driver')
def get_nics(self, identity):

View File

@ -22,6 +22,7 @@ import sys
from sushy_tools.emulator.drivers import libvirtdriver
from sushy_tools.emulator.drivers import novadriver
from sushy_tools import error
import flask
@ -85,6 +86,9 @@ def returns_json(decorated_func):
@app.errorhandler(Exception)
@returns_json
def all_exception_handler(message):
if isinstance(message, error.AliasAccessError):
url = flask.url_for(flask.request.endpoint, identity=message.args[0])
return flask.redirect(url, Response=flask.Response)
return flask.render_template('error.json', message=message), 500
@ -104,8 +108,7 @@ def system_collection_resource():
app.logger.debug('Serving systems list')
return flask.render_template(
'system_collection.json', system_count=len(systems),
systems=systems)
'system_collection.json', system_count=len(systems), systems=systems)
@app.route('/redfish/v1/Systems/<identity>', methods=['GET', 'PATCH'])
@ -117,7 +120,9 @@ def system_resource(identity):
app.logger.debug('Serving resources for system "%s"', identity)
return flask.render_template(
'system.json', identity=identity,
'system.json',
identity=identity,
name=driver.name(identity),
uuid=driver.uuid(identity),
power_state=driver.get_power_state(identity),
total_memory_gb=driver.get_total_memory(identity),

View File

@ -1,7 +1,7 @@
{
"@odata.type": "#ComputerSystem.v1_1_0.ComputerSystem",
"Id": {{ identity|string|tojson }},
"Name": {{ identity|string|tojson }},
"Name": {{ name|string|tojson }},
"UUID": {{ uuid|string|tojson }},
"Status": {
"State": "Enabled",

View File

@ -16,3 +16,7 @@
class FishyError(Exception):
"""Create generic sushy-tools exception object"""
class AliasAccessError(FishyError):
"""Node access attempted via an alias, not UUID"""

View File

@ -9,159 +9,151 @@
# 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 libvirt
import uuid
import libvirt
from oslotest import base
from six.moves import mock
from sushy_tools.emulator.drivers.libvirtdriver import LibvirtDriver
from sushy_tools.error import FishyError
from sushy_tools import error
class LibvirtDriverTestCase(base.BaseTestCase):
name = 'QEmu-fedora-i686'
uuid = 'c7a5fdbd-cdaf-9455-926a-d65c16db1809'
def setUp(self):
self.test_driver = LibvirtDriver()
super(LibvirtDriverTestCase, self).setUp()
@mock.patch('libvirt.open', autospec=True)
def test__get_domain_by_name(self, libvirt_mock):
domain_id = 'name'
domain_info = 'domain'
conn_mock = libvirt_mock.return_value
lookupByName_mock = conn_mock.lookupByName
lookupByName_mock.return_value = domain_info
lookupByUUID_mock = conn_mock.lookupByUUID
domain = self.test_driver._get_domain(domain_id)
self.assertEqual(domain_info, domain)
lookupByName_mock.assert_called_once_with(domain_id)
self.assertFalse(lookupByUUID_mock.called)
domain_mock = lookupByUUID_mock.return_value
domain_mock.UUIDString.return_value = self.uuid
self.assertRaises(
error.AliasAccessError, self.test_driver._get_domain, self.name)
@mock.patch('libvirt.open', autospec=True)
def test__get_domain_by_uuid(self, libvirt_mock):
domain_id = uuid.UUID('b9fbc4f5-2c81-4c80-97ea-272621fb7360')
domain_info = 'domain'
domain_id = uuid.UUID(self.uuid)
conn_mock = libvirt_mock.return_value
lookupByName_mock = conn_mock.lookupByName
lookupByName_mock.side_effect = libvirt.libvirtError(
'domain not found')
lookupByUUID_mock = conn_mock.lookupByUUID
lookupByUUID_mock.return_value = domain_info
domain = self.test_driver._get_domain(str(domain_id))
self.assertEqual(domain_info, domain)
lookupByName_mock.assert_called_once_with(str(domain_id))
self.test_driver._get_domain(str(domain_id))
lookupByUUID_mock.assert_called_once_with(domain_id.bytes)
@mock.patch('libvirt.openReadOnly', autospec=True)
def test_uuid(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock.UUIDString.return_value = 'zzzz-yyyy-xxxx'
uuid = self.test_driver.uuid('name')
self.assertEqual('zzzz-yyyy-xxxx', uuid)
domain_mock.UUIDString.return_value = self.uuid
self.assertRaises(error.AliasAccessError,
self.test_driver.uuid, 'name')
@mock.patch('libvirt.openReadOnly', autospec=True)
def test_systems(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
conn_mock.listDefinedDomains.return_value = ['host0', 'host1']
domain = mock.MagicMock()
domain.UUIDString.return_value = self.uuid
conn_mock.listDefinedDomains.return_value = [domain]
systems = self.test_driver.systems
self.assertEqual(['host0', 'host1'], systems)
self.assertEqual([self.uuid], systems)
@mock.patch('libvirt.openReadOnly', autospec=True)
def test_get_power_state_on(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock.isActive.return_value = True
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.UUIDString.return_value = self.uuid
power_state = self.test_driver.get_power_state('zzzz-yyyy-xxxx')
domain_mock.isActive.return_value = True
domain_mock.maxMemory.return_value = 1024 * 1024
domain_mock.maxVcpus.return_value = 2
power_state = self.test_driver.get_power_state(self.uuid)
self.assertEqual('On', power_state)
@mock.patch('libvirt.openReadOnly', autospec=True)
def test_get_power_state_off(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.isActive.return_value = False
power_state = self.test_driver.get_power_state('zzzz-yyyy-xxxx')
power_state = self.test_driver.get_power_state(self.uuid)
self.assertEqual('Off', power_state)
@mock.patch('libvirt.open', autospec=True)
def test_set_power_state_on(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.isActive.return_value = False
self.test_driver.set_power_state('zzzz-yyyy-xxxx', 'On')
self.test_driver.set_power_state(self.uuid, 'On')
domain_mock.create.assert_called_once_with()
@mock.patch('libvirt.open', autospec=True)
def test_set_power_state_forceon(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.isActive.return_value = False
self.test_driver.set_power_state('zzzz-yyyy-xxxx', 'ForceOn')
self.test_driver.set_power_state(self.uuid, 'ForceOn')
domain_mock.create.assert_called_once_with()
@mock.patch('libvirt.open', autospec=True)
def test_set_power_state_forceoff(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.isActive.return_value = True
self.test_driver.set_power_state('zzzz-yyyy-xxxx', 'ForceOff')
self.test_driver.set_power_state(self.uuid, 'ForceOff')
domain_mock.destroy.assert_called_once_with()
@mock.patch('libvirt.open', autospec=True)
def test_set_power_state_gracefulshutdown(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.isActive.return_value = True
self.test_driver.set_power_state('zzzz-yyyy-xxxx', 'GracefulShutdown')
self.test_driver.set_power_state(self.uuid, 'GracefulShutdown')
domain_mock.shutdown.assert_called_once_with()
@mock.patch('libvirt.open', autospec=True)
def test_set_power_state_gracefulrestart(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.isActive.return_value = True
self.test_driver.set_power_state('zzzz-yyyy-xxxx', 'GracefulRestart')
self.test_driver.set_power_state(self.uuid, 'GracefulRestart')
domain_mock.reboot.assert_called_once_with()
@mock.patch('libvirt.open', autospec=True)
def test_set_power_state_forcerestart(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.isActive.return_value = True
self.test_driver.set_power_state('zzzz-yyyy-xxxx', 'ForceRestart')
self.test_driver.set_power_state(self.uuid, 'ForceRestart')
domain_mock.reset.assert_called_once_with()
@mock.patch('libvirt.open', autospec=True)
def test_set_power_state_nmi(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.isActive.return_value = True
self.test_driver.set_power_state('zzzz-yyyy-xxxx', 'Nmi')
self.test_driver.set_power_state(self.uuid, 'Nmi')
domain_mock.injectNMI.assert_called_once_with()
@ -171,10 +163,10 @@ class LibvirtDriverTestCase(base.BaseTestCase):
data = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = data
boot_device = self.test_driver.get_boot_device('zzzz-yyyy-xxxx')
boot_device = self.test_driver.get_boot_device(self.uuid)
self.assertEqual('Cd', boot_device)
@ -184,10 +176,10 @@ class LibvirtDriverTestCase(base.BaseTestCase):
data = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = data
self.test_driver.set_boot_device('zzzz-yyyy-xxxx', 'Hdd')
self.test_driver.set_boot_device(self.uuid, 'Hdd')
conn_mock.defineXML.assert_called_once_with(mock.ANY)
@ -197,10 +189,10 @@ class LibvirtDriverTestCase(base.BaseTestCase):
data = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = data
boot_mode = self.test_driver.get_boot_mode('zzzz-yyyy-xxxx')
boot_mode = self.test_driver.get_boot_mode(self.uuid)
self.assertEqual('Legacy', boot_mode)
@ -211,10 +203,10 @@ class LibvirtDriverTestCase(base.BaseTestCase):
data = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = data
self.test_driver.set_boot_mode('zzzz-yyyy-xxxx', 'Uefi')
self.test_driver.set_boot_mode(self.uuid, 'Uefi')
conn_mock = libvirt_rw_mock.return_value
conn_mock.defineXML.assert_called_once_with(mock.ANY)
@ -222,22 +214,22 @@ class LibvirtDriverTestCase(base.BaseTestCase):
@mock.patch('libvirt.openReadOnly', autospec=True)
def test_get_total_memory(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.maxMemory.return_value = 1024 * 1024
memory = self.test_driver.get_total_memory('zzzz-yyyy-xxxx')
memory = self.test_driver.get_total_memory(self.uuid)
self.assertEqual(1, memory)
@mock.patch('libvirt.openReadOnly', autospec=True)
def test_get_total_cpus(self, libvirt_mock):
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.isActive.return_value = True
domain_mock.XMLDesc.return_value = b'<empty/>'
domain_mock.maxVcpus.return_value = 2
cpus = self.test_driver.get_total_cpus('zzzz-yyyy-xxxx')
cpus = self.test_driver.get_total_cpus(self.uuid)
self.assertEqual(2, cpus)
@ -247,10 +239,10 @@ class LibvirtDriverTestCase(base.BaseTestCase):
domain_xml = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = domain_xml
bios_attributes = self.test_driver.get_bios('xxx-yyy-zzz')
bios_attributes = self.test_driver.get_bios(self.uuid)
self.assertEqual(LibvirtDriver.DEFAULT_BIOS_ATTRIBUTES,
bios_attributes)
conn_mock.defineXML.assert_called_once_with(mock.ANY)
@ -261,10 +253,10 @@ class LibvirtDriverTestCase(base.BaseTestCase):
domain_xml = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = domain_xml
bios_attributes = self.test_driver.get_bios('xxx-yyy-zzz')
bios_attributes = self.test_driver.get_bios(self.uuid)
self.assertEqual({"BootMode": "Bios",
"EmbeddedSata": "Raid",
"NicBoot1": "NetworkBoot",
@ -278,10 +270,10 @@ class LibvirtDriverTestCase(base.BaseTestCase):
domain_xml = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = domain_xml
self.test_driver.set_bios('xxx-yyy-zzz',
self.test_driver.set_bios(self.uuid,
{"BootMode": "Uefi",
"ProcTurboMode": "Enabled"})
conn_mock.defineXML.assert_called_once_with(mock.ANY)
@ -292,10 +284,10 @@ class LibvirtDriverTestCase(base.BaseTestCase):
domain_xml = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = domain_xml
self.test_driver.reset_bios('xxx-yyy-zzz')
self.test_driver.reset_bios(self.uuid)
conn_mock.defineXML.assert_called_once_with(mock.ANY)
def test__process_bios_attributes_get_default(self):
@ -358,12 +350,12 @@ class LibvirtDriverTestCase(base.BaseTestCase):
domain_xml = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = domain_xml
conn_mock.defineXML.side_effect = libvirt.libvirtError(
'because I can')
self.assertRaises(FishyError,
self.assertRaises(error.FishyError,
self.test_driver._process_bios,
'xxx-yyy-zzz',
{"BootMode": "Uefi",
@ -375,10 +367,10 @@ class LibvirtDriverTestCase(base.BaseTestCase):
domain_xml = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = domain_xml
nics = self.test_driver.get_nics('xxx-yyy-zzz')
nics = self.test_driver.get_nics(self.uuid)
self.assertEqual([{'id': '00:11:22:33:44:55',
'mac': '00:11:22:33:44:55'},
{'id': '52:54:00:4e:5d:37',
@ -391,8 +383,8 @@ class LibvirtDriverTestCase(base.BaseTestCase):
domain_xml = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = domain_xml
nics = self.test_driver.get_nics('xxx-yyy-zzz')
nics = self.test_driver.get_nics(self.uuid)
self.assertEqual([], nics)

View File

@ -19,6 +19,9 @@ from sushy_tools.emulator import main
@mock.patch('sushy_tools.emulator.main.driver', autospec=True)
class EmulatorTestCase(base.BaseTestCase):
name = 'QEmu-fedora-i686'
uuid = 'c7a5fdbd-cdaf-9455-926a-d65c16db1809'
def setUp(self):
main.driver = None
self.app = main.app.test_client()
@ -27,7 +30,7 @@ class EmulatorTestCase(base.BaseTestCase):
def test_error(self, driver_mock):
driver_mock.get_power_state.side_effect = Exception('Fish is dead')
response = self.app.get('/redfish/v1/Systems/xxxx-yyyy-zzzz')
response = self.app.get('/redfish/v1/Systems/' + self.uuid)
self.assertEqual('500 INTERNAL SERVER ERROR', response.status)
@ -145,7 +148,7 @@ class EmulatorTestCase(base.BaseTestCase):
def test_get_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')
response = self.app.get('/redfish/v1/Systems/' + self.uuid + '/BIOS')
self.assertEqual('200 OK', response.status)
self.assertEqual('BIOS', response.json['Id'])
@ -157,7 +160,7 @@ class EmulatorTestCase(base.BaseTestCase):
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')
'/redfish/v1/Systems/' + self.uuid + '/BIOS/Settings')
self.assertEqual(200, response.status_code)
self.assertEqual('Settings', response.json['Id'])
@ -189,34 +192,34 @@ class EmulatorTestCase(base.BaseTestCase):
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')
response = self.app.post('/redfish/v1/Systems/' + self.uuid +
'/BIOS/Actions/Bios.ResetBios')
self.assertEqual(204, response.status_code)
driver_mock.reset_bios.assert_called_once_with('xxxx-yyyy-zzzz')
driver_mock.reset_bios.assert_called_once_with(self.uuid)
def test_ethernet_interfaces_collection(self, driver_mock):
driver_mock.get_nics.return_value = [{'id': 'nic1',
'mac': '52:54:00:4e:5d:37'},
{'id': 'nic2',
'mac': '00:11:22:33:44:55'}]
response = self.app.get('redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces')
response = self.app.get('redfish/v1/Systems/' + self.uuid +
'/EthernetInterfaces')
self.assertEqual(200, response.status_code)
self.assertEqual('Ethernet Interface Collection',
response.json['Name'])
self.assertEqual(2, response.json['Members@odata.count'])
self.assertEqual(['/redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces/nic1',
'/redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces/nic2'],
self.assertEqual(['/redfish/v1/Systems/' + self.uuid +
'/EthernetInterfaces/nic1',
'/redfish/v1/Systems/' + self.uuid +
'/EthernetInterfaces/nic2'],
[m['@odata.id'] for m in response.json['Members']])
def test_ethernet_interfaces_collection_empty(self, driver_mock):
driver_mock.get_nics.return_value = []
response = self.app.get('redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces')
response = self.app.get('redfish/v1/Systems/' + self.uuid +
'/EthernetInterfaces')
self.assertEqual(200, response.status_code)
self.assertEqual('Ethernet Interface Collection',
@ -229,8 +232,8 @@ class EmulatorTestCase(base.BaseTestCase):
'mac': '52:54:00:4e:5d:37'},
{'id': 'nic2',
'mac': '00:11:22:33:44:55'}]
response = self.app.get('/redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces/nic2')
response = self.app.get('/redfish/v1/Systems/' + self.uuid +
'/EthernetInterfaces/nic2')
self.assertEqual(200, response.status_code)
self.assertEqual('nic2', response.json['Id'])
@ -239,8 +242,8 @@ class EmulatorTestCase(base.BaseTestCase):
response.json['PermanentMACAddress'])
self.assertEqual('00:11:22:33:44:55',
response.json['MACAddress'])
self.assertEqual('/redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces/nic2',
self.assertEqual('/redfish/v1/Systems/' + self.uuid +
'/EthernetInterfaces/nic2',
response.json['@odata.id'])
def test_ethernet_interface_not_found(self, driver_mock):
@ -248,7 +251,7 @@ class EmulatorTestCase(base.BaseTestCase):
'mac': '52:54:00:4e:5d:37'},
{'id': 'nic2',
'mac': '00:11:22:33:44:55'}]
response = self.app.get('/redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces/nic3')
response = self.app.get('/redfish/v1/Systems/' + self.uuid +
'/EthernetInterfaces/nic3')
self.assertEqual(404, response.status_code)

View File

@ -23,6 +23,9 @@ from sushy_tools import error
class NovaDriverTestCase(base.BaseTestCase):
name = 'QEmu-fedora-i686'
uuid = 'c7a5fdbd-cdaf-9455-926a-d65c16db1809'
def setUp(self):
self.nova_patcher = mock.patch('openstack.connect', autospec=True)
self.nova_mock = self.nova_patcher.start()
@ -36,89 +39,88 @@ class NovaDriverTestCase(base.BaseTestCase):
super(NovaDriverTestCase, self).tearDown()
def test_uuid(self):
server = mock.Mock(id='zzzz-yyyy-xxxx')
server = mock.Mock(id=self.uuid)
self.nova_mock.return_value.get_server.return_value = server
uuid = self.test_driver.uuid('zzzz-yyyy-xxxx')
self.assertEqual('zzzz-yyyy-xxxx', uuid)
uuid = self.test_driver.uuid(self.uuid)
self.assertEqual(self.uuid, uuid)
def test_systems(self):
server0 = mock.Mock(id='host0')
server1 = mock.Mock(id='host1')
self.nova_mock.return_value.list_servers.return_value = [
server0, server1]
systems = self.test_driver.systems
self.assertEqual(['host0', 'host1'], systems)
def test_get_power_state_on(self,):
server = mock.Mock(id='zzzz-yyyy-xxxx',
server = mock.Mock(id=self.uuid,
power_state=1)
self.nova_mock.return_value.get_server.return_value = server
power_state = self.test_driver.get_power_state('zzzz-yyyy-xxxx')
power_state = self.test_driver.get_power_state(self.uuid)
self.assertEqual('On', power_state)
def test_get_power_state_off(self):
server = mock.Mock(id='zzzz-yyyy-xxxx',
server = mock.Mock(id=self.uuid,
power_state=0)
self.nova_mock.return_value.get_server.return_value = server
power_state = self.test_driver.get_power_state('zzzz-yyyy-xxxx')
power_state = self.test_driver.get_power_state(self.uuid)
self.assertEqual('Off', power_state)
def test_set_power_state_on(self):
server = mock.Mock(id='zzzz-yyyy-xxxx', power_state=0)
server = mock.Mock(id=self.uuid, power_state=0)
self.nova_mock.return_value.get_server.return_value = server
self.test_driver.set_power_state('zzzz-yyyy-xxxx', 'On')
self.test_driver.set_power_state(self.uuid, 'On')
compute = self.nova_mock.return_value.compute
compute.start_server.assert_called_once_with('zzzz-yyyy-xxxx')
compute.start_server.assert_called_once_with(self.uuid)
def test_set_power_state_forceon(self):
server = mock.Mock(id='zzzz-yyyy-xxxx', power_state=0)
server = mock.Mock(id=self.uuid, power_state=0)
self.nova_mock.return_value.get_server.return_value = server
self.test_driver.set_power_state('zzzz-yyyy-xxxx', 'ForceOn')
self.test_driver.set_power_state(self.uuid, 'ForceOn')
compute = self.nova_mock.return_value.compute
compute.start_server.assert_called_once_with('zzzz-yyyy-xxxx')
compute.start_server.assert_called_once_with(self.uuid)
def test_set_power_state_forceoff(self):
server = mock.Mock(id='zzzz-yyyy-xxxx', power_state=1)
server = mock.Mock(id=self.uuid, power_state=1)
self.nova_mock.return_value.get_server.return_value = server
self.test_driver.set_power_state('zzzz-yyyy-xxxx', 'ForceOff')
self.test_driver.set_power_state(self.uuid, 'ForceOff')
compute = self.nova_mock.return_value.compute
compute.stop_server.assert_called_once_with('zzzz-yyyy-xxxx')
compute.stop_server.assert_called_once_with(self.uuid)
def test_set_power_state_gracefulshutdown(self):
server = mock.Mock(id='zzzz-yyyy-xxxx', power_state=1)
server = mock.Mock(id=self.uuid, power_state=1)
self.nova_mock.return_value.get_server.return_value = server
self.test_driver.set_power_state('zzzz-yyyy-xxxx', 'GracefulShutdown')
self.test_driver.set_power_state(self.uuid, 'GracefulShutdown')
compute = self.nova_mock.return_value.compute
compute.stop_server.assert_called_once_with('zzzz-yyyy-xxxx')
compute.stop_server.assert_called_once_with(self.uuid)
def test_set_power_state_gracefulrestart(self):
server = mock.Mock(id='zzzz-yyyy-xxxx', power_state=1)
server = mock.Mock(id=self.uuid, power_state=1)
self.nova_mock.return_value.get_server.return_value = server
self.test_driver.set_power_state('zzzz-yyyy-xxxx', 'GracefulRestart')
self.test_driver.set_power_state(self.uuid, 'GracefulRestart')
compute = self.nova_mock.return_value.compute
compute.reboot_server.assert_called_once_with(
'zzzz-yyyy-xxxx', reboot_type='SOFT')
self.uuid, reboot_type='SOFT')
def test_set_power_state_forcerestart(self):
server = mock.Mock(id='zzzz-yyyy-xxxx', power_state=1)
server = mock.Mock(id=self.uuid, power_state=1)
self.nova_mock.return_value.get_server.return_value = server
self.test_driver.set_power_state(
'zzzz-yyyy-xxxx', 'ForceRestart')
self.uuid, 'ForceRestart')
compute = self.nova_mock.return_value.compute
compute.reboot_server.assert_called_once_with(
'zzzz-yyyy-xxxx', reboot_type='HARD')
self.uuid, reboot_type='HARD')
def test_get_boot_device(self):
server = mock.Mock(id='zzzz-yyyy-xxxx')
server = mock.Mock(id=self.uuid)
self.nova_mock.return_value.get_server.return_value = server
boot_device = self.test_driver.get_boot_device('zzzz-yyyy-xxxx')
boot_device = self.test_driver.get_boot_device(self.uuid)
self.assertEqual('Pxe', boot_device)
get_server_metadata = (
@ -126,58 +128,70 @@ class NovaDriverTestCase(base.BaseTestCase):
get_server_metadata.assert_called_once_with(server.id)
def test_set_boot_device(self):
server = mock.Mock(id='zzzz-yyyy-xxxx')
server = mock.Mock(id=self.uuid)
self.nova_mock.return_value.get_server.return_value = server
compute = self.nova_mock.return_value.compute
set_server_metadata = compute.set_server_metadata
self.test_driver.set_boot_device('zzzz-yyyy-xxxx', 'Pxe')
self.test_driver.set_boot_device(self.uuid, 'Pxe')
set_server_metadata.assert_called_once_with(
'zzzz-yyyy-xxxx', **{'libvirt:pxe-first': '1'}
self.uuid, **{'libvirt:pxe-first': '1'}
)
def test_get_boot_mode(self):
server = mock.Mock(id=self.uuid, image=dict(id=self.uuid))
self.nova_mock.return_value.get_server.return_value = server
image = mock.Mock(hw_firmware_type='bios')
self.nova_mock.return_value.image.find_image.return_value = image
boot_mode = self.test_driver.get_boot_mode('zzzz-yyyy-xxxx')
boot_mode = self.test_driver.get_boot_mode(self.uuid)
self.assertEqual('Legacy', boot_mode)
def test_set_boot_mode(self):
self.assertRaises(
error.FishyError, self.test_driver.set_boot_mode,
'zzzz-yyyy-xxxx', 'Legacy')
self.uuid, 'Legacy')
def test_get_total_memory(self):
server = mock.Mock(id=self.uuid)
self.nova_mock.return_value.get_server.return_value = server
flavor = mock.Mock(ram=1024)
self.nova_mock.return_value.get_flavor.return_value = flavor
memory = self.test_driver.get_total_memory('zzzz-yyyy-xxxx')
memory = self.test_driver.get_total_memory(self.uuid)
self.assertEqual(1, memory)
def test_get_total_cpus(self):
server = mock.Mock(id=self.uuid)
self.nova_mock.return_value.get_server.return_value = server
flavor = mock.Mock(vcpus=2)
self.nova_mock.return_value.get_flavor.return_value = flavor
cpus = self.test_driver.get_total_cpus('zzzz-yyyy-xxxx')
cpus = self.test_driver.get_total_cpus(self.uuid)
self.assertEqual(2, cpus)
def test_get_bios(self):
self.assertRaises(error.FishyError, self.test_driver.get_bios,
'xxx-yyy-zzz')
self.assertRaises(
error.FishyError, self.test_driver.get_bios, self.uuid)
def test_set_bios(self):
self.assertRaises(error.FishyError, self.test_driver.set_bios,
'xxx-yyy-zzz', {'attribute 1': 'value 1'})
self.assertRaises(
error.FishyError,
self.test_driver.set_bios,
self.uuid,
{'attribute 1': 'value 1'})
def test_reset_bios(self):
self.assertRaises(error.FishyError, self.test_driver.reset_bios,
'xxx-yyy-zzz')
self.assertRaises(
error.FishyError, self.test_driver.reset_bios, self.uuid)
def test_get_nics(self):
addresses = Munch(
@ -199,10 +213,13 @@ class NovaDriverTestCase(base.BaseTestCase):
u'version': 4,
u'addr': u'10.0.0.10',
u'OS-EXT-IPS:type': u'fixed'})]})
server = mock.Mock(addresses=addresses)
server = mock.Mock(id=self.uuid, addresses=addresses)
self.nova_mock.return_value.get_server.return_value = server
nics = self.test_driver.get_nics('xxxx-yyyy-zzzz')
test_driver = OpenStackDriver('fake-cloud')
nics = test_driver.get_nics(self.uuid)
self.assertEqual([{'id': 'fa:16:3e:22:18:31',
'mac': 'fa:16:3e:22:18:31'},
{'id': 'fa:16:3e:46:e3:ac',
@ -210,9 +227,10 @@ class NovaDriverTestCase(base.BaseTestCase):
sorted(nics, key=lambda k: k['id']))
def test_get_nics_empty(self):
server = mock.Mock(addresses=None)
server = mock.Mock(id=self.uuid, addresses=None)
self.nova_mock.return_value.get_server.return_value = server
nics = self.test_driver.get_nics('xxxx-yyyy-zzzz')
test_driver = OpenStackDriver('fake-cloud')
nics = test_driver.get_nics(self.uuid)
self.assertEqual(set(), nics)
def test_get_nics_error(self):
@ -231,9 +249,9 @@ class NovaDriverTestCase(base.BaseTestCase):
u'version': 4,
u'addr': u'10.0.0.10',
u'OS-EXT-IPS:type': u'fixed'})]})
server = mock.Mock(addresses=addresses)
server = mock.Mock(id=self.uuid, addresses=addresses)
self.nova_mock.return_value.get_server.return_value = server
nics = self.test_driver.get_nics('xxxx-yyyy-zzzz')
nics = self.test_driver.get_nics(self.uuid)
self.assertEqual([{'id': 'fa:16:3e:22:18:31',
'mac': 'fa:16:3e:22:18:31'}],
nics)
'mac': 'fa:16:3e:22:18:31'}], nics)