diff --git a/.mypy.ini b/.mypy.ini index cf6c2344..b9a990fe 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -1,6 +1,23 @@ [mypy] -# Global mypy configuration -mypy_path = test/unit +explicit_package_bases = True + +[mypy-pydantic] +ignore_missing_imports = True + +[mypy-pydantic.*] +ignore_missing_imports = True + +[mypy-pytest] +ignore_missing_imports = True + +[mypy-serviceability_dummy_data] +ignore_missing_imports = True + +[mypy-instinct_shaped_engine] +ignore_missing_imports = True + +[mypy-nodescraper.connection.redfish.redfish_params] +ignore_errors = True [mypy-nodescraper.base.regexanalyzer] ignore_errors = True @@ -121,3 +138,6 @@ ignore_errors = True [mypy-test.unit.framework.test_cli] ignore_errors = True + +[mypy-test.unit.framework.test_plugin_execution_target] +ignore_errors = True diff --git a/README.md b/README.md index 31361c7e..14fa516a 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ options: Comma-separated built-in names and/or plugin config JSON paths (e.g. --plugin- configs=NodeStatus,/path/c.json). Built-ins: - AllPlugins, NodeStatus (default: None) + AllIbPlugins, NodeStatus (default: None) --system-config STRING Path to system config json (default: None) --connection-config STRING @@ -574,8 +574,8 @@ Below is an example that skips sudo requiring plugins and disables analysis. #### Plugin config: **'--plugin-configs' command** A plugin config can be used to compare the system data against the config specifications. -Built-in configs include **NodeStatus** (a subset of plugins) and **AllPlugins** (runs every -registered plugin with default arguments—useful for generating a reference config from the full system). +Built-in configs include **NodeStatus** (a subset of plugins) and **AllIbPlugins** (runs every +registered in-band plugin with default arguments—useful for generating a reference config from the full system). **NodeStatus plus additional plugins** — built-in configs merge with plugins named after `run-plugins`. Values are comma-separated; pass as **`--plugin-configs=…`** or **`--plugin-configs` …** (same as other @@ -743,9 +743,9 @@ This command can be used to generate a reference config that is populated with c configurations. Plugins that use analyzer args (where applicable) will be populated with system data. -**Run all registered plugins (AllPlugins config):** +**Run all registered in-band plugins (AllIbPlugins config):** ```sh -node-scraper --plugin-configs=AllPlugins +node-scraper --plugin-configs=AllIbPlugins ``` diff --git a/nodescraper/pluginrecipe/__init__.py b/nodescraper/pluginrecipe/__init__.py index b28ca993..deb0b934 100644 --- a/nodescraper/pluginrecipe/__init__.py +++ b/nodescraper/pluginrecipe/__init__.py @@ -7,7 +7,7 @@ ############################################################################### from nodescraper.models import PluginConfig -from .all_plugins import AllPlugins +from .all_ib_plugins import AllIbPlugins from .node_status import NodeStatus from .pluginrecipe import ( ANALYZE_ONLY, @@ -24,7 +24,7 @@ "ANALYZE_ONLY", "COLLECT_AND_ANALYZE", "COLLECT_ONLY", - "AllPlugins", + "AllIbPlugins", "AnalyzerOnlyPluginRecipe", "CollectorOnlyPluginRecipe", "NodeStatus", diff --git a/nodescraper/pluginrecipe/all_ib_plugins.py b/nodescraper/pluginrecipe/all_ib_plugins.py new file mode 100644 index 00000000..eef7597d --- /dev/null +++ b/nodescraper/pluginrecipe/all_ib_plugins.py @@ -0,0 +1,52 @@ +############################################################################### +# +# MIT License +# +# Copyright (c) 2026 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +############################################################################### +from __future__ import annotations + +from nodescraper.connection.inband import InBandConnectionManager + +from .discovery import PluginDiscovery +from .pluginrecipe import PluginRecipe + + +class AllIbPlugins(PluginRecipe): + """Run all registered in-band plugins with default arguments.""" + + @classmethod + def plugin_names(cls) -> tuple[str, ...]: + """Return every in-band plugin registered at runtime. + + Returns: + tuple[str, ...]: Sorted names of all in-band plugins in the plugin registry. + """ + discovery = PluginDiscovery() + return tuple( + sorted( + name + for name in discovery.registered_plugin_names() + if getattr(discovery.load_plugin_class(name), "CONNECTION_TYPE", None) + is InBandConnectionManager + ) + ) diff --git a/nodescraper/pluginrecipe/all_plugins.py b/nodescraper/pluginrecipe/all_plugins.py deleted file mode 100644 index 948c12e7..00000000 --- a/nodescraper/pluginrecipe/all_plugins.py +++ /dev/null @@ -1,24 +0,0 @@ -############################################################################### -# -# MIT License -# -# Copyright (c) 2025 Advanced Micro Devices, Inc. -# -############################################################################### -from __future__ import annotations - -from .discovery import PluginDiscovery -from .pluginrecipe import PluginRecipe - - -class AllPlugins(PluginRecipe): - """Run all registered plugins with default arguments.""" - - @classmethod - def plugin_names(cls) -> tuple[str, ...]: - """Return every plugin registered at runtime. - - Returns: - tuple[str, ...]: Sorted names of all plugins in the plugin registry. - """ - return PluginDiscovery().registered_plugin_names() diff --git a/pyproject.toml b/pyproject.toml index d2f1bdef..a60b7846 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,7 +71,7 @@ node-scraper = "nodescraper.cli:cli_entry" [project.entry-points."nodescraper.plugin_configs"] NodeStatus = "nodescraper.pluginrecipe.node_status:NodeStatus" -AllPlugins = "nodescraper.pluginrecipe.all_plugins:AllPlugins" +AllIbPlugins = "nodescraper.pluginrecipe.all_ib_plugins:AllIbPlugins" [tool.black] line-length = 100 diff --git a/test/unit/cli/test_plugin_configs_cli.py b/test/unit/cli/test_plugin_configs_cli.py index 90e1171a..be6fd383 100644 --- a/test/unit/cli/test_plugin_configs_cli.py +++ b/test/unit/cli/test_plugin_configs_cli.py @@ -10,7 +10,7 @@ from nodescraper.cli.cli import build_parser from nodescraper.configregistry import ConfigRegistry -from nodescraper.pluginrecipe.all_plugins import AllPlugins +from nodescraper.pluginrecipe.all_ib_plugins import AllIbPlugins from nodescraper.pluginrecipe.node_status import NodeStatus from nodescraper.pluginregistry import PluginRegistry @@ -18,16 +18,16 @@ def _parser(): plugin_reg = PluginRegistry() config_reg = ConfigRegistry(load_entry_point_configs=False) - for recipe in (NodeStatus, AllPlugins): + for recipe in (NodeStatus, AllIbPlugins): config_reg.configs[recipe.name()] = recipe.plugin_config() return build_parser(plugin_reg, config_reg)[0] def test_plugin_configs_equals_form_parses_csv() -> None: - ns = _parser().parse_args(["--plugin-configs=NodeStatus,AllPlugins"]) - assert ns.plugin_configs == ["NodeStatus", "AllPlugins"] + ns = _parser().parse_args(["--plugin-configs=NodeStatus,AllIbPlugins"]) + assert ns.plugin_configs == ["NodeStatus", "AllIbPlugins"] def test_plugin_configs_space_separated_parses() -> None: - ns = _parser().parse_args(["--plugin-configs", "NodeStatus,AllPlugins"]) - assert ns.plugin_configs == ["NodeStatus", "AllPlugins"] + ns = _parser().parse_args(["--plugin-configs", "NodeStatus,AllIbPlugins"]) + assert ns.plugin_configs == ["NodeStatus", "AllIbPlugins"] diff --git a/test/unit/framework/test_pluginrecipe.py b/test/unit/framework/test_pluginrecipe.py index 55b65450..9adeb30f 100644 --- a/test/unit/framework/test_pluginrecipe.py +++ b/test/unit/framework/test_pluginrecipe.py @@ -12,8 +12,9 @@ import pytest +from nodescraper.connection.inband import InBandConnectionManager from nodescraper.models import PluginConfig -from nodescraper.pluginrecipe.all_plugins import AllPlugins +from nodescraper.pluginrecipe.all_ib_plugins import AllIbPlugins from nodescraper.pluginrecipe.discovery import PluginDiscovery from nodescraper.pluginrecipe.node_status import NodeStatus from nodescraper.pluginrecipe.pluginrecipe import ( @@ -77,9 +78,21 @@ def test_node_status_recipe_matches_registered_plugins() -> None: assert set(NodeStatus.plugin_names()) == expected & available -def test_all_plugins_recipe_matches_registry() -> None: - plugin_reg = PluginRegistry() - assert set(AllPlugins.plugin_names()) == set(plugin_reg.plugins) +def test_all_ib_plugins_recipe_returns_only_ib_plugins() -> None: + discovery = PluginDiscovery() + for name in AllIbPlugins.plugin_names(): + plugin_class = discovery.load_plugin_class(name) + assert getattr(plugin_class, "CONNECTION_TYPE", None) is InBandConnectionManager + + +def test_all_ib_plugins_recipe_excludes_oob_plugins() -> None: + all_names = set(PluginRegistry().plugins) + ib_names = set(AllIbPlugins.plugin_names()) + discovery = PluginDiscovery() + non_ib = all_names - ib_names + for name in non_ib: + plugin_class = discovery.load_plugin_class(name) + assert getattr(plugin_class, "CONNECTION_TYPE", None) is not InBandConnectionManager def test_node_status_plugin_config_shape() -> None: @@ -90,11 +103,11 @@ def test_node_status_plugin_config_shape() -> None: assert config.plugins["DmesgPlugin"] == COLLECT_AND_ANALYZE.as_config() -def test_all_plugins_plugin_config_shape() -> None: - config = AllPlugins.plugin_config() - assert config.name == "AllPlugins" - assert config.desc == "Run all registered plugins with default arguments." - assert len(config.plugins) == len(PluginRegistry().plugins) +def test_all_ib_plugins_plugin_config_shape() -> None: + config = AllIbPlugins.plugin_config() + assert config.name == "AllIbPlugins" + assert config.desc == "Run all registered in-band plugins with default arguments." + assert len(config.plugins) == len(AllIbPlugins.plugin_names()) def test_collector_only_recipe_sets_analysis_false() -> None: