def test_rank_sections_by_supersedes_no_matching_sections(): fallback = _create_creator("desired", "desired", []) assert utils.rank_sections_by_supersedes( [ _create_creator("foo", "foo", []), ], {ParsedSectionName("desired")}, ) == [] assert utils.rank_sections_by_supersedes( [ fallback, _create_creator("foo", "foo", []), ], {ParsedSectionName("desired")}, ) == [fallback[1]] assert utils.rank_sections_by_supersedes( [ fallback, _create_creator("foo", "foo", []), _create_creator("desired", "bar", []), # will create "bar", not "desired"! ], {ParsedSectionName("desired")}, ) == [fallback[1]]
def create_snmp_section_plugin( *, name: str, detect_spec: SNMPDetectBaseType, fetch: Union[SNMPTree, List[SNMPTree]], parsed_section_name: Optional[str] = None, parse_function: Union[SimpleSNMPParseFunction, SNMPParseFunction, None] = None, host_label_function: Optional[HostLabelFunction] = None, supersedes: Optional[List[str]] = None, module: Optional[str] = None, validate_creation_kwargs: bool = True, ) -> SNMPSectionPlugin: """Return an SNMPSectionPlugin object after validating and converting the arguments one by one For a detailed description of the parameters please refer to the exposed function in the 'register' namespace of the API. """ section_name = SectionName(name) # normalize to List[SNMPTree] tree_list = [fetch] if isinstance(fetch, SNMPTree) else fetch if validate_creation_kwargs: _validate_detect_spec(detect_spec) _validate_fetch_spec(tree_list) if parse_function is not None: needs_bytes = any(oid.encoding == "binary" for tree in tree_list for oid in tree.oids) _validate_parse_function( parse_function, expected_annotation=_create_parse_annotation( needs_bytes=needs_bytes, is_list=isinstance(fetch, list), ), ) if host_label_function is not None: validate_function_arguments( type_label="host_label", function=host_label_function, has_item=False, default_params=None, # CMK-5181 sections=[ParsedSectionName("__always_just_one_section__")], ) return SNMPSectionPlugin( section_name, ParsedSectionName( parsed_section_name if parsed_section_name else str(section_name)), _create_snmp_parse_function(parse_function, isinstance(fetch, SNMPTree)), _create_host_label_function(host_label_function), _create_supersedes(section_name, supersedes), detect_spec, tree_list, module, )
def _create_sections(sections: Optional[List[str]], plugin_name: CheckPluginName) -> List[ParsedSectionName]: if sections is None: return [ParsedSectionName(str(plugin_name))] if not isinstance(sections, list): raise TypeError("[%s]: 'sections' must be a list of str, got %r" % (plugin_name, sections)) if not sections: raise ValueError("[%s]: 'sections' must not be empty" % plugin_name) return [ParsedSectionName(n) for n in sections]
def create_snmp_section_plugin( *, name: str, detect_spec: SNMPDetectSpec, trees: List[SNMPTree], parsed_section_name: Optional[str] = None, parse_function: Optional[SNMPParseFunction] = None, host_label_function: Optional[HostLabelFunction] = None, supersedes: Optional[List[str]] = None, module: Optional[str] = None, validate_creation_kwargs: bool = True, ) -> SNMPSectionPlugin: """Return an SNMPSectionPlugin object after validating and converting the arguments one by one For a detailed description of the parameters please refer to the exposed function in the 'register' namespace of the API. """ section_name = SectionName(name) if validate_creation_kwargs: _validate_detect_spec(detect_spec) _validate_snmp_trees(trees) if parse_function is not None: needs_bytes = any( isinstance(oid, OIDBytes) for tree in trees for oid in tree.oids) _validate_parse_function( parse_function, expected_annotation=( # (SNMPStringByteTable, "SNMPStringByteTable") if needs_bytes else (SNMPStringTable, "SNMPStringTable")), ) if host_label_function is not None: validate_function_arguments( type_label="host_label", function=host_label_function, has_item=False, default_params=None, # CMK-5181 sections=[ParsedSectionName("__always_just_one_section__")], ) return SNMPSectionPlugin( section_name, ParsedSectionName( parsed_section_name if parsed_section_name else str(section_name)), _create_snmp_parse_function(parse_function, trees), _create_host_label_function(host_label_function), _create_supersedes(section_name, supersedes), detect_spec, trees, module, )
def create_subscribed_sections( sections: Optional[List[str]], plugin_name: Union[InventoryPluginName, CheckPluginName], ) -> List[ParsedSectionName]: if sections is None: return [ParsedSectionName(str(plugin_name))] if not isinstance(sections, list): raise TypeError("'sections' must be a list of str, got %r" % (sections,)) if not sections: raise ValueError("'sections' must not be empty") return [ParsedSectionName(n) for n in sections]
def test_create_check_plugin_from_legacy_with_params(): plugin = check_plugins_legacy.create_check_plugin_from_legacy( "norris", { **MINIMAL_CHECK_INFO, "group": "norris_rule", "default_levels_variable": "norris_default_levels", }, [], {"norris_default_levels": { "levels": (23, 42) }}, lambda _x: {"norris_default_levels": { "levels_lower": (1, 2) }}, ) assert plugin.name == CheckPluginName("norris") assert plugin.sections == [ParsedSectionName("norris")] assert plugin.service_name == MINIMAL_CHECK_INFO["service_description"] assert plugin.discovery_function.__name__ == "discovery_migration_wrapper" assert plugin.discovery_default_parameters is None assert plugin.discovery_ruleset_name is None assert plugin.check_function.__name__ == "check_migration_wrapper" assert plugin.check_default_parameters == { "levels": (23, 42), "levels_lower": (1, 2), } assert plugin.check_ruleset_name == RuleSetName("norris_rule") assert plugin.cluster_check_function is None
def test_create_snmp_section_plugin(): trees: List[SNMPTree] = [ SNMPTree( base='.1.2.3', oids=[OIDEnd(), '2.3'], ), ] detect = SNMPDetectSpec([ [('.1.2.3.4.5', 'Foo.*', True)], ]) plugin = section_plugins.create_snmp_section_plugin( name="norris", parsed_section_name="chuck", parse_function=_parse_dummy, fetch=trees, detect_spec=detect, supersedes=["foo", "bar"], ) assert isinstance(plugin, SNMPSectionPlugin) assert len(plugin) == 8 assert plugin.name == SectionName("norris") assert plugin.parsed_section_name == ParsedSectionName("chuck") assert plugin.parse_function is _parse_dummy assert plugin.host_label_function is section_plugins._noop_host_label_function assert plugin.detect_spec == detect assert plugin.trees == trees assert plugin.supersedes == {SectionName("bar"), SectionName("foo")}
def test_get_section_cluster_kwargs(patch_register, required_sections, expected_result): node1_section_content = { SectionName("one"): NODE_1, SectionName("two"): NODE_1, SectionName("three"): NODE_1 } node2_section_content = { SectionName("two"): NODE_2, SectionName("three"): NODE_2, } parsed_sections_broker = ParsedSectionsBroker({ HostKey("node1", "127.0.0.1", SourceType.HOST): AgentHostSections(sections=node1_section_content), HostKey("node2", "127.0.0.1", SourceType.HOST): AgentHostSections(sections=node2_section_content), }) kwargs = parsed_sections_broker.get_section_cluster_kwargs( [ HostKey("node1", "127.0.0.1", SourceType.HOST), HostKey("node2", "127.0.0.1", SourceType.HOST), ], [ParsedSectionName(n) for n in required_sections], ) assert expected_result == kwargs,\ "Section content: Expected '%s' but got '%s'" % (expected_result, kwargs)
def test_parse_sections_unsuperseded(monkeypatch: MonkeyPatch) -> None: assert (ParsedSectionsResolver( section_plugins=(SECTION_ONE, SECTION_THREE), ).resolve(_get_parser(), ParsedSectionName("parsed")) is not None)
def create_snmp_section_plugin( *, name: str, detect_spec: SNMPDetectSpec, trees: List[SNMPTree], parsed_section_name: Optional[str] = None, parse_function: Optional[SNMPParseFunction] = None, host_label_function: Optional[HostLabelFunction] = None, supersedes: Optional[List[str]] = None, module: Optional[str] = None, ) -> SNMPSectionPlugin: """Return an SNMPSectionPlugin object after validating and converting the arguments one by one For a detailed description of the parameters please refer to the exposed function in the 'register' namespace of the API. """ section_name = SectionName(name) _validate_detect_spec(detect_spec) _validate_snmp_trees(trees) return SNMPSectionPlugin( section_name, ParsedSectionName( parsed_section_name if parsed_section_name else str(section_name)), _create_snmp_parse_function(parse_function, trees), _create_host_label_function( host_label_function, default_params=None, ), _create_supersedes(section_name, supersedes), detect_spec, trees, module, )
def create_agent_section_plugin( *, name: str, parsed_section_name: Optional[str] = None, parse_function: AgentParseFunction, host_label_function: Optional[HostLabelFunction] = None, supersedes: Optional[List[str]] = None, module: Optional[str] = None, ) -> AgentSectionPlugin: """Return an AgentSectionPlugin object after validating and converting the arguments one by one For a detailed description of the parameters please refer to the exposed function in the 'register' namespace of the API. """ # TODO (mo): Well, implement it, and remove pragma below! if supersedes is not None: raise NotImplementedError("supersedes is not yet available") if parsed_section_name is not None: raise NotImplementedError("parsed_section_name is not yet available") section_name = SectionName(name) _validate_parse_function( parse_function, expected_annotation=(AgentStringTable, "AgentStringTable"), ) return AgentSectionPlugin( section_name, ParsedSectionName(parsed_section_name if parsed_section_name else str(section_name)), parse_function, _create_host_label_function(host_label_function), _create_supersedes(supersedes), module, )
def test_create_snmp_section_plugin(): trees: List[SNMPTree] = [ SNMPTree( base=".1.2.3", oids=[OIDEnd(), "2.3"], ), ] detect = SNMPDetectSpecification([ [(".1.2.3.4.5", "Foo.*", True)], ]) plugin = section_plugins.create_snmp_section_plugin( name="norris", parsed_section_name="chuck", parse_function=_parse_dummy, fetch=trees, detect_spec=detect, supersedes=["foo", "bar"], ) assert isinstance(plugin, SNMPSectionPlugin) assert len(plugin) == 11 assert plugin.name == SectionName("norris") assert plugin.parsed_section_name == ParsedSectionName("chuck") assert plugin.parse_function is _parse_dummy assert plugin.host_label_function is section_plugins._noop_host_label_function assert plugin.host_label_default_parameters is None assert plugin.host_label_ruleset_name is None assert plugin.host_label_ruleset_type == "merged" assert plugin.detect_spec == detect assert plugin.trees == trees assert plugin.supersedes == {SectionName("bar"), SectionName("foo")}
def test_get_section_kwargs( required_sections: List[str], expected_result: Dict[str, Dict[str, str]]) -> None: node_sections = AgentHostSections( sections={ SectionName("one"): NODE_1, SectionName("two"): NODE_1, SectionName("three"): NODE_1, }) host_key = HostKey(HostName("node1"), HostAddress("127.0.0.1"), SourceType.HOST) parsed_sections_broker = ParsedSectionsBroker({ host_key: ( ParsedSectionsResolver(section_plugins=[ SECTION_ONE, SECTION_TWO, SECTION_THREE, SECTION_FOUR ]), SectionsParser(host_sections=node_sections), ), }) kwargs = get_section_kwargs( parsed_sections_broker, host_key, [ParsedSectionName(n) for n in required_sections], ) assert expected_result == kwargs
def test_get_section_cluster_kwargs(patch_register, required_sections, expected_result): node1_section_content = { SectionName("one"): NODE_1, SectionName("two"): NODE_1, SectionName("three"): NODE_1 } node2_section_content = { SectionName("two"): NODE_2, SectionName("three"): NODE_2, } multi_host_sections = MultiHostSections() multi_host_sections.setdefault( HostKey("node1", "127.0.0.1", SourceType.HOST), AgentHostSections(sections=node1_section_content), ) multi_host_sections.setdefault( HostKey("node2", "127.0.0.1", SourceType.HOST), AgentHostSections(sections=node2_section_content), ) kwargs = multi_host_sections.get_section_cluster_kwargs( [ HostKey("node1", "127.0.0.1", SourceType.HOST), HostKey("node2", "127.0.0.1", SourceType.HOST), ], [ParsedSectionName(n) for n in required_sections], ) assert expected_result == kwargs,\ "Section content: Expected '%s' but got '%s'" % (expected_result, kwargs)
def _create_host_label_function( host_label_function: Optional[HostLabelFunction], has_params: bool, ) -> HostLabelFunction: if host_label_function is None: return _noop_host_label_function validate_function_arguments( "host_label", host_label_function, has_item=False, sections=[ParsedSectionName("__always_just_one_section__")], has_params=has_params, ) @functools.wraps(host_label_function) def filtered_generator(*args, **kwargs): """Only let HostLabel through This allows for better typing in base code. """ for label in host_label_function( # type: ignore[misc] # Bug: None not callable *args, **kwargs, ): if not isinstance(label, HostLabel): raise TypeError("unexpected type in host label function: %r" % type(label)) yield label return filtered_generator
def test_get_section_kwargs(monkeypatch, required_sections, expected_result): _set_up(monkeypatch, "node1", None, {}) node_section_content = { SectionName("one"): NODE_1, # TODO (mo): CMK-4232 # SectionName("two"): NODE_1, SectionName("three"): NODE_1 } host_key = HostKey("node1", "127.0.0.1", SourceType.HOST) multi_host_sections = MultiHostSections() multi_host_sections.setdefault( host_key, AgentHostSections(sections=node_section_content), ) kwargs = multi_host_sections.get_section_kwargs( host_key, [ParsedSectionName(n) for n in required_sections], ) assert expected_result == kwargs,\ "Section content: Expected '%s' but got '%s'" % (expected_result, kwargs)
def test_get_section_cluster_kwargs(monkeypatch, required_sections, expected_result): _set_up(monkeypatch, "cluster", ["node2", "node1"], {"node1": "cluster", "node2": "cluster"}) node1_section_content = { SectionName("one"): NODE_1, # TODO (mo): CMK-4232 # SectionName("two"): NODE_1, SectionName("three"): NODE_1 } node2_section_content = { SectionName("two"): NODE_2, SectionName("three"): NODE_2, } multi_host_sections = MultiHostSections() multi_host_sections.setdefault( HostKey("node1", "127.0.0.1", SourceType.HOST), AgentHostSections(sections=node1_section_content), ) multi_host_sections.setdefault( HostKey("node2", "127.0.0.1", SourceType.HOST), AgentHostSections(sections=node2_section_content), ) kwargs = multi_host_sections.get_section_cluster_kwargs( HostKey("cluster", None, SourceType.HOST), [ParsedSectionName(n) for n in required_sections], "_service_description", ) assert expected_result == kwargs,\ "Section content: Expected '%s' but got '%s'" % (expected_result, kwargs)
def create_agent_section_plugin( *, name: str, parsed_section_name: Optional[str] = None, parse_function: Optional[AgentParseFunction] = None, host_label_function: Optional[HostLabelFunction] = None, supersedes: Optional[List[str]] = None, module: Optional[str] = None, ) -> AgentSectionPlugin: """Return an AgentSectionPlugin object after validating and converting the arguments one by one For a detailed description of the parameters please refer to the exposed function in the 'register' namespace of the API. """ section_name = SectionName(name) return AgentSectionPlugin( section_name, ParsedSectionName( parsed_section_name if parsed_section_name else str(section_name)), _create_agent_parse_function(parse_function), _create_host_label_function( host_label_function, # TODO: # The following is a special case for the ps plugin. This should be done # in a more general sense when CMK-5158 is addressed. Make sure to grep for # "CMK-5158" in the code base. {} if name in ("ps", "ps_lnx") else None, ), _create_supersedes(section_name, supersedes), module, )
def test_create_agent_section_plugin(): with pytest.raises(NotImplementedError): plugin = section_plugins.create_agent_section_plugin( name="norris", parsed_section_name="chuck", parse_function=_parse_dummy, supersedes=None, forbidden_names=[], ) with pytest.raises(NotImplementedError): plugin = section_plugins.create_agent_section_plugin( name="norris", parsed_section_name=None, parse_function=_parse_dummy, supersedes=["Foo", "Bar"], forbidden_names=[], ) plugin = section_plugins.create_agent_section_plugin( name="norris", parsed_section_name=None, # "chuck" parse_function=_parse_dummy, supersedes=None, # ["Foo", "Bar"], forbidden_names=[], ) assert isinstance(plugin, section_types.AgentSectionPlugin) assert len(plugin) == 6 assert plugin.name == SectionName("norris") assert plugin.parsed_section_name == ParsedSectionName( "norris") # "chuck") assert plugin.parse_function is _parse_dummy assert plugin.host_label_function is section_plugins._noop_host_label_function assert plugin.supersedes == [] # [SectionName("Bar"), SectionName("Foo")]
def _section(name: str, parsed_section_name: str, supersedes: Set[str]) -> SectionPlugin: section = trivial_section_factory(SectionName(name)) return section._replace( parsed_section_name=ParsedSectionName(parsed_section_name), supersedes={SectionName(n) for n in supersedes}, )
def test_straight_forward_case(self): resolver, parser = self.make_provider(section_plugins=[ _section("section_one", "parsed_section_name", set()), ]) resolved = resolver.resolve( parser, # type: ignore[arg-type] ParsedSectionName("parsed_section_name"), ) assert resolved parsed, section = resolved assert parsed and parsed.data == 1 assert section and section.name == SectionName("section_one") assert resolver.resolve( parser, # type: ignore[arg-type] ParsedSectionName("no_such_section"), ) is None
def test_parse_sections_superseded(monkeypatch): host_key, mhs = _get_host_section_for_parse_sections_test() monkeypatch.setattr( agent_based_register._config, "get_section_plugin", MOCK_SECTIONS.get, ) assert mhs.determine_applicable_sections( {ParsedSectionName("parsed"), ParsedSectionName("parsed_four")}, host_key.source_type, ) == [ SECTION_FOUR, ] assert mhs.get_parsed_section(host_key, ParsedSectionName("parsed")) is None
def create_agent_section_plugin( *, name: str, parsed_section_name: Optional[str] = None, parse_function: Optional[AgentParseFunction] = None, host_label_function: Optional[HostLabelFunction] = None, supersedes: Optional[List[str]] = None, module: Optional[str] = None, validate_creation_kwargs: bool = True, ) -> AgentSectionPlugin: """Return an AgentSectionPlugin object after validating and converting the arguments one by one For a detailed description of the parameters please refer to the exposed function in the 'register' namespace of the API. """ section_name = SectionName(name) if validate_creation_kwargs: if parse_function is not None: _validate_parse_function( parse_function, expected_annotation=_create_parse_annotation(), ) if host_label_function is not None: validate_function_arguments( type_label="host_label", function=host_label_function, has_item=False, # TODO: # The following is a special case for the ps plugin. This should be done # in a more general sense when CMK-5158 is addressed. Make sure to grep for # "CMK-5158" in the code base. default_params={} if name in ("ps", "ps_lnx") else None, sections=[ParsedSectionName("__always_just_one_section__")], ) return AgentSectionPlugin( section_name, ParsedSectionName( parsed_section_name if parsed_section_name else str(section_name)), _create_agent_parse_function(parse_function), _create_host_label_function(host_label_function), _create_supersedes(section_name, supersedes), module, )
def trivial_section_factory(section_name: SectionName) -> AgentSectionPlugin: return AgentSectionPlugin( name=section_name, parsed_section_name=ParsedSectionName(str(section_name)), parse_function=parse_to_string_table, host_label_function=_noop_host_label_function, supersedes=set(), module=None, )
def test_superseder_is_present(self): resolver, parser = self.make_provider(section_plugins=[ _section("section_one", "parsed_section_one", set()), _section("section_two", "parsed_section_two", {"section_one"}), ]) assert resolver.resolve( parser, # type: ignore[arg-type] ParsedSectionName("parsed_section_one"), ) is None
def test_create_snmp_section_plugin(): trees: List[SNMPTree] = [ section_types.SNMPTree( base='.1.2.3', oids=[OIDEnd(), '2.3'], ), ] detect = [ [('.1.2.3.4.5', 'Foo.*', True)], ] with pytest.raises(NotImplementedError): plugin = section_plugins.create_snmp_section_plugin( name="norris", parsed_section_name="chuck", parse_function=_parse_dummy, trees=trees, detect_spec=detect, supersedes=None, forbidden_names=[], ) with pytest.raises(NotImplementedError): plugin = section_plugins.create_snmp_section_plugin( name="norris", parsed_section_name=None, parse_function=_parse_dummy, trees=trees, detect_spec=detect, supersedes=["Foo", "Bar"], forbidden_names=[], ) plugin = section_plugins.create_snmp_section_plugin( name="norris", parsed_section_name=None, # "chuck", parse_function=_parse_dummy, trees=trees, detect_spec=detect, supersedes=None, # ["Foo", "Bar"], forbidden_names=[], ) assert isinstance(plugin, section_types.SNMPSectionPlugin) assert len(plugin) == 8 assert plugin.name == SectionName("norris") assert plugin.parsed_section_name == ParsedSectionName( "norris") # "chuck") assert plugin.parse_function is _parse_dummy assert plugin.host_label_function is section_plugins._noop_host_label_function assert plugin.detect_spec == detect assert plugin.trees == trees assert plugin.supersedes == [] # [SectionName("Bar"), SectionName("Foo")]
def trivial_section_factory(section_name: SectionName) -> AgentSectionPlugin: return AgentSectionPlugin( name=section_name, parsed_section_name=ParsedSectionName(str(section_name)), parse_function=lambda string_table: string_table, host_label_function=_noop_host_label_function, host_label_default_parameters=None, host_label_ruleset_name=None, host_label_ruleset_type="merged", # doesn't matter, use default. supersedes=set(), module=None, )
def _test_section( *, section_name: str, parsed_section_name: str, parse_function: Callable, supersedes: Iterable[str], ) -> section_plugins.AgentSectionPlugin: return section_plugins.trivial_section_factory(SectionName(section_name))._replace( parsed_section_name=ParsedSectionName(parsed_section_name), parse_function=parse_function, supersedes={SectionName(n) for n in supersedes}, )
def test_get_parsed_section(patch_register, node_sections, expected_result): parsed_sections_broker = ParsedSectionsBroker({ HostKey("node1", "127.0.0.1", SourceType.HOST): SectionsParser(host_sections=node_sections) }) content = parsed_sections_broker.get_parsed_section( HostKey("node1", "127.0.0.1", SourceType.HOST), ParsedSectionName("parsed"), ) assert expected_result == content
def test_create_check_plugin(): plugin = check_plugins.create_check_plugin(**MINIMAL_CREATION_KWARGS) assert plugin.name == CheckPluginName(MINIMAL_CREATION_KWARGS["name"]) assert plugin.sections == [ParsedSectionName(MINIMAL_CREATION_KWARGS["name"])] assert plugin.service_name == MINIMAL_CREATION_KWARGS["service_name"] assert plugin.discovery_function.__name__ == MINIMAL_CREATION_KWARGS[ "discovery_function"].__name__ assert plugin.discovery_default_parameters == {} assert plugin.discovery_ruleset_name is None assert plugin.check_function.__name__ == MINIMAL_CREATION_KWARGS["check_function"].__name__ assert plugin.check_default_parameters == {} assert plugin.check_ruleset_name is None