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.
Files changed (197) hide show
  1. amd_node_scraper-0.0.1.dist-info/LICENSE +21 -0
  2. amd_node_scraper-0.0.1.dist-info/METADATA +424 -0
  3. amd_node_scraper-0.0.1.dist-info/RECORD +197 -0
  4. amd_node_scraper-0.0.1.dist-info/WHEEL +5 -0
  5. amd_node_scraper-0.0.1.dist-info/entry_points.txt +2 -0
  6. amd_node_scraper-0.0.1.dist-info/top_level.txt +1 -0
  7. nodescraper/__init__.py +32 -0
  8. nodescraper/base/__init__.py +34 -0
  9. nodescraper/base/inbandcollectortask.py +118 -0
  10. nodescraper/base/inbanddataplugin.py +39 -0
  11. nodescraper/base/regexanalyzer.py +120 -0
  12. nodescraper/cli/__init__.py +29 -0
  13. nodescraper/cli/cli.py +511 -0
  14. nodescraper/cli/constants.py +27 -0
  15. nodescraper/cli/dynamicparserbuilder.py +171 -0
  16. nodescraper/cli/helper.py +517 -0
  17. nodescraper/cli/inputargtypes.py +129 -0
  18. nodescraper/configbuilder.py +123 -0
  19. nodescraper/configregistry.py +66 -0
  20. nodescraper/configs/node_status.json +19 -0
  21. nodescraper/connection/__init__.py +25 -0
  22. nodescraper/connection/inband/__init__.py +46 -0
  23. nodescraper/connection/inband/inband.py +171 -0
  24. nodescraper/connection/inband/inbandlocal.py +93 -0
  25. nodescraper/connection/inband/inbandmanager.py +151 -0
  26. nodescraper/connection/inband/inbandremote.py +173 -0
  27. nodescraper/connection/inband/sshparams.py +43 -0
  28. nodescraper/constants.py +26 -0
  29. nodescraper/enums/__init__.py +40 -0
  30. nodescraper/enums/eventcategory.py +89 -0
  31. nodescraper/enums/eventpriority.py +42 -0
  32. nodescraper/enums/executionstatus.py +44 -0
  33. nodescraper/enums/osfamily.py +34 -0
  34. nodescraper/enums/systeminteraction.py +41 -0
  35. nodescraper/enums/systemlocation.py +33 -0
  36. nodescraper/generictypes.py +36 -0
  37. nodescraper/interfaces/__init__.py +44 -0
  38. nodescraper/interfaces/connectionmanager.py +143 -0
  39. nodescraper/interfaces/dataanalyzertask.py +138 -0
  40. nodescraper/interfaces/datacollectortask.py +185 -0
  41. nodescraper/interfaces/dataplugin.py +356 -0
  42. nodescraper/interfaces/plugin.py +127 -0
  43. nodescraper/interfaces/resultcollator.py +56 -0
  44. nodescraper/interfaces/task.py +164 -0
  45. nodescraper/interfaces/taskresulthook.py +39 -0
  46. nodescraper/models/__init__.py +48 -0
  47. nodescraper/models/analyzerargs.py +93 -0
  48. nodescraper/models/collectorargs.py +30 -0
  49. nodescraper/models/connectionconfig.py +34 -0
  50. nodescraper/models/datamodel.py +171 -0
  51. nodescraper/models/datapluginresult.py +39 -0
  52. nodescraper/models/event.py +158 -0
  53. nodescraper/models/pluginconfig.py +38 -0
  54. nodescraper/models/pluginresult.py +39 -0
  55. nodescraper/models/systeminfo.py +44 -0
  56. nodescraper/models/taskresult.py +185 -0
  57. nodescraper/models/timerangeargs.py +38 -0
  58. nodescraper/pluginexecutor.py +274 -0
  59. nodescraper/pluginregistry.py +152 -0
  60. nodescraper/plugins/__init__.py +25 -0
  61. nodescraper/plugins/inband/__init__.py +25 -0
  62. nodescraper/plugins/inband/amdsmi/__init__.py +28 -0
  63. nodescraper/plugins/inband/amdsmi/amdsmi_analyzer.py +821 -0
  64. nodescraper/plugins/inband/amdsmi/amdsmi_collector.py +1313 -0
  65. nodescraper/plugins/inband/amdsmi/amdsmi_plugin.py +43 -0
  66. nodescraper/plugins/inband/amdsmi/amdsmidata.py +1002 -0
  67. nodescraper/plugins/inband/amdsmi/analyzer_args.py +50 -0
  68. nodescraper/plugins/inband/amdsmi/cper.py +65 -0
  69. nodescraper/plugins/inband/bios/__init__.py +29 -0
  70. nodescraper/plugins/inband/bios/analyzer_args.py +64 -0
  71. nodescraper/plugins/inband/bios/bios_analyzer.py +93 -0
  72. nodescraper/plugins/inband/bios/bios_collector.py +93 -0
  73. nodescraper/plugins/inband/bios/bios_plugin.py +43 -0
  74. nodescraper/plugins/inband/bios/biosdata.py +30 -0
  75. nodescraper/plugins/inband/cmdline/__init__.py +25 -0
  76. nodescraper/plugins/inband/cmdline/analyzer_args.py +80 -0
  77. nodescraper/plugins/inband/cmdline/cmdline_analyzer.py +113 -0
  78. nodescraper/plugins/inband/cmdline/cmdline_collector.py +77 -0
  79. nodescraper/plugins/inband/cmdline/cmdline_plugin.py +43 -0
  80. nodescraper/plugins/inband/cmdline/cmdlinedata.py +30 -0
  81. nodescraper/plugins/inband/device_enumeration/__init__.py +29 -0
  82. nodescraper/plugins/inband/device_enumeration/analyzer_args.py +73 -0
  83. nodescraper/plugins/inband/device_enumeration/device_enumeration_analyzer.py +81 -0
  84. nodescraper/plugins/inband/device_enumeration/device_enumeration_collector.py +176 -0
  85. nodescraper/plugins/inband/device_enumeration/device_enumeration_plugin.py +45 -0
  86. nodescraper/plugins/inband/device_enumeration/deviceenumdata.py +36 -0
  87. nodescraper/plugins/inband/dimm/__init__.py +25 -0
  88. nodescraper/plugins/inband/dimm/collector_args.py +31 -0
  89. nodescraper/plugins/inband/dimm/dimm_collector.py +151 -0
  90. nodescraper/plugins/inband/dimm/dimm_plugin.py +40 -0
  91. nodescraper/plugins/inband/dimm/dimmdata.py +30 -0
  92. nodescraper/plugins/inband/dkms/__init__.py +25 -0
  93. nodescraper/plugins/inband/dkms/analyzer_args.py +85 -0
  94. nodescraper/plugins/inband/dkms/dkms_analyzer.py +106 -0
  95. nodescraper/plugins/inband/dkms/dkms_collector.py +76 -0
  96. nodescraper/plugins/inband/dkms/dkms_plugin.py +43 -0
  97. nodescraper/plugins/inband/dkms/dkmsdata.py +33 -0
  98. nodescraper/plugins/inband/dmesg/__init__.py +28 -0
  99. nodescraper/plugins/inband/dmesg/analyzer_args.py +33 -0
  100. nodescraper/plugins/inband/dmesg/collector_args.py +39 -0
  101. nodescraper/plugins/inband/dmesg/dmesg_analyzer.py +503 -0
  102. nodescraper/plugins/inband/dmesg/dmesg_collector.py +164 -0
  103. nodescraper/plugins/inband/dmesg/dmesg_plugin.py +44 -0
  104. nodescraper/plugins/inband/dmesg/dmesgdata.py +116 -0
  105. nodescraper/plugins/inband/fabrics/__init__.py +28 -0
  106. nodescraper/plugins/inband/fabrics/fabrics_collector.py +726 -0
  107. nodescraper/plugins/inband/fabrics/fabrics_plugin.py +37 -0
  108. nodescraper/plugins/inband/fabrics/fabricsdata.py +140 -0
  109. nodescraper/plugins/inband/journal/__init__.py +28 -0
  110. nodescraper/plugins/inband/journal/collector_args.py +33 -0
  111. nodescraper/plugins/inband/journal/journal_collector.py +107 -0
  112. nodescraper/plugins/inband/journal/journal_plugin.py +40 -0
  113. nodescraper/plugins/inband/journal/journaldata.py +44 -0
  114. nodescraper/plugins/inband/kernel/__init__.py +25 -0
  115. nodescraper/plugins/inband/kernel/analyzer_args.py +64 -0
  116. nodescraper/plugins/inband/kernel/kernel_analyzer.py +91 -0
  117. nodescraper/plugins/inband/kernel/kernel_collector.py +129 -0
  118. nodescraper/plugins/inband/kernel/kernel_plugin.py +43 -0
  119. nodescraper/plugins/inband/kernel/kerneldata.py +32 -0
  120. nodescraper/plugins/inband/kernel_module/__init__.py +25 -0
  121. nodescraper/plugins/inband/kernel_module/analyzer_args.py +59 -0
  122. nodescraper/plugins/inband/kernel_module/kernel_module_analyzer.py +211 -0
  123. nodescraper/plugins/inband/kernel_module/kernel_module_collector.py +264 -0
  124. nodescraper/plugins/inband/kernel_module/kernel_module_data.py +60 -0
  125. nodescraper/plugins/inband/kernel_module/kernel_module_plugin.py +43 -0
  126. nodescraper/plugins/inband/memory/__init__.py +25 -0
  127. nodescraper/plugins/inband/memory/analyzer_args.py +45 -0
  128. nodescraper/plugins/inband/memory/memory_analyzer.py +98 -0
  129. nodescraper/plugins/inband/memory/memory_collector.py +330 -0
  130. nodescraper/plugins/inband/memory/memory_plugin.py +43 -0
  131. nodescraper/plugins/inband/memory/memorydata.py +90 -0
  132. nodescraper/plugins/inband/network/__init__.py +28 -0
  133. nodescraper/plugins/inband/network/network_collector.py +1828 -0
  134. nodescraper/plugins/inband/network/network_plugin.py +37 -0
  135. nodescraper/plugins/inband/network/networkdata.py +319 -0
  136. nodescraper/plugins/inband/nvme/__init__.py +28 -0
  137. nodescraper/plugins/inband/nvme/nvme_collector.py +167 -0
  138. nodescraper/plugins/inband/nvme/nvme_plugin.py +37 -0
  139. nodescraper/plugins/inband/nvme/nvmedata.py +45 -0
  140. nodescraper/plugins/inband/os/__init__.py +25 -0
  141. nodescraper/plugins/inband/os/analyzer_args.py +64 -0
  142. nodescraper/plugins/inband/os/os_analyzer.py +73 -0
  143. nodescraper/plugins/inband/os/os_collector.py +131 -0
  144. nodescraper/plugins/inband/os/os_plugin.py +43 -0
  145. nodescraper/plugins/inband/os/osdata.py +31 -0
  146. nodescraper/plugins/inband/package/__init__.py +25 -0
  147. nodescraper/plugins/inband/package/analyzer_args.py +48 -0
  148. nodescraper/plugins/inband/package/package_analyzer.py +253 -0
  149. nodescraper/plugins/inband/package/package_collector.py +273 -0
  150. nodescraper/plugins/inband/package/package_plugin.py +43 -0
  151. nodescraper/plugins/inband/package/packagedata.py +41 -0
  152. nodescraper/plugins/inband/pcie/__init__.py +29 -0
  153. nodescraper/plugins/inband/pcie/analyzer_args.py +63 -0
  154. nodescraper/plugins/inband/pcie/pcie_analyzer.py +1081 -0
  155. nodescraper/plugins/inband/pcie/pcie_collector.py +690 -0
  156. nodescraper/plugins/inband/pcie/pcie_data.py +2017 -0
  157. nodescraper/plugins/inband/pcie/pcie_plugin.py +43 -0
  158. nodescraper/plugins/inband/process/__init__.py +25 -0
  159. nodescraper/plugins/inband/process/analyzer_args.py +45 -0
  160. nodescraper/plugins/inband/process/collector_args.py +31 -0
  161. nodescraper/plugins/inband/process/process_analyzer.py +91 -0
  162. nodescraper/plugins/inband/process/process_collector.py +115 -0
  163. nodescraper/plugins/inband/process/process_plugin.py +46 -0
  164. nodescraper/plugins/inband/process/processdata.py +34 -0
  165. nodescraper/plugins/inband/rocm/__init__.py +25 -0
  166. nodescraper/plugins/inband/rocm/analyzer_args.py +66 -0
  167. nodescraper/plugins/inband/rocm/rocm_analyzer.py +100 -0
  168. nodescraper/plugins/inband/rocm/rocm_collector.py +205 -0
  169. nodescraper/plugins/inband/rocm/rocm_plugin.py +43 -0
  170. nodescraper/plugins/inband/rocm/rocmdata.py +62 -0
  171. nodescraper/plugins/inband/storage/__init__.py +25 -0
  172. nodescraper/plugins/inband/storage/analyzer_args.py +38 -0
  173. nodescraper/plugins/inband/storage/collector_args.py +31 -0
  174. nodescraper/plugins/inband/storage/storage_analyzer.py +152 -0
  175. nodescraper/plugins/inband/storage/storage_collector.py +110 -0
  176. nodescraper/plugins/inband/storage/storage_plugin.py +44 -0
  177. nodescraper/plugins/inband/storage/storagedata.py +70 -0
  178. nodescraper/plugins/inband/sysctl/__init__.py +29 -0
  179. nodescraper/plugins/inband/sysctl/analyzer_args.py +67 -0
  180. nodescraper/plugins/inband/sysctl/sysctl_analyzer.py +81 -0
  181. nodescraper/plugins/inband/sysctl/sysctl_collector.py +101 -0
  182. nodescraper/plugins/inband/sysctl/sysctl_plugin.py +43 -0
  183. nodescraper/plugins/inband/sysctl/sysctldata.py +42 -0
  184. nodescraper/plugins/inband/syslog/__init__.py +28 -0
  185. nodescraper/plugins/inband/syslog/syslog_collector.py +121 -0
  186. nodescraper/plugins/inband/syslog/syslog_plugin.py +37 -0
  187. nodescraper/plugins/inband/syslog/syslogdata.py +46 -0
  188. nodescraper/plugins/inband/uptime/__init__.py +25 -0
  189. nodescraper/plugins/inband/uptime/uptime_collector.py +88 -0
  190. nodescraper/plugins/inband/uptime/uptime_plugin.py +37 -0
  191. nodescraper/plugins/inband/uptime/uptimedata.py +31 -0
  192. nodescraper/resultcollators/__init__.py +25 -0
  193. nodescraper/resultcollators/tablesummary.py +159 -0
  194. nodescraper/taskresulthooks/__init__.py +28 -0
  195. nodescraper/taskresulthooks/filesystemloghook.py +88 -0
  196. nodescraper/typeutils.py +171 -0
  197. nodescraper/utils.py +412 -0
@@ -0,0 +1,37 @@
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 .fabrics_collector import FabricsCollector
29
+ from .fabricsdata import FabricsDataModel
30
+
31
+
32
+ class FabricsPlugin(InBandDataPlugin[FabricsDataModel, None, None]):
33
+ """Plugin for collection of InfiniBand/RDMA fabrics configuration data"""
34
+
35
+ DATA_MODEL = FabricsDataModel
36
+
37
+ COLLECTOR = FabricsCollector
@@ -0,0 +1,140 @@
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 typing import Dict, List, Optional
27
+
28
+ from pydantic import BaseModel, Field
29
+
30
+ from nodescraper.models import DataModel
31
+
32
+
33
+ class IbstatDevice(BaseModel):
34
+ """InfiniBand device information from ibstat"""
35
+
36
+ ca_name: Optional[str] = None # CA name (e.g., "mlx5_0")
37
+ ca_type: Optional[str] = None # CA type
38
+ number_of_ports: Optional[int] = None # Number of physical ports
39
+ firmware_version: Optional[str] = None # Firmware version
40
+ hardware_version: Optional[str] = None # Hardware version
41
+ node_guid: Optional[str] = None # Node GUID
42
+ system_image_guid: Optional[str] = None # System image GUID
43
+ ports: Dict[int, Dict[str, str]] = Field(default_factory=dict) # Port number -> port attributes
44
+ raw_output: str = "" # Raw command output
45
+
46
+
47
+ class IbvDeviceInfo(BaseModel):
48
+ """InfiniBand verbs device information from ibv_devinfo"""
49
+
50
+ device: Optional[str] = None # Device name (e.g., "mlx5_0")
51
+ node_guid: Optional[str] = None # Node GUID
52
+ sys_image_guid: Optional[str] = None # System image GUID
53
+ vendor_id: Optional[str] = None # Vendor ID
54
+ vendor_part_id: Optional[str] = None # Vendor part ID
55
+ hw_ver: Optional[str] = None # Hardware version
56
+ fw_ver: Optional[str] = None # Firmware version
57
+ node_type: Optional[str] = None # Node type
58
+ transport_type: Optional[str] = None # Transport type (e.g., "InfiniBand", "Ethernet")
59
+ ports: Dict[int, Dict[str, str]] = Field(default_factory=dict) # Port number -> port attributes
60
+ raw_output: str = "" # Raw command output
61
+
62
+
63
+ class IbdevNetdevMapping(BaseModel):
64
+ """Mapping between IB device and network interface"""
65
+
66
+ ib_device: str # InfiniBand device name (e.g., "mlx5_0")
67
+ port: int # Port number
68
+ netdev: Optional[str] = None # Network device name (e.g., "ib0", "eth0")
69
+ state: Optional[str] = None # Port state (e.g., "Up", "Down")
70
+ pkey: Optional[str] = None # Partition key
71
+ guid: Optional[str] = None # GUID
72
+
73
+
74
+ class OfedInfo(BaseModel):
75
+ """OFED version and information"""
76
+
77
+ version: Optional[str] = None # OFED version
78
+ raw_output: str = "" # Raw command output
79
+
80
+
81
+ class MstDevice(BaseModel):
82
+ """Mellanox Software Tools device information"""
83
+
84
+ device: str # Device path (e.g., "/dev/mst/mt4123_pciconf0")
85
+ pci_address: Optional[str] = None # PCI address
86
+ rdma_device: Optional[str] = None # RDMA device name
87
+ net_device: Optional[str] = None # Network device name
88
+ attributes: Dict[str, str] = Field(default_factory=dict) # Additional attributes
89
+
90
+
91
+ class MstStatus(BaseModel):
92
+ """Mellanox Software Tools status"""
93
+
94
+ mst_started: bool = False # Whether MST service is started
95
+ devices: List[MstDevice] = Field(default_factory=list) # List of MST devices
96
+ raw_output: str = "" # Raw command output
97
+
98
+
99
+ class RdmaDevice(BaseModel):
100
+ """RDMA device information from rdma command"""
101
+
102
+ device: str # Device name (e.g., "mlx5_0")
103
+ node_type: Optional[str] = None # Node type
104
+ transport: Optional[str] = None # Transport type
105
+ node_guid: Optional[str] = None # Node GUID
106
+ sys_image_guid: Optional[str] = None # System image GUID
107
+ state: Optional[str] = None # Device state
108
+ attributes: Dict[str, str] = Field(default_factory=dict) # Additional attributes
109
+
110
+
111
+ class RdmaLink(BaseModel):
112
+ """RDMA link information"""
113
+
114
+ device: str # Device name
115
+ port: int # Port number
116
+ state: Optional[str] = None # Link state
117
+ physical_state: Optional[str] = None # Physical state
118
+ netdev: Optional[str] = None # Associated network device
119
+ attributes: Dict[str, str] = Field(default_factory=dict) # Additional attributes
120
+
121
+
122
+ class RdmaInfo(BaseModel):
123
+ """Complete RDMA information from rdma command"""
124
+
125
+ devices: List[RdmaDevice] = Field(default_factory=list) # RDMA devices
126
+ links: List[RdmaLink] = Field(default_factory=list) # RDMA links
127
+ raw_output: str = "" # Raw command output
128
+
129
+
130
+ class FabricsDataModel(DataModel):
131
+ """Complete InfiniBand/RDMA fabrics configuration data"""
132
+
133
+ ibstat_devices: List[IbstatDevice] = Field(default_factory=list) # ibstat output
134
+ ibv_devices: List[IbvDeviceInfo] = Field(default_factory=list) # ibv_devinfo output
135
+ ibdev_netdev_mappings: List[IbdevNetdevMapping] = Field(
136
+ default_factory=list
137
+ ) # ibdev2netdev output
138
+ ofed_info: Optional[OfedInfo] = None # OFED version info
139
+ mst_status: Optional[MstStatus] = None # MST status
140
+ rdma_info: Optional[RdmaInfo] = None # RDMA information
@@ -0,0 +1,28 @@
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 .journal_plugin import JournalPlugin
27
+
28
+ __all__ = ["JournalPlugin"]
@@ -0,0 +1,33 @@
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 typing import Optional
28
+
29
+ from nodescraper.models import CollectorArgs
30
+
31
+
32
+ class JournalCollectorArgs(CollectorArgs):
33
+ boot: Optional[int] = None
@@ -0,0 +1,107 @@
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 typing import Optional
27
+
28
+ from pydantic import ValidationError
29
+
30
+ from nodescraper.base import InBandDataCollector
31
+ from nodescraper.enums import EventCategory, EventPriority, ExecutionStatus, OSFamily
32
+ from nodescraper.models import TaskResult
33
+ from nodescraper.utils import get_exception_details
34
+
35
+ from .collector_args import JournalCollectorArgs
36
+ from .journaldata import JournalData
37
+
38
+
39
+ class JournalCollector(InBandDataCollector[JournalData, JournalCollectorArgs]):
40
+ """Read journal log via journalctl."""
41
+
42
+ SUPPORTED_OS_FAMILY = {OSFamily.LINUX}
43
+ DATA_MODEL = JournalData
44
+ CMD = "journalctl --no-pager --system --output=short-iso"
45
+
46
+ def _read_with_journalctl(self, args: Optional[JournalCollectorArgs] = None):
47
+ """Read journal logs using journalctl
48
+
49
+ Returns:
50
+ str|None: system journal read
51
+ """
52
+
53
+ cmd = "journalctl --no-pager --system --output=short-iso"
54
+ try:
55
+ # safe check for args.boot
56
+ if args is not None and getattr(args, "boot", None):
57
+ cmd = f"journalctl --no-pager -b {args.boot} --system --output=short-iso"
58
+
59
+ res = self._run_sut_cmd(cmd, sudo=True, log_artifact=False, strip=False)
60
+
61
+ except ValidationError as val_err:
62
+ self._log_event(
63
+ category=EventCategory.OS,
64
+ description="Exception while running journalctl",
65
+ data=get_exception_details(val_err),
66
+ priority=EventPriority.ERROR,
67
+ console_log=True,
68
+ )
69
+ self.result.message = "Could not read journalctl data"
70
+ self.result.status = ExecutionStatus.ERROR
71
+ return None
72
+
73
+ if res.exit_code != 0:
74
+ self._log_event(
75
+ category=EventCategory.OS,
76
+ description="Error reading journalctl",
77
+ data={"command": res.command, "exit_code": res.exit_code},
78
+ priority=EventPriority.ERROR,
79
+ console_log=True,
80
+ )
81
+ self.result.message = "Could not read journalctl data"
82
+ self.result.status = ExecutionStatus.ERROR
83
+ return None
84
+
85
+ return res.stdout
86
+
87
+ def collect_data(
88
+ self,
89
+ args: Optional[JournalCollectorArgs] = None,
90
+ ) -> tuple[TaskResult, Optional[JournalData]]:
91
+ """Collect journal logs
92
+
93
+ Args:
94
+ args (_type_, optional): Collection args. Defaults to None.
95
+
96
+ Returns:
97
+ tuple[TaskResult, Optional[JournalData]]: Tuple of results and data model or none.
98
+ """
99
+ if args is None:
100
+ args = JournalCollectorArgs()
101
+
102
+ journal_log = self._read_with_journalctl(args)
103
+ if journal_log:
104
+ data = JournalData(journal_log=journal_log)
105
+ self.result.message = self.result.message or "Journal data collected"
106
+ return self.result, data
107
+ return self.result, None
@@ -0,0 +1,40 @@
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 .collector_args import JournalCollectorArgs
29
+ from .journal_collector import JournalCollector
30
+ from .journaldata import JournalData
31
+
32
+
33
+ class JournalPlugin(InBandDataPlugin[JournalData, JournalCollectorArgs, None]):
34
+ """Plugin for collection of journal data"""
35
+
36
+ DATA_MODEL = JournalData
37
+
38
+ COLLECTOR = JournalCollector
39
+
40
+ COLLECTOR_ARGS = JournalCollectorArgs
@@ -0,0 +1,44 @@
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 os
27
+
28
+ from nodescraper.models import DataModel
29
+
30
+
31
+ class JournalData(DataModel):
32
+ """Data model for journal logs"""
33
+
34
+ journal_log: str
35
+
36
+ def log_model(self, log_path: str):
37
+ """Log data model to a file
38
+
39
+ Args:
40
+ log_path (str): log path
41
+ """
42
+ log_name = os.path.join(log_path, "journal.log")
43
+ with open(log_name, "w", encoding="utf-8") as log_filename:
44
+ log_filename.write(self.journal_log)
@@ -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,64 @@
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 typing import Union
27
+
28
+ from pydantic import Field, field_validator
29
+
30
+ from nodescraper.models import AnalyzerArgs
31
+ from nodescraper.plugins.inband.kernel.kerneldata import KernelDataModel
32
+
33
+
34
+ class KernelAnalyzerArgs(AnalyzerArgs):
35
+ exp_kernel: Union[str, list] = Field(default_factory=list)
36
+ regex_match: bool = False
37
+
38
+ @field_validator("exp_kernel", mode="before")
39
+ @classmethod
40
+ def validate_exp_kernel(cls, exp_kernel: Union[str, list]) -> list:
41
+ """support str or list input for exp_kernel
42
+
43
+ Args:
44
+ exp_kernel (Union[str, list]): exp kernel input
45
+
46
+ Returns:
47
+ list: exp kernel list
48
+ """
49
+ if isinstance(exp_kernel, str):
50
+ exp_kernel = [exp_kernel]
51
+
52
+ return exp_kernel
53
+
54
+ @classmethod
55
+ def build_from_model(cls, datamodel: KernelDataModel) -> "KernelAnalyzerArgs":
56
+ """build analyzer args from data model
57
+
58
+ Args:
59
+ datamodel (KernelDataModel): data model for plugin
60
+
61
+ Returns:
62
+ KernelAnalyzerArgs: instance of analyzer args class
63
+ """
64
+ return cls(exp_kernel=datamodel.kernel_version)
@@ -0,0 +1,91 @@
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 KernelAnalyzerArgs
34
+ from .kerneldata import KernelDataModel
35
+
36
+
37
+ class KernelAnalyzer(DataAnalyzer[KernelDataModel, KernelAnalyzerArgs]):
38
+ """Check kernel matches expected versions"""
39
+
40
+ DATA_MODEL = KernelDataModel
41
+
42
+ def analyze_data(
43
+ self, data: KernelDataModel, args: Optional[KernelAnalyzerArgs] = None
44
+ ) -> TaskResult:
45
+ """Analyze the kernel data against expected versions.
46
+
47
+ Args:
48
+ data (KernelDataModel): Kernel data to analyze.
49
+ args (Optional[KernelAnalyzerArgs], optional): Kernel analysis arguments. Defaults to None.
50
+
51
+ Returns:
52
+ TaskResult: Result of the analysis containing status and message.
53
+ """
54
+ if not args:
55
+ self.result.message = "Expected kernel not provided"
56
+ self.result.status = ExecutionStatus.NOT_RAN
57
+ return self.result
58
+
59
+ for kernel in args.exp_kernel:
60
+ if args.regex_match:
61
+ try:
62
+ regex_data = re.compile(kernel)
63
+ except re.error:
64
+ self._log_event(
65
+ category=EventCategory.RUNTIME,
66
+ description="Kernel regex is invalid",
67
+ data={"regex": kernel},
68
+ priority=EventPriority.ERROR,
69
+ )
70
+ continue
71
+ if regex_data.match(data.kernel_version):
72
+ self.result.message = "Kernel matches expected"
73
+ self.result.status = ExecutionStatus.OK
74
+ return self.result
75
+ elif data.kernel_version == kernel:
76
+ self.result.message = "Kernel matches expected"
77
+ self.result.status = ExecutionStatus.OK
78
+ return self.result
79
+
80
+ self.result.message = (
81
+ f"Kernel mismatch! Expected: {args.exp_kernel}, actual: {data.kernel_version}"
82
+ )
83
+ self.result.status = ExecutionStatus.ERROR
84
+ self._log_event(
85
+ category=EventCategory.OS,
86
+ description=f"{self.result.message}",
87
+ data={"expected": args.exp_kernel, "actual": data.kernel_version},
88
+ priority=EventPriority.CRITICAL,
89
+ console_log=True,
90
+ )
91
+ return self.result