Contributors: hines@google.com, robjs@google.com, bneville@arista.com, roman.dodin@nokia.com Last Updated: 2022-11-02
The purpose of Healthz is to allow a component inside of a system to report its
health. The concept of asking "Are you healthy?" is a general design principle
in distributed systems.
The ability to also include "implementation specific" details about the health
of the system or component is very standard for network devices in the form for
"show tech", "diag" or "debug" commands. These are very useful for getting
diagnostics about the system state to the implementers. Healthz exposes these
interfaces as queryable endpoints to allow operators to validate "health" on
components and if "unhealthy" gather implementor specific data to help triage
or reproduce issues.
Healthz provides a means by which a user may initiate checks of health
(through the Check RPC) or a system may report the results of a check that it
has initiated of its own accord.
Following a health check occurring, a caller uses the List or Get RPC to
discover the health "events" (expressed as a ComponentStatus message) that
are associated with a component and its corresponding subcomponents. Each event
reflects a collection of data that is required to debug or further root cause
the fault that occurs with an entity in the system.
The Artifact RPC is used to retrieve specific artifacts that are listed by
the target system in the List or Get RPC. Once retrieved an event, which
corresponds to a series of artifacts, can be 'acknowledged' by the client of
the RPC. Acknowledged events are no longer returned in the list of events by
default. The device may use the acknowledged status as a hint to allow garbage
collection of artifacts that are no longer relevant. The device itself is
responsible for garbage collection any may, if necessary, garbage collect
artifacts that are not yet acknowledged. It is expected that events are
persisted across restarts of the system or its hardware and software
components, and they are removed only for resource management reasons.
Whilst the system may initiate health checks itself, these should be safe to
perform operations that do not impact the device's functionality. Expensive
checks (e.g., pausing protocols, or dumping internal database state) that are
potentially service impacting should require use of the Check RPC.
Healthz works in conjunction with telemetry streamed via gNMI, OpenConfig
paths for a specific component are streamed to indicate when components become
unhealthy, allowing the receiving system to determine that further inspection
of the component's health is required. The following paths (defined in the
openconfig-platform model) are used:
component/healthz/state/status (enumerated value)
component/healthz/state/last-unhealthy (timestamp)
component/healthz/state/unhealthy-count (int64)
Originally, the gNOI Healthz endpoint defined single transactional API for getting the "healthz" status of a component. As discussed in the above issue, due to large data volume or to an interactive debug output there is a requirement that it support the ability to stream a status from the device.
To ensure that this can be done using a secure channel with the relevant ACL
and encryption, this streaming is implemented within the Healthz service.
This approach further allows the concept of a historical set of collected
artifacts to be reported by the device.
As described above, by default health checks that are performed automatically
by the device SHOULD NOT be performance impacting. The Check RPC is used to
ensure the creation of artifacts that are expensive to collect.
Thus -- a system relying on healthz for reporting of device status, needs
to consider the following workflow.
- A component of the system becomes unhealthy. The device MUST generate
a health state via telemetry that indicates that the
healthz/state/statusof the component has transitioned toUNHEALTHY. It is left for the device implementor to determine which artifacts are generated automatically by the system immediately. The artifact collection SHOULD NOT impact the performance of the system. - The responding client system observes the transition to
UNHEALTHYand canListevents that have occurred on the component. The client SHOULD be aware that not all artifacts that may be required may have automatically been collected and aCheckRPC may be required to collect the artifacts that were considered performance impacting. This allows the client systems to co-ordinate to reduce the operational risk of collecting this data (e.g, by removing traffic from the network device). In order to specify that theCheckrefers to a previously reported event, theevent_idfield in the request must be populated with the ID reported inGetorList. - If the component becomes healthy again, even if no
Healthzcalls were made to the system, telemetry information MUST be updated to ensure that external clients are updated as to the current health status.
In order that the relevant information for a particular event is collected, the device SHOULD ensure that the non-system-impacting artifact collection that is performed at the time of the event is sufficient that error conditions can be understood and debugged.
Where a gNMI path (gnoi.types.Path) is used in Healthz, the path specified
should be the complete path to a specific component - i.e.,
/components/component[name=FOO].
rpc Get(GetRequest) returns (GetResponse) {}Get allows a user to retrieve the latest set of health statuses that are
associated with a specific component and any of its corresponding
subcomponents. In contrast to List the Get RPC should return only the
latest event (i.e., ComponentStatus message).
The GetResponse returned includes a ComponentStatus message which
corresponds to the latest health event for the component itself and each
subcomponent being reported on. Thus, multiple ComponentStatus messages may
be reported for a single component. Each message includes a set of
ArtifactHeader messages that correspond to the health event -- and provide
identifiers and types for the artifacts that can be returned by the system.
All artifacts that are listed within the same ComponentStatus message are
expected to have a shared acknowledgement state, and expiry time.
rpc List(ListRequest) returns (ListResponse) {}List returns all events that are associated with a particular component. In
contrast to Get, it returns all events that the target has for the device. By
default, events that are acknowledged are not returned.
List returns a series of ComponentStatus messages. These messages have the
same semantics as those that are returned by the Get RPC, described above.
rpc Acknowledge(AcknowledgeRequest) returns (AcknowledgeResponse) {}Acknowledge is used by a client to indicate to the target device that a
particular (component, event) tuple has been retrieved by the client. This
allows a device to intelligently determine whether to retain artifacts. Devices
MUST ensure that artifact storage for healthz does not cause resource
exhaustion and SHOULD remove acknowledged artifacts before those that have not
yet received an acknowledgment.
rpc Artifact(ArtifactRequest) returns (stream ArtifactResponse) {}Artifact allows a user to retrieve a specific artifact that is related to an
event that has occurred. Since these artifacts may be large, the Artifact RPC
is implemented as a server-side streaming RPC. The Artifact RPC ensures that
a target sends these potentially large artifacts only when explicitly requested
by the client.
rpc Check(CheckRequest) returns (CheckResponse) {}Check allows a client to execute a set of "validations" against the specified
component. The component, as with other operations, is specified in terms of
the gNMI path.
The result of the Check produces a healthz ComponentStatus message which
will contain a list of the generated artifacts used in the validation process.
A call to the Check endpoint will allow for "very expensive" debugging
commands such as causing the device to pause and snapshot its system database
or to examine the state of a protocol. These commands will likely be
considered "service impacting" and should have a clear security ACL restricting
their use during normal operations of the device.
The CheckRequest message includes an event_id field. When populated this
indicates that the Check should be performed for an event that has already
occurred within the system. The device should trigger artifact collection of
those artifacts that were not automatically collected. A CheckRequest for
a previous event_id MUST NOT overwrite previous artifacts that were collected
at the time of the event. The artifacts that are collected MUST be returned
in the artifact list for the event when reported by the Get or List RPCs.
Write the core dump to a file system.
A call to Healthz.Get should respond with the current state of the component
and provide feedback that there is an artifact available to be requested.
A Healthz.Artifact() call should stream the core dump over the service back
to the caller.
The component that is specified should correspond to the software process that implements the BGP protocol in the system.
Logs / dumps collected and the gNMI components are marked unhealthy.
A call to Healthz.Get should respond with the current state of the component and provide feedback that there is an artifact available to be requested.
A Healthz.Artifact() call should stream the core dump over the service back
to the caller.
A Healthz.Artifact() call should stream the logs over the service back to the
caller.
The component that is reported on should be of type
CHASSIS.
Since there are no artifacts the Healthz.Get should just return the status of the component and no other action is necessary
The component reported on via telemetry should correspond to the device's
chassis and be of type
CHASSIS.
For a component healthz could be used to provide an I/O dump of a specific debugging command redirected as a byte stream. It could also be output like a top or show interfaces where the data is periodically updated (each "frame" would be sent over the stream as a separate message). This would allow for show tech like information to be collected and sent to vendors in a programmatic secure way but not completely reinventing the wheel.
To achieve this use case, extensions to the existing specification are required.
For components which can provide a "snapshot" of state the healthz artifact endpoint can be provided to take a snapshot of state (ideally serialized as a protobuf or other typed data structure) and provided to the caller.
Examples:
- Get optical data from i2c bus on optical systems.
- Get system database state for the core pub/sub of a device.
For a component in the system the developers could provide a debug log for that
specific component or other trace / dump information. The Check() and
Artifact() APIs could be used in these cases to create the setup and then
download the specific data in a secure, reliable way (rather than a general
file scp). If the device can "automatically" generate these specific data the
Get API can also be used to check for existence and to download the
artifacts. Note that to support this use case, additional gNMI paths are likely
required to signal existence of this type of data.
An event is created internally by the system for a linecard rebooting unexpectedly. The chassis process will take a core of the component. Snapshot it's log for the component. Snapshot any relevant state in a system database for the component and create a healthz event which includes pointers to these 3 artifacts.
The external monitoring system will receive a gNMI update reporting that the specific component became unhealthy.
An event monitoring agent can then call the healthz service specifying the
faulty component, and thus retrieve the current event and the associated
artifacts. Since the component becoming healthy is an externally reportable
event (i.e., may need to be reported to the vendor to initiate an RMA) the
system decides to retrieve the artifacts and store them within a bug tracking
system case. Once the artifacts are retrieved the system will mark the event
as acknowledged and the server can then use its local retention policy to clean
up those events.