diff --git a/agent_based/ospfv3_general.py b/agent_based/ospfv3_general.py index c6f909e54f9d8625119bf20dc6231a5be5880869..ff62f865aa10c320be4c603001c51a7f9339f412 100644 --- a/agent_based/ospfv3_general.py +++ b/agent_based/ospfv3_general.py @@ -10,6 +10,7 @@ # Monitor status of OSPFv3 general status # # 2021-09-17: rewritten for CMK 2.0 +# 2021-10-02: added WATO options # # sample snmpwalk # .1.3.6.1.2.1.191.1.1.1.0 = Gauge32: 50529054 @@ -111,8 +112,11 @@ def parse_ospfv3_general(string_table: StringTable) -> Optional[OspfV3General]: ) -def discovery_ospfv3_general(section: OspfV3General) -> DiscoveryResult: - yield Service() +def discovery_ospfv3_general(params, section: OspfV3General) -> DiscoveryResult: + if section.AdminStatus != 'disabled': + yield Service() + elif params['admin_disabled']: + yield Service() def check_ospfv3_general(params, section: OspfV3General) -> CheckResult: @@ -128,7 +132,7 @@ def check_ospfv3_general(params, section: OspfV3General) -> CheckResult: yield Result(state=State.OK, notice=f'Stub router advertisement: {section.StubRouterAdvertisement}') if section.AdminStatus == 'disabled': - yield Result(state=State.WARN, notice='Admin disabled') + yield Result(state=State(params['state_admin_disabled']), notice='Admin disabled') yield Metric(name='ospf3_general_lsacount', value=section.AsScopeLsaCount) yield Metric(name='ospf3_general_rxnewlsas', value=section.RxNewLsas) @@ -178,6 +182,11 @@ register.check_plugin( discovery_function=discovery_ospfv3_general, check_function=check_ospfv3_general, check_default_parameters={ + 'state_admin_disabled': 1, }, check_ruleset_name='ospfv3_general', + discovery_ruleset_name='discovery_ospfv3_general', + discovery_default_parameters={ + 'admin_disabled': False, + }, ) diff --git a/agent_based/ospfv3_interface.py b/agent_based/ospfv3_interface.py index 9e01868f4a44c24e784b2c71a09868a9bf4dbbd0..479e31885e4c241b8d3c33257aafc26257d16e65 100644 --- a/agent_based/ospfv3_interface.py +++ b/agent_based/ospfv3_interface.py @@ -10,6 +10,7 @@ # Monitor status of OSPFv3 enabled interfaces # # 2021-09-17: rewritten for CMK 2.0 +# 2021-10-02: added WATO options # # sample snmpwalk # @@ -186,7 +187,13 @@ def check_ospfv3_interface(item, params, section: Dict[str, OspfV3Interface]) -> yield Result(state=State.OK, summary=f'Area: {interface.IfAreaId}') yield Result(state=State.OK, summary=f'DR: {interface.IfDesignatedRouter}') yield Result(state=State.OK, summary=f'BDR: {interface.IfBackupDesignatedRouter}') - yield Result(state=State.OK, summary=f'State: {interface.IfState}') + + if interface.IfState in ['down']: + yield Result(state=State(params['state_if_down']), notice=f'State: {interface.IfState}') + elif interface.IfState in ['waiting', 'standby']: + yield Result(state=State(params['state_if_wait_stby']), notice=f'State: {interface.IfState}') + else: + yield Result(state=State.OK, summary=f'State: {interface.IfState}') yield Result(state=State.OK, notice=f'Link scope LSA checksum: {interface.IfLinkLsaCksumSum}') yield Result(state=State.OK, notice=f'Interface type: {interface.IfType}') @@ -197,13 +204,7 @@ def check_ospfv3_interface(item, params, section: Dict[str, OspfV3Interface]) -> yield Result(state=State.OK, notice=f'Interface metric value: {interface.IfMetricValue}') if interface.IfAdminStatus == 'disabled': - yield Result(state=State.WARN, notice='Admin status is disabled') - - if interface.IfState in ['down']: - yield Result(state=State.CRIT, notice=f'State is {interface.IfState}') - - if interface.IfState in ['waiting', 'standby']: - yield Result(state=State.WARN, notice=f'state is {interface.IfState}') + yield Result(state=State(params['state_admin_disabled']), notice='Admin status is disabled') yield Metric(name='ospfv3_interface_events', value=interface.IfEvents) yield Metric(name='ospfv3_interface_linkscopelsacount', value=interface.IfLinkScopeLsaCount) @@ -259,6 +260,9 @@ register.check_plugin( discovery_function=discovery_ospfv3_interface, check_function=check_ospfv3_interface, check_default_parameters={ + 'state_admin_disabled': 1, + 'state_if_down': 2, + 'state_if_wait_stby': 1, }, check_ruleset_name='ospfv3_interface', ) diff --git a/agent_based/ospfv3_neighbor.py b/agent_based/ospfv3_neighbor.py index f074333c2a50910bb513ef3058d465cc74b4e21b..f349bade6a06eaa1606fa0f81a21a85ba12e45d0 100644 --- a/agent_based/ospfv3_neighbor.py +++ b/agent_based/ospfv3_neighbor.py @@ -10,6 +10,7 @@ # Monitor status of OSPFv3 neighbors # # 2021-09-17: rewritten for CMK 2.0 +# 2021-10-02: added WATO options # # .1.3.6.1.2.1.191.1.9.1.4.1.0.50529054 = INTEGER: 2 # .1.3.6.1.2.1.191.1.9.1.5.1.0.50529054 = Hex-STRING: FE 80 00 00 00 00 00 00 01 92 01 68 00 00 00 03 @@ -160,27 +161,41 @@ def discovery_ospfv3_neighbor(section: Dict[str, OspfV3Neighbor]) -> DiscoveryRe def check_ospfv3_neighbor(item, params, section: Dict[str, OspfV3Neighbor]) -> CheckResult: + + not_found_state = params['state_not_found'] + + for neighbour, neighbourAlias, neighbourNotFoundState in params.get('peer_list', []): + if item == neighbour: + yield Result(state=State.OK, summary=f'[{neighbourAlias}]') + not_found_state = neighbourNotFoundState + try: neighbor = section[item] except KeyError: - yield Result(state=State.UNKNOWN, notice='Item not found in SNMP data') + yield Result(state=State(not_found_state), notice='Item not found in SNMP data') return - nbrstatus = ospf_nbr_state(neighbor.nbrState) + # default monitoring states for ospfNbrState + neighbor_states = { + '1': 2, # down + '2': 1, # attempt + '3': 1, # init + '4': 0, # twoWay + '5': 1, # exchangeStart + '6': 1, # exchange + '7': 1, # loading + '8': 0, # full + } yield Result(state=State.OK, summary=f'Neighbor ID: {neighbor.nbrRtrId}') - # yield Result(state=State.OK, summary=f'. on interface: {neighbor.nbrLocalInterface}') + # yield Result(state=State.OK, summary=f'On interface: {neighbor.nbrLocalInterface}') - nbrstate = neighbor.nbrState + neighbor_states.update(params.get('neighbor_states', neighbor_states)) # update neighbor_states with params - if nbrstate in params['critical_states']: - yield Result(state=State.CRIT, notice=f'State: {nbrstatus}') - elif nbrstate in params['warning_states']: - yield Result(state=State.WARN, notice=f'State: {nbrstatus}') - elif nbrstate in params['ok_states']: - yield Result(state=State.OK, summary=f'State: {nbrstatus}') - else: - yield Result(state=State.UNKNOWN, notice='Invalid Output from Agent') + yield Result( + state=State(neighbor_states.get(neighbor.nbrState, 3)), + summary=f'Status: {ospf_nbr_state(neighbor.nbrState)}' + ) yield Result(state=State.OK, notice=f'Neighbor options: {neighbor.nbrOptions}') yield Result(state=State.OK, notice=f'Neighbor priority: {neighbor.nbrPriority}') @@ -232,9 +247,6 @@ register.check_plugin( discovery_function=discovery_ospfv3_neighbor, check_function=check_ospfv3_neighbor, check_default_parameters={ - 'ok_states': [8, 4], - 'warning_states': [2, 3, 5, 6, 7], - 'critical_states': [1], }, check_ruleset_name='ospfv3_neighbor', ) diff --git a/agent_based/ospfv3_virtuallink.py b/agent_based/ospfv3_virtuallink.py index f78aeb3854aca5940e2326524eed10b1e223d9b5..74c07fc3f8dfb43bb73c461614702b928986c495 100644 --- a/agent_based/ospfv3_virtuallink.py +++ b/agent_based/ospfv3_virtuallink.py @@ -10,6 +10,7 @@ # Monitor status of OSPFv3 virtual-links # # 2021-09-17: rewritten for CMK 2.0 +# 2021-10-02: added WATO options # # .1.3.6.1.2.1.191.1.11.1.3.3.50529054 = INTEGER: 0 # .1.3.6.1.2.1.191.1.11.1.4.3.50529054 = Gauge32: 0 @@ -155,27 +156,41 @@ def discovery_ospfv3_virtuallink(section: Dict[str, OspfV3VirtualLink]) -> Disco def check_ospfv3_virtuallink(item, params, section: Dict[str, OspfV3VirtualLink]) -> CheckResult: + + not_found_state = params['state_not_found'] + + for virtual_link, alias, NotFoundState in params.get('peer_list', []): + if item == virtual_link: + yield Result(state=State.OK, summary=f'[{alias}]') + not_found_state = NotFoundState + try: virtual_link = section[item] except KeyError: - yield Result(state=State.UNKNOWN, notice='Item not found in SNMP data') + yield Result(state=State(not_found_state), notice='Item not found in SNMP data') return - nbrstatus = ospf_nbr_state(virtual_link.VirtNbrState) + # default monitoring states for ospfNbrState + neighbor_states = { + '1': 2, # down + '2': 1, # attempt + '3': 1, # init + '4': 0, # twoWay + '5': 1, # exchangeStart + '6': 1, # exchange + '7': 1, # loading + '8': 0, # full + } + + neighbor_states.update(params.get('neighbor_states', neighbor_states)) # update neighbor_states with params yield Result(state=State.OK, summary=f'Neighbor ID: {virtual_link.VirtNbrId}') yield Result(state=State.OK, summary=f'Area: {virtual_link.VirtNbrArea}') - nbrstate = virtual_link.VirtNbrState - - if nbrstate in params['critical_states']: - yield Result(state=State.CRIT, notice='State: {nbrstatus}') - elif nbrstate in params['warning_states']: - yield Result(state=State.WARN, notice=f'State: {nbrstatus}') - elif nbrstate in params['ok_states']: - yield Result(state=State.OK, summary=f', State: {nbrstatus}') - else: - yield Result(state=State.UNKNOWN, notice='Invalid Output from Agent') + yield Result( + state=State(neighbor_states.get(virtual_link.VirtNbrState, 3)), + summary=f'Status: {ospf_nbr_state(virtual_link.VirtNbrState)}' + ) yield Result(state=State.OK, notice=f'Virtual link options: {virtual_link.VirtNbrOptions}') yield Result(state=State.OK, notice=f'Virtual link hello suppressed: {virtual_link.VirtNbrHelloSuppressed}') @@ -228,9 +243,6 @@ register.check_plugin( discovery_function=discovery_ospfv3_virtuallink, check_function=check_ospfv3_virtuallink, check_default_parameters={ - 'ok_states': [8, 4], - 'warning_states': [2, 3, 5, 6, 7], - 'critical_states': [1], }, check_ruleset_name='ospfv3_virtuallink', ) diff --git a/ospfv3.mkp b/ospfv3.mkp index e46832ab2faabdf1ed8b4d742e190900e05650fa..5ad8fcccb6f6edaf3119ad1e22956d931158ef85 100644 Binary files a/ospfv3.mkp and b/ospfv3.mkp differ diff --git a/packages/ospfv3 b/packages/ospfv3 index 5ac9a2f96fac658de96e3b922bb343794d219c6c..be7a5c493e5591f6e027058f9240c7cb58ba0b27 100644 --- a/packages/ospfv3 +++ b/packages/ospfv3 @@ -7,11 +7,11 @@ 'ospfv3_neighbor.py', 'ospfv3_virtuallink.py', 'utils/ospfv3.py'], - 'web': ['plugins/metrics/ospfv3.py']}, + 'web': ['plugins/metrics/ospfv3.py', 'plugins/wato/ospfv3.py']}, 'name': 'ospfv3', - 'num_files': 7, + 'num_files': 8, 'title': 'Collection of OSPFv3 checks', - 'version': '20210917.v0.2', + 'version': '20211002.v0.3', 'version.min_required': '2.0.0', - 'version.packaged': '2021.07.14', + 'version.packaged': '2021.09.20', 'version.usable_until': None} \ No newline at end of file diff --git a/web/plugins/metrics/ospfv3.py b/web/plugins/metrics/ospfv3.py index 58e9e6c1a9b267bb1691554075eb4072a139cb28..0cb2beb915d14725f8b9a436a6745fbfd458f388 100644 --- a/web/plugins/metrics/ospfv3.py +++ b/web/plugins/metrics/ospfv3.py @@ -46,7 +46,7 @@ metric_info['ospfv3_events'] = { 'color': '26/a', } metric_info['ospfv3_lsretransqlen'] = { - 'title': _('queue length'), + 'title': _('Queue length'), 'unit': 'count', 'color': '16/a', } diff --git a/web/plugins/wato/ospfv3.py b/web/plugins/wato/ospfv3.py new file mode 100644 index 0000000000000000000000000000000000000000..b6a632e9dbbbd036c157ad8ded1a4e164d35ae2a --- /dev/null +++ b/web/plugins/wato/ospfv3.py @@ -0,0 +1,370 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# License: GNU General Public License v2 +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2021-09-28 +# +# wato plugin for ospfv3_neighbor check +# +# +from cmk.gui.i18n import _ +from cmk.gui.valuespec import ( + Dictionary, + TextAscii, + ListOf, + Tuple, + TextUnicode, + MonitoringState, + FixedValue, +) + +from cmk.gui.plugins.wato import ( + CheckParameterRulespecWithItem, + rulespec_registry, + RulespecGroupCheckParametersNetworking, + RulespecGroupCheckParametersDiscovery, + HostRulespec, +) + +neighbor_states = ('neighbor_states', + Dictionary( + title=_('State to report for OSPF neighbor state'), + help=_('Map each OSPF state to a CheckMK monitoring state'), + elements=[ + ('1', + MonitoringState( + title=_('1 - down'), + help=_( + 'This is the first OSPF neighbor state. It means that no information (hellos) has ' + 'been received from this neighbor, but hello packets can still be sent to the ' + 'neighbor in this state. During the fully adjacent neighbor state, if a router ' + 'doesn\'t receive hello packet from a neighbor within the RouterDeadInterval time ' + '(RouterDeadInterval = 4*HelloInterval by default) or if the manually configured ' + 'neighbor is being removed from the configuration, then the neighbor state changes ' + 'from Full to Down. Default monitoring state is "CRIT"'), + default_value=2, + )), + ('2', + MonitoringState( + title=_('2 - attempt'), + help=_( + 'This state is only valid for manually configured neighbors in an NBMA ' + 'environment. In Attempt state, the router sends unicast hello packets every poll ' + 'interval to the neighbor, from which hellos have not been received within the ' + 'dead interval. Default monitoring state is "WARN"'), + default_value=1, + )), + ('3', + MonitoringState( + title=_('3 - init'), + help=_( + 'This state specifies that the router has received a hello packet from its ' + 'neighbor, but the receiving router\'s ID was not included in the hello packet. ' + 'When a router receives a hello packet from a neighbor, it should list the ' + 'sender\'s router ID in its hello packet as an acknowledgment that it received a ' + 'valid hello packet. Default monitoring state is "WARN"'), + default_value=1, + )), + ('4', + MonitoringState( + title=_('4 - twoWay'), + help=_( + 'This state designates that bi-directional communication has been established ' + 'between two routers. Bi-directional means that each router has seen the other\'s ' + 'hello packet. This state is attained when the router receiving the hello packet ' + 'sees its own Router ID within the received hello packet\'s neighbor field. At ' + 'this state, a router decides whether to become adjacent with this neighbor. On ' + 'broadcast media and non-broadcast multiaccess networks, a router becomes full ' + 'only with the designated router (DR) and the backup designated router (BDR); it ' + 'stays in the 2-way state with all other neighbors. On Point-to-point and ' + 'Point-to-multipoint networks, a router becomes full with all connected routers. ' + 'At the end of this stage, the DR and BDR for broadcast and non-broadcast ' + 'multiacess networks are elected. For more information on the DR election process, ' + 'refer to DR Election. Note: Receiving a Database Descriptor (DBD) packet from a ' + 'neighbor in the init state will also a cause a transition to 2-way state. Default ' + 'monitoring state is "OK"'), + default_value=0, + )), + ('5', + MonitoringState( + title=_('5 - exchangeStart'), + help=_('Once the DR and BDR are elected, the actual process of exchanging link state ' + 'information can start between the routers and their DR and BDR. In this state, ' + 'the routers and their DR and BDR establish a master-slave relationship and ' + 'choose the initial sequence number for adjacency formation. The router with ' + 'the higher router ID becomes the master and starts the exchange, and as such, ' + 'is the only router that can increment the sequence number. Note that one would ' + 'logically conclude that the DR/BDR with the highest router ID will become the ' + 'master during this process of master-slave relation. Remember that the DR/BDR ' + 'election might be purely by virtue of a higher priority configured on the ' + 'router instead of highest router ID. Thus, it is possible that a DR plays the ' + 'role of slave. And also note that master/slave election is on a per-neighbor ' + 'basis. Default monitoring state is "WARN"'), + default_value=1, + )), + ('6', + MonitoringState( + title=_('6 - exchange'), + help=_( + 'In the exchange state, OSPF routers exchange database descriptor (DBD) packets. ' + 'Database descriptors contain link-state advertisement (LSA) headers only and ' + 'describe the contents of the entire link-state database. Each DBD packet has a ' + 'sequence number which can be incremented only by master which is explicitly ' + 'acknowledged by slave. Routers also send link-state request packets and ' + 'link-state update packets (which contain the entire LSA) in this state. The ' + 'contents of the DBD received are compared to the information contained in the ' + 'routers link-state database to check if new or more current link-state ' + 'information is available with the neighbor. Default monitoring state is "WARN"'), + default_value=1, + )), + ('7', + MonitoringState( + title=_('7 - loading'), + help=_( + 'In this state, the actual exchange of link state information occurs. Based on the ' + 'information provided by the DBDs, routers send link-state request packets. The ' + 'neighbor then provides the requested link-state information in link-state update ' + 'packets. During the adjacency, if a router receives an outdated or missing LSA, ' + 'it requests that LSA by sending a link-state request packet. All link-state ' + 'update packets are acknowledged. Default monitoring state is "WARN"'), + default_value=1, + )), + ('8', + MonitoringState( + title=_('8 - full'), + help=_('In this state, routers are fully adjacent with each other. All the router and ' + 'network LSAs are exchanged and the routers databases are fully synchronized. ' + 'Full is the normal state for an OSPF router. If a router is stuck in another ' + 'state, it\'s an indication that there are problems in forming adjacencies. The ' + 'only exception to this is the 2-way state, which is normal in a broadcast ' + 'network. Routers achieve the full state with their DR and BDR only. Neighbors ' + 'always see each other as 2-way. Default monitoring state is "OK"'), + default_value=0, + )), + ])) + + +# ##################################################### +# +# OSPFv3 General +# +# ##################################################### + + +def _parameter_valuespec_ospfv3_general(): + return Dictionary( + elements=[ + ('state_admin_disabled', + MonitoringState( + title=_('State to report if OSPFv3 is admin disabled'), + help=_('Monitoring state if the OSPFv3 process is admin disabled. Default state is "WARNING"'), + default_value=1, + )), + ], + ) + + +rulespec_registry.register( + CheckParameterRulespecWithItem( + check_group_name='ospfv3_general', + group=RulespecGroupCheckParametersNetworking, + match_type='dict', + parameter_valuespec=_parameter_valuespec_ospfv3_general, + title=lambda: _('OSPFv3 general'), + )) + + +def _valuespec_discovery_ospfv3_general(): + return Dictionary( + title=_('OSPFv3 general'), + elements=[ + ('admin_disabled', + FixedValue( + True, + title=_('discover admin disabled OSPFv3 process'), + totext=_('discover admin disabled OSPFv3 process'), + default_value=False, + )), + ], + ) + + +rulespec_registry.register( + HostRulespec( + group=RulespecGroupCheckParametersDiscovery, + match_type='dict', + name='discovery_ospfv3_general', + valuespec=_valuespec_discovery_ospfv3_general, + )) + + +# ##################################################### +# +# OSPFv3 Interface +# +# ##################################################### + + +def _parameter_valuespec_ospfv3_interface(): + return Dictionary( + elements=[ + ('state_admin_disabled', + MonitoringState( + title=_('State to report if OSPFv3 is admin disabled'), + help=_('Monitoring state if OSPFv3 is admin disabled. Default state is "WARNING"'), + default_value=1, + )), + ('state_if_down', + MonitoringState( + title=_('State to report if OSPFv3 is down'), + help=_('Monitoring state if OSPFv3 is down. Default state is "CRITICAL"'), + default_value=2, + )), + ('state_if_wait_stby', + MonitoringState( + title=_('State to report if OSPFv3 is in waiting or standby'), + help=_('Monitoring state if OSPFv3 is waiting/standby. Default state is "WARNING"'), + default_value=1, + )), + ], + ) + + +rulespec_registry.register( + CheckParameterRulespecWithItem( + check_group_name='ospfv3_interface', + group=RulespecGroupCheckParametersNetworking, + item_spec=lambda: TextAscii(title=_('OSPFv3 interface'), ), + match_type='dict', + parameter_valuespec=_parameter_valuespec_ospfv3_interface, + title=lambda: _('OSPFv3 interface'), + )) + + +# ##################################################### +# +# OSPFv3 neighbor +# +# ##################################################### + + +def _parameter_valuespec_ospfv3_neighbor(): + return Dictionary( + elements=[ + ('state_not_found', + MonitoringState( + title=_('State to report if neighbor not found'), + help=_('Default monitoring state if the neighbor is not found in the SNMP data. ' + 'Default state is "UNKNOWN"'), + default_value=3, + )), + neighbor_states, + ('peer_list', + ListOf( + Tuple( + title=_('Neighbors'), + elements=[ + TextUnicode( + title=_('OSPFv3 Neighbor'), + help=_( + 'The configured value must match a OSPFv3 Neighbor item reported by the monitored ' + 'device. For example: "FE80::192:168:10:148 on Vlan1"'), + allow_empty=False, + ), + TextUnicode( + title=_('OSPFv3 Neighbor Alias'), + help=_('You can configure an individual alias here for the OSPF Neighbor matching ' + 'the text configured in the "OSPFv3 Neighbor" field. The alias will ' + 'be shown in the check info (i.e. [your alias])'), + allow_empty=False, + ), + MonitoringState( + default_value=2, + title=_('State if not found'), + help=_('You can configure an individual state if the OSPFv3 Neighbor matching the text ' + 'configured in the "OSPFv3 Neighbor" field is not found. ' + 'Default state is "CRITICAL".') + )]), + add_label=_('Add OSPFv3 Neighbor'), + movable=False, + title=_('Neighbor specific configuration'), + )), + ], + ) + + +rulespec_registry.register( + CheckParameterRulespecWithItem( + check_group_name='ospfv3_neighbor', + group=RulespecGroupCheckParametersNetworking, + item_spec=lambda: TextAscii(title=_('OSPFv3 Neighbor'), ), + match_type='dict', + parameter_valuespec=_parameter_valuespec_ospfv3_neighbor, + title=lambda: _('OSPFv3 neighbor'), + )) + + +# ##################################################### +# +# OSPFv3 virtual link +# +# ##################################################### + + +def _parameter_valuespec_ospfv3_virtuallink(): + return Dictionary( + elements=[ + ('state_not_found', + MonitoringState( + title=_('State to report if virtual link not found'), + help=_('Default monitoring state if the virtual link is not found in the SNMP data. ' + 'Default monitoring state is "UNKNOWN"'), + default_value=3, + )), + neighbor_states, + ('peer_list', + ListOf( + Tuple( + title=_('Virtual Link'), + elements=[ + TextUnicode( + title=_('OSPFv3 Virtual-Link'), + help=_( + 'The configured value must match a OSPFv3 Virtual-Link item reported by the monitored ' + 'device. For example: "2003::192:168:0:1"'), + allow_empty=False, + ), + TextUnicode( + title=_('OSPFv3 Virtual-Link Alias'), + help=_('You can configure an individual alias here for the OSPFv3 Virtual-Link matching ' + 'the text configured in the "OSPFv3 Virtual-Link" field. The alias will ' + 'be shown in the check info (i.e. [your alias])'), + allow_empty=False, + ), + MonitoringState( + default_value=2, + title=_('State if not found'), + help=_('You can configure an individual state if the OSPFv3 Virtual-Link matching the ' + 'text configured in the "OSPFv3 Virtual-Link" field is not found. ' + 'Default state is "CRITICAL".') + )]), + add_label=_('Add Virtual-Link'), + movable=False, + title=_('Virtual-Link specific configuration'), + )), + ], + ) + + +rulespec_registry.register( + CheckParameterRulespecWithItem( + check_group_name='ospfv3_virtuallink', + group=RulespecGroupCheckParametersNetworking, + item_spec=lambda: TextAscii(title=_('OSPFv3 virtual link'), ), + match_type='dict', + parameter_valuespec=_parameter_valuespec_ospfv3_virtuallink, + title=lambda: _('OSPFv3 virtual link'), + ))