Highlight in red host names in rule conditions that no longer exist

This commit is contained in:
Luigi D'Acunto 2026-09-28 15:03:56 +02:00
parent 4dabc35932
commit 63177a9573
3 changed files with 46 additions and 1 deletions

View file

@ -5,6 +5,11 @@ All notable changes to **Checkmk SwissKnife** are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.24.0] - 2026-09-28
### Added
- On rule list pages (`mode=edit_ruleset`), exact host names in a rule's "Host name" condition that are not linked to a host (i.e. the host no longer exists in Checkmk) are now highlighted in red with a tooltip. Regexes, host groups and host tags are ignored, and the highlight works for mixed conditions ("matches regex …, is host01 or matches regex …") and for negated ones ("is not" / "does not match regex").
## [2.23.0] - 2026-09-28 ## [2.23.0] - 2026-09-28
### Added ### Added

View file

@ -24,6 +24,7 @@ A [Tampermonkey](https://www.tampermonkey.net/) userscript that enhances the Che
| **Rule Match Status** | Colors each rule row green (match) or dimmed (no match) when a ruleset is opened with host/service context | `highlightRuleMatchStatus` | | **Rule Match Status** | Colors each rule row green (match) or dimmed (no match) when a ruleset is opened with host/service context | `highlightRuleMatchStatus` |
| **Relevant Only Filter** | Adds a "Relevant only" toggle above the rule list to hide all non-matching and non-highlighted rows | `addRulesetFilterToggle` | | **Relevant Only Filter** | Adds a "Relevant only" toggle above the rule list to hide all non-matching and non-highlighted rows | `addRulesetFilterToggle` |
| **Ruleset Free-Text Filter** | Adds a search box above the rule list on any ruleset page to hide rules and folders whose row text doesn't contain the typed string; mutually exclusive with "Relevant only" | `addRulesetTextFilter` | | **Ruleset Free-Text Filter** | Adds a search box above the rule list on any ruleset page to hide rules and folders whose row text doesn't contain the typed string; mutually exclusive with "Relevant only" | `addRulesetTextFilter` |
| **Missing Host Highlight** | Paints in red the exact host names in a rule's "Host name" condition that are not linked to a host, i.e. hosts that no longer exist | `highlightMissingHosts` |
| **Extra Column — Host Actions** | Inserts an Extra column in monitoring tables with per-host buttons: Service Discovery, copy FQDN, copy short hostname, copy IP | `addInventoryButtons` | | **Extra Column — Host Actions** | Inserts an Extra column in monitoring tables with per-host buttons: Service Discovery, copy FQDN, copy short hostname, copy IP | `addInventoryButtons` |
| **Monitor Button in WATO Folder** | Adds a green eye icon next to each active host in WATO folder listings to open its monitoring view in a new tab | `addWatoFolderMonitorButtons` | | **Monitor Button in WATO Folder** | Adds a green eye icon next to each active host in WATO folder listings to open its monitoring view in a new tab | `addWatoFolderMonitorButtons` |
| **Configure in WATO Menu** | Adds a host-selector dropdown and Open button to the monitoring view menu bar for bulk-opening hosts in WATO | `addViewWatoMenu` | | **Configure in WATO Menu** | Adds a host-selector dropdown and Open button to the monitoring view menu bar for bulk-opening hosts in WATO | `addViewWatoMenu` |
@ -90,6 +91,13 @@ Applies to: every `mode=edit_ruleset` page, with or without host/service context
--- ---
### Missing Host Highlight
In a rule's "Host name" condition, exact host names that are not linked to a host (the host no longer exists in Checkmk) are shown in red with a wavy underline and a tooltip. Regexes, host groups and host tags are ignored. Works on mixed conditions ("matches regex …, is host01 or matches regex …") and on negated ones ("is not", "does not match regex").
Applies to: every `mode=edit_ruleset` page, with or without host/service context.
---
### Extra Column with Host Actions ### Extra Column with Host Actions
Adds a dedicated **Extra** column before the Host column in all monitoring view tables. Each row gets up to four icon buttons: Adds a dedicated **Extra** column before the Host column in all monitoring view tables. Each row gets up to four icon buttons:

View file

@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name Checkmk SwissKnife // @name Checkmk SwissKnife
// @namespace https://luigidacunto.com/ // @namespace https://luigidacunto.com/
// @version 2.23.0 // @version 2.24.0
// @checkmk 2.3.x - 2.4.x // @checkmk 2.3.x - 2.4.x
// @description Collection of UI improvements for Checkmk WATO. Each fix or enhancement is added here as an independent feature. // @description Collection of UI improvements for Checkmk WATO. Each fix or enhancement is added here as an independent feature.
// @author Luigi D'Acunto // @author Luigi D'Acunto
@ -893,6 +893,37 @@
} }
// =========================================================================
// FEATURE: Missing Host Highlight
//
// In a rule's "Host name ..." condition, exact host names are rendered as a
// link to the host only if the host still exists; an unlinked name means the
// host was deleted. Those names are painted red. Regexes are ignored.
// =========================================================================
function highlightMissingHosts(doc) {
if (doc.body.dataset.cmkMissingHosts === '1') return;
const items = doc.querySelectorAll('tr.data li.condition');
if (!items.length) return;
doc.body.dataset.cmkMissingHosts = '1';
injectStyles(doc, 'cmk-sk-missing-host-styles', `
b.cmk-sk-missing-host { color: #ff4d4d !important; text-decoration: underline wavy #ff4d4d; }
`);
items.forEach(li => {
if (!li.textContent.trim().startsWith('Host name')) return;
li.querySelectorAll('b').forEach(b => {
// Text right before each <b> tells regex ("matches regex", "one of regex") from exact name ("is", "is not")
const before = b.previousSibling ? b.previousSibling.textContent : '';
if (/regex/.test(before) || b.querySelector('a')) return;
b.classList.add('cmk-sk-missing-host');
b.title = 'Host not found in Checkmk (deleted?)';
});
});
}
// ========================================================================= // =========================================================================
// FEATURE: Inventory Button on view.py // FEATURE: Inventory Button on view.py
// //
@ -2049,6 +2080,7 @@
highlightRuleMatchStatus(doc); highlightRuleMatchStatus(doc);
addRulesetFilterToggle(doc); addRulesetFilterToggle(doc);
addRulesetTextFilter(doc); addRulesetTextFilter(doc);
highlightMissingHosts(doc);
} }
function tryAddInventoryButtons() { function tryAddInventoryButtons() {