Summary
Let a check declare an optional exclude: Rhai predicate; Wanda evaluates it per target using host metadata supplied by Trento Web, and drops excluded hosts before dispatching the gathering request.
Motivation
Today a check execution runs against every host of the selected target — either a single host, or every host of a cluster. There is no way for a check author to declare "this check does not apply to host X" based on properties of the host itself.
We want check authors to express, inside the check definition, a predicate that decides per-host whether the check should run at all, evaluated against data the Web UI already knows about each host.
Use Cases outline
-
As a check author, I want to declare that a check does not apply to hosts with certain properties (e.g. provider, OS family, cluster role), so that I don’t need to maintain near-duplicate checks.
-
As a user running an execution, I want excluded hosts to be clearly surfaced in the result, distinct from failed or skipped ones, so that I can tell why a host was not evaluated.
-
As a catalog maintainer, I want applicability logic to live next to the check it belongs to, instead of being scattered across Web, Wanda and catalog curation.
Detailed Design
Overview
-
Trento Web attaches a small, structured "host data" payload to each target in the execution request.
-
The execution-request contract is extended so each target carries its host data alongside
agent_idandchecks. -
A check definition gains an optional top-level
exclude:field, containing a Rhai expression evaluated against the host data. -
Wanda evaluates the
excludepredicate per (host, check) pair and filters out excluded pairs before dispatchingFactsGatheringRequestedto the agents. -
Excluded pairs are reported in the execution result with a clear "excluded" status, distinct from failed or skipped, so the UI can render it.
Component changes
Trento Web
For each host in the execution request, attach a free-form attributes map (see Contracts). Initial keys are whatever the catalog asks for — plausible candidates drawn from the existing host read model include provider, os_family, arch, roles, cluster_role, is_majority_maker — but the proto does not fix the set, and Web is free to start emitting new keys when a check author needs them.
A corresponding UI change was implemented alongside the server-side changes: the excluded result status is surfaced in the execution detail view, so users can clearly see why a host was not evaluated for a given check.
Contracts
The change is confined to the Target message in target.proto, which is already carried by ExecutionRequested.targets. FactsGatheringRequested is not affected: host data is consumed by Wanda before dispatch and is never forwarded to agents.
Current shape
// contracts/proto/target.proto
syntax = "proto3";
package Trento.Checks.V1;
message Target {
string agent_id = 1;
repeated string checks = 2;
}
Proposed shape
Add a single new field attributes on Target, typed as map<string, google.protobuf.Value>. The map is free-form: there are no typed fields, no reserved keys, and no schema-level contract on the set of attributes Web emits. Values use google.protobuf.Value so scalars, lists and nested structs are all representable without breaking the wire format. This mirrors the existing ExecutionRequested.env field (same package, same import), so we do not introduce a new convention.
// contracts/proto/target.proto
syntax = "proto3";
package Trento.Checks.V1;
import "google/protobuf/struct.proto";
message Target {
string agent_id = 1;
repeated string checks = 2;
// Free-form host attributes known to Trento Web at request time.
// Consumed by Wanda to evaluate each check's `exclude` predicate;
// never forwarded to agents.
//
// Keys are opaque strings agreed between Trento Web (producer) and
// check authors (consumers); the contract on which keys exist and
// what they mean lives outside the proto file.
map<string, google.protobuf.Value> attributes = 3;
}
Checks
A new optional top-level field exclude: on a check, containing a Rhai expression.
Contract:
-
The script receives one host’s data as input and must return a boolean.
-
true⇒ exclude this host from this check. -
Absent field ⇒ never exclude (current behaviour).
id: "ABC123"
name: Check that does not apply to majority maker nodes
exclude: |
host.is_majority_maker == true
facts:
- ...
expectations:
- ...
In an HA cluster, a majority maker node participates in quorum decisions but does not run the workload being checked. Checks targeting the workload (e.g. SAP or database configuration) should skip such nodes entirely rather than produce spurious failures or forcing authors to maintain a separate "non-majority-maker" variant of the check.
Wanda
Before dispatching FactsGatheringRequested to agents, Wanda:
-
Evaluates each check’s
excludepredicate against each target’s host data. -
Filters the (host, check) pairs accordingly.
-
Reports excluded pairs in the execution result with a clear "excluded" status, distinct from failed / skipped, so the UI can render it.
The predicate runs in the same Rhai sandbox Wanda already uses for checks; no new sandboxing is introduced.
Non-goals
-
Changing how
when:conditions work. -
Letting the predicate query remote facts: it only sees host data Web already has; no extra round-trip.
-
User-authored ad-hoc exclusions from the UI.
-
Security sandboxing changes:
excluderuns in the same Rhai sandbox Wanda already uses for checks.
Summary of Changes
| Action | Target | Description |
|---|---|---|
Attach host data to execution targets |
Trento Web |
For each host in an execution request, forward a structured "host data" payload (majority maker, provider, OS family, roles, arch, cluster role, …) to Wanda. |
Extend |
Contracts |
Add |
New optional |
Checks catalog |
Top-level Rhai expression that receives one host’s data and returns a boolean. |
Evaluate |
Wanda |
Filter (host, check) pairs before sending |