Merge "Add Simple Storage resource support"
This commit is contained in:
commit
3d65187c0c
@ -85,6 +85,62 @@ You should be able to flip its power state via the Redfish call:
|
|||||||
You can have as many domains as you need. The domains can be concurrently
|
You can have as many domains as you need. The domains can be concurrently
|
||||||
managed over Redfish and some other tool like *Virtual BMC*.
|
managed over Redfish and some other tool like *Virtual BMC*.
|
||||||
|
|
||||||
|
|
||||||
|
Simple Storage resource
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
For emulating the *Simple Storage* resource, some additional preparation is
|
||||||
|
required on the host side.
|
||||||
|
|
||||||
|
First, you need to create, build and start a libvirt storage pool using virsh:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
virsh pool-define-as testPool dir - - - - "/testPool"
|
||||||
|
virsh pool-build testPool
|
||||||
|
virsh pool-start testPool
|
||||||
|
virsh pool-autostart testPool
|
||||||
|
|
||||||
|
Next, create a storage volume in the above created storage pool:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
virsh vol-create-as testPool testVol 1G
|
||||||
|
|
||||||
|
Next, attach the created volume to the virtual machine/domain:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
virsh attach-disk vbmc-node /testPool/testVol sda
|
||||||
|
|
||||||
|
Now, query the *Simple Storage* resource collection for the `vbmc-node` domain
|
||||||
|
in a closely similar format (with 'ide' and 'scsi', here, referring to the two
|
||||||
|
Redfish Simple Storage Controllers available for this domain):
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
curl http://localhost:8000/redfish/v1/vbmc-node/SimpleStorage
|
||||||
|
{
|
||||||
|
"@odata.type": "#SimpleStorageCollection.SimpleStorageCollection",
|
||||||
|
"Name": "Simple Storage Collection",
|
||||||
|
"Members@odata.count": 2,
|
||||||
|
"Members": [
|
||||||
|
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Systems/vbmc-node/SimpleStorage/ide"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Systems/vbmc-node/SimpleStorage/scsi"
|
||||||
|
}
|
||||||
|
|
||||||
|
],
|
||||||
|
"Oem": {},
|
||||||
|
"@odata.context": "/redfish/v1/$metadata#SimpleStorageCollection.SimpleStorageCollection",
|
||||||
|
"@odata.id": "/redfish/v1/Systems/vbmc-node/SimpleStorage"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
UEFI boot
|
UEFI boot
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds emulation support for Simple Storage resource to libvirt
|
||||||
|
virtualization backend of the dynamic Redfish emulator. The emulation
|
||||||
|
functionality assumes that the storage devices attached to a VM are
|
||||||
|
configured as a libvirt Volume via a storage pool. Devices not configured
|
||||||
|
as a Volume will not be considered for emulation purposes.
|
@ -626,6 +626,37 @@ def system_reset_bios(identity):
|
|||||||
return '', 204
|
return '', 204
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/redfish/v1/Systems/<identity>/SimpleStorage',
|
||||||
|
methods=['GET'])
|
||||||
|
@ensure_instance_access
|
||||||
|
@returns_json
|
||||||
|
def simple_storage_collection(identity):
|
||||||
|
with Resources() as resources:
|
||||||
|
simple_storage_controllers = (
|
||||||
|
resources.systems.get_simple_storage_collection(identity))
|
||||||
|
|
||||||
|
return flask.render_template(
|
||||||
|
'simple_storage_collection.json', identity=identity,
|
||||||
|
simple_storage_controllers=simple_storage_controllers)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/redfish/v1/Systems/<identity>/SimpleStorage/<simple_storage_id>',
|
||||||
|
methods=['GET'])
|
||||||
|
@ensure_instance_access
|
||||||
|
@returns_json
|
||||||
|
def simple_storage(identity, simple_storage_id):
|
||||||
|
with Resources() as resources:
|
||||||
|
simple_storage_controllers = (
|
||||||
|
resources.systems.get_simple_storage_collection(identity))
|
||||||
|
try:
|
||||||
|
storage_controller = simple_storage_controllers[simple_storage_id]
|
||||||
|
except KeyError:
|
||||||
|
app.logger.debug('"%s" Simple Storage resource was not found')
|
||||||
|
return 'Not found', 404
|
||||||
|
return flask.render_template('simple_storage.json', identity=identity,
|
||||||
|
simple_storage=storage_controller)
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
parser = argparse.ArgumentParser('sushy-emulator')
|
parser = argparse.ArgumentParser('sushy-emulator')
|
||||||
parser.add_argument('--config',
|
parser.add_argument('--config',
|
||||||
|
@ -192,3 +192,10 @@ class AbstractSystemsDriver(DriverBase):
|
|||||||
|
|
||||||
:raises: `error.FishyError` if boot device can't be set
|
:raises: `error.FishyError` if boot device can't be set
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_simple_storage_collection(self, identity):
|
||||||
|
"""Get a dict of Simple Storage Controllers and their devices
|
||||||
|
|
||||||
|
:returns: dict of Simple Storage Controllers and their atributes
|
||||||
|
"""
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
@ -839,3 +840,96 @@ class LibvirtDriver(AbstractSystemsDriver):
|
|||||||
'%(error)s' % {'uri': self._uri, 'error': e})
|
'%(error)s' % {'uri': self._uri, 'error': e})
|
||||||
|
|
||||||
raise error.FishyError(msg)
|
raise error.FishyError(msg)
|
||||||
|
|
||||||
|
def _find_device_by_path(self, vol_path):
|
||||||
|
"""Get device attributes using path
|
||||||
|
|
||||||
|
:param vol_path: path for the libvirt volume
|
||||||
|
:returns: a dict (or None) of the corresponding device attributes
|
||||||
|
"""
|
||||||
|
with libvirt_open(self._uri, readonly=True) as conn:
|
||||||
|
try:
|
||||||
|
vol = conn.storageVolLookupByPath(vol_path)
|
||||||
|
except libvirt.libvirtError as e:
|
||||||
|
msg = ('Could not find storage volume by path '
|
||||||
|
'"%(path)s" at libvirt URI "%(uri)s": '
|
||||||
|
'%(err)s' %
|
||||||
|
{'path': vol_path, 'uri': self._uri,
|
||||||
|
'err': e})
|
||||||
|
logger.debug(msg)
|
||||||
|
return
|
||||||
|
disk_device = {
|
||||||
|
'Name': vol.name(),
|
||||||
|
'CapacityBytes': vol.info()[1]
|
||||||
|
}
|
||||||
|
return disk_device
|
||||||
|
|
||||||
|
def _find_device_from_pool(self, pool_name, vol_name):
|
||||||
|
"""Get device attributes from pool
|
||||||
|
|
||||||
|
:param pool_name: libvirt pool name
|
||||||
|
:param vol_name: libvirt volume name
|
||||||
|
:returns: a dict (or None) of the corresponding device attributes
|
||||||
|
"""
|
||||||
|
with libvirt_open(self._uri, readonly=True) as conn:
|
||||||
|
try:
|
||||||
|
pool = conn.storagePoolLookupByName(pool_name)
|
||||||
|
except libvirt.libvirtError as e:
|
||||||
|
msg = ('Error finding Storage Pool by name "%(name)s" at'
|
||||||
|
'libvirt URI "%(uri)s": %(err)s' %
|
||||||
|
{'name': pool_name, 'uri': self._uri, 'err': e})
|
||||||
|
logger.debug(msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
vol = pool.storageVolLookupByName(vol_name)
|
||||||
|
except libvirt.libvirtError as e:
|
||||||
|
msg = ('Error finding Storage Volume by name "%(name)s" '
|
||||||
|
'in Pool '"%(pName)s"' at libvirt URI "%(uri)s"'
|
||||||
|
': %(err)s' %
|
||||||
|
{'name': vol_name, 'pName': pool_name,
|
||||||
|
'uri': self._uri, 'err': e})
|
||||||
|
logger.debug(msg)
|
||||||
|
return
|
||||||
|
disk_device = {
|
||||||
|
'Name': vol.name(),
|
||||||
|
'CapacityBytes': vol.info()[1]
|
||||||
|
}
|
||||||
|
return disk_device
|
||||||
|
|
||||||
|
def get_simple_storage_collection(self, identity):
|
||||||
|
"""Get a dict of simple storage controllers and their devices
|
||||||
|
|
||||||
|
Only those storage devices that are configured as a libvirt volume
|
||||||
|
via a pool and attached to the domain will reflect as a device.
|
||||||
|
Others are skipped.
|
||||||
|
|
||||||
|
:param identity: libvirt domain or ID
|
||||||
|
:returns: dict of simple storage controller dict with their attributes
|
||||||
|
"""
|
||||||
|
domain = self._get_domain(identity, readonly=True)
|
||||||
|
tree = ET.fromstring(domain.XMLDesc())
|
||||||
|
simple_storage = defaultdict(lambda: defaultdict(DeviceList=list()))
|
||||||
|
|
||||||
|
for disk_element in tree.findall(".//disk/target[@bus]/.."):
|
||||||
|
source_element = disk_element.find('source')
|
||||||
|
if source_element is not None:
|
||||||
|
disk_type = disk_element.attrib['type']
|
||||||
|
ctl_type = disk_element.find('target').attrib['bus']
|
||||||
|
disk_device = None
|
||||||
|
if disk_type in ('file', 'block'):
|
||||||
|
if disk_type == 'file':
|
||||||
|
vol_path = source_element.attrib['file']
|
||||||
|
else:
|
||||||
|
vol_path = source_element.attrib['dev']
|
||||||
|
disk_device = self._find_device_by_path(vol_path)
|
||||||
|
elif disk_type == 'volume':
|
||||||
|
pool_name = source_element.attrib['pool']
|
||||||
|
vol_name = source_element.attrib['volume']
|
||||||
|
disk_device = self._find_device_from_pool(pool_name,
|
||||||
|
vol_name)
|
||||||
|
if disk_device is not None:
|
||||||
|
simple_storage[ctl_type]['Id'] = ctl_type
|
||||||
|
simple_storage[ctl_type]['Name'] = ctl_type
|
||||||
|
simple_storage[ctl_type]['DeviceList'].append(disk_device)
|
||||||
|
return simple_storage
|
||||||
|
@ -371,3 +371,6 @@ class OpenStackDriver(AbstractSystemsDriver):
|
|||||||
:raises: `error.FishyError` if boot device can't be set
|
:raises: `error.FishyError` if boot device can't be set
|
||||||
"""
|
"""
|
||||||
raise error.NotSupportedError('Not implemented')
|
raise error.NotSupportedError('Not implemented')
|
||||||
|
|
||||||
|
def get_simple_storage_collection(self, identity):
|
||||||
|
raise error.NotSupportedError('Not implemented')
|
||||||
|
21
sushy_tools/emulator/templates/simple_storage.json
Normal file
21
sushy_tools/emulator/templates/simple_storage.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"@odata.type": "#SimpleStorage.v1_2_0.SimpleStorage",
|
||||||
|
"Id": {{ simple_storage['Id']|string|tojson }},
|
||||||
|
"Name": {{ "%s Controller"|format(simple_storage['Name'])|tojson }},
|
||||||
|
"Devices": [
|
||||||
|
{% for device in simple_storage['DeviceList'] %}
|
||||||
|
{
|
||||||
|
"@odata.type": "#SimpleStorage.v1_1_0.Device",
|
||||||
|
"Name": {{ device['Name']|string|tojson }},
|
||||||
|
"CapacityBytes": {{ device['CapacityBytes'] }},
|
||||||
|
"Status": {
|
||||||
|
"@odata.type": "#Resource.Status",
|
||||||
|
"State": "Enabled",
|
||||||
|
"Health": "OK"
|
||||||
|
}
|
||||||
|
}{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
],
|
||||||
|
"@odata.context": "/redfish/v1/$metadata#SimpleStorage.SimpleStorage",
|
||||||
|
"@odata.id": {{ "/redfish/v1/Systems/%s/SimpleStorage/%s"|format(identity, simple_storage['Id'])|tojson }}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"@odata.type": "#SimpleStorageCollection.SimpleStorageCollection",
|
||||||
|
"Name": "Simple Storage Collection",
|
||||||
|
"Members@odata.count": {{ simple_storage_controllers|length }},
|
||||||
|
"Members": [
|
||||||
|
{% for simple_storage in simple_storage_controllers %}
|
||||||
|
{
|
||||||
|
"@odata.id": {{ "/redfish/v1/Systems/%s/SimpleStorage/%s"|format(identity, simple_storage_controllers[simple_storage]['Id'])|tojson }}
|
||||||
|
}{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
],
|
||||||
|
"Oem": {},
|
||||||
|
"@odata.context": "/redfish/v1/$metadata#SimpleStorageCollection.SimpleStorageCollection",
|
||||||
|
"@odata.id": {{ "/redfish/v1/Systems/%s/SimpleStorage"|format(identity)|tojson }}
|
||||||
|
}
|
||||||
|
|
42
sushy_tools/tests/unit/emulator/domain_simple_storage.xml
Normal file
42
sushy_tools/tests/unit/emulator/domain_simple_storage.xml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<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='x86_64' machine='pc'>hvm</type>
|
||||||
|
<boot dev='cdrom'/>
|
||||||
|
<loader type='rom'/>
|
||||||
|
</os>
|
||||||
|
<devices>
|
||||||
|
<emulator>/usr/bin/qemu-system-x86_64</emulator>
|
||||||
|
<disk type='file' device='disk'>
|
||||||
|
<driver name='qemu' type='qcow2'/>
|
||||||
|
<source file='/var/lib/libvirt/images/testVM1.img'/>
|
||||||
|
<target dev='vda' bus='virtio'/>
|
||||||
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
|
||||||
|
</disk>
|
||||||
|
<disk type='file' device='disk'>
|
||||||
|
<driver name='qemu' type='raw'/>
|
||||||
|
<source file='/home/varsha/Documents/testPool/testVol1.img'/>
|
||||||
|
<target dev='hdb' bus='ide'/>
|
||||||
|
<address type='drive' controller='0' bus='0' target='0' unit='1'/>
|
||||||
|
</disk>
|
||||||
|
<disk type='block' device='disk'>
|
||||||
|
<driver name='qemu' type='raw' cache='none' io='native'/>
|
||||||
|
<source dev='/dev/sdb1'/>
|
||||||
|
<target dev='vdc' bus='virtio'/>
|
||||||
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/>
|
||||||
|
</disk>
|
||||||
|
<disk type='volume' device='disk'>
|
||||||
|
<driver name='qemu' type='raw'/>
|
||||||
|
<source pool='blk-pool0' volume='blk-pool0-vol0'/>
|
||||||
|
<target dev='hdk' bus='ide'/>
|
||||||
|
</disk>
|
||||||
|
<interface type='network'>
|
||||||
|
<source network='default'/>
|
||||||
|
</interface>
|
||||||
|
<graphics type='vnc' port='-1'/>
|
||||||
|
</devices>
|
||||||
|
</domain>
|
@ -567,3 +567,81 @@ class LibvirtDriverTestCase(base.BaseTestCase):
|
|||||||
|
|
||||||
nics = self.test_driver.get_nics(self.uuid)
|
nics = self.test_driver.get_nics(self.uuid)
|
||||||
self.assertEqual([], nics)
|
self.assertEqual([], nics)
|
||||||
|
|
||||||
|
@mock.patch('libvirt.openReadOnly', autospec=True)
|
||||||
|
def test_get_simple_storage_collection(self, libvirt_mock):
|
||||||
|
with open('sushy_tools/tests/unit/emulator/'
|
||||||
|
'domain_simple_storage.xml', 'r') as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
conn_mock = libvirt_mock.return_value
|
||||||
|
dom_mock = conn_mock.lookupByUUID.return_value
|
||||||
|
dom_mock.XMLDesc.return_value = data
|
||||||
|
vol_mock = conn_mock.storageVolLookupByPath.return_value
|
||||||
|
vol_mock.name.side_effect = ['testVM1.img', 'testVol1.img', 'sdb1']
|
||||||
|
vol_mock.info.side_effect = [['testVM1.img', 100000],
|
||||||
|
['testVol1.img', 200000],
|
||||||
|
['sdb1', 150000]]
|
||||||
|
pool_mock = conn_mock.storagePoolLookupByName.return_value
|
||||||
|
pvol_mock = pool_mock.storageVolLookupByName.return_value
|
||||||
|
pvol_mock.name.return_value = 'blk-pool0-vol0'
|
||||||
|
pvol_mock.info.return_value = ['volType', 300000]
|
||||||
|
|
||||||
|
simple_storage_response = (self.test_driver
|
||||||
|
.get_simple_storage_collection(self.uuid))
|
||||||
|
|
||||||
|
simple_storage_expected = {
|
||||||
|
'virtio': {
|
||||||
|
'Id': 'virtio',
|
||||||
|
'Name': 'virtio',
|
||||||
|
'DeviceList': [
|
||||||
|
{
|
||||||
|
'Name': 'testVM1.img',
|
||||||
|
'CapacityBytes': 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Name': 'sdb1',
|
||||||
|
'CapacityBytes': 150000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'ide': {
|
||||||
|
'Id': 'ide',
|
||||||
|
'Name': 'ide',
|
||||||
|
'DeviceList': [
|
||||||
|
{
|
||||||
|
'Name': 'testVol1.img',
|
||||||
|
'CapacityBytes': 200000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Name': 'blk-pool0-vol0',
|
||||||
|
'CapacityBytes': 300000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertEqual(simple_storage_response, simple_storage_expected)
|
||||||
|
|
||||||
|
@mock.patch('libvirt.openReadOnly', autospec=True)
|
||||||
|
def test_get_simple_storage_collection_empty(self, libvirt_mock):
|
||||||
|
with open('sushy_tools/tests/unit/emulator/domain.xml') as f:
|
||||||
|
domain_xml = f.read()
|
||||||
|
|
||||||
|
conn_mock = libvirt_mock.return_value
|
||||||
|
dom_mock = conn_mock.lookupByUUID.return_value
|
||||||
|
dom_mock.XMLDesc.return_value = domain_xml
|
||||||
|
vol_mock = conn_mock.storageVolLookupByPath.return_value
|
||||||
|
vol_mock.name.side_effect = ['testVM1.img', 'testVol1.img', 'sdb1']
|
||||||
|
vol_mock.info.side_effect = [['testType1', 100000],
|
||||||
|
['testType2', 200000],
|
||||||
|
['testType1', 150000]]
|
||||||
|
pool_mock = conn_mock.storagePoolLookupByName.return_value
|
||||||
|
pvol_mock = pool_mock.storageVolLookupByName.return_value
|
||||||
|
pvol_mock.name.return_value = 'blk-pool0-vol0'
|
||||||
|
pvol_mock.info.return_value = ['volType', 300000]
|
||||||
|
|
||||||
|
simple_storage_response = (self.test_driver
|
||||||
|
.get_simple_storage_collection(self.uuid))
|
||||||
|
|
||||||
|
self.assertEqual({}, simple_storage_response)
|
||||||
|
@ -256,3 +256,8 @@ class NovaDriverTestCase(base.BaseTestCase):
|
|||||||
nics = self.test_driver.get_nics(self.uuid)
|
nics = self.test_driver.get_nics(self.uuid)
|
||||||
self.assertEqual([{'id': 'fa:16:3e:22:18:31',
|
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)
|
||||||
|
|
||||||
|
def test_get_simple_storage_collection(self):
|
||||||
|
self.assertRaises(
|
||||||
|
error.FishyError,
|
||||||
|
self.test_driver.get_simple_storage_collection, self.uuid)
|
||||||
|
@ -574,3 +574,147 @@ class EmulatorTestCase(base.BaseTestCase):
|
|||||||
self.assertEqual(204, response.status_code)
|
self.assertEqual(204, response.status_code)
|
||||||
|
|
||||||
vmedia_mock.eject_image.called_once_with('CD')
|
vmedia_mock.eject_image.called_once_with('CD')
|
||||||
|
|
||||||
|
def test_simple_storage_collection(self, resources_mock):
|
||||||
|
resources_mock = resources_mock.return_value.__enter__.return_value
|
||||||
|
systems_mock = resources_mock.systems
|
||||||
|
systems_mock.get_simple_storage_collection.return_value = {
|
||||||
|
'virtio': {
|
||||||
|
'Id': 'virtio',
|
||||||
|
'Name': 'virtio',
|
||||||
|
'DeviceList': [
|
||||||
|
{
|
||||||
|
'Name': 'testVM1.img',
|
||||||
|
'CapacityBytes': 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Name': 'sdb1',
|
||||||
|
'CapacityBytes': 150000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'ide': {
|
||||||
|
'Id': 'ide',
|
||||||
|
'Name': 'ide',
|
||||||
|
'DeviceList': [
|
||||||
|
{
|
||||||
|
'Name': 'testVol1.img',
|
||||||
|
'CapacityBytes': 200000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Name': 'blk-pool0-vol0',
|
||||||
|
'CapacityBytes': 300000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response = self.app.get('redfish/v1/Systems/' + self.uuid +
|
||||||
|
'/SimpleStorage')
|
||||||
|
|
||||||
|
self.assertEqual(200, response.status_code)
|
||||||
|
self.assertEqual('Simple Storage Collection',
|
||||||
|
response.json['Name'])
|
||||||
|
self.assertEqual(2, response.json['Members@odata.count'])
|
||||||
|
self.assertEqual({'/redfish/v1/Systems/' + self.uuid +
|
||||||
|
'/SimpleStorage/virtio',
|
||||||
|
'/redfish/v1/Systems/' + self.uuid +
|
||||||
|
'/SimpleStorage/ide'},
|
||||||
|
{m['@odata.id'] for m in response.json['Members']})
|
||||||
|
|
||||||
|
def test_simple_storage_collection_empty(self, resources_mock):
|
||||||
|
resources_mock = resources_mock.return_value.__enter__.return_value
|
||||||
|
systems_mock = resources_mock.systems
|
||||||
|
systems_mock.get_simple_storage_collection.return_value = []
|
||||||
|
response = self.app.get('redfish/v1/Systems/' + self.uuid +
|
||||||
|
'/SimpleStorage')
|
||||||
|
|
||||||
|
self.assertEqual(200, response.status_code)
|
||||||
|
self.assertEqual('Simple Storage Collection',
|
||||||
|
response.json['Name'])
|
||||||
|
self.assertEqual(0, response.json['Members@odata.count'])
|
||||||
|
self.assertEqual([], response.json['Members'])
|
||||||
|
|
||||||
|
def test_simple_storage(self, resources_mock):
|
||||||
|
resources_mock = resources_mock.return_value.__enter__.return_value
|
||||||
|
systems_mock = resources_mock.systems
|
||||||
|
systems_mock.get_simple_storage_collection.return_value = {
|
||||||
|
'virtio': {
|
||||||
|
'Id': 'virtio',
|
||||||
|
'Name': 'virtio',
|
||||||
|
'DeviceList': [
|
||||||
|
{
|
||||||
|
'Name': 'testVM1.img',
|
||||||
|
'CapacityBytes': 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Name': 'sdb1',
|
||||||
|
'CapacityBytes': 150000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'ide': {
|
||||||
|
'Id': 'ide',
|
||||||
|
'Name': 'ide',
|
||||||
|
'DeviceList': [
|
||||||
|
{
|
||||||
|
'Name': 'testVol1.img',
|
||||||
|
'CapacityBytes': 200000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Name': 'blk-pool0-vol0',
|
||||||
|
'CapacityBytes': 300000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response = self.app.get('/redfish/v1/Systems/' + self.uuid +
|
||||||
|
'/SimpleStorage/virtio')
|
||||||
|
|
||||||
|
self.assertEqual(200, response.status_code)
|
||||||
|
self.assertEqual('virtio', response.json['Id'])
|
||||||
|
self.assertEqual('virtio Controller', response.json['Name'])
|
||||||
|
self.assertEqual('testVM1.img', response.json['Devices'][0]['Name'])
|
||||||
|
self.assertEqual(100000, response.json['Devices'][0]['CapacityBytes'])
|
||||||
|
self.assertEqual('sdb1', response.json['Devices'][1]['Name'])
|
||||||
|
self.assertEqual(150000, response.json['Devices'][1]['CapacityBytes'])
|
||||||
|
self.assertEqual('/redfish/v1/Systems/' + self.uuid +
|
||||||
|
'/SimpleStorage/virtio',
|
||||||
|
response.json['@odata.id'])
|
||||||
|
|
||||||
|
def test_simple_storage_not_found(self, resources_mock):
|
||||||
|
resources_mock = resources_mock.return_value.__enter__.return_value
|
||||||
|
systems_mock = resources_mock.systems
|
||||||
|
systems_mock.get_simple_storage_collection.return_value = {
|
||||||
|
'virtio': {
|
||||||
|
'Id': 'virtio',
|
||||||
|
'Name': 'virtio',
|
||||||
|
'DeviceList': [
|
||||||
|
{
|
||||||
|
'Name': 'testVM1.img',
|
||||||
|
'CapacityBytes': 100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Name': 'sdb1',
|
||||||
|
'CapacityBytes': 150000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'ide': {
|
||||||
|
'Id': 'ide',
|
||||||
|
'Name': 'ide',
|
||||||
|
'DeviceList': [
|
||||||
|
{
|
||||||
|
'Name': 'testVol1.img',
|
||||||
|
'CapacityBytes': 200000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Name': 'blk-pool0-vol0',
|
||||||
|
'CapacityBytes': 300000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response = self.app.get('/redfish/v1/Systems/' + self.uuid +
|
||||||
|
'/SimpleStorage/scsi')
|
||||||
|
|
||||||
|
self.assertEqual(404, response.status_code)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user