amd-node-scraper 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- amd_node_scraper-0.0.1.dist-info/LICENSE +21 -0
- amd_node_scraper-0.0.1.dist-info/METADATA +424 -0
- amd_node_scraper-0.0.1.dist-info/RECORD +197 -0
- amd_node_scraper-0.0.1.dist-info/WHEEL +5 -0
- amd_node_scraper-0.0.1.dist-info/entry_points.txt +2 -0
- amd_node_scraper-0.0.1.dist-info/top_level.txt +1 -0
- nodescraper/__init__.py +32 -0
- nodescraper/base/__init__.py +34 -0
- nodescraper/base/inbandcollectortask.py +118 -0
- nodescraper/base/inbanddataplugin.py +39 -0
- nodescraper/base/regexanalyzer.py +120 -0
- nodescraper/cli/__init__.py +29 -0
- nodescraper/cli/cli.py +511 -0
- nodescraper/cli/constants.py +27 -0
- nodescraper/cli/dynamicparserbuilder.py +171 -0
- nodescraper/cli/helper.py +517 -0
- nodescraper/cli/inputargtypes.py +129 -0
- nodescraper/configbuilder.py +123 -0
- nodescraper/configregistry.py +66 -0
- nodescraper/configs/node_status.json +19 -0
- nodescraper/connection/__init__.py +25 -0
- nodescraper/connection/inband/__init__.py +46 -0
- nodescraper/connection/inband/inband.py +171 -0
- nodescraper/connection/inband/inbandlocal.py +93 -0
- nodescraper/connection/inband/inbandmanager.py +151 -0
- nodescraper/connection/inband/inbandremote.py +173 -0
- nodescraper/connection/inband/sshparams.py +43 -0
- nodescraper/constants.py +26 -0
- nodescraper/enums/__init__.py +40 -0
- nodescraper/enums/eventcategory.py +89 -0
- nodescraper/enums/eventpriority.py +42 -0
- nodescraper/enums/executionstatus.py +44 -0
- nodescraper/enums/osfamily.py +34 -0
- nodescraper/enums/systeminteraction.py +41 -0
- nodescraper/enums/systemlocation.py +33 -0
- nodescraper/generictypes.py +36 -0
- nodescraper/interfaces/__init__.py +44 -0
- nodescraper/interfaces/connectionmanager.py +143 -0
- nodescraper/interfaces/dataanalyzertask.py +138 -0
- nodescraper/interfaces/datacollectortask.py +185 -0
- nodescraper/interfaces/dataplugin.py +356 -0
- nodescraper/interfaces/plugin.py +127 -0
- nodescraper/interfaces/resultcollator.py +56 -0
- nodescraper/interfaces/task.py +164 -0
- nodescraper/interfaces/taskresulthook.py +39 -0
- nodescraper/models/__init__.py +48 -0
- nodescraper/models/analyzerargs.py +93 -0
- nodescraper/models/collectorargs.py +30 -0
- nodescraper/models/connectionconfig.py +34 -0
- nodescraper/models/datamodel.py +171 -0
- nodescraper/models/datapluginresult.py +39 -0
- nodescraper/models/event.py +158 -0
- nodescraper/models/pluginconfig.py +38 -0
- nodescraper/models/pluginresult.py +39 -0
- nodescraper/models/systeminfo.py +44 -0
- nodescraper/models/taskresult.py +185 -0
- nodescraper/models/timerangeargs.py +38 -0
- nodescraper/pluginexecutor.py +274 -0
- nodescraper/pluginregistry.py +152 -0
- nodescraper/plugins/__init__.py +25 -0
- nodescraper/plugins/inband/__init__.py +25 -0
- nodescraper/plugins/inband/amdsmi/__init__.py +28 -0
- nodescraper/plugins/inband/amdsmi/amdsmi_analyzer.py +821 -0
- nodescraper/plugins/inband/amdsmi/amdsmi_collector.py +1313 -0
- nodescraper/plugins/inband/amdsmi/amdsmi_plugin.py +43 -0
- nodescraper/plugins/inband/amdsmi/amdsmidata.py +1002 -0
- nodescraper/plugins/inband/amdsmi/analyzer_args.py +50 -0
- nodescraper/plugins/inband/amdsmi/cper.py +65 -0
- nodescraper/plugins/inband/bios/__init__.py +29 -0
- nodescraper/plugins/inband/bios/analyzer_args.py +64 -0
- nodescraper/plugins/inband/bios/bios_analyzer.py +93 -0
- nodescraper/plugins/inband/bios/bios_collector.py +93 -0
- nodescraper/plugins/inband/bios/bios_plugin.py +43 -0
- nodescraper/plugins/inband/bios/biosdata.py +30 -0
- nodescraper/plugins/inband/cmdline/__init__.py +25 -0
- nodescraper/plugins/inband/cmdline/analyzer_args.py +80 -0
- nodescraper/plugins/inband/cmdline/cmdline_analyzer.py +113 -0
- nodescraper/plugins/inband/cmdline/cmdline_collector.py +77 -0
- nodescraper/plugins/inband/cmdline/cmdline_plugin.py +43 -0
- nodescraper/plugins/inband/cmdline/cmdlinedata.py +30 -0
- nodescraper/plugins/inband/device_enumeration/__init__.py +29 -0
- nodescraper/plugins/inband/device_enumeration/analyzer_args.py +73 -0
- nodescraper/plugins/inband/device_enumeration/device_enumeration_analyzer.py +81 -0
- nodescraper/plugins/inband/device_enumeration/device_enumeration_collector.py +176 -0
- nodescraper/plugins/inband/device_enumeration/device_enumeration_plugin.py +45 -0
- nodescraper/plugins/inband/device_enumeration/deviceenumdata.py +36 -0
- nodescraper/plugins/inband/dimm/__init__.py +25 -0
- nodescraper/plugins/inband/dimm/collector_args.py +31 -0
- nodescraper/plugins/inband/dimm/dimm_collector.py +151 -0
- nodescraper/plugins/inband/dimm/dimm_plugin.py +40 -0
- nodescraper/plugins/inband/dimm/dimmdata.py +30 -0
- nodescraper/plugins/inband/dkms/__init__.py +25 -0
- nodescraper/plugins/inband/dkms/analyzer_args.py +85 -0
- nodescraper/plugins/inband/dkms/dkms_analyzer.py +106 -0
- nodescraper/plugins/inband/dkms/dkms_collector.py +76 -0
- nodescraper/plugins/inband/dkms/dkms_plugin.py +43 -0
- nodescraper/plugins/inband/dkms/dkmsdata.py +33 -0
- nodescraper/plugins/inband/dmesg/__init__.py +28 -0
- nodescraper/plugins/inband/dmesg/analyzer_args.py +33 -0
- nodescraper/plugins/inband/dmesg/collector_args.py +39 -0
- nodescraper/plugins/inband/dmesg/dmesg_analyzer.py +503 -0
- nodescraper/plugins/inband/dmesg/dmesg_collector.py +164 -0
- nodescraper/plugins/inband/dmesg/dmesg_plugin.py +44 -0
- nodescraper/plugins/inband/dmesg/dmesgdata.py +116 -0
- nodescraper/plugins/inband/fabrics/__init__.py +28 -0
- nodescraper/plugins/inband/fabrics/fabrics_collector.py +726 -0
- nodescraper/plugins/inband/fabrics/fabrics_plugin.py +37 -0
- nodescraper/plugins/inband/fabrics/fabricsdata.py +140 -0
- nodescraper/plugins/inband/journal/__init__.py +28 -0
- nodescraper/plugins/inband/journal/collector_args.py +33 -0
- nodescraper/plugins/inband/journal/journal_collector.py +107 -0
- nodescraper/plugins/inband/journal/journal_plugin.py +40 -0
- nodescraper/plugins/inband/journal/journaldata.py +44 -0
- nodescraper/plugins/inband/kernel/__init__.py +25 -0
- nodescraper/plugins/inband/kernel/analyzer_args.py +64 -0
- nodescraper/plugins/inband/kernel/kernel_analyzer.py +91 -0
- nodescraper/plugins/inband/kernel/kernel_collector.py +129 -0
- nodescraper/plugins/inband/kernel/kernel_plugin.py +43 -0
- nodescraper/plugins/inband/kernel/kerneldata.py +32 -0
- nodescraper/plugins/inband/kernel_module/__init__.py +25 -0
- nodescraper/plugins/inband/kernel_module/analyzer_args.py +59 -0
- nodescraper/plugins/inband/kernel_module/kernel_module_analyzer.py +211 -0
- nodescraper/plugins/inband/kernel_module/kernel_module_collector.py +264 -0
- nodescraper/plugins/inband/kernel_module/kernel_module_data.py +60 -0
- nodescraper/plugins/inband/kernel_module/kernel_module_plugin.py +43 -0
- nodescraper/plugins/inband/memory/__init__.py +25 -0
- nodescraper/plugins/inband/memory/analyzer_args.py +45 -0
- nodescraper/plugins/inband/memory/memory_analyzer.py +98 -0
- nodescraper/plugins/inband/memory/memory_collector.py +330 -0
- nodescraper/plugins/inband/memory/memory_plugin.py +43 -0
- nodescraper/plugins/inband/memory/memorydata.py +90 -0
- nodescraper/plugins/inband/network/__init__.py +28 -0
- nodescraper/plugins/inband/network/network_collector.py +1828 -0
- nodescraper/plugins/inband/network/network_plugin.py +37 -0
- nodescraper/plugins/inband/network/networkdata.py +319 -0
- nodescraper/plugins/inband/nvme/__init__.py +28 -0
- nodescraper/plugins/inband/nvme/nvme_collector.py +167 -0
- nodescraper/plugins/inband/nvme/nvme_plugin.py +37 -0
- nodescraper/plugins/inband/nvme/nvmedata.py +45 -0
- nodescraper/plugins/inband/os/__init__.py +25 -0
- nodescraper/plugins/inband/os/analyzer_args.py +64 -0
- nodescraper/plugins/inband/os/os_analyzer.py +73 -0
- nodescraper/plugins/inband/os/os_collector.py +131 -0
- nodescraper/plugins/inband/os/os_plugin.py +43 -0
- nodescraper/plugins/inband/os/osdata.py +31 -0
- nodescraper/plugins/inband/package/__init__.py +25 -0
- nodescraper/plugins/inband/package/analyzer_args.py +48 -0
- nodescraper/plugins/inband/package/package_analyzer.py +253 -0
- nodescraper/plugins/inband/package/package_collector.py +273 -0
- nodescraper/plugins/inband/package/package_plugin.py +43 -0
- nodescraper/plugins/inband/package/packagedata.py +41 -0
- nodescraper/plugins/inband/pcie/__init__.py +29 -0
- nodescraper/plugins/inband/pcie/analyzer_args.py +63 -0
- nodescraper/plugins/inband/pcie/pcie_analyzer.py +1081 -0
- nodescraper/plugins/inband/pcie/pcie_collector.py +690 -0
- nodescraper/plugins/inband/pcie/pcie_data.py +2017 -0
- nodescraper/plugins/inband/pcie/pcie_plugin.py +43 -0
- nodescraper/plugins/inband/process/__init__.py +25 -0
- nodescraper/plugins/inband/process/analyzer_args.py +45 -0
- nodescraper/plugins/inband/process/collector_args.py +31 -0
- nodescraper/plugins/inband/process/process_analyzer.py +91 -0
- nodescraper/plugins/inband/process/process_collector.py +115 -0
- nodescraper/plugins/inband/process/process_plugin.py +46 -0
- nodescraper/plugins/inband/process/processdata.py +34 -0
- nodescraper/plugins/inband/rocm/__init__.py +25 -0
- nodescraper/plugins/inband/rocm/analyzer_args.py +66 -0
- nodescraper/plugins/inband/rocm/rocm_analyzer.py +100 -0
- nodescraper/plugins/inband/rocm/rocm_collector.py +205 -0
- nodescraper/plugins/inband/rocm/rocm_plugin.py +43 -0
- nodescraper/plugins/inband/rocm/rocmdata.py +62 -0
- nodescraper/plugins/inband/storage/__init__.py +25 -0
- nodescraper/plugins/inband/storage/analyzer_args.py +38 -0
- nodescraper/plugins/inband/storage/collector_args.py +31 -0
- nodescraper/plugins/inband/storage/storage_analyzer.py +152 -0
- nodescraper/plugins/inband/storage/storage_collector.py +110 -0
- nodescraper/plugins/inband/storage/storage_plugin.py +44 -0
- nodescraper/plugins/inband/storage/storagedata.py +70 -0
- nodescraper/plugins/inband/sysctl/__init__.py +29 -0
- nodescraper/plugins/inband/sysctl/analyzer_args.py +67 -0
- nodescraper/plugins/inband/sysctl/sysctl_analyzer.py +81 -0
- nodescraper/plugins/inband/sysctl/sysctl_collector.py +101 -0
- nodescraper/plugins/inband/sysctl/sysctl_plugin.py +43 -0
- nodescraper/plugins/inband/sysctl/sysctldata.py +42 -0
- nodescraper/plugins/inband/syslog/__init__.py +28 -0
- nodescraper/plugins/inband/syslog/syslog_collector.py +121 -0
- nodescraper/plugins/inband/syslog/syslog_plugin.py +37 -0
- nodescraper/plugins/inband/syslog/syslogdata.py +46 -0
- nodescraper/plugins/inband/uptime/__init__.py +25 -0
- nodescraper/plugins/inband/uptime/uptime_collector.py +88 -0
- nodescraper/plugins/inband/uptime/uptime_plugin.py +37 -0
- nodescraper/plugins/inband/uptime/uptimedata.py +31 -0
- nodescraper/resultcollators/__init__.py +25 -0
- nodescraper/resultcollators/tablesummary.py +159 -0
- nodescraper/taskresulthooks/__init__.py +28 -0
- nodescraper/taskresulthooks/filesystemloghook.py +88 -0
- nodescraper/typeutils.py +171 -0
- nodescraper/utils.py +412 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
#
|
|
3
|
+
# MIT License
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
###############################################################################
|
|
26
|
+
import re
|
|
27
|
+
from typing import Optional
|
|
28
|
+
|
|
29
|
+
from nodescraper.base import InBandDataCollector
|
|
30
|
+
from nodescraper.enums import EventCategory, EventPriority, ExecutionStatus, OSFamily
|
|
31
|
+
from nodescraper.models import TaskResult
|
|
32
|
+
|
|
33
|
+
from .kerneldata import KernelDataModel
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class KernelCollector(InBandDataCollector[KernelDataModel, None]):
|
|
37
|
+
"""Read kernel version"""
|
|
38
|
+
|
|
39
|
+
DATA_MODEL = KernelDataModel
|
|
40
|
+
CMD_WINDOWS = "wmic os get Version /Value"
|
|
41
|
+
CMD = "sh -c 'uname -a'"
|
|
42
|
+
|
|
43
|
+
def _parse_kernel_version(self, uname_a: str) -> Optional[str]:
|
|
44
|
+
"""Extract the kernel release from `uname -a` output.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
uname_a (str): The full output string from the `uname -a` command.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Optional[str]: The parsed kernel release (e.g., "5.13.0-30-generic")
|
|
51
|
+
if found, otherwise None.
|
|
52
|
+
"""
|
|
53
|
+
if not uname_a:
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
result = uname_a.strip().split()
|
|
57
|
+
if len(result) >= 3:
|
|
58
|
+
return result[2]
|
|
59
|
+
|
|
60
|
+
# if some change in output look for a version-like string (e.g. 4.18.0-553.el8_10.x86_64)
|
|
61
|
+
match = re.search(r"\d+\.\d+\.\d+[\w\-\.]*", uname_a)
|
|
62
|
+
if match:
|
|
63
|
+
return match.group(0)
|
|
64
|
+
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
def collect_data(
|
|
68
|
+
self,
|
|
69
|
+
args=None,
|
|
70
|
+
) -> tuple[TaskResult, Optional[KernelDataModel]]:
|
|
71
|
+
"""
|
|
72
|
+
Collect kernel version data.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
tuple[TaskResult, Optional[KernelDataModel]]: tuple containing the task result and kernel data model or None if not found.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
kernel = None
|
|
79
|
+
kernel_info = None
|
|
80
|
+
|
|
81
|
+
if self.system_info.os_family == OSFamily.WINDOWS:
|
|
82
|
+
res = self._run_sut_cmd(self.CMD_WINDOWS)
|
|
83
|
+
if res.exit_code == 0:
|
|
84
|
+
kernel_info = res.stdout
|
|
85
|
+
kernel = [line for line in res.stdout.splitlines() if "Version=" in line][0].split(
|
|
86
|
+
"="
|
|
87
|
+
)[1]
|
|
88
|
+
else:
|
|
89
|
+
res = self._run_sut_cmd(self.CMD)
|
|
90
|
+
if res.exit_code == 0:
|
|
91
|
+
kernel_info = res.stdout
|
|
92
|
+
kernel = self._parse_kernel_version(kernel_info)
|
|
93
|
+
if not kernel:
|
|
94
|
+
self._log_event(
|
|
95
|
+
category=EventCategory.OS,
|
|
96
|
+
description="Could not extract kernel version from 'uname -a'",
|
|
97
|
+
data={"command": res.command, "exit_code": res.exit_code},
|
|
98
|
+
priority=EventPriority.ERROR,
|
|
99
|
+
console_log=True,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if res.exit_code != 0:
|
|
103
|
+
self._log_event(
|
|
104
|
+
category=EventCategory.OS,
|
|
105
|
+
description="Error checking kernel version",
|
|
106
|
+
data={"command": res.command, "exit_code": res.exit_code},
|
|
107
|
+
priority=EventPriority.ERROR,
|
|
108
|
+
console_log=True,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if kernel_info and kernel:
|
|
112
|
+
|
|
113
|
+
kernel_data = KernelDataModel(kernel_info=kernel_info, kernel_version=kernel)
|
|
114
|
+
self._log_event(
|
|
115
|
+
category="KERNEL_READ",
|
|
116
|
+
description="Kernel version read",
|
|
117
|
+
data=kernel_data.model_dump(),
|
|
118
|
+
priority=EventPriority.INFO,
|
|
119
|
+
)
|
|
120
|
+
else:
|
|
121
|
+
kernel_data = None
|
|
122
|
+
|
|
123
|
+
self.result.message = (
|
|
124
|
+
"Kernel not found"
|
|
125
|
+
if not kernel_info
|
|
126
|
+
else f"Kernel info: {kernel_info} | Kernel version: {kernel if kernel else 'Kernel version not found'}"
|
|
127
|
+
)
|
|
128
|
+
self.result.status = ExecutionStatus.OK if kernel_info else ExecutionStatus.ERROR
|
|
129
|
+
return self.result, kernel_data
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
#
|
|
3
|
+
# MIT License
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
###############################################################################
|
|
26
|
+
from nodescraper.base import InBandDataPlugin
|
|
27
|
+
|
|
28
|
+
from .analyzer_args import KernelAnalyzerArgs
|
|
29
|
+
from .kernel_analyzer import KernelAnalyzer
|
|
30
|
+
from .kernel_collector import KernelCollector
|
|
31
|
+
from .kerneldata import KernelDataModel
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class KernelPlugin(InBandDataPlugin[KernelDataModel, None, KernelAnalyzerArgs]):
|
|
35
|
+
"""Plugin for collection and analysis of kernel data"""
|
|
36
|
+
|
|
37
|
+
DATA_MODEL = KernelDataModel
|
|
38
|
+
|
|
39
|
+
COLLECTOR = KernelCollector
|
|
40
|
+
|
|
41
|
+
ANALYZER = KernelAnalyzer
|
|
42
|
+
|
|
43
|
+
ANALYZER_ARGS = KernelAnalyzerArgs
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
#
|
|
3
|
+
# MIT License
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
###############################################################################
|
|
26
|
+
|
|
27
|
+
from nodescraper.models import DataModel
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class KernelDataModel(DataModel):
|
|
31
|
+
kernel_info: str
|
|
32
|
+
kernel_version: str
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
#
|
|
3
|
+
# MIT License
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
###############################################################################
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
#
|
|
3
|
+
# MIT License
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
###############################################################################
|
|
26
|
+
import re
|
|
27
|
+
|
|
28
|
+
from nodescraper.models import AnalyzerArgs
|
|
29
|
+
from nodescraper.plugins.inband.kernel_module.kernel_module_data import (
|
|
30
|
+
KernelModuleDataModel,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class KernelModuleAnalyzerArgs(AnalyzerArgs):
|
|
35
|
+
kernel_modules: dict[str, dict] = {}
|
|
36
|
+
regex_filter: list[str] = ["amd"]
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def build_from_model(cls, datamodel: KernelModuleDataModel) -> "KernelModuleAnalyzerArgs":
|
|
40
|
+
"""build analyzer args from data model and filter by regex_filter
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
datamodel (KernelModuleDataModel): data model for plugin
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
KernelModuleAnalyzerArgs: instance of analyzer args class
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
pattern_regex = re.compile("amd", re.IGNORECASE)
|
|
50
|
+
filtered_mods = {
|
|
51
|
+
name: data
|
|
52
|
+
for name, data in datamodel.kernel_modules.items()
|
|
53
|
+
if pattern_regex.search(name)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return cls(
|
|
57
|
+
kernel_modules=filtered_mods,
|
|
58
|
+
regex_filter=[],
|
|
59
|
+
)
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
#
|
|
3
|
+
# MIT License
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
###############################################################################
|
|
26
|
+
import re
|
|
27
|
+
from typing import Optional
|
|
28
|
+
|
|
29
|
+
from nodescraper.enums import EventCategory, EventPriority, ExecutionStatus
|
|
30
|
+
from nodescraper.interfaces import DataAnalyzer
|
|
31
|
+
from nodescraper.models import TaskResult
|
|
32
|
+
|
|
33
|
+
from .analyzer_args import KernelModuleAnalyzerArgs
|
|
34
|
+
from .kernel_module_data import KernelModuleDataModel
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class KernelModuleAnalyzer(DataAnalyzer[KernelModuleDataModel, KernelModuleAnalyzerArgs]):
|
|
38
|
+
"""Check kernel matches expected versions"""
|
|
39
|
+
|
|
40
|
+
DATA_MODEL = KernelModuleDataModel
|
|
41
|
+
|
|
42
|
+
def filter_modules_by_pattern(
|
|
43
|
+
self, modules: dict[str, dict], patterns: list[str] = None
|
|
44
|
+
) -> tuple[dict[str, dict], list[str]]:
|
|
45
|
+
"""Filter modules by pattern
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
modules (dict[str, dict]): modules to be filtered
|
|
49
|
+
patterns (list[str], optional): pattern to us. Defaults to None.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
tuple[dict[str, dict], list[str]]: tuple - dict of modules filtered,
|
|
53
|
+
list of unmatched pattern
|
|
54
|
+
"""
|
|
55
|
+
if patterns is None:
|
|
56
|
+
return modules, []
|
|
57
|
+
|
|
58
|
+
matched_modules = {}
|
|
59
|
+
unmatched_patterns = []
|
|
60
|
+
|
|
61
|
+
pattern_match_flags = {p: False for p in patterns}
|
|
62
|
+
|
|
63
|
+
for mod_name in modules:
|
|
64
|
+
for p in patterns:
|
|
65
|
+
if re.search(p, mod_name, re.IGNORECASE):
|
|
66
|
+
matched_modules[mod_name] = modules[mod_name]
|
|
67
|
+
pattern_match_flags[p] = True
|
|
68
|
+
break
|
|
69
|
+
|
|
70
|
+
unmatched_patterns = [p for p, matched in pattern_match_flags.items() if not matched]
|
|
71
|
+
|
|
72
|
+
return matched_modules, unmatched_patterns
|
|
73
|
+
|
|
74
|
+
def filter_modules_by_name_and_param(
|
|
75
|
+
self, modules: dict[str, dict], to_match: dict[str, dict]
|
|
76
|
+
) -> tuple[dict[str, dict], dict[str, dict]]:
|
|
77
|
+
"""Filter modules by name, param and value
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
modules (dict[str, dict]): modules to be filtered
|
|
81
|
+
to_match (dict[str, dict]): modules to match
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
tuple[dict[str, dict], dict[str, dict]]: tuple - dict of modules filtered,
|
|
85
|
+
dict of modules unmatched
|
|
86
|
+
"""
|
|
87
|
+
if not to_match:
|
|
88
|
+
return modules, {}
|
|
89
|
+
|
|
90
|
+
filtered = {}
|
|
91
|
+
unmatched = {}
|
|
92
|
+
|
|
93
|
+
for mod_name, expected_data in to_match.items():
|
|
94
|
+
expected_params = expected_data.get("parameters", {})
|
|
95
|
+
actual_data = modules.get(mod_name)
|
|
96
|
+
|
|
97
|
+
if not actual_data:
|
|
98
|
+
unmatched[mod_name] = expected_data
|
|
99
|
+
continue
|
|
100
|
+
|
|
101
|
+
actual_params = actual_data.get("parameters", {})
|
|
102
|
+
param_mismatches = {}
|
|
103
|
+
|
|
104
|
+
for param, expected_val in expected_params.items():
|
|
105
|
+
actual_val = actual_params.get(param)
|
|
106
|
+
if actual_val != expected_val:
|
|
107
|
+
param_mismatches[param] = {
|
|
108
|
+
"expected": expected_val,
|
|
109
|
+
"actual": actual_val if actual_val is not None else "<missing>",
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if param_mismatches:
|
|
113
|
+
unmatched[mod_name] = {"parameters": param_mismatches}
|
|
114
|
+
else:
|
|
115
|
+
filtered[mod_name] = actual_data
|
|
116
|
+
|
|
117
|
+
return filtered, unmatched
|
|
118
|
+
|
|
119
|
+
def analyze_data(
|
|
120
|
+
self, data: KernelModuleDataModel, args: Optional[KernelModuleAnalyzerArgs] = None
|
|
121
|
+
) -> TaskResult:
|
|
122
|
+
"""Analyze the kernel modules and associated parameters.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
data (KernelModuleDataModel): KernelModule data to analyze.
|
|
126
|
+
args (Optional[KernelModuleAnalyzerArgs], optional): KernelModule analyzer args.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
TaskResult: Result of the analysis containing status and message.
|
|
130
|
+
"""
|
|
131
|
+
if not args:
|
|
132
|
+
args = KernelModuleAnalyzerArgs()
|
|
133
|
+
else:
|
|
134
|
+
if args.regex_filter and args.kernel_modules:
|
|
135
|
+
self.logger.warning(
|
|
136
|
+
"Both regex_filter and kernel_modules provided in analyzer args. kernel_modules will be ignored"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
self.result.status = ExecutionStatus.OK
|
|
140
|
+
|
|
141
|
+
if args.regex_filter:
|
|
142
|
+
try:
|
|
143
|
+
filtered_modules, unmatched_pattern = self.filter_modules_by_pattern(
|
|
144
|
+
data.kernel_modules, args.regex_filter
|
|
145
|
+
)
|
|
146
|
+
except re.error:
|
|
147
|
+
self._log_event(
|
|
148
|
+
category=EventCategory.RUNTIME,
|
|
149
|
+
description="KernelModule regex is invalid",
|
|
150
|
+
data={"regex_filters": {args.regex_filter}},
|
|
151
|
+
priority=EventPriority.ERROR,
|
|
152
|
+
)
|
|
153
|
+
self.result.message = (
|
|
154
|
+
f"Kernel modules failed to match regex. Regex: {args.regex_filter}"
|
|
155
|
+
)
|
|
156
|
+
self.result.status = ExecutionStatus.ERROR
|
|
157
|
+
return self.result
|
|
158
|
+
|
|
159
|
+
if unmatched_pattern:
|
|
160
|
+
self._log_event(
|
|
161
|
+
category=EventCategory.RUNTIME,
|
|
162
|
+
description="KernelModules did not match all patterns",
|
|
163
|
+
data={"unmatched_pattern: ": unmatched_pattern},
|
|
164
|
+
priority=EventPriority.INFO,
|
|
165
|
+
)
|
|
166
|
+
self.result.message = f"Kernel modules failed to match every pattern. Unmatched patterns: {unmatched_pattern}"
|
|
167
|
+
self.result.status = ExecutionStatus.ERROR
|
|
168
|
+
return self.result
|
|
169
|
+
|
|
170
|
+
self._log_event(
|
|
171
|
+
category=EventCategory.OS,
|
|
172
|
+
description="KernelModules analyzed",
|
|
173
|
+
data={"filtered_modules": filtered_modules},
|
|
174
|
+
priority=EventPriority.INFO,
|
|
175
|
+
)
|
|
176
|
+
return self.result
|
|
177
|
+
|
|
178
|
+
elif args.kernel_modules:
|
|
179
|
+
filtered_modules, not_matched = self.filter_modules_by_name_and_param(
|
|
180
|
+
data.kernel_modules, args.kernel_modules
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# no modules matched
|
|
184
|
+
if not filtered_modules and not_matched:
|
|
185
|
+
self._log_event(
|
|
186
|
+
category=EventCategory.RUNTIME,
|
|
187
|
+
description="KernelModules: no modules matched",
|
|
188
|
+
data=args.kernel_modules,
|
|
189
|
+
priority=EventPriority.ERROR,
|
|
190
|
+
)
|
|
191
|
+
self.result.message = f"Kernel modules not matched: {not_matched}"
|
|
192
|
+
self.result.status = ExecutionStatus.ERROR
|
|
193
|
+
return self.result
|
|
194
|
+
# some modules matched
|
|
195
|
+
elif filtered_modules and not_matched:
|
|
196
|
+
|
|
197
|
+
self._log_event(
|
|
198
|
+
category=EventCategory.RUNTIME,
|
|
199
|
+
description="KernelModules: not all modules matched",
|
|
200
|
+
data=not_matched,
|
|
201
|
+
priority=EventPriority.ERROR,
|
|
202
|
+
)
|
|
203
|
+
self.result.message = f"Kernel modules not matched: {not_matched}"
|
|
204
|
+
self.result.status = ExecutionStatus.ERROR
|
|
205
|
+
return self.result
|
|
206
|
+
else:
|
|
207
|
+
self.result.message = (
|
|
208
|
+
"No values provided in analysis args for: kernel_modules and regex_match"
|
|
209
|
+
)
|
|
210
|
+
self.result.status = ExecutionStatus.NOT_RAN
|
|
211
|
+
return self.result
|