Adding basic support for processors schema

Adds logic to provide basic support for Redfish Processor schema [1]

[1] https://redfish.dmtf.org/schemas/v1/Processor.v1_10_0.json

Story: 2007454
Task: 39128

Change-Id: I0eee22a18dde54e887e2a5d3ed1db141fec163f7
This commit is contained in:
Riccardo Pittau 2020-11-08 00:24:32 +01:00
parent 3a05eed4d2
commit ef0baa7215
8 changed files with 171 additions and 6 deletions

View File

@ -155,3 +155,4 @@ SUSHY_EMULATOR_VOLUMES = {
}
]
}

View File

@ -0,0 +1,4 @@
---
features:
- |
Adds basic support for Redfish Processor schema.

View File

@ -568,6 +568,33 @@ def ethernet_interface(identity, nic_id):
return 'Not found', 404
@app.route('/redfish/v1/Systems/<identity>/Processors',
methods=['GET'])
@ensure_instance_access
@returns_json
def processors_collection(identity):
processors = app.systems.get_processors(identity)
return flask.render_template(
'processors_collection.json', identity=identity,
processors=processors)
@app.route('/redfish/v1/Systems/<identity>/Processors/<processor_id>',
methods=['GET'])
@ensure_instance_access
@returns_json
def processor(identity, processor_id):
processors = app.systems.get_processors(identity)
for proc in processors:
if proc['id'] == processor_id:
return flask.render_template(
'processor.json', identity=identity, processor=proc)
return 'Not found', 404
@app.route('/redfish/v1/Systems/<identity>/Actions/ComputerSystem.Reset',
methods=['POST'])
@ensure_instance_access

View File

@ -439,6 +439,8 @@ class LibvirtDriver(AbstractSystemsDriver):
def get_boot_mode(self, identity):
"""Get computer system boot mode.
:param identity: libvirt domain name or ID
:returns: either *UEFI* or *Legacy* as `str` or `None` if
current boot mode can't be determined
"""
@ -459,6 +461,8 @@ class LibvirtDriver(AbstractSystemsDriver):
def set_boot_mode(self, identity, boot_mode):
"""Set computer system boot mode.
:param identity: libvirt domain name or ID
:param boot_mode: string literal requesting boot mode
change on the system. Valid values are: *UEFI*, *Legacy*.
@ -572,11 +576,8 @@ class LibvirtDriver(AbstractSystemsDriver):
:returns: available CPU count as `int` or `None` if CPU count
can't be determined
"""
domain = self._get_domain(identity, readonly=True)
tree = ET.fromstring(domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE))
total_cpus = 0
domain = self._get_domain(identity, readonly=True)
if domain.isActive():
total_cpus = domain.maxVcpus()
@ -584,7 +585,10 @@ class LibvirtDriver(AbstractSystemsDriver):
# If we can't get it from maxVcpus() try to find it by
# inspecting the domain XML
if total_cpus <= 0:
tree = ET.fromstring(
domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE))
vcpu_element = tree.find('.//vcpu')
if vcpu_element is not None:
total_cpus = int(vcpu_element.text)
@ -747,10 +751,45 @@ class LibvirtDriver(AbstractSystemsDriver):
for iface in tree.findall(
".//devices/interface[@type='network']/mac")]
def get_processors(self, identity):
"""Get list of processors
:param identity: libvirt domain name or ID
:returns: list of processors dict with their attributes
"""
domain = self._get_domain(identity, readonly=True)
processors_count = self.get_total_cpus(identity)
# NOTE(rpittau) not a lot we can provide if the domain is not active
processors = [{'id': 'CPU{0}'.format(x),
'socket': 'CPU {0}'.format(x)}
for x in range(processors_count)]
if domain.isActive():
tree = ET.fromstring(domain.XMLDesc())
model = tree.find('.//cpu/model').text
vendor = tree.find('.//cpu/vendor').text
try:
cores = tree.find('.//cpu/topology').get('cores')
threads = tree.find('.//cpu/topology').get('threads')
except AttributeError:
cores = 'N/A'
threads = 'N/A'
for processor in processors:
processor['model'] = model
processor['vendor'] = vendor
processor['cores'] = cores
processor['threads'] = threads
return processors
def get_boot_image(self, identity, device):
"""Get backend VM boot image info
:param identity: node name or ID
:param identity: libvirt domain name or ID
:param device: device type (from
`sushy_tools.emulator.constants`)
:returns: a `tuple` of (boot_image, write_protected, inserted)
@ -981,7 +1020,7 @@ class LibvirtDriver(AbstractSystemsDriver):
write_protected=True):
"""Set backend VM boot image
:param identity: node name or ID
:param identity: libvirt domain name or ID
:param device: device type (from
`sushy_tools.emulator.constants`)
:param boot_image: path to the image file or `None` to remove

View File

@ -0,0 +1,21 @@
{
"@odata.type": "#Processor.v1_0_7.Processor",
"Id": {{ processor['id']|string|tojson }},
"Name": "Processor",
"Socket": {{ processor['socket']|string|tojson }},
"ProcessorType": "CPU",
"ProcessorArchitecture": "x86",
"InstructionSet": "x86-64",
"Manufacturer": {{ processor['vendor']|string|tojson }},
"Model": {{ processor['model']|string|tojson }},
"TotalCores": {{ processor['cores']|string|tojson }},
"TotalThreads": {{ processor['threads']|string|tojson }},
"Status": {
"@odata.type": "#Resource.Status",
"State": "Enabled",
"Health": "OK"
},
"@odata.context": "/redfish/v1/$metadata#Processor.Processor",
"@odata.id": {{ "/redfish/v1/Systems/%s/Processors/%s"|format(identity, processor['Id'])|tojson }},
"@Redfish.Copyright": "Copyright 2014-2019 DMTF. For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright"
}

View File

@ -0,0 +1,15 @@
{
"@odata.type": "#ProcessorCollection.ProcessorCollection",
"Name": "Processors Collection",
"Members@odata.count": {{ processors|length}},
"Members": [
{% for processor in processors %}
{
"@odata.id": {{ "/redfish/v1/Systems/%s/Processors/%s"|format(identity, processor.id)|tojson }}
}{% if not loop.last %},{% endif %}
{% endfor %}
],
"@odata.context": "/redfish/v1/$metadata#ProcessorCollection.ProcessorCollection",
"@odata.id": {{ "/redfish/v1/Systems/%s/Processors/%s"|format(identity, processor)|tojson }},
"@Redfish.Copyright": "Copyright 2014-2020 DMTF. For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright"
}

View File

@ -0,0 +1,32 @@
<domain type='kvm' id='1'>
<name>test-node</name>
<uuid>da64d3a4-0b06-428b-9afb-73b4a4101bb3</uuid>
<memory unit='KiB'>1048576</memory>
<currentMemory unit='KiB'>1048576</currentMemory>
<vcpu placement='static'>2</vcpu>
<resource>
<partition>/machine</partition>
</resource>
<os>
<type arch='x86_64' machine='pc-q35-5.1'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
</features>
<cpu match='exact'>
<model fallback='allow'>core2duo</model>
<vendor>Intel</vendor>
<topology sockets='1' cores='2' threads='1'/>
<feature policy='disable' name='lahf_lm'/>
</cpu>
<clock offset='utc'>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='pit' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
</domain>

View File

@ -917,6 +917,32 @@ class LibvirtDriverTestCase(base.BaseTestCase):
nics = self.test_driver.get_nics(self.uuid)
self.assertEqual([], nics)
@mock.patch('libvirt.openReadOnly', autospec=True)
def test_get_processors(self, libvirt_mock):
with open(
'sushy_tools/tests/unit/emulator/domain_processors.xml') as f:
domain_xml = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = domain_xml
domain_mock.maxVcpus.return_value = 2
processors = self.test_driver.get_processors(self.uuid)
self.assertEqual([{'cores': '2',
'id': 'CPU0',
'model': 'core2duo',
'socket': 'CPU 0',
'threads': '1',
'vendor': 'Intel'},
{'cores': '2',
'id': 'CPU1',
'model': 'core2duo',
'socket': 'CPU 1',
'threads': '1',
'vendor': 'Intel'}],
sorted(processors, key=lambda k: k['id']))
@mock.patch('libvirt.openReadOnly', autospec=True)
def test_get_simple_storage_collection(self, libvirt_mock):
with open('sushy_tools/tests/unit/emulator/'