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 .network_collector import NetworkCollector
29
+ from .networkdata import NetworkDataModel
30
+
31
+
32
+ class NetworkPlugin(InBandDataPlugin[NetworkDataModel, None, None]):
33
+ """Plugin for collection of network configuration data"""
34
+
35
+ DATA_MODEL = NetworkDataModel
36
+
37
+ COLLECTOR = NetworkCollector
@@ -0,0 +1,319 @@
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 IpAddress(BaseModel):
34
+ """Individual IP address on an interface"""
35
+
36
+ address: str # "192.168.1.100"
37
+ prefix_len: Optional[int] = None # 24
38
+ scope: Optional[str] = None # "global", "link", "host"
39
+ family: Optional[str] = None # "inet", "inet6"
40
+ label: Optional[str] = None # interface label/alias
41
+ broadcast: Optional[str] = None # broadcast address
42
+
43
+
44
+ class NetworkInterface(BaseModel):
45
+ """Network interface information"""
46
+
47
+ name: str # "eth0", "lo", etc
48
+ index: Optional[int] = None # interface index
49
+ state: Optional[str] = None # "UP", "DOWN", "UNKNOWN"
50
+ mtu: Optional[int] = None # Maximum Transmission Unit
51
+ qdisc: Optional[str] = None # Queuing discipline
52
+ mac_address: Optional[str] = None # MAC/hardware address
53
+ flags: List[str] = Field(default_factory=list) # ["UP", "BROADCAST", "MULTICAST"]
54
+ addresses: List[IpAddress] = Field(default_factory=list) # IP addresses on this interface
55
+
56
+
57
+ class Route(BaseModel):
58
+ """Routing table entry"""
59
+
60
+ destination: str # "default", "192.168.1.0/24", etc
61
+ gateway: Optional[str] = None # Gateway IP
62
+ device: Optional[str] = None # Network interface
63
+ protocol: Optional[str] = None # "kernel", "boot", "static", etc
64
+ scope: Optional[str] = None # "link", "global", "host"
65
+ metric: Optional[int] = None # Route metric/priority
66
+ source: Optional[str] = None # Preferred source address
67
+ table: Optional[str] = None # Routing table name/number
68
+
69
+
70
+ class RoutingRule(BaseModel):
71
+ """Routing policy rule"""
72
+
73
+ priority: int # Rule priority
74
+ source: Optional[str] = None # Source address/network
75
+ destination: Optional[str] = None # Destination address/network
76
+ table: Optional[str] = None # Routing table to use
77
+ action: Optional[str] = None # "lookup", "unreachable", "prohibit", etc
78
+ iif: Optional[str] = None # Input interface
79
+ oif: Optional[str] = None # Output interface
80
+ fwmark: Optional[str] = None # Firewall mark
81
+
82
+
83
+ class Neighbor(BaseModel):
84
+ """ARP/Neighbor table entry"""
85
+
86
+ ip_address: str # IP address of the neighbor
87
+ device: Optional[str] = None # Network interface
88
+ mac_address: Optional[str] = None # Link layer (MAC) address
89
+ state: Optional[str] = None # "REACHABLE", "STALE", "DELAY", "PROBE", "FAILED", "INCOMPLETE"
90
+ flags: List[str] = Field(default_factory=list) # Additional flags like "router", "proxy"
91
+
92
+
93
+ class EthtoolInfo(BaseModel):
94
+ """Ethtool information for a network interface"""
95
+
96
+ interface: str # Interface name this info belongs to
97
+ raw_output: str # Raw ethtool command output
98
+ settings: Dict[str, str] = Field(default_factory=dict) # Parsed key-value settings
99
+ supported_link_modes: List[str] = Field(default_factory=list) # Supported link modes
100
+ advertised_link_modes: List[str] = Field(default_factory=list) # Advertised link modes
101
+ speed: Optional[str] = None # Link speed (e.g., "10000Mb/s")
102
+ duplex: Optional[str] = None # Duplex mode (e.g., "Full")
103
+ port: Optional[str] = None # Port type (e.g., "Twisted Pair")
104
+ auto_negotiation: Optional[str] = None # Auto-negotiation status (e.g., "on", "off")
105
+ link_detected: Optional[str] = None # Link detection status (e.g., "yes", "no")
106
+
107
+
108
+ class BroadcomNicDevice(BaseModel):
109
+ """Broadcom NIC device information from niccli --list_devices"""
110
+
111
+ device_num: int # Device number (1, 2, 3, etc.)
112
+ model: Optional[str] = None # e.g., "Broadcom BCM57608 1x400G QSFP-DD PCIe Ethernet NIC"
113
+ adapter_port: Optional[str] = None # e.g., "Adp#1 Port#1"
114
+ interface_name: Optional[str] = None # e.g., "benic1p1"
115
+ mac_address: Optional[str] = None # e.g., "8C:84:74:37:C3:70"
116
+ pci_address: Optional[str] = None # e.g., "0000:06:00.0"
117
+
118
+
119
+ class BroadcomNicQosAppEntry(BaseModel):
120
+ """APP TLV entry in Broadcom NIC QoS configuration"""
121
+
122
+ priority: Optional[int] = None
123
+ sel: Optional[int] = None
124
+ dscp: Optional[int] = None
125
+ protocol: Optional[str] = None # "UDP or DCCP", etc.
126
+ port: Optional[int] = None
127
+
128
+
129
+ class BroadcomNicQos(BaseModel):
130
+ """Broadcom NIC QoS information from niccli --dev X qos --ets --show"""
131
+
132
+ device_num: int # Device number this QoS info belongs to
133
+ raw_output: str # Raw command output
134
+ # ETS Configuration
135
+ prio_map: Dict[int, int] = Field(
136
+ default_factory=dict
137
+ ) # Priority to TC mapping {0: 0, 1: 0, ...}
138
+ tc_bandwidth: List[int] = Field(
139
+ default_factory=list
140
+ ) # TC bandwidth percentages [50, 50, 0, ...]
141
+ tsa_map: Dict[int, str] = Field(
142
+ default_factory=dict
143
+ ) # TC to TSA mapping {0: "ets", 1: "ets", ...}
144
+ # PFC Configuration
145
+ pfc_enabled: Optional[int] = None # Bitmap of PFC enabled priorities
146
+ # APP TLV entries
147
+ app_entries: List[BroadcomNicQosAppEntry] = Field(default_factory=list)
148
+ # TC Rate Limit
149
+ tc_rate_limit: List[int] = Field(default_factory=list) # TC rate limits [100, 100, 100, ...]
150
+
151
+
152
+ class PensandoNicCard(BaseModel):
153
+ """Pensando NIC card information from nicctl show card"""
154
+
155
+ id: str # Card ID (UUID format)
156
+ pcie_bdf: str # PCIe Bus:Device.Function (e.g., "0000:06:00.0")
157
+ asic: Optional[str] = None # ASIC type (e.g., "salina")
158
+ fw_partition: Optional[str] = None # Firmware partition (e.g., "A")
159
+ serial_number: Optional[str] = None # Serial number (e.g., "FPL25330294")
160
+
161
+
162
+ class PensandoNicDcqcn(BaseModel):
163
+ """Pensando NIC DCQCN information from nicctl show dcqcn"""
164
+
165
+ nic_id: str # NIC ID (UUID format)
166
+ pcie_bdf: str # PCIe Bus:Device.Function (e.g., "0000:06:00.0")
167
+ lif_id: Optional[str] = None # Lif ID (UUID format)
168
+ roce_device: Optional[str] = None # ROCE device name (e.g., "rocep9s0")
169
+ dcqcn_profile_id: Optional[str] = None # DCQCN profile id (e.g., "1")
170
+ status: Optional[str] = None # Status (e.g., "Disabled")
171
+
172
+
173
+ class PensandoNicEnvironment(BaseModel):
174
+ """Pensando NIC environment information from nicctl show environment"""
175
+
176
+ nic_id: str # NIC ID (UUID format)
177
+ pcie_bdf: str # PCIe Bus:Device.Function (e.g., "0000:06:00.0")
178
+ # Power measurements in Watts
179
+ total_power_drawn: Optional[float] = None # Total power drawn (pin)
180
+ core_power: Optional[float] = None # Core power (pout1)
181
+ arm_power: Optional[float] = None # ARM power (pout2)
182
+ # Temperature measurements in Celsius
183
+ local_board_temperature: Optional[float] = None # Local board temperature
184
+ die_temperature: Optional[float] = None # Die temperature
185
+ # Voltage measurements in millivolts
186
+ input_voltage: Optional[float] = None # Input voltage
187
+ core_voltage: Optional[float] = None # Core voltage
188
+ # Frequency measurements in MHz
189
+ core_frequency: Optional[float] = None # Core frequency
190
+ cpu_frequency: Optional[float] = None # CPU frequency
191
+ p4_stage_frequency: Optional[float] = None # P4 stage frequency
192
+
193
+
194
+ class PensandoNicPcieAts(BaseModel):
195
+ """Pensando NIC PCIe ATS information from nicctl show pcie ats"""
196
+
197
+ nic_id: str # NIC ID (UUID format)
198
+ pcie_bdf: str # PCIe Bus:Device.Function (e.g., "0000:06:00.0")
199
+ status: str # Status (e.g., "Disabled", "Enabled")
200
+
201
+
202
+ class PensandoNicPort(BaseModel):
203
+ """Pensando NIC port information from nicctl show port"""
204
+
205
+ nic_id: str # NIC ID (UUID format)
206
+ pcie_bdf: str # PCIe Bus:Device.Function (e.g., "0000:06:00.0")
207
+ port_id: str # Port ID (UUID format)
208
+ port_name: str # Port name (e.g., "eth1/1")
209
+ # Spec fields
210
+ spec_ifindex: Optional[str] = None
211
+ spec_type: Optional[str] = None
212
+ spec_speed: Optional[str] = None
213
+ spec_admin_state: Optional[str] = None
214
+ spec_fec_type: Optional[str] = None
215
+ spec_pause_type: Optional[str] = None
216
+ spec_num_lanes: Optional[int] = None
217
+ spec_mtu: Optional[int] = None
218
+ spec_tx_pause: Optional[str] = None
219
+ spec_rx_pause: Optional[str] = None
220
+ spec_auto_negotiation: Optional[str] = None
221
+ # Status fields
222
+ status_physical_port: Optional[int] = None
223
+ status_operational_status: Optional[str] = None
224
+ status_link_fsm_state: Optional[str] = None
225
+ status_fec_type: Optional[str] = None
226
+ status_cable_type: Optional[str] = None
227
+ status_num_lanes: Optional[int] = None
228
+ status_speed: Optional[str] = None
229
+ status_auto_negotiation: Optional[str] = None
230
+ status_mac_id: Optional[int] = None
231
+ status_mac_channel: Optional[int] = None
232
+ status_mac_address: Optional[str] = None
233
+ status_transceiver_type: Optional[str] = None
234
+ status_transceiver_state: Optional[str] = None
235
+ status_transceiver_pid: Optional[str] = None
236
+
237
+
238
+ class PensandoNicQosScheduling(BaseModel):
239
+ """QoS Scheduling entry"""
240
+
241
+ priority: int
242
+ scheduling_type: Optional[str] = None # e.g., "DWRR"
243
+ bandwidth: Optional[int] = None # Bandwidth in percentage
244
+ rate_limit: Optional[str] = None # Rate limit (e.g., "N/A" or value in Gbps)
245
+
246
+
247
+ class PensandoNicQos(BaseModel):
248
+ """Pensando NIC QoS information from nicctl show qos"""
249
+
250
+ nic_id: str # NIC ID (UUID format)
251
+ pcie_bdf: str # PCIe Bus:Device.Function (e.g., "0000:06:00.0")
252
+ port_id: str # Port ID (UUID format)
253
+ classification_type: Optional[str] = None # e.g., "DSCP"
254
+ dscp_bitmap: Optional[str] = None # DSCP bitmap
255
+ dscp_range: Optional[str] = None # DSCP range (e.g., "0-63")
256
+ dscp_priority: Optional[int] = None # Priority mapped from DSCP
257
+ pfc_priority_bitmap: Optional[str] = None # PFC priority bitmap
258
+ pfc_no_drop_priorities: Optional[str] = None # PFC no-drop priorities
259
+ scheduling: List[PensandoNicQosScheduling] = Field(default_factory=list) # Scheduling entries
260
+
261
+
262
+ class PensandoNicRdmaStatistic(BaseModel):
263
+ """RDMA statistic entry"""
264
+
265
+ name: str # Statistic name
266
+ count: int # Count value
267
+
268
+
269
+ class PensandoNicRdmaStatistics(BaseModel):
270
+ """Pensando NIC RDMA statistics from nicctl show rdma statistics"""
271
+
272
+ nic_id: str # NIC ID (UUID format)
273
+ pcie_bdf: str # PCIe Bus:Device.Function (e.g., "0000:06:00.0")
274
+ statistics: List[PensandoNicRdmaStatistic] = Field(default_factory=list) # Statistics entries
275
+
276
+
277
+ class PensandoNicVersionHostSoftware(BaseModel):
278
+ """Pensando NIC host software version from nicctl show version host-software"""
279
+
280
+ nicctl: Optional[str] = None # nicctl version
281
+ ipc_driver: Optional[str] = None # IPC driver version
282
+ ionic_driver: Optional[str] = None # ionic driver version
283
+
284
+
285
+ class PensandoNicVersionFirmware(BaseModel):
286
+ """Pensando NIC firmware version from nicctl show version firmware"""
287
+
288
+ nic_id: str # NIC ID (UUID format)
289
+ pcie_bdf: str # PCIe Bus:Device.Function (e.g., "0000:06:00.0")
290
+ cpld: Optional[str] = None # CPLD version
291
+ boot0: Optional[str] = None # Boot0 version
292
+ uboot_a: Optional[str] = None # Uboot-A version
293
+ firmware_a: Optional[str] = None # Firmware-A version
294
+ device_config_a: Optional[str] = None # Device config-A version
295
+
296
+
297
+ class NetworkDataModel(DataModel):
298
+ """Complete network configuration data"""
299
+
300
+ interfaces: List[NetworkInterface] = Field(default_factory=list)
301
+ routes: List[Route] = Field(default_factory=list)
302
+ rules: List[RoutingRule] = Field(default_factory=list)
303
+ neighbors: List[Neighbor] = Field(default_factory=list)
304
+ ethtool_info: Dict[str, EthtoolInfo] = Field(
305
+ default_factory=dict
306
+ ) # Interface name -> EthtoolInfo mapping
307
+ broadcom_nic_devices: List[BroadcomNicDevice] = Field(default_factory=list)
308
+ broadcom_nic_qos: Dict[int, BroadcomNicQos] = Field(
309
+ default_factory=dict
310
+ ) # Device number -> QoS info mapping
311
+ pensando_nic_cards: List[PensandoNicCard] = Field(default_factory=list)
312
+ pensando_nic_dcqcn: List[PensandoNicDcqcn] = Field(default_factory=list)
313
+ pensando_nic_environment: List[PensandoNicEnvironment] = Field(default_factory=list)
314
+ pensando_nic_pcie_ats: List[PensandoNicPcieAts] = Field(default_factory=list)
315
+ pensando_nic_ports: List[PensandoNicPort] = Field(default_factory=list)
316
+ pensando_nic_qos: List[PensandoNicQos] = Field(default_factory=list)
317
+ pensando_nic_rdma_statistics: List[PensandoNicRdmaStatistics] = Field(default_factory=list)
318
+ pensando_nic_version_host_software: Optional[PensandoNicVersionHostSoftware] = None
319
+ pensando_nic_version_firmware: List[PensandoNicVersionFirmware] = Field(default_factory=list)
@@ -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 .nvme_plugin import NvmePlugin
27
+
28
+ __all__ = ["NvmePlugin"]
@@ -0,0 +1,167 @@
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
+ import re
28
+ from typing import Optional
29
+
30
+ from pydantic import ValidationError
31
+
32
+ from nodescraper.base import InBandDataCollector
33
+ from nodescraper.enums import EventCategory, EventPriority, ExecutionStatus, OSFamily
34
+ from nodescraper.models import TaskResult
35
+
36
+ from .nvmedata import NvmeDataModel
37
+
38
+
39
+ class NvmeCollector(InBandDataCollector[NvmeDataModel, None]):
40
+ """Collect NVMe details from the system."""
41
+
42
+ DATA_MODEL = NvmeDataModel
43
+ CMD_LINUX = {
44
+ "smart_log": "nvme smart-log {dev}",
45
+ "error_log": "nvme error-log {dev} --log-entries=256",
46
+ "id_ctrl": "nvme id-ctrl {dev}",
47
+ "id_ns": "nvme id-ns {dev}{ns}",
48
+ "fw_log": "nvme fw-log {dev}",
49
+ "self_test_log": "nvme self-test-log {dev}",
50
+ "get_log": "nvme get-log {dev} --log-id=6 --log-len=512",
51
+ "telemetry_log": "nvme telemetry-log {dev} --output-file={dev}_{f_name}",
52
+ }
53
+ CMD_TEMPLATES = list(CMD_LINUX.values())
54
+
55
+ TELEMETRY_FILENAME = "telemetry_log.bin"
56
+
57
+ def collect_data(
58
+ self,
59
+ args=None,
60
+ ) -> tuple[TaskResult, Optional[NvmeDataModel]]:
61
+ """Collect detailed NVMe information from all NVMe devices.
62
+
63
+ Returns:
64
+ tuple[TaskResult, Optional[NvmeDataModel]]: Task result and data model with NVMe command outputs.
65
+ """
66
+ if self.system_info.os_family == OSFamily.WINDOWS:
67
+ self._log_event(
68
+ category=EventCategory.SW_DRIVER,
69
+ description="NVMe collection not supported on Windows",
70
+ priority=EventPriority.WARNING,
71
+ )
72
+ self.result.message = "NVMe data collection skipped on Windows"
73
+ self.result.status = ExecutionStatus.NOT_RAN
74
+ return self.result, None
75
+
76
+ nvme_devices = self._get_nvme_devices()
77
+ if not nvme_devices:
78
+ self._log_event(
79
+ category=EventCategory.SW_DRIVER,
80
+ description="No NVMe devices found",
81
+ priority=EventPriority.ERROR,
82
+ )
83
+ self.result.message = "No NVMe devices found"
84
+ self.result.status = ExecutionStatus.ERROR
85
+ return self.result, None
86
+
87
+ all_device_data = {}
88
+ f_name = self.TELEMETRY_FILENAME
89
+
90
+ for dev in nvme_devices:
91
+ device_data = {}
92
+ ns_suffix = "n1"
93
+ cmd_map = {
94
+ k: v.format(dev=dev, ns=ns_suffix, f_name=f_name) for k, v in self.CMD_LINUX.items()
95
+ }
96
+
97
+ for key, cmd in cmd_map.items():
98
+ res = self._run_sut_cmd(cmd, sudo=True)
99
+ if "--output-file" in cmd:
100
+ _ = self._read_sut_file(filename=f"{dev}_{f_name}", encoding=None)
101
+
102
+ if res.exit_code == 0:
103
+ device_data[key] = res.stdout
104
+ else:
105
+ self._log_event(
106
+ category=EventCategory.SW_DRIVER,
107
+ description=f"Failed to execute NVMe command: '{cmd}'",
108
+ data={"command": cmd, "exit_code": res.exit_code},
109
+ priority=EventPriority.WARNING,
110
+ console_log=True,
111
+ )
112
+
113
+ if device_data:
114
+ all_device_data[os.path.basename(dev)] = device_data
115
+
116
+ if all_device_data:
117
+ try:
118
+ nvme_data = NvmeDataModel(devices=all_device_data)
119
+ except ValidationError as exp:
120
+ self._log_event(
121
+ category=EventCategory.SW_DRIVER,
122
+ description="Validation error while building NvmeDataModel",
123
+ data={"errors": exp.errors(include_url=False)},
124
+ priority=EventPriority.ERROR,
125
+ )
126
+ self.result.message = "NVMe data invalid format"
127
+ self.result.status = ExecutionStatus.ERROR
128
+ return self.result, None
129
+
130
+ self._log_event(
131
+ category=EventCategory.SW_DRIVER,
132
+ description="Collected NVMe data",
133
+ data=nvme_data.model_dump(),
134
+ priority=EventPriority.INFO,
135
+ )
136
+ self.result.message = "NVMe data successfully collected"
137
+ self.result.status = ExecutionStatus.OK
138
+ return self.result, nvme_data
139
+ else:
140
+
141
+ self._log_event(
142
+ category=EventCategory.SW_DRIVER,
143
+ description="Failed to collect any NVMe data",
144
+ priority=EventPriority.ERROR,
145
+ )
146
+ self.result.message = "No NVMe data collected"
147
+ self.result.status = ExecutionStatus.ERROR
148
+ return self.result, None
149
+
150
+ def _get_nvme_devices(self) -> list[str]:
151
+ nvme_devs = []
152
+
153
+ res = self._run_sut_cmd("ls /dev", sudo=False)
154
+ if res.exit_code != 0:
155
+ self._log_event(
156
+ category=EventCategory.SW_DRIVER,
157
+ description="Failed to list /dev directory",
158
+ data={"exit_code": res.exit_code, "stderr": res.stderr},
159
+ priority=EventPriority.ERROR,
160
+ )
161
+ return []
162
+
163
+ for entry in res.stdout.strip().splitlines():
164
+ if re.fullmatch(r"nvme\d+$", entry):
165
+ nvme_devs.append(f"/dev/{entry}")
166
+
167
+ return nvme_devs
@@ -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 .nvme_collector import NvmeCollector
29
+ from .nvmedata import NvmeDataModel
30
+
31
+
32
+ class NvmePlugin(InBandDataPlugin[NvmeDataModel, None, None]):
33
+ """Plugin for collection and analysis of nvme data"""
34
+
35
+ DATA_MODEL = NvmeDataModel
36
+
37
+ COLLECTOR = NvmeCollector
@@ -0,0 +1,45 @@
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 BaseModel
29
+
30
+ from nodescraper.models import DataModel
31
+
32
+
33
+ class DeviceNvmeData(BaseModel):
34
+ smart_log: Optional[str] = None
35
+ error_log: Optional[str] = None
36
+ id_ctrl: Optional[str] = None
37
+ id_ns: Optional[str] = None
38
+ fw_log: Optional[str] = None
39
+ self_test_log: Optional[str] = None
40
+ get_log: Optional[str] = None
41
+ telemetry_log: Optional[str] = None
42
+
43
+
44
+ class NvmeDataModel(DataModel):
45
+ devices: dict[str, DeviceNvmeData]
@@ -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
+ ###############################################################################