Skip to content

Missing Healthz Field in Generated *oc.Component Go Struct #142

@prathapcv

Description

@prathapcv

Repository: github.com/openconfig/ondatra
Affected Version: v0.14.1 (current latest, released Feb 18, 2026)
Severity: Medium — causes silent data loss and unmarshal error floods
Date: March 26, 2026

Summary
The openconfig-platform-healthz YANG model augments the /components/component
hierarchy with a healthz container that includes three leaves for monitoring
component health status. This model has been part of the OpenConfig public
schema since January 2023. However, the generated *oc.Component Go struct
in ondatra v0.14.1/gnmi/oc/structs-0.go does not contain a Healthz
field, causing unmarshal errors and silent data loss in any test that reads full
component state telemetry from a DUT that advertises healthz data.

Problem Details
YANG Model Definition
The openconfig-platform-healthz YANG model defines the following aug-
mentation:

YANG Path : /components/component/healthz/state/status
Type : enum
Description : Component health status: UNSPECIFIED, HEALTHY, UNHEALTHY

YANG Path : /components/component/healthz/state/last-unhealthy
Type : timeticks64
Description : Nanoseconds since Unix epoch when component was last unhealthy

YANG Path : /components/component/healthz/state/unhealthy-count
Type : uint64
Description : Counter for number of times component transitioned to unhealthy state

Source: openconfig-platform-healthz.yang
Module Revision: 2023-04-11 (v0.1.1)
YANG Augmentation:

module openconfig-platform-healthz {
// ... namespace and imports ...
augment "/oc-platform:components/oc-platform:component" {
description "Augment healthz information into the /components/component hierarchy.";
uses platform-health-top;
}
grouping platform-health-top {
container healthz {
container state {
config false;
leaf status {
type enumeration { enum UNSPECIFIED; enum HEALTHY; enum UNHEALTHY; }
oc-ext:telemetry-on-change;
}
leaf last-unhealthy { type oc-types:timeticks64; }
leaf unhealthy-count { type uint64; }
}
}
}
}

Generated Go Struct Issue

The *oc.Component struct in ondatra v0.14.1/gnmi/oc/structs-0.go is missing the Healthz field:
type Component struct {
AllocatedPower *uint32 path:"state/allocated-power" ...
Backplane *Component_Backplane path:"backplane" ...
BaseMacAddress *string path:"state/base-mac-address" ...
BootLoader *Component_BootLoader path:"boot-loader" ...
BootTime *uint64 path:"state/boot-time" ...
Chassis *Component_Chassis path:"chassis" ...
// ... other fields ...
HardwareVersion *string path:"state/hardware-version" ...
Id *string path:"state/id" ...
// � HEALTHZ FIELD IS MISSING HERE
InstallComponent *string path:"state/install-component" ...
// ... other fields continue ...
}

Runtime Error Messages
When a DUT advertises healthz state data and a test calls gnmi.GetAll(t,
dut, gnmi.OC().ComponentAny().State()), the following errors appear:

Unmarshal string_val:"UNHEALTHY" into origin:"openconfig"
elem:{name:"components"}
elem:{name:"component" key:{key:"name" value:"CHASSIS0"}}
elem:{name:"healthz"} elem:{name:"state"} elem:{name:"status"}:
path "/components/component[name=CHASSIS0]/healthz/state/status" is invalid and cannot be ma
to a generated GoStruct field: rpc error: code = InvalidArgument desc = no match found in *o
for path elem:{name:"healthz"} elem:{name:"state"} elem:{name:"status"}

Unmarshal uint_val:1774337554888000000 into origin:"openconfig"
elem:{name:"components"}
elem:{name:"component" key:{key:"name" value:"CHASSIS0"}}
elem:{name:"healthz"} elem:{name:"state"} elem:{name:"last-unhealthy"}:
path "/components/component[name=CHASSIS0]/healthz/state/last-unhealthy" is invalid and cann
to a generated GoStruct field: rpc error: code = InvalidArgument desc = no match found in *o
for path elem:{name:"healthz"} elem:{name:"state"} elem:{name:"last-unhealthy"}

Unmarshal uint_val:1 into origin:"openconfig"
elem:{name:"components"}
elem:{name:"component" key:{key:"name" value:"CHASSIS0"}}
elem:{name:"healthz"} elem:{name:"state"} elem:{name:"unhealthy-count"}:
path "/components/component[name=CHASSIS0]/healthz/state/unhealthy-count" is invalid and can
to a generated GoStruct field: rpc error: code = InvalidArgument desc = no match found in *o
for path elem:{name:"healthz"} elem:{name:"state"} elem:{name:"unhealthy-count"}

These errors appear once per healthz leaf per component, flooding test
output and making it difficult to diagnose real issues.

Root Cause Analysis
The openconfig-platform-healthz.yang model is not being included in the set of YANG models fed to ygen (the Go struct code generator) when
ondatra’s gnmi/oc package is regenerated.

Evidence: - OpenConfig models v5.6.0 (bundled in ondatra v0.14.1)
includes openconfig-platform-healthz.yang - The healthz model has
been in the public schema since January 2023 (revision 0.1.0) - The
generated *oc.Component struct contains fields for many augmenting
modules (e.g., openconfig-platform-cpu, openconfig-platform-fan,
openconfig-platform-transceiver) - But openconfig-platform-healthz
is conspicuously absent

Impact Analysis

Affected Code
Any test that calls gnmi.GetAll() on full component state will be affected:

File: feature/container/failover/tests/supervisor_failover/failover_test.go
Locations: L554
Pattern: gnmi.GetAll(t, dut, gnmi.OC().ComponentAny().State())

File: feature/platform/tests/telemetry_inventory_test/telemetry_inventory_test.go
Locations: L381, L948, L1038
Pattern: gnmi.GetAll(t, dut, gnmi.OC().ComponentAny().State())

File: feature/platform/tests/breakout_subscription_test/breakout_subscription_test.go
Locations: L506, L553
Pattern: gnmi.GetAll(t, dut, gnmi.OC().ComponentAny().State())

File: feature/interface/singleton/tests/singleton_with_breakouts/singleton_with_breakouts_test.go
Locations: L134, L177
Pattern: gnmi.GetAll(t, dut, gnmi.OC().ComponentAny().State())

File: feature/gnoi/system/tests/complete_chassis_reboot/complete_chassis_reboot_test.go
Location: L115, L228
Pattern: gnmi.GetAll(t, dut, gnmi.OC().ComponentAny().State())

File: internal/components/components.go
Location: L52, L76
Pattern: gnmi.GetAll[*oc.Component](t, dut, gnmi.OC().ComponentAny().State())

Consequences

  1. Silent Data Loss: Healthz telemetry data from DUTs is silently dropped during unmarshal. Tests cannot access component health status.
  2. Error Flooding: Multiple unmarshal errors appear in test logs, reducing signal-to-noise ratio and making it harder to diagnose actual issues.
  3. Schema Compliance Gap: The generated Go structs do not fully represent the OpenConfig platform schema, breaking strict schema validation.
  4. Impossible to Query Healthz: No typed path available to query healthz data via ygnmi (e.g., gnmi.OC().Component(name).Healthz().State().Status().State() doesn’t exist).

Requested Fix

Add openconfig-platform-healthz.yang to the YANG model set used for code generation in ondatra.

Expected Outcome

The regenerated *oc.Component struct should include:

type Component struct {
// ... existing fields ...
Healthz *Component_Healthz path:"healthz" module:"openconfig-pl // ... rest of fields ... type Component_Healthz struct { State *Component_Healthz_State path:"state" module:"openconfig-platform-healthz"`
}
}

type Component_Healthz_State struct {
Status E_ComponentHealthzStatus path:"status" module:"openconfig-platform-hea LastUnhealthy *uint64 path:"last-unhealthy" module:"openconfig-plat
UnhealthyCount *uint64 `path:"unhealthy-count" module:"openconfig-pla
}

type E_ComponentHealthzStatus int32
const (
E_ComponentHealthzStatus_UNSPECIFIED E_ComponentHealthzStatus = iota
E_ComponentHealthzStatus_HEALTHY
E_ComponentHealthzStatus_UNHEALTHY
)

This would allow: -All healthz leaves to unmarshal without error - Typed ygnmi paths: gnmi.OC().Component(name).Healthz().State().Status().State() - Full schema compliance with OpenConfig models v5.6.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions