Skip to content

Commit c58d3b1

Browse files
committed
Merge branch 'development' into alex_kernel_mods
2 parents ec8ca43 + 5516a9e commit c58d3b1

File tree

17 files changed

+173
-37
lines changed

17 files changed

+173
-37
lines changed

nodescraper/cli/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ def build_parser(
185185
"--gen-reference-config-from-logs",
186186
dest="reference_config_from_logs",
187187
type=log_path_arg,
188-
help="Generate reference config from previous run logfiles. Writes to ./reference_config.json.",
188+
help="Generate reference config from previous run logfiles. Writes to --output-path/reference_config.json if provided, otherwise ./reference_config.json.",
189189
)
190190

191191
config_builder_parser.add_argument(

nodescraper/cli/helper.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -344,11 +344,13 @@ def generate_reference_config(
344344

345345
plugin = plugin_reg.plugins.get(obj.source)
346346

347-
args = extract_analyzer_args_from_model(plugin, data_model, logger)
348-
if not args:
349-
continue
350-
plugins[obj.source] = {"analysis_args": {}}
351-
plugins[obj.source]["analysis_args"] = args.model_dump(exclude_none=True)
347+
if obj.source not in plugins:
348+
plugins[obj.source] = {}
349+
350+
a_args = extract_analyzer_args_from_model(plugin, data_model, logger)
351+
if a_args:
352+
plugins[obj.source]["analysis_args"] = a_args.model_dump(exclude_none=True)
353+
352354
plugin_config.plugins = plugins
353355

354356
return plugin_config

nodescraper/interfaces/dataplugin.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ def analyze(
241241
Returns:
242242
TaskResult: result of data analysis
243243
"""
244+
244245
if self.ANALYZER is None:
245246
self.analysis_result = TaskResult(
246247
status=ExecutionStatus.NOT_RAN,

nodescraper/interfaces/task.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ def max_event_priority_level(self) -> EventPriority:
8080
def max_event_priority_level(self, input_value: str | EventPriority):
8181
if isinstance(input_value, str):
8282
value: EventPriority = getattr(EventPriority, input_value)
83+
elif isinstance(input_value, int):
84+
value = EventPriority(input_value)
8385
elif isinstance(input_value, EventPriority):
8486
value: EventPriority = input_value
8587
else:

nodescraper/models/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#
2525
###############################################################################
2626
from .analyzerargs import AnalyzerArgs
27+
from .collectorargs import CollectorArgs
2728
from .datamodel import DataModel
2829
from .datapluginresult import DataPluginResult
2930
from .event import Event
@@ -35,6 +36,7 @@
3536

3637
__all__ = [
3738
"AnalyzerArgs",
39+
"CollectorArgs",
3840
"DataModel",
3941
"TaskResult",
4042
"Event",
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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 pydantic import BaseModel
27+
28+
29+
class CollectorArgs(BaseModel):
30+
model_config = {"extra": "forbid", "exclude_none": True}

nodescraper/pluginexecutor.py

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from pydantic import BaseModel
3434

3535
from nodescraper.constants import DEFAULT_LOGGER
36-
from nodescraper.interfaces import ConnectionManager, DataPlugin
36+
from nodescraper.interfaces import ConnectionManager, DataPlugin, PluginInterface
3737
from nodescraper.models import PluginConfig, SystemInfo
3838
from nodescraper.models.pluginresult import PluginResult
3939
from nodescraper.pluginregistry import PluginRegistry
@@ -165,16 +165,25 @@ def run_queue(self) -> list[PluginResult]:
165165
plugin_inst = plugin_class(**init_payload)
166166

167167
run_payload = copy.deepcopy(plugin_args)
168-
169168
run_args = TypeUtils.get_func_arg_types(plugin_class.run, plugin_class)
169+
170170
for arg in run_args.keys():
171171
if arg == "preserve_connection" and issubclass(plugin_class, DataPlugin):
172172
run_payload[arg] = True
173-
elif arg in self.plugin_config.global_args:
174-
run_payload[arg] = self.plugin_config.global_args[arg]
175173

176-
# TODO
177-
# enable global substitution in collection and analysis args
174+
try:
175+
global_run_args = self.apply_global_args_to_plugin(
176+
plugin_inst, plugin_class, self.plugin_config.global_args
177+
)
178+
run_payload.update(global_run_args)
179+
except ValueError as ve:
180+
self.logger.error(
181+
"Invalid global_args for plugin %s: %s. Skipping plugin.",
182+
plugin_name,
183+
str(ve),
184+
)
185+
continue
186+
178187
self.logger.info("-" * 50)
179188
plugin_results.append(plugin_inst.run(**run_payload))
180189
except Exception as e:
@@ -210,3 +219,42 @@ def run_queue(self) -> list[PluginResult]:
210219
)
211220

212221
return plugin_results
222+
223+
def apply_global_args_to_plugin(
224+
self,
225+
plugin_inst: PluginInterface,
226+
plugin_class: type,
227+
global_args: dict,
228+
) -> dict:
229+
"""
230+
Applies global arguments to the plugin instance, including standard attributes
231+
and merging Pydantic model arguments (collection_args, analysis_args).
232+
233+
Args:
234+
plugin_inst: The plugin instance to update.
235+
plugin_class: The plugin class (needed for model instantiation).
236+
global_args: Dict of global argument overrides.
237+
"""
238+
239+
run_args = {}
240+
for key in global_args:
241+
if key in ["collection_args", "analysis_args"] and isinstance(plugin_inst, DataPlugin):
242+
continue
243+
else:
244+
run_args[key] = global_args[key]
245+
246+
if "collection_args" in global_args and hasattr(plugin_class, "COLLECTOR_ARGS"):
247+
plugin_fields = set(plugin_class.COLLECTOR_ARGS.__fields__.keys())
248+
filtered = {
249+
k: v for k, v in global_args["collection_args"].items() if k in plugin_fields
250+
}
251+
if filtered:
252+
run_args["collection_args"] = filtered
253+
254+
if "analysis_args" in global_args and hasattr(plugin_class, "ANALYZER_ARGS"):
255+
plugin_fields = set(plugin_class.ANALYZER_ARGS.__fields__.keys())
256+
filtered = {k: v for k, v in global_args["analysis_args"].items() if k in plugin_fields}
257+
if filtered:
258+
run_args["analysis_args"] = filtered
259+
260+
return run_args

nodescraper/plugins/inband/bios/bios_collector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def collect_data(
5555
0
5656
].split("=")[1]
5757
else:
58-
res = self._run_sut_cmd("sh -c 'dmidecode -s bios-version'", sudo=True)
58+
res = self._run_sut_cmd("sh -c 'cat /sys/devices/virtual/dmi/id/bios_version'")
5959
if res.exit_code == 0:
6060
bios = res.stdout
6161

nodescraper/plugins/inband/os/analyzer_args.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,4 @@ def build_from_model(cls, datamodel: OsDataModel) -> "OsAnalyzerArgs":
5959
Returns:
6060
OsAnalyzerArgs: instance of analyzer args class
6161
"""
62-
return cls(exp_os=datamodel.os_version)
62+
return cls(exp_os=datamodel.os_name)

nodescraper/plugins/inband/os/os_collector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def collect_data(self, args=None) -> tuple[TaskResult, OsDataModel | None]:
8585
PRETTY_STR = "PRETTY_NAME" # noqa: N806
8686
res = self._run_sut_cmd(
8787
f"sh -c '( lsb_release -ds || (cat /etc/*release | grep {PRETTY_STR}) || uname -om ) 2>/dev/null | head -n1'",
88-
sudo=True,
88+
sudo=False,
8989
)
9090
# search for PRETTY_NAME in res
9191
if res.exit_code == 0:

0 commit comments

Comments
 (0)