From ef0baa721582c2fbb4a60d8c5dcb6117493fdd41 Mon Sep 17 00:00:00 2001 From: Riccardo Pittau Date: Sun, 8 Nov 2020 00:24:32 +0100 Subject: [PATCH] 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 --- doc/source/admin/emulator.conf | 1 + ...add-processor-schema-f23195a923f5830f.yaml | 4 ++ sushy_tools/emulator/main.py | 27 ++++++++++ .../resources/systems/libvirtdriver.py | 51 ++++++++++++++++--- sushy_tools/emulator/templates/processor.json | 21 ++++++++ .../templates/processors_collection.json | 15 ++++++ .../tests/unit/emulator/domain_processors.xml | 32 ++++++++++++ .../resources/systems/test_libvirt.py | 26 ++++++++++ 8 files changed, 171 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/add-processor-schema-f23195a923f5830f.yaml create mode 100644 sushy_tools/emulator/templates/processor.json create mode 100644 sushy_tools/emulator/templates/processors_collection.json create mode 100644 sushy_tools/tests/unit/emulator/domain_processors.xml diff --git a/doc/source/admin/emulator.conf b/doc/source/admin/emulator.conf index 95019eff..e5bb0e13 100644 --- a/doc/source/admin/emulator.conf +++ b/doc/source/admin/emulator.conf @@ -155,3 +155,4 @@ SUSHY_EMULATOR_VOLUMES = { } ] } + diff --git a/releasenotes/notes/add-processor-schema-f23195a923f5830f.yaml b/releasenotes/notes/add-processor-schema-f23195a923f5830f.yaml new file mode 100644 index 00000000..44f6b8c6 --- /dev/null +++ b/releasenotes/notes/add-processor-schema-f23195a923f5830f.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Adds basic support for Redfish Processor schema. diff --git a/sushy_tools/emulator/main.py b/sushy_tools/emulator/main.py index ce5bba3b..e82cd0ff 100755 --- a/sushy_tools/emulator/main.py +++ b/sushy_tools/emulator/main.py @@ -568,6 +568,33 @@ def ethernet_interface(identity, nic_id): return 'Not found', 404 +@app.route('/redfish/v1/Systems//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//Processors/', + 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//Actions/ComputerSystem.Reset', methods=['POST']) @ensure_instance_access diff --git a/sushy_tools/emulator/resources/systems/libvirtdriver.py b/sushy_tools/emulator/resources/systems/libvirtdriver.py index 8151abf3..6ab155a0 100644 --- a/sushy_tools/emulator/resources/systems/libvirtdriver.py +++ b/sushy_tools/emulator/resources/systems/libvirtdriver.py @@ -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 diff --git a/sushy_tools/emulator/templates/processor.json b/sushy_tools/emulator/templates/processor.json new file mode 100644 index 00000000..d8ce0717 --- /dev/null +++ b/sushy_tools/emulator/templates/processor.json @@ -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" +} diff --git a/sushy_tools/emulator/templates/processors_collection.json b/sushy_tools/emulator/templates/processors_collection.json new file mode 100644 index 00000000..de3af7fd --- /dev/null +++ b/sushy_tools/emulator/templates/processors_collection.json @@ -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" +} \ No newline at end of file diff --git a/sushy_tools/tests/unit/emulator/domain_processors.xml b/sushy_tools/tests/unit/emulator/domain_processors.xml new file mode 100644 index 00000000..67013e5a --- /dev/null +++ b/sushy_tools/tests/unit/emulator/domain_processors.xml @@ -0,0 +1,32 @@ + + test-node + da64d3a4-0b06-428b-9afb-73b4a4101bb3 + 1048576 + 1048576 + 2 + + /machine + + + hvm + + + + + + + + core2duo + Intel + + + + + + + + + destroy + restart + destroy + diff --git a/sushy_tools/tests/unit/emulator/resources/systems/test_libvirt.py b/sushy_tools/tests/unit/emulator/resources/systems/test_libvirt.py index 119126bb..f906e423 100644 --- a/sushy_tools/tests/unit/emulator/resources/systems/test_libvirt.py +++ b/sushy_tools/tests/unit/emulator/resources/systems/test_libvirt.py @@ -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/'