A YANG Data Model for Service Assurance
Extracted elements (27)
Circular dependency detection is performed at the server rather than enforced as a YANG XPath constraint because implementing a full graph-traversal reachability check in XPath is impractical, and because merging two independently loop-free graphs can produce a graph with a loop (as demonstrated in RFC 9417 Section 3.1.1).
New subservice types are added via augmentation of a separate YANG module (not by modifying the base module). Naming conventions are prescribed: module names start with `ietf-service-assurance-`, namespaces with `urn:ietf:params:xml:ns:yang:ietf-service-assurance-`, and prefixes with `sain-`, enabling consistent vendor and IETF extensions.
The `assured-services` container is a denormalized query-optimization index: without it, retrieving all subservices for a specific service instance would require recursively following dependency leafrefs starting from the service-instance node. The container precomputes and flattens this traversal.
The relationship between `health-score` and symptom `health-score-weight` values is intentionally left to the implementor. The only normative constraint is that a sub-100 score must be accompanied by at least one symptom; how weights are aggregated into a score is implementation-specific.
All YANG modules in this document conform to the Network Management Datastore Architecture (NMDA) defined in RFC 8342. The module uses `config false` for read-only operational state nodes and `config true` (default) for configurable nodes, consistent with NMDA datastore separation.
A health score strictly less than 100 must be explained by at least one currently active symptom with a `health-score-weight` greater than 0. This invariant links the numerical health score to observable symptoms.
A server implementing `ietf-service-assurance` MUST check for dependency loops whenever the assurance graph is modified, and MUST reject any modification that would create a circular dependency, since circular dependencies prevent health-score computation.
A subservice declaration MUST provide a `type` (identityref derived from `subservice-base`) and an `id` (string unique among subservices of the same type). Together, `type` and `id` form the unique key for a subservice instance.
`agent-id` MUST be unique among all agents of the assurance system, and `symptom-id` MUST be unique among all symptoms raised by a given agent, so that the pair `(agent-id, symptom-id)` globally identifies a symptom.
Service instances MUST be modeled as a particular type of subservice with exactly two parameters: `service` (the service name as defined in the network orchestrator) and `instance-name` (the name of the specific instance to be assured).
When the `under-maintenance` container is present on a subservice, a `contact` MUST be provided to identify who or which software is responsible for the maintenance.
Each subservice entry in the `subservices` list is keyed by `type` (an `identityref` derived from `subservice-base`) and `id` (a string unique within its type). It carries configurable fields (`under-maintenance`, `parameter` choice) and read-only telemetry (`health-score`, `symptoms`, `last-change`, `label`).
The `agents` read-only container lists all agents contributing to the assurance graph, each identified by a unique string `id`. For each agent, a `symptoms` list maps symptom `id` strings to human-readable `description` strings, serving as a glossary for interpreting symptom identifiers in subservice telemetry.
The `assurance-graph-last-change` read-only leaf (type `yang:date-and-time`) records the timestamp of the most recent structural change to the assurance graph, including additions/deletions of subservices, dependencies, or maintenance status modifications. Changes to health scores or symptoms alone do not update this field.
The `assured-services` read-only container provides an alternate, query-optimized index into the assurance graph, organized by service name and instance name. For each service instance, the `subservices` sub-list enumerates all descendant subservices in that instance's assurance subgraph, enabling retrieval in a single query rather than recursive dependency traversal.
The `dependencies` container within each subservice holds a list of dependency references (leafrefs to `type` and `id`), each with an optional `dependency-type` identityref. Two standard dependency types are defined: `impacting` (the dependency's status directly affects the dependent's health) and `informational` (symptoms may be relevant for diagnosis but do not affect health score).
The `health-score` read-only leaf is typed as `int8` with range `-1..100`. A value of 100 means healthy, 0 means broken, values in between indicate degradation, and the special value -1 indicates the score could not be computed (e.g., a required metric was unavailable).
The `ietf-service-assurance-device` module augments the `parameter` choice in the base module with a `parameters` container (conditioned on `device-type` subservice identity) containing a single mandatory `device` leaf (string) that identifies the device to monitor.
The `ietf-service-assurance-interface` module augments the `parameter` choice with a `parameters` container (conditioned on `interface-type`) containing two mandatory string leaves: `device` (the hosting device) and `interface` (the interface name), aligned with the `ietf-interfaces` model from RFC 8343.
The `ietf-service-assurance` YANG module defines the base assurance graph, comprising a list of subservice instances keyed by `[type id]`, each carrying health status, symptoms, and dependency references. The graph represents service assurance by hierarchically decomposing a service into atomic subservices.
The `symptoms` container holds a list keyed by `[start-date-time agent-id symptom-id]`, with a `unique` constraint on `[agent-id symptom-id]`. Each symptom entry references the agent and symptom via leafrefs into the `agents` container, and carries a `health-score-weight` (uint8, 0..100), a `start-date-time`, and an optional `stop-date-time`.
The `under-maintenance` presence container, when present, suppresses symptom emission for the subservice and all subservices that depend on it. It has a mandatory `contact` leaf (free-form string) identifying who or what is responsible for the maintenance.
IANA has registered three entries in the YANG Module Names registry (RFC 7950): `ietf-service-assurance` (prefix `sain`), `ietf-service-assurance-device` (prefix `sain-device`), and `ietf-service-assurance-interface` (prefix `sain-interface`), all referencing RFC 9418. These modules are not maintained by IANA.
IANA has registered three URIs in the IETF XML Registry (RFC 3688): `urn:ietf:params:xml:ns:yang:ietf-service-assurance`, `urn:ietf:params:xml:ns:yang:ietf-service-assurance-device`, and `urn:ietf:params:xml:ns:yang:ietf-service-assurance-interface`, all registered by the OPSAWG WG.
NETCONF access to these modules MUST use SSH (RFC 6242) as the mandatory-to-implement secure transport, and RESTCONF access MUST use TLS 1.3 (RFC 8446). The Network Configuration Access Control Model (NACM, RFC 8341) MUST be used to restrict access to authorized users.
Read access to `/subservices/subservice`, `/agents/agent`, and `/assured-services/assured-service` must be controlled via NACM (RFC 8341), as these subtrees reveal underlying network structure, deployed services, and customer service topology. Customer access should be scoped strictly to their own service nodes.
Write access to `/subservices/subservice` is highly sensitive: unauthorized modifications can alter the assurance graph, causing false-positive alerts (reporting healthy services as broken, wasting operator time) or false-negative suppression (hiding real failures), potentially resulting in SLA violations or disruption of emergency services.