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,41 @@
|
|
|
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 enum import IntEnum
|
|
27
|
+
from functools import total_ordering
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@total_ordering
|
|
31
|
+
class SystemInteractionLevel(IntEnum):
|
|
32
|
+
"""Interaction levels, used to determine what types of actions can be taken when interacting with system"""
|
|
33
|
+
|
|
34
|
+
PASSIVE = 0 # read only data collection
|
|
35
|
+
INTERACTIVE = 1 # enable actions that may modify state of the SUT
|
|
36
|
+
DISRUPTIVE = 2 # enable actions that can interfere with driver or other core components
|
|
37
|
+
|
|
38
|
+
def __lt__(self, other: "SystemInteractionLevel") -> bool:
|
|
39
|
+
if self.__class__ is other.__class__:
|
|
40
|
+
return self.value < other.value
|
|
41
|
+
return NotImplemented
|
|
@@ -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
|
+
import enum
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SystemLocation(enum.Enum):
|
|
30
|
+
"""Enum defining location of system"""
|
|
31
|
+
|
|
32
|
+
LOCAL = enum.auto()
|
|
33
|
+
REMOTE = enum.auto()
|
|
@@ -0,0 +1,36 @@
|
|
|
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 TYPE_CHECKING, Optional, TypeVar
|
|
27
|
+
|
|
28
|
+
from pydantic import BaseModel
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from nodescraper.models import DataModel
|
|
32
|
+
|
|
33
|
+
TDataModel = TypeVar("TDataModel", bound="DataModel")
|
|
34
|
+
TModelType = TypeVar("TModelType", bound=BaseModel)
|
|
35
|
+
TCollectArg = TypeVar("TCollectArg", bound=Optional[BaseModel])
|
|
36
|
+
TAnalyzeArg = TypeVar("TAnalyzeArg", bound=Optional[BaseModel])
|
|
@@ -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
|
+
from .connectionmanager import ConnectionManager
|
|
27
|
+
from .dataanalyzertask import DataAnalyzer
|
|
28
|
+
from .datacollectortask import DataCollector
|
|
29
|
+
from .dataplugin import DataPlugin
|
|
30
|
+
from .plugin import PluginInterface
|
|
31
|
+
from .resultcollator import PluginResultCollator
|
|
32
|
+
from .task import Task
|
|
33
|
+
from .taskresulthook import TaskResultHook
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"ConnectionManager",
|
|
37
|
+
"Task",
|
|
38
|
+
"DataPlugin",
|
|
39
|
+
"DataAnalyzer",
|
|
40
|
+
"DataCollector",
|
|
41
|
+
"PluginInterface",
|
|
42
|
+
"TaskResultHook",
|
|
43
|
+
"PluginResultCollator",
|
|
44
|
+
]
|
|
@@ -0,0 +1,143 @@
|
|
|
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 __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import abc
|
|
29
|
+
import logging
|
|
30
|
+
import types
|
|
31
|
+
from functools import wraps
|
|
32
|
+
from typing import Callable, Generic, Optional, TypeVar, Union
|
|
33
|
+
|
|
34
|
+
from pydantic import BaseModel
|
|
35
|
+
|
|
36
|
+
from nodescraper.enums import EventCategory, EventPriority, ExecutionStatus
|
|
37
|
+
from nodescraper.models import SystemInfo, TaskResult
|
|
38
|
+
from nodescraper.typeutils import TypeUtils
|
|
39
|
+
from nodescraper.utils import get_exception_traceback
|
|
40
|
+
|
|
41
|
+
from .task import Task
|
|
42
|
+
from .taskresulthook import TaskResultHook
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def connect_decorator(func: Callable[..., TaskResult]) -> Callable[..., TaskResult]:
|
|
46
|
+
@wraps(func)
|
|
47
|
+
def wrapper(
|
|
48
|
+
connection_manager: "ConnectionManager",
|
|
49
|
+
**kwargs,
|
|
50
|
+
) -> TaskResult:
|
|
51
|
+
connection_manager.logger.info(
|
|
52
|
+
"Initializing connection: %s", connection_manager.__class__.__name__
|
|
53
|
+
)
|
|
54
|
+
connection_manager.result = connection_manager._init_result()
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
result = func(connection_manager, **kwargs)
|
|
58
|
+
except Exception as exception:
|
|
59
|
+
connection_manager._log_event(
|
|
60
|
+
category=EventCategory.RUNTIME,
|
|
61
|
+
description=f"Exception: {str(exception)}",
|
|
62
|
+
data=get_exception_traceback(exception),
|
|
63
|
+
priority=EventPriority.CRITICAL,
|
|
64
|
+
console_log=True,
|
|
65
|
+
)
|
|
66
|
+
connection_manager.result.status = ExecutionStatus.EXECUTION_FAILURE
|
|
67
|
+
result = connection_manager.result
|
|
68
|
+
|
|
69
|
+
result.finalize()
|
|
70
|
+
|
|
71
|
+
connection_manager._run_hooks(result)
|
|
72
|
+
|
|
73
|
+
return result
|
|
74
|
+
|
|
75
|
+
return wrapper
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
TConnection = TypeVar("TConnection")
|
|
79
|
+
TConnectionManager = TypeVar("TConnectionManager", bound="ConnectionManager")
|
|
80
|
+
TConnectArg = TypeVar("TConnectArg", bound="Optional[BaseModel]")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class ConnectionManager(Task, Generic[TConnection, TConnectArg]):
|
|
84
|
+
"""Base class for all connection management tasks"""
|
|
85
|
+
|
|
86
|
+
TASK_TYPE = "CONNECTION_MANAGER"
|
|
87
|
+
|
|
88
|
+
def __init__(
|
|
89
|
+
self,
|
|
90
|
+
system_info: SystemInfo,
|
|
91
|
+
logger: Optional[logging.Logger] = None,
|
|
92
|
+
max_event_priority_level: Union[EventPriority, str] = EventPriority.CRITICAL,
|
|
93
|
+
parent: Optional[str] = None,
|
|
94
|
+
task_result_hooks: Optional[list[TaskResultHook], None] = None,
|
|
95
|
+
connection_args: Optional[Union[TConnectArg, dict]] = None,
|
|
96
|
+
**kwargs,
|
|
97
|
+
):
|
|
98
|
+
super().__init__(
|
|
99
|
+
system_info=system_info,
|
|
100
|
+
logger=logger,
|
|
101
|
+
max_event_priority_level=max_event_priority_level,
|
|
102
|
+
parent="connection" if not parent else parent,
|
|
103
|
+
task_result_hooks=task_result_hooks,
|
|
104
|
+
**kwargs,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
if isinstance(connection_args, dict):
|
|
108
|
+
generic_map = TypeUtils.get_generic_map(self.__class__)
|
|
109
|
+
connection_arg_model = generic_map.get(TConnectArg)
|
|
110
|
+
if not connection_arg_model:
|
|
111
|
+
raise ValueError("No model defined for connection args")
|
|
112
|
+
|
|
113
|
+
connection_args = connection_arg_model(**connection_args)
|
|
114
|
+
|
|
115
|
+
self.connection_args = connection_args
|
|
116
|
+
self.connection: Optional[TConnection] = None
|
|
117
|
+
|
|
118
|
+
def __init_subclass__(cls, **kwargs) -> None:
|
|
119
|
+
super().__init_subclass__(**kwargs)
|
|
120
|
+
|
|
121
|
+
if hasattr(cls, "connect"):
|
|
122
|
+
cls.connect = connect_decorator(cls.connect)
|
|
123
|
+
|
|
124
|
+
def __enter__(self):
|
|
125
|
+
"""Context manager enter"""
|
|
126
|
+
return self
|
|
127
|
+
|
|
128
|
+
def __exit__(
|
|
129
|
+
self,
|
|
130
|
+
_exc_type: type[Exception],
|
|
131
|
+
_exc_value: Exception,
|
|
132
|
+
traceback: types.TracebackType,
|
|
133
|
+
):
|
|
134
|
+
self.disconnect()
|
|
135
|
+
|
|
136
|
+
@abc.abstractmethod
|
|
137
|
+
def connect(self) -> TaskResult:
|
|
138
|
+
"""initialize connection"""
|
|
139
|
+
|
|
140
|
+
def disconnect(self):
|
|
141
|
+
"""disconnect connection (Optional)"""
|
|
142
|
+
self.connection = None
|
|
143
|
+
self.result.status = ExecutionStatus.UNSET
|
|
@@ -0,0 +1,138 @@
|
|
|
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 __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import abc
|
|
29
|
+
import inspect
|
|
30
|
+
from functools import wraps
|
|
31
|
+
from typing import Any, Callable, Generic, Optional, Type, Union
|
|
32
|
+
|
|
33
|
+
from pydantic import BaseModel, ValidationError
|
|
34
|
+
|
|
35
|
+
from nodescraper.enums import EventCategory, EventPriority, ExecutionStatus
|
|
36
|
+
from nodescraper.generictypes import TAnalyzeArg, TDataModel
|
|
37
|
+
from nodescraper.interfaces.task import Task
|
|
38
|
+
from nodescraper.models import TaskResult
|
|
39
|
+
from nodescraper.models.datamodel import DataModel
|
|
40
|
+
from nodescraper.typeutils import TypeUtils
|
|
41
|
+
from nodescraper.utils import get_exception_traceback
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def analyze_decorator(func: Callable[..., TaskResult]) -> Callable[..., TaskResult]:
|
|
45
|
+
@wraps(func)
|
|
46
|
+
def wrapper(
|
|
47
|
+
analyzer: "DataAnalyzer",
|
|
48
|
+
data: DataModel,
|
|
49
|
+
args: Optional[Union[TAnalyzeArg, dict]] = None,
|
|
50
|
+
) -> TaskResult:
|
|
51
|
+
analyzer.logger.info("Running data analyzer: %s", analyzer.__class__.__name__)
|
|
52
|
+
analyzer.result = analyzer._init_result()
|
|
53
|
+
|
|
54
|
+
if not isinstance(data, analyzer.DATA_MODEL):
|
|
55
|
+
analyzer._log_event(
|
|
56
|
+
category=EventCategory.RUNTIME,
|
|
57
|
+
description="Analyzer passed invalid data",
|
|
58
|
+
data={"data_type": type(data), "expected": analyzer.DATA_MODEL.__name__},
|
|
59
|
+
priority=EventPriority.CRITICAL,
|
|
60
|
+
console_log=True,
|
|
61
|
+
)
|
|
62
|
+
analyzer.result.message = "Invalid data input"
|
|
63
|
+
analyzer.result.status = ExecutionStatus.EXECUTION_FAILURE
|
|
64
|
+
else:
|
|
65
|
+
try:
|
|
66
|
+
if isinstance(args, dict):
|
|
67
|
+
arg_types = TypeUtils.get_func_arg_types(func)
|
|
68
|
+
analyze_arg_model = next(
|
|
69
|
+
(
|
|
70
|
+
type_class.type_class
|
|
71
|
+
for type_class in arg_types["args"].type_classes
|
|
72
|
+
if issubclass(type_class.type_class, BaseModel)
|
|
73
|
+
),
|
|
74
|
+
None,
|
|
75
|
+
)
|
|
76
|
+
if not analyze_arg_model:
|
|
77
|
+
raise ValueError("No model defined for analysis args")
|
|
78
|
+
args = analyze_arg_model(**args) # type: ignore
|
|
79
|
+
func(analyzer, data, args)
|
|
80
|
+
except ValidationError as exception:
|
|
81
|
+
analyzer._log_event(
|
|
82
|
+
category=EventCategory.RUNTIME,
|
|
83
|
+
description="Validation error during analysis",
|
|
84
|
+
data={"errors": exception.errors(include_url=False)},
|
|
85
|
+
priority=EventPriority.CRITICAL,
|
|
86
|
+
console_log=True,
|
|
87
|
+
)
|
|
88
|
+
analyzer.result.status = ExecutionStatus.EXECUTION_FAILURE
|
|
89
|
+
except Exception as exception:
|
|
90
|
+
analyzer._log_event(
|
|
91
|
+
category=EventCategory.RUNTIME,
|
|
92
|
+
description=f"Exception during data analysis: {str(exception)}",
|
|
93
|
+
data=get_exception_traceback(exception),
|
|
94
|
+
priority=EventPriority.CRITICAL,
|
|
95
|
+
console_log=True,
|
|
96
|
+
)
|
|
97
|
+
analyzer.result.status = ExecutionStatus.EXECUTION_FAILURE
|
|
98
|
+
|
|
99
|
+
result = analyzer.result
|
|
100
|
+
result.finalize(analyzer.logger)
|
|
101
|
+
|
|
102
|
+
analyzer._run_hooks(result)
|
|
103
|
+
|
|
104
|
+
return result
|
|
105
|
+
|
|
106
|
+
return wrapper
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class DataAnalyzer(Task, abc.ABC, Generic[TDataModel, TAnalyzeArg]):
|
|
110
|
+
"""Parent class for all data analyzers"""
|
|
111
|
+
|
|
112
|
+
TASK_TYPE = "DATA_ANALYZER"
|
|
113
|
+
|
|
114
|
+
DATA_MODEL: Type[TDataModel]
|
|
115
|
+
|
|
116
|
+
def __init_subclass__(cls, **kwargs: dict[str, Any]) -> None:
|
|
117
|
+
super().__init_subclass__(**kwargs)
|
|
118
|
+
if not inspect.isabstract(cls) and cls.DATA_MODEL is None:
|
|
119
|
+
raise TypeError(f"No data model set for {cls.__name__}")
|
|
120
|
+
|
|
121
|
+
if hasattr(cls, "analyze_data"):
|
|
122
|
+
setattr(cls, "analyze_data", analyze_decorator(cls.analyze_data)) # noqa
|
|
123
|
+
|
|
124
|
+
@abc.abstractmethod
|
|
125
|
+
def analyze_data(
|
|
126
|
+
self,
|
|
127
|
+
data: TDataModel,
|
|
128
|
+
args: Optional[TAnalyzeArg],
|
|
129
|
+
) -> TaskResult:
|
|
130
|
+
"""Analyze the provided data and return a TaskResult
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
data (TDataModel): data to analyze
|
|
134
|
+
args (Optional[TAnalyzeArg]): Optional arguments for analysis. Dicts will be handled in the decorator"
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
TaskResult: Task result containing the analysis outcome
|
|
138
|
+
"""
|
|
@@ -0,0 +1,185 @@
|
|
|
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 abc
|
|
27
|
+
import inspect
|
|
28
|
+
import logging
|
|
29
|
+
from functools import wraps
|
|
30
|
+
from typing import Callable, ClassVar, Generic, Optional, Type, Union
|
|
31
|
+
|
|
32
|
+
from pydantic import BaseModel, ValidationError
|
|
33
|
+
|
|
34
|
+
from nodescraper.enums import (
|
|
35
|
+
EventCategory,
|
|
36
|
+
EventPriority,
|
|
37
|
+
ExecutionStatus,
|
|
38
|
+
SystemInteractionLevel,
|
|
39
|
+
)
|
|
40
|
+
from nodescraper.generictypes import TCollectArg, TDataModel
|
|
41
|
+
from nodescraper.interfaces.task import SystemCompatibilityError, Task
|
|
42
|
+
from nodescraper.models import DataModel, SystemInfo, TaskResult
|
|
43
|
+
from nodescraper.typeutils import TypeUtils
|
|
44
|
+
from nodescraper.utils import get_exception_traceback
|
|
45
|
+
|
|
46
|
+
from .connectionmanager import TConnection
|
|
47
|
+
from .taskresulthook import TaskResultHook
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def collect_decorator(
|
|
51
|
+
func: Callable[..., tuple[TaskResult, Optional[TDataModel]]],
|
|
52
|
+
) -> Callable[..., tuple[TaskResult, Optional[TDataModel]]]:
|
|
53
|
+
@wraps(func)
|
|
54
|
+
def wrapper(
|
|
55
|
+
collector: "DataCollector", args: Optional[TCollectArg] = None
|
|
56
|
+
) -> tuple[TaskResult, Optional[TDataModel]]:
|
|
57
|
+
collector.logger.info("Running data collector: %s", collector.__class__.__name__)
|
|
58
|
+
collector.result = collector._init_result()
|
|
59
|
+
try:
|
|
60
|
+
if isinstance(args, dict):
|
|
61
|
+
arg_types = TypeUtils.get_func_arg_types(func)
|
|
62
|
+
collection_arg_model = next(
|
|
63
|
+
(
|
|
64
|
+
type_class.type_class
|
|
65
|
+
for type_class in arg_types["args"].type_classes
|
|
66
|
+
if issubclass(type_class.type_class, BaseModel)
|
|
67
|
+
),
|
|
68
|
+
None,
|
|
69
|
+
)
|
|
70
|
+
if not collection_arg_model:
|
|
71
|
+
raise ValueError("No model defined for analysis args")
|
|
72
|
+
args = collection_arg_model(**args) # type: ignore
|
|
73
|
+
result, data = func(collector, args)
|
|
74
|
+
except Exception as exception:
|
|
75
|
+
if isinstance(exception, ValidationError):
|
|
76
|
+
collector._log_event(
|
|
77
|
+
category=EventCategory.RUNTIME,
|
|
78
|
+
description="Pydantic validation error",
|
|
79
|
+
data={"errors": exception.errors(include_url=False)},
|
|
80
|
+
priority=EventPriority.CRITICAL,
|
|
81
|
+
console_log=True,
|
|
82
|
+
)
|
|
83
|
+
else:
|
|
84
|
+
collector._log_event(
|
|
85
|
+
category=EventCategory.RUNTIME,
|
|
86
|
+
description=f"Exception: {str(exception)}",
|
|
87
|
+
data=get_exception_traceback(exception),
|
|
88
|
+
priority=EventPriority.CRITICAL,
|
|
89
|
+
console_log=True,
|
|
90
|
+
)
|
|
91
|
+
collector.result.status = ExecutionStatus.EXECUTION_FAILURE
|
|
92
|
+
result = collector.result
|
|
93
|
+
data = None
|
|
94
|
+
|
|
95
|
+
if data is None and not result.status:
|
|
96
|
+
result.status = ExecutionStatus.EXECUTION_FAILURE
|
|
97
|
+
|
|
98
|
+
result.finalize(collector.logger)
|
|
99
|
+
|
|
100
|
+
collector._run_hooks(result, data=data)
|
|
101
|
+
|
|
102
|
+
return result, data
|
|
103
|
+
|
|
104
|
+
return wrapper
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class DataCollector(Task, abc.ABC, Generic[TConnection, TDataModel, TCollectArg]):
|
|
108
|
+
"""Parent class for all data collectors"""
|
|
109
|
+
|
|
110
|
+
TASK_TYPE = "DATA_COLLECTOR"
|
|
111
|
+
|
|
112
|
+
DATA_MODEL: Type[TDataModel]
|
|
113
|
+
|
|
114
|
+
# A set of supported SKUs for this data collector
|
|
115
|
+
SUPPORTED_SKUS: ClassVar[Optional[set[str]]] = None
|
|
116
|
+
|
|
117
|
+
# A set of supported Platforms for this data collector,
|
|
118
|
+
SUPPORTED_PLATFORMS: ClassVar[Optional[set[str]]] = None
|
|
119
|
+
|
|
120
|
+
def __init__(
|
|
121
|
+
self,
|
|
122
|
+
system_info: SystemInfo,
|
|
123
|
+
connection: TConnection,
|
|
124
|
+
logger: Optional[logging.Logger] = None,
|
|
125
|
+
system_interaction_level: Union[
|
|
126
|
+
SystemInteractionLevel, str
|
|
127
|
+
] = SystemInteractionLevel.INTERACTIVE,
|
|
128
|
+
max_event_priority_level: Union[EventPriority, str] = EventPriority.CRITICAL,
|
|
129
|
+
parent: Optional[str] = None,
|
|
130
|
+
task_result_hooks: Optional[list[TaskResultHook]] = None,
|
|
131
|
+
**kwargs,
|
|
132
|
+
):
|
|
133
|
+
"""data collector init function
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
system_info (SystemInfo): system info object for target system for data collection
|
|
137
|
+
system_interaction (SystemInteraction): enum to indicate the type of actions that can be performed when interacting with the system
|
|
138
|
+
event_reporter (str, optional): Described the reporter of the event. Defaults to DEFAULT_EVENT_REPORTER.
|
|
139
|
+
logger (Optional[logging.Logger], optional): python logger object. Defaults to None.
|
|
140
|
+
log_path (Optional[str], optional): file system log path. Defaults to None.
|
|
141
|
+
"""
|
|
142
|
+
super().__init__(
|
|
143
|
+
system_info=system_info,
|
|
144
|
+
logger=logger,
|
|
145
|
+
max_event_priority_level=max_event_priority_level,
|
|
146
|
+
parent=parent,
|
|
147
|
+
task_result_hooks=task_result_hooks,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if isinstance(system_interaction_level, str):
|
|
151
|
+
system_interaction_level = getattr(SystemInteractionLevel, system_interaction_level)
|
|
152
|
+
|
|
153
|
+
self.system_interaction_level = system_interaction_level
|
|
154
|
+
self.connection = connection
|
|
155
|
+
|
|
156
|
+
if self.SUPPORTED_SKUS and self.system_info.sku not in self.SUPPORTED_SKUS:
|
|
157
|
+
raise SystemCompatibilityError(
|
|
158
|
+
f"{self.system_info.sku} SKU is not supported for this collector"
|
|
159
|
+
)
|
|
160
|
+
if self.SUPPORTED_PLATFORMS and self.system_info.platform not in self.SUPPORTED_PLATFORMS:
|
|
161
|
+
raise SystemCompatibilityError(
|
|
162
|
+
f"{self.system_info.platform} platform is not supported for this collector"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
def __init_subclass__(cls, **kwargs) -> None:
|
|
166
|
+
super().__init_subclass__(**kwargs)
|
|
167
|
+
if not inspect.isabstract(cls):
|
|
168
|
+
if not hasattr(cls, "DATA_MODEL"):
|
|
169
|
+
raise TypeError(f"No data model set for {cls.__name__}")
|
|
170
|
+
if not issubclass(cls.DATA_MODEL, DataModel):
|
|
171
|
+
raise TypeError(f"DATA_MODEL must be a subclass of DataModel in {cls.__name__}")
|
|
172
|
+
if hasattr(cls, "collect_data"):
|
|
173
|
+
cls.collect_data = collect_decorator(cls.collect_data)
|
|
174
|
+
else:
|
|
175
|
+
raise TypeError(f"Data collector {cls.__name__} must implement collect_data")
|
|
176
|
+
|
|
177
|
+
@abc.abstractmethod
|
|
178
|
+
def collect_data(
|
|
179
|
+
self, args: Optional[TCollectArg] = None
|
|
180
|
+
) -> tuple[TaskResult, Optional[TDataModel]]:
|
|
181
|
+
"""Collect data from a target system
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
tuple[TaskResult, DataModel]: tuple containing result and data model
|
|
185
|
+
"""
|