diff --git a/ironic_python_agent/dmi_inspector.py b/ironic_python_agent/dmi_inspector.py new file mode 100644 index 000000000..8bd85736c --- /dev/null +++ b/ironic_python_agent/dmi_inspector.py @@ -0,0 +1,134 @@ +# Copyright (C) 2017 Intel Corporation +# +# 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. + +from oslo_concurrency import processutils +from oslo_log import log as logging + +from ironic_python_agent import utils + + +LOG = logging.getLogger(__name__) + + +def collect_dmidecode_info(data, failures): + """Collect detailed processor, memory and bios info. + + The data is gathered using dmidecode utility. + + :param data: mutable dict that we'll send to inspector + :param failures: AccumulatedFailures object + """ + try: + shret, _err = utils.execute('dmidecode', '-t', 'bios', + '-t', 'processor', '-t', 'memory') + except (processutils.ProcessExecutionError, OSError) as exc: + failures.add('failed to run dmidecode: %s', exc) + return + + data['dmi'] = {} + try: + data['dmi'] = parse_dmi(shret) + except (ValueError, IndexError) as exc: + LOG.warning('Failed to collect dmidecode info %s:', exc) + + +def parse_dmi(data): + """Parse the dmidecode output. + + Returns a dict. + """ + TYPE = { + 'bios': 0, + 'cpu': 4, + 'memory': 16, + 'devices': 17, + } + + dmi_info = { + 'bios': {}, + 'cpu': [], + 'memory': {'devices': []}, + } + + memorydata, devicedata = [], [] + + # Dmi data blocks are separated by a blank line. + # First line in each block starts with 'Handle 0x'. + for infoblock in data.split('\n\n'): + if not len(infoblock): + continue + + if infoblock.startswith('Handle 0x'): + try: + # Determine DMI type value. Handle line will look like this: + # Handle 0x0018, DMI type 17, 27 bytes + dmi_type = int(infoblock.split(',', 2)[1].strip()[ + len('DMI type'):]) + except (ValueError, IndexError) as exc: + LOG.warning('Failed to parse Handle type in dmi output: %s', + exc) + continue + + if dmi_type in TYPE.values(): + sectiondata = _parse_handle_block(infoblock) + + if dmi_type == TYPE['bios']: + dmi_info['bios'] = sectiondata + elif dmi_type == TYPE['cpu']: + dmi_info['cpu'].append(sectiondata) + elif dmi_type == TYPE['memory']: + memorydata.append(sectiondata) + elif dmi_type == TYPE['devices']: + devicedata.append(sectiondata) + + return _save_data(dmi_info, memorydata, devicedata) + + +def _parse_handle_block(lines): + rows = {} + list_value = False + for line in lines.splitlines(): + line = line.strip() + if ':' in line: + list_value = False + k, v = [i.strip() for i in line.split(':', 1)] + if v: + rows[k] = v + else: + rows[k] = [] + list_value = True + elif 'Handle 0x' in line: + rows['Handle'] = line + elif list_value: + rows[k].append(line) + + return rows + + +def _save_data(dmi_info, memorydata, devicedata): + if memorydata: + try: + device_count = sum([int(d['Number Of Devices']) + for d in memorydata]) + dmi_info['memory'] = memorydata[0] + dmi_info['memory']['Number Of Devices'] = device_count + dmi_info['memory'].pop('Handle') + except (KeyError) as exc: + LOG.warning('Failed to process memory dmi data: %s', exc) + raise + + if devicedata: + dmi_info['memory']['devices'] = devicedata + + return dmi_info diff --git a/ironic_python_agent/tests/unit/test_dmi_inspector.py b/ironic_python_agent/tests/unit/test_dmi_inspector.py new file mode 100644 index 000000000..2a22fba91 --- /dev/null +++ b/ironic_python_agent/tests/unit/test_dmi_inspector.py @@ -0,0 +1,681 @@ +# Copyright (C) 2017 Intel Corporation +# +# 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 mock +from oslo_concurrency import processutils + +from ironic_python_agent import dmi_inspector +from ironic_python_agent.tests.unit import base +from ironic_python_agent import utils + +BIOS_DATA = (""" +# dmidecode 3.0 +Getting SMBIOS data from sysfs. +SMBIOS 2.7 present. + +Handle 0x0000, DMI type 0, 24 bytes +Address: 0xF0000 +ROM Size: 16384 kB +Characteristics: + PCI is supported + +Handle 0x000B, DMI type 13, 22 bytes +BIOS Language Information + Installable Languages: 1 + enUS +""", "") + +BIOS_OUTPUT = {'bios': { + 'Address': '0xF0000', + 'Characteristics': ['PCI is supported'], + 'Handle': 'Handle 0x0000, DMI type 0, 24 bytes', + 'ROM Size': '16384 kB'}, + 'cpu': [], + 'memory': {'devices': []}} + +MEMORY_DATA = (""" +# dmidecode 3.0 +Getting SMBIOS data from sysfs. +SMBIOS 2.7 present. + +Handle 0x0038, DMI type 16, 23 bytes +Physical Memory Array + Maximum Capacity: 192 GB + Number Of Devices: 6 + +Handle 0x003A, DMI type 17, 40 bytes +Memory Device + Array Handle: 0x0038 + Size: 16384 MB + Form Factor: DIMM + Speed: 2133 MHz + +Handle 0x0044, DMI type 16, 23 bytes +Physical Memory Array + Maximum Capacity: 192 GB + Number Of Devices: 6 + +Handle 0x0046, DMI type 17, 40 bytes +Memory Device + Array Handle: 0x0044 + Size: 16384 MB + Form Factor: DIMM + Speed: 2133 MHz +""", "") + +MEMORY_OUTPUT = { + 'bios': {}, + 'cpu': [], + 'memory': { + 'Maximum Capacity': '192 GB', + 'Number Of Devices': 12, + 'devices': [{'Array Handle': '0x0038', + 'Form Factor': 'DIMM', + 'Handle': 'Handle 0x003A, DMI type 17, 40 bytes', + 'Size': '16384 MB', + 'Speed': '2133 MHz'}, + {'Array Handle': '0x0044', + 'Form Factor': 'DIMM', + 'Handle': 'Handle 0x0046, DMI type 17, 40 bytes', + 'Size': '16384 MB', + 'Speed': '2133 MHz'}]}} + +CPU_DATA = (""" +# dmidecode 3.0 +Getting SMBIOS data from sysfs. +SMBIOS 2.7 present. + +Handle 0x0038, DMI type 4, 23 bytes +Family: Xeon +""", "") + +CPU_OUTPUT = {'bios': {}, + 'cpu': [ + {'Family': 'Xeon', + 'Handle': 'Handle 0x0038, DMI type 4, 23 bytes'}], + 'memory': {'devices': []}} + +DMI_DATA = (""" +# dmidecode 2.12 +SMBIOS 2.5 present. + +Handle 0x0000, DMI type 4, 35 bytes +Processor Information + Socket Designation: J1PR + Type: Central Processor + Family: Core i7 + Manufacturer: Intel(R) Corporation + ID: C2 06 02 00 FF FB EB BF + Signature: Type 0, Family 6, Model 44, Stepping 2 + Flags: + FPU (Floating-point unit on-chip) + VME (Virtual mode extension) + DE (Debugging extension) + PSE (Page size extension) + TSC (Time stamp counter) + MSR (Model specific registers) + PAE (Physical address extension) + MCE (Machine check exception) + CX8 (CMPXCHG8 instruction supported) + APIC (On-chip APIC hardware supported) + SEP (Fast system call) + MTRR (Memory type range registers) + PGE (Page global enable) + MCA (Machine check architecture) + CMOV (Conditional move instruction supported) + PAT (Page attribute table) + PSE-36 (36-bit page size extension) + CLFSH (CLFLUSH instruction supported) + DS (Debug store) + ACPI (ACPI supported) + MMX (MMX technology supported) + FXSR (FXSAVE and FXSTOR instructions supported) + SSE (Streaming SIMD extensions) + SSE2 (Streaming SIMD extensions 2) + SS (Self-snoop) + HTT (Multi-threading) + TM (Thermal monitor supported) + PBE (Pending break enabled) + Version: Intel(R) Core(TM) i7 CPU X 980 @ 3.33GHz + Voltage: 1.2 V + External Clock: 135 MHz + Max Speed: 4000 MHz + Current Speed: 3381 MHz + Status: Populated, Enabled + Upgrade: Socket LGA1366 + L1 Cache Handle: 0x0002 + L2 Cache Handle: 0x0003 + L3 Cache Handle: 0x0004 + Serial Number: Not Specified + Asset Tag: Not Specified + Part Number: Not Specified + +Handle 0x0005, DMI type 0, 24 bytes +BIOS Information + Vendor: Intel Corp. + Version: SOX5810J.86A.5561.2011.0516.2023 + Release Date: 05/16/2011 + Address: 0xF0000 + Runtime Size: 64 kB + ROM Size: 2048 kB + Characteristics: + PCI is supported + BIOS is upgradeable + BIOS shadowing is allowed + Boot from CD is supported + Selectable boot is supported + EDD is supported + 8042 keyboard services are supported (int 9h) + Serial services are supported (int 14h) + Printer services are supported (int 17h) + CGA/mono video services are supported (int 10h) + ACPI is supported + USB legacy is supported + ATAPI Zip drive boot is supported + BIOS boot specification is supported + Function key-initiated network boot is supported + Targeted content distribution is supported + BIOS Revision: 0.0 + Firmware Revision: 0.0 + +Handle 0x0012, DMI type 13, 22 bytes +BIOS Language Information + Language Description Format: Abbreviated + Installable Languages: 1 + enUS + Currently Installed Language: enUS + +Handle 0x0014, DMI type 16, 15 bytes +Physical Memory Array + Location: System Board Or Motherboard + Use: System Memory + Error Correction Type: None + Maximum Capacity: 16 GB + Error Information Handle: Not Provided + Number Of Devices: 4 + +Handle 0x0016, DMI type 17, 27 bytes +Memory Device + Array Handle: 0x0014 + Error Information Handle: Not Provided + Total Width: 64 bits + Data Width: 64 bits + Size: 2048 MB + Form Factor: DIMM + Set: None + Locator: J1MY + Bank Locator: CHAN A DIMM 0 + Type: DDR3 + Type Detail: Synchronous + Speed: 1333 MHz + Manufacturer: 0x0198 + Serial Number: 0x700ECE90 + Asset Tag: Unknown + Part Number: 0x393930353437312D3030312E4130304C4620 + +Handle 0x0017, DMI type 17, 27 bytes +Memory Device + Array Handle: 0x0014 + Error Information Handle: Not Provided + Total Width: Unknown + Data Width: Unknown + Size: No Module Installed + Form Factor: DIMM + Set: None + Locator: J2MY + Bank Locator: CHAN A DIMM 1 + Type: DDR3 + Type Detail: Synchronous + Speed: 1333 MHz + Manufacturer: NO DIMM + Serial Number: NO DIMM + Asset Tag: NO DIMM + Part Number: NO DIMM + +Handle 0x0018, DMI type 17, 27 bytes +Memory Device + Array Handle: 0x0014 + Error Information Handle: Not Provided + Total Width: 64 bits + Data Width: 64 bits + Size: 2048 MB + Form Factor: DIMM + Set: None + Locator: J3MY + Bank Locator: CHAN B DIMM 0 + Type: DDR3 + Type Detail: Synchronous + Speed: 1333 MHz + Manufacturer: 0x0198 + Serial Number: 0x700ED090 + Asset Tag: Unknown + Part Number: 0x393930353437312D3030312E4130304C4620 + +Handle 0x0019, DMI type 17, 27 bytes +Memory Device + Array Handle: 0x0014 + Error Information Handle: Not Provided + Total Width: 64 bits + Data Width: 64 bits + Size: 2048 MB + Form Factor: DIMM + Set: None + Locator: J4MY + Bank Locator: CHAN C DIMM 0 + Type: DDR3 + Type Detail: Synchronous + Speed: 1333 MHz + Manufacturer: 0x0198 + Serial Number: 0x6F0ED090 + Asset Tag: Unknown + Part Number: 0x393930353437312D3030312E4130304C4620 +""", "") + +DMI_OUTPUT = { + 'dmi': { + 'bios': { + 'Address': '0xF0000', + 'BIOS Revision': '0.0', + 'Characteristics': [ + 'PCI is supported', + 'BIOS is upgradeable', + 'BIOS shadowing is allowed', + 'Boot from CD is supported', + 'Selectable boot is supported', + 'EDD is supported', + '8042 keyboard services are supported (int 9h)', + 'Serial services are supported (int 14h)', + 'Printer services are supported (int 17h)', + 'CGA/mono video services are supported (int 10h)', + 'ACPI is supported', + 'USB legacy is supported', + 'ATAPI Zip drive boot is supported', + 'BIOS boot specification is supported', + 'Function key-initiated network boot is supported', + 'Targeted content distribution is supported'], + 'Firmware Revision': '0.0', + 'Handle': 'Handle 0x0005, DMI type 0, 24 bytes', + 'ROM Size': '2048 kB', + 'Release Date': '05/16/2011', + 'Runtime Size': '64 kB', + 'Vendor': 'Intel Corp.', + 'Version': 'SOX5810J.86A.5561.2011.0516.2023'}, + 'cpu': [{ + 'Asset Tag': 'Not Specified', + 'Current Speed': '3381 MHz', + 'External Clock': '135 MHz', + 'Family': 'Core i7', + 'Flags': [ + 'FPU (Floating-point unit on-chip)', + 'VME (Virtual mode extension)', + 'DE (Debugging extension)', + 'PSE (Page size extension)', + 'TSC (Time stamp counter)', + 'MSR (Model specific registers)', + 'PAE (Physical address extension)', + 'MCE (Machine check exception)', + 'CX8 (CMPXCHG8 instruction supported)', + 'APIC (On-chip APIC hardware supported)', + 'SEP (Fast system call)', + 'MTRR (Memory type range registers)', + 'PGE (Page global enable)', + 'MCA (Machine check architecture)', + 'CMOV (Conditional move instruction supported)', + 'PAT (Page attribute table)', + 'PSE-36 (36-bit page size extension)', + 'CLFSH (CLFLUSH instruction supported)', + 'DS (Debug store)', + 'ACPI (ACPI supported)', + 'MMX (MMX technology supported)', + 'FXSR (FXSAVE and FXSTOR instructions supported)', + 'SSE (Streaming SIMD extensions)', + 'SSE2 (Streaming SIMD extensions 2)', + 'SS (Self-snoop)', + 'HTT (Multi-threading)', + 'TM (Thermal monitor supported)', + 'PBE (Pending break enabled)'], + 'Handle': 'Handle 0x0000, DMI type 4, 35 bytes', + 'ID': 'C2 06 02 00 FF FB EB BF', + 'L1 Cache Handle': '0x0002', + 'L2 Cache Handle': '0x0003', + 'L3 Cache Handle': '0x0004', + 'Manufacturer': 'Intel(R) Corporation', + 'Max Speed': '4000 MHz', + 'Part Number': 'Not Specified', + 'Serial Number': 'Not Specified', + 'Signature': 'Type 0, Family 6, Model 44, Stepping 2', + 'Socket Designation': 'J1PR', + 'Status': 'Populated, Enabled', + 'Type': 'Central Processor', + 'Upgrade': 'Socket LGA1366', + 'Version': 'Intel(R) Core(TM) i7 CPU X 980 @ 3.33GHz', # noqa + 'Voltage': '1.2 V'}], + 'memory': { + 'Error Correction Type': 'None', + 'Error Information Handle': 'Not Provided', + 'Location': 'System Board Or Motherboard', + 'Maximum Capacity': '16 GB', + 'Number Of Devices': 4, + 'Use': 'System Memory', + 'devices': [ + {'Array Handle': '0x0014', + 'Asset Tag': 'Unknown', + 'Bank Locator': 'CHAN A DIMM 0', + 'Data Width': '64 bits', + 'Error Information Handle': 'Not Provided', + 'Form Factor': 'DIMM', + 'Handle': 'Handle 0x0016, DMI type 17, 27 bytes', + 'Locator': 'J1MY', + 'Manufacturer': '0x0198', + 'Part Number': '0x393930353437312D3030312E4130304C4620', + 'Serial Number': '0x700ECE90', + 'Set': 'None', + 'Size': '2048 MB', + 'Speed': '1333 MHz', + 'Total Width': '64 bits', + 'Type': 'DDR3', + 'Type Detail': 'Synchronous'}, + {'Array Handle': '0x0014', + 'Asset Tag': 'NO DIMM', + 'Bank Locator': 'CHAN A DIMM 1', + 'Data Width': 'Unknown', + 'Error Information Handle': 'Not Provided', + 'Form Factor': 'DIMM', + 'Handle': 'Handle 0x0017, DMI type 17, 27 bytes', + 'Locator': 'J2MY', + 'Manufacturer': 'NO DIMM', + 'Part Number': 'NO DIMM', + 'Serial Number': 'NO DIMM', + 'Set': 'None', + 'Size': 'No Module Installed', + 'Speed': '1333 MHz', + 'Total Width': 'Unknown', + 'Type': 'DDR3', + 'Type Detail': 'Synchronous'}, + {'Array Handle': '0x0014', + 'Asset Tag': 'Unknown', + 'Bank Locator': 'CHAN B DIMM 0', + 'Data Width': '64 bits', + 'Error Information Handle': 'Not Provided', + 'Form Factor': 'DIMM', + 'Handle': 'Handle 0x0018, DMI type 17, 27 bytes', + 'Locator': 'J3MY', + 'Manufacturer': '0x0198', + 'Part Number': '0x393930353437312D3030312E4130304C4620', + 'Serial Number': '0x700ED090', + 'Set': 'None', + 'Size': '2048 MB', + 'Speed': '1333 MHz', + 'Total Width': '64 bits', + 'Type': 'DDR3', + 'Type Detail': 'Synchronous'}, + {'Array Handle': '0x0014', + 'Asset Tag': 'Unknown', + 'Bank Locator': 'CHAN C DIMM 0', + 'Data Width': '64 bits', + 'Error Information Handle': 'Not Provided', + 'Form Factor': 'DIMM', + 'Handle': 'Handle 0x0019, DMI type 17, 27 bytes', + 'Locator': 'J4MY', + 'Manufacturer': '0x0198', + 'Part Number': '0x393930353437312D3030312E4130304C4620', + 'Serial Number': '0x6F0ED090', + 'Set': 'None', + 'Size': '2048 MB', + 'Speed': '1333 MHz', + 'Total Width': '64 bits', + 'Type': 'DDR3', + 'Type Detail': 'Synchronous'}]}}} + +DMM_OUTPUT = {'dmi': {'bios': {'Address': '0xF0000', + 'BIOS Revision': '0.0', + 'Characteristics': ['PCI is supported', + 'BIOS is upgradeable', + 'BIOS shadowing is allowed', + 'Boot from CD is supported', + 'Selectable boot is supported', + 'EDD is supported', + '8042 keyboard services are supported (int 9h)', # noqa + 'Serial services are supported (int 14h)', # noqa + 'Printer services are supported (int 17h)', # noqa + 'CGA/mono video services are supported (int 10h)', # noqa + 'ACPI is supported', + 'USB legacy is supported', + 'ATAPI Zip drive boot is supported', + 'BIOS boot specification is supported', # noqa + 'Function key-initiated network boot is supported', # noqa + 'Targeted content distribution is supported'], # noqa + 'Firmware Revision': '0.0', + 'Handle': 'Handle 0x0005, DMI type 0, 24 bytes', + 'ROM Size': '2048 kB', + 'Release Date': '05/16/2011', + 'Runtime Size': '64 kB', + 'Vendor': 'Intel Corp.', + 'Version': 'SOX5810J.86A.5561.2011.0516.2023'}, + 'cpu': [{'Asset Tag': 'Not Specified', + 'Current Speed': '3381 MHz', + 'External Clock': '135 MHz', + 'Family': 'Core i7', + 'Flags': ['FPU (Floating-point unit on-chip)', + 'VME (Virtual mode extension)', + 'DE (Debugging extension)', + 'PSE (Page size extension)', + 'TSC (Time stamp counter)', + 'MSR (Model specific registers)', + 'PAE (Physical address extension)', + 'MCE (Machine check exception)', + 'CX8 (CMPXCHG8 instruction supported)', + 'APIC (On-chip APIC hardware supported)', + 'SEP (Fast system call)', + 'MTRR (Memory type range registers)', + 'PGE (Page global enable)', + 'MCA (Machine check architecture)', + 'CMOV (Conditional move instruction supported)', # noqa + 'PAT (Page attribute table)', + 'PSE-36 (36-bit page size extension)', + 'CLFSH (CLFLUSH instruction supported)', + 'DS (Debug store)', + 'ACPI (ACPI supported)', + 'MMX (MMX technology supported)', + 'FXSR (FXSAVE and FXSTOR instructions supported)', # noqa + 'SSE (Streaming SIMD extensions)', + 'SSE2 (Streaming SIMD extensions 2)', + 'SS (Self-snoop)', + 'HTT (Multi-threading)', + 'TM (Thermal monitor supported)', + 'PBE (Pending break enabled)'], + 'Handle': 'Handle 0x0000, DMI type 4, 35 bytes', + 'ID': 'C2 06 02 00 FF FB EB BF', + 'L1 Cache Handle': '0x0002', + 'L2 Cache Handle': '0x0003', + 'L3 Cache Handle': '0x0004', + 'Manufacturer': 'Intel(R) Corporation', + 'Max Speed': '4000 MHz', + 'Part Number': 'Not Specified', + 'Serial Number': 'Not Specified', + 'Signature': 'Type 0, Family 6, Model 44, Stepping 2', + 'Socket Designation': 'J1PR', + 'Status': 'Populated, Enabled', + 'Type': 'Central Processor', + 'Upgrade': 'Socket LGA1366', + 'Version': 'Intel(R) Core(TM) i7 CPU X 980 @ 3.33GHz', # noqa + 'Voltage': '1.2 V'}], + 'memory': {'Error Correction Type': 'None', + 'Error Information Handle': 'Not Provided', + 'Location': 'System Board Or Motherboard', + 'Maximum Capacity': '16 GB', + 'Number Of Devices': 4, + 'Use': 'System Memory', + 'devices': [{'Array Handle': '0x0014', + 'Asset Tag': 'Unknown', + 'Bank Locator': 'CHAN A DIMM 0', + 'Data Width': '64 bits', + 'Error Information Handle': 'Not Provided', # noqa + 'Form Factor': 'DIMM', + 'Handle': 'Handle 0x0016, DMI type 17, 27 bytes', # noqa + 'Locator': 'J1MY', + 'Manufacturer': '0x0198', + 'Part Number': '0x393930353437312D3030312E4130304C4620', # noqa + 'Serial Number': '0x700ECE90', + 'Set': 'None', + 'Size': '2048 MB', + 'Speed': '1333 MHz', + 'Total Width': '64 bits', + 'Type': 'DDR3', + 'Type Detail': 'Synchronous'}, + {'Array Handle': '0x0014', + 'Asset Tag': 'NO DIMM', + 'Bank Locator': 'CHAN A DIMM 1', + 'Data Width': 'Unknown', + 'Error Information Handle': 'Not Provided', # noqa + 'Form Factor': 'DIMM', + 'Handle': 'Handle 0x0017, DMI type 17, 27 bytes', # noqa + 'Locator': 'J2MY', + 'Manufacturer': 'NO DIMM', + 'Part Number': 'NO DIMM', + 'Serial Number': 'NO DIMM', + 'Set': 'None', + 'Size': 'No Module Installed', + 'Speed': '1333 MHz', + 'Total Width': 'Unknown', + 'Type': 'DDR3', + 'Type Detail': 'Synchronous'}, + {'Array Handle': '0x0014', + 'Asset Tag': 'Unknown', + 'Bank Locator': 'CHAN B DIMM 0', + 'Data Width': '64 bits', + 'Error Information Handle': 'Not Provided', # noqa + 'Form Factor': 'DIMM', + 'Handle': 'Handle 0x0018, DMI type 17, 27 bytes', # noqa + 'Locator': 'J3MY', + 'Manufacturer': '0x0198', + 'Part Number': '0x393930353437312D3030312E4130304C4620', # noqa + 'Serial Number': '0x700ED090', + 'Set': 'None', + 'Size': '2048 MB', + 'Speed': '1333 MHz', + 'Total Width': '64 bits', + 'Type': 'DDR3', + 'Type Detail': 'Synchronous'}, + {'Array Handle': '0x0014', + 'Asset Tag': 'Unknown', + 'Bank Locator': 'CHAN C DIMM 0', + 'Data Width': '64 bits', + 'Error Information Handle': 'Not Provided', # noqa + 'Form Factor': 'DIMM', + 'Handle': 'Handle 0x0019, DMI type 17, 27 bytes', # noqa + 'Locator': 'J4MY', + 'Manufacturer': '0x0198', + 'Part Number': '0x393930353437312D3030312E4130304C4620', # noqa + 'Serial Number': '0x6F0ED090', + 'Set': 'None', + 'Size': '2048 MB', + 'Speed': '1333 MHz', + 'Total Width': '64 bits', + 'Type': 'DDR3', + 'Type Detail': 'Synchronous'}]}}} + + +class TestCollectDmidecodeInfo(base.IronicAgentTest): + def setUp(self): + super(TestCollectDmidecodeInfo, self).setUp() + self.data = {} + self.failures = utils.AccumulatedFailures() + + @mock.patch.object(utils, 'execute', autospec=True) + def test_dmidecode_info_ok(self, mock_execute): + mock_execute.return_value = DMI_DATA + + dmi_inspector.collect_dmidecode_info(self.data, None) + + for key in ('bios', 'memory', 'cpu'): + self.assertTrue(self.data['dmi'][key]) + + self.assertEqual(DMI_OUTPUT, self.data) + + mock_execute.assert_called_once_with('dmidecode', '-t', 'bios', + '-t', 'processor', '-t', 'memory') + + @mock.patch.object(utils, 'execute', autospec=True) + def test_dmidecode_info_bad_data(self, mock_execute): + mock_execute.return_value = ("""Handle 0x0000\nFoo\nBar: Baz\n""", "") + expected = {'dmi': {'bios': {}, 'cpu': [], 'memory': {'devices': []}}} + + dmi_inspector.collect_dmidecode_info(self.data, None) + + self.assertEqual(expected, self.data) + + mock_execute.assert_called_once_with('dmidecode', '-t', 'bios', + '-t', 'processor', '-t', 'memory') + + @mock.patch.object(utils, 'execute', autospec=True) + def test_dmidecode_info_failure(self, mock_execute): + mock_execute.side_effect = processutils.ProcessExecutionError() + + dmi_inspector.collect_dmidecode_info(self.data, self.failures) + + self.assertTrue(self.failures) + self.assertNotIn('dmi', self.data) + mock_execute.assert_called_once_with('dmidecode', '-t', 'bios', + '-t', 'processor', '-t', 'memory') + + def test_parse_dmi_bios(self): + inputdata = BIOS_DATA[0] + expected = BIOS_OUTPUT + + ret = dmi_inspector.parse_dmi(inputdata) + self.assertEqual(expected, ret) + + def test_parse_dmi_cpu(self): + inputdata = CPU_DATA[0] + expected = CPU_OUTPUT + + ret = dmi_inspector.parse_dmi(inputdata) + self.assertEqual(expected, ret) + + def test_parse_dmi_memory(self): + inputdata = MEMORY_DATA[0] + expected = MEMORY_OUTPUT + + ret = dmi_inspector.parse_dmi(inputdata) + self.assertEqual(expected, ret) + + def test_save_data(self): + dmi_info = {} + dmi_info['bios'] = {} + dmi_info['cpu'] = [] + dmi_info['memory'] = {} + dmi_info['memory']['devices'] = {} + mem = [{'Handle': 'handle', 'Number Of Devices': '2'}, + {'Handle': 'handle', 'Number Of Devices': '2'}] + devices = [{'bar': 'foo'}, {'bar': 'foo'}] + expected = {'bios': {}, + 'cpu': [], + 'memory': {'Number Of Devices': 4, + 'devices': [{'bar': 'foo'}, {'bar': 'foo'}]}} + + ret = dmi_inspector._save_data(dmi_info, mem, devices) + self.assertEqual(expected, ret) + + self.assertRaises(KeyError, + dmi_inspector._save_data, + dmi_info, + [{'foo': 'bar', 'Handle': '0x10'}], + [{'bar': 'foo'}, {'bar': 'foo'}]) + + self.assertRaises(KeyError, + dmi_inspector._save_data, + dmi_info, + [{'foo': 'bar', 'Number Of Devices': '2'}], + [{'bar': 'foo'}, {'bar': 'foo'}]) diff --git a/releasenotes/notes/collect-dmi-output-f2e9feabef16bacf.yaml b/releasenotes/notes/collect-dmi-output-f2e9feabef16bacf.yaml new file mode 100644 index 000000000..b0fbc11cb --- /dev/null +++ b/releasenotes/notes/collect-dmi-output-f2e9feabef16bacf.yaml @@ -0,0 +1,4 @@ +--- +features: + - Adds a new optional dmidecode output collector called ``dmi-decode``. + It collects dmi output for BIOS, processor and memory information. diff --git a/setup.cfg b/setup.cfg index 7c41fc9e6..be41fd755 100644 --- a/setup.cfg +++ b/setup.cfg @@ -41,6 +41,7 @@ ironic_python_agent.inspector.collectors = extra-hardware = ironic_python_agent.inspector:collect_extra_hardware pci-devices = ironic_python_agent.inspector:collect_pci_devices_info numa-topology = ironic_python_agent.numa_inspector:collect_numa_topology_info + dmi-decode = ironic_python_agent.dmi_inspector:collect_dmidecode_info [pbr] autodoc_index_modules = True