Skip to content

Commit

Permalink
Fix incorrect parsing of lscpu output
Browse files Browse the repository at this point in the history
Original solution expected always ``key: val`` pair on each line.
However, it has not been expected that val could be actually empty
string, which would lead to situation where the following line is
interpreted as a value.

The new solution updates the parsing for output on RHEL 7, but also
calls newly ``lscpu -J`` on RHEL 8+ to obtain data in the JSON format,
which drops all possible parsing problems from our side.

Fixes oamg#1182
  • Loading branch information
dkubek committed Feb 21, 2024
1 parent b875ae2 commit 639238a
Show file tree
Hide file tree
Showing 16 changed files with 277 additions and 113 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/codespell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
./repos/system_upgrade/el8toel9/actors/xorgdrvfact/tests/files/journalctl-xorg-intel,\
./repos/system_upgrade/el8toel9/actors/xorgdrvfact/tests/files/journalctl-xorg-qxl,\
./repos/system_upgrade/el8toel9/actors/xorgdrvfact/tests/files/journalctl-xorg-without-qxl,\
./repos/system_upgrade/common/actors/scancpu/tests/files/lscpu_s390x,\
./repos/system_upgrade/common/actors/scancpu/tests/files,\
./etc/leapp/files/device_driver_deprecation_data.json,\
./etc/leapp/files/pes-events.json,\
./etc/leapp/files/repomap.json,\
Expand Down
39 changes: 25 additions & 14 deletions repos/system_upgrade/common/actors/scancpu/libraries/scancpu.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
import json
import re

from leapp.libraries.common.config import architecture
from leapp.libraries.common.config.version import get_source_major_version
from leapp.libraries.stdlib import api, CalledProcessError, run
from leapp.models import CPUInfo, DetectedDeviceOrDriver, DeviceDriverDeprecationData

LSCPU_NAME_VALUE = re.compile(r'(?P<name>[^:]+):\s+(?P<value>.+)\n?')
LSCPU_NAME_VALUE = re.compile(r'^(?P<name>[^:]+):[^\S\n]+(?P<value>.+)\n?', flags=re.MULTILINE)
PPC64LE_MODEL = re.compile(r'\d+\.\d+ \(pvr (?P<family>[0-9a-fA-F]+) 0*[0-9a-fA-F]+\)')


def _get_lscpu_output():
def _get_lscpu_output(output_json=False):
try:
result = run(['lscpu'])
result = run(['lscpu', '-J' if output_json else ''])
return result.get('stdout', '')
except (OSError, CalledProcessError):
api.current_logger().debug('Executing `lscpu` failed', exc_info=True)
return ''


def _parse_lscpu_output():
if get_source_major_version() == '7':
return dict(LSCPU_NAME_VALUE.findall(_get_lscpu_output()))

lscpu = _get_lscpu_output(output_json=True)
try:
parsed_json = json.loads(lscpu)
# The json contains one entry "lscpu" which is a list of dictionaries
# with 2 keys "field" (name of the field from lscpu) and "data" (value
# of the field).
return dict((entry['field'].rstrip(':'), entry['data']) for entry in parsed_json['lscpu'])
except ValueError:
api.current_logger().debug('Failed to parse json output from `lscpu`. Got:\n{}'.format(lscpu))

return dict()


def _get_cpu_flags(lscpu):
flags = lscpu.get('Flags', '')
return flags.split()
Expand Down Expand Up @@ -128,24 +147,16 @@ def _find_deprecation_data_entries(lscpu):
arch_prefix, is_detected = architecture.ARCH_ARM64, _is_detected_aarch64

if arch_prefix and is_detected:
return [
_to_detected_device(entry) for entry in _get_cpu_entries_for(arch_prefix)
if is_detected(lscpu, entry)
]
return [_to_detected_device(entry) for entry in _get_cpu_entries_for(arch_prefix) if is_detected(lscpu, entry)]

api.current_logger().warning('Unsupported platform could not detect relevant CPU information')
return []


def process():
lscpu = dict(LSCPU_NAME_VALUE.findall(_get_lscpu_output()))
lscpu = _parse_lscpu_output()
api.produce(*_find_deprecation_data_entries(lscpu))
# Backwards compatibility
machine_type = lscpu.get('Machine type')
flags = _get_cpu_flags(lscpu)
api.produce(
CPUInfo(
machine_type=int(machine_type) if machine_type else None,
flags=flags
)
)
api.produce(CPUInfo(machine_type=int(machine_type) if machine_type else None, flags=flags))
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a
b
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"lscpu": [
{"field": "Architecture:", "data": "aarch64"},
{"field": "Byte Order:", "data": "Little Endian"},
{"field": "CPU(s):", "data": "160"},
{"field": "On-line CPU(s) list:", "data": "0-159"},
{"field": "Thread(s) per core:", "data": "1"},
{"field": "Core(s) per socket:", "data": "80"},
{"field": "Socket(s):", "data": "2"},
{"field": "NUMA node(s):", "data": "4"},
{"field": "Vendor ID:", "data": "ARM"},
{"field": "BIOS Vendor ID:", "data": "Ampere(R)"},
{"field": "Model:", "data": "1"},
{"field": "Model name:", "data": "Neoverse-N1"},
{"field": "BIOS Model name:", "data": "Ampere(R) Altra(R) Processor"},
{"field": "Stepping:", "data": "r3p1"},
{"field": "CPU max MHz:", "data": "3000.0000"},
{"field": "CPU min MHz:", "data": "1000.0000"},
{"field": "BogoMIPS:", "data": "50.00"},
{"field": "L1d cache:", "data": "64K"},
{"field": "L1i cache:", "data": "64K"},
{"field": "L2 cache:", "data": "1024K"},
{"field": "NUMA node0 CPU(s):", "data": "0-79"},
{"field": "NUMA node1 CPU(s):", "data": "80-159"},
{"field": "NUMA node2 CPU(s):", "data": null},
{"field": "NUMA node3 CPU(s):", "data": null},
{"field": "Flags:", "data": "fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs"}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"lscpu": [
{"field": "Architecture:", "data": "ppc64le"},
{"field": "Byte Order:", "data": "Little Endian"},
{"field": "CPU(s):", "data": "8"},
{"field": "On-line CPU(s) list:", "data": "0-7"},
{"field": "Thread(s) per core:", "data": "1"},
{"field": "Core(s) per socket:", "data": "1"},
{"field": "Socket(s):", "data": "8"},
{"field": "NUMA node(s):", "data": "1"},
{"field": "Model:", "data": "2.1 (pvr 004b 0201)"},
{"field": "Model name:", "data": "POWER8E (raw), altivec supported"},
{"field": "Hypervisor vendor:", "data": "KVM"},
{"field": "Virtualization type:", "data": "para"},
{"field": "L1d cache:", "data": "64K"},
{"field": "L1i cache:", "data": "32K"},
{"field": "NUMA node0 CPU(s):", "data": "0-7"}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"lscpu": [
{"field": "Architecture:", "data": "s390x"},
{"field": "CPU op-mode(s):", "data": "32-bit, 64-bit"},
{"field": "Byte Order:", "data": "Big Endian"},
{"field": "CPU(s):", "data": "4"},
{"field": "On-line CPU(s) list:", "data": "0-3"},
{"field": "Thread(s) per core:", "data": "1"},
{"field": "Core(s) per socket:", "data": "1"},
{"field": "Socket(s) per book:", "data": "1"},
{"field": "Book(s) per drawer:", "data": "1"},
{"field": "Drawer(s):", "data": "4"},
{"field": "NUMA node(s):", "data": "1"},
{"field": "Vendor ID:", "data": "IBM/S390"},
{"field": "Machine type:", "data": "3931"},
{"field": "CPU dynamic MHz:", "data": "5200"},
{"field": "CPU static MHz:", "data": "5200"},
{"field": "BogoMIPS:", "data": "3331.00"},
{"field": "Hypervisor:", "data": "KVM/Linux"},
{"field": "Hypervisor vendor:", "data": "KVM"},
{"field": "Virtualization type:", "data": "full"},
{"field": "Dispatching mode:", "data": "horizontal"},
{"field": "L1d cache:", "data": "128K"},
{"field": "L1i cache:", "data": "128K"},
{"field": "L2 cache:", "data": "32768K"},
{"field": "L3 cache:", "data": "262144K"},
{"field": "NUMA node0 CPU(s):", "data": "0-3"},
{"field": "Flags:", "data": "esan3 zarch stfle msa ldisp eimm dfp edat etf3eh highgprs te vx vxd vxe gs vxe2 vxp sort dflt vxp2 nnpa sie"}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"lscpu": [
{"field": "Architecture:", "data": "x86_64"},
{"field": "CPU op-mode(s):", "data": "32-bit, 64-bit"},
{"field": "Byte Order:", "data": "Little Endian"},
{"field": "CPU(s):", "data": "2"},
{"field": "On-line CPU(s) list:", "data": "0,1"},
{"field": "Thread(s) per core:", "data": "1"},
{"field": "Core(s) per socket:", "data": "1"},
{"field": "Socket(s):", "data": "2"},
{"field": "NUMA node(s):", "data": "1"},
{"field": "Vendor ID:", "data": "GenuineIntel"},
{"field": "BIOS Vendor ID:", "data": "QEMU"},
{"field": "CPU family:", "data": "6"},
{"field": "Model:", "data": "165"},
{"field": "Model name:", "data": "Intel(R) Core(TM) i7-10850H CPU @ 2.70GHz"},
{"field": "BIOS Model name:", "data": "pc-i440fx-7.2"},
{"field": "Stepping:", "data": "2"},
{"field": "CPU MHz:", "data": "2712.006"},
{"field": "BogoMIPS:", "data": "5424.01"},
{"field": "Virtualization:", "data": "VT-x"},
{"field": "Hypervisor vendor:", "data": "KVM"},
{"field": "Virtualization type:", "data": "full"},
{"field": "L1d cache:", "data": "32K"},
{"field": "L1i cache:", "data": "32K"},
{"field": "L2 cache:", "data": "4096K"},
{"field": "L3 cache:", "data": "16384K"},
{"field": "NUMA node0 CPU(s):", "data": "0,1"},
{"field": "Flags:", "data": "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm xsaveopt cqm_llc cqm_occup_llc dtherm ida arat pln pts md_clear flush_l1d"}
]
}

This file was deleted.

This file was deleted.

38 changes: 0 additions & 38 deletions repos/system_upgrade/common/actors/scancpu/tests/files/lscpu_s390x

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Architecture: aarch64
Byte Order: Little Endian
CPU(s): 160
On-line CPU(s) list: 0-159
Thread(s) per core: 1
Core(s) per socket: 80
Socket(s): 2
NUMA node(s): 4
Vendor ID: ARM
BIOS Vendor ID: Ampere(R)
Model: 1
Model name: Neoverse-N1
BIOS Model name: Ampere(R) Altra(R) Processor
Stepping: r3p1
CPU max MHz: 3000.0000
CPU min MHz: 1000.0000
BogoMIPS: 50.00
L1d cache: 64K
L1i cache: 64K
L2 cache: 1024K
NUMA node0 CPU(s): 0-79
NUMA node1 CPU(s): 80-159
NUMA node2 CPU(s):
NUMA node3 CPU(s):
Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Architecture:
Flags: flag
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Architecture: ppc64le
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 8
NUMA node(s): 1
Model: 2.1 (pvr 004b 0201)
Model name: POWER8E (raw), altivec supported
Hypervisor vendor: KVM
Virtualization type: para
L1d cache: 64K
L1i cache: 32K
NUMA node0 CPU(s): 0-7
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Architecture: s390x
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Big Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s) per book: 1
Book(s) per drawer: 1
Drawer(s): 4
NUMA node(s): 1
Vendor ID: IBM/S390
Machine type: 3931
CPU dynamic MHz: 5200
CPU static MHz: 5200
BogoMIPS: 3331.00
Hypervisor: KVM/Linux
Hypervisor vendor: KVM
Virtualization type: full
Dispatching mode: horizontal
L1d cache: 128K
L1i cache: 128K
L2 cache: 32768K
L3 cache: 262144K
NUMA node0 CPU(s): 0-3
Flags: esan3 zarch stfle msa ldisp eimm dfp edat etf3eh highgprs te vx vxd vxe gs vxe2 vxp sort dflt vxp2 nnpa sie
Loading

0 comments on commit 639238a

Please sign in to comment.