Skip to content

Commit 19cc3ca

Browse files
Fix gnmiext skipping updates due to missing fields in YANG payload
When fields are absent in the YANG payload, they are skipped when the payload is unmarshaled into a Go struct. This lead to invalid comparisons, as the `gnmiext.Client` failed to detect changes in this case. This commit fixes this issue, by resetting struct fields not present in the YANG payload with a json struct tag back to their zero value.
1 parent 54c88e1 commit 19cc3ca

File tree

1 file changed

+29
-0
lines changed

1 file changed

+29
-0
lines changed

internal/provider/cisco/gnmiext/v2/client.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/go-logr/logr"
1717
gpb "github.com/openconfig/gnmi/proto/gnmi"
1818
"github.com/openconfig/ygot/ygot"
19+
"github.com/tidwall/gjson"
1920
"google.golang.org/grpc"
2021
)
2122

@@ -308,6 +309,33 @@ func (c *Client) Marshal(v any) (b []byte, err error) {
308309
return b, nil
309310
}
310311

312+
// zeroUnknownFields sets struct fields to their zero value
313+
// if they are not present in the provided JSON byte slice.
314+
func zeroUnknownFields(b []byte, rv reflect.Value) {
315+
switch rv.Kind() {
316+
case reflect.Pointer:
317+
zeroUnknownFields(b, rv.Elem())
318+
case reflect.Struct:
319+
rt := rv.Type()
320+
for i := range rt.NumField() {
321+
if tag, ok := rt.Field(i).Tag.Lookup("json"); ok {
322+
parts := strings.Split(tag, ",")
323+
if parts[0] != "" && parts[0] != "-" {
324+
sf := rv.Field(i)
325+
raw := gjson.GetBytes(b, parts[0]).Raw
326+
if raw != "" {
327+
zeroUnknownFields([]byte(raw), sf)
328+
continue
329+
}
330+
if !sf.IsZero() && sf.CanSet() {
331+
sf.Set(reflect.Zero(sf.Type()))
332+
}
333+
}
334+
}
335+
}
336+
}
337+
}
338+
311339
// Unmarshal unmarshals the provided byte slice into the provided destination.
312340
// If the destination implements the [Marshaler] interface, it will be unmarshaled using that.
313341
// Otherwise, [json.Unmarshal] is used.
@@ -326,6 +354,7 @@ func (c *Client) Unmarshal(b []byte, dst any) (err error) {
326354
if ok && b[0] == '[' && b[len(b)-1] == ']' {
327355
b = b[1 : len(b)-1]
328356
}
357+
zeroUnknownFields(b, reflect.ValueOf(dst))
329358
if um, ok := dst.(Marshaler); ok {
330359
if err := um.UnmarshalYANG(c.capabilities, b); err != nil {
331360
return fmt.Errorf("gnmiext: failed to unmarshal value: %w", err)

0 commit comments

Comments
 (0)