Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions ygnmi/gnmi.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,12 +517,22 @@ func populateSetRequest(req *gpb.SetRequest, path *gpb.Path, val interface{}, op
} else if s, ok := val.(string); ok && strings.HasSuffix(path.Origin, "_cli") {
typedVal = &gpb.TypedValue{Value: &gpb.TypedValue_AsciiVal{AsciiVal: s}}
} else if opt.preferProto {
typedVal, err = ygot.EncodeTypedValue(val, gpb.Encoding_JSON_IETF, &ygot.RFC7951JSONConfig{AppendModuleName: true, PreferShadowPath: preferShadowPath})
typedVal, err = ygot.EncodeTypedValue(val, gpb.Encoding_JSON_IETF, &ygot.RFC7951JSONConfig{AppendModuleName: opt.appendModuleName, PreferShadowPath: preferShadowPath})
} else {
typedVal = &gpb.TypedValue{Value: &gpb.TypedValue_JsonIetfVal{}}
// Since the GoStructs are generated using preferOperationalState, we
// need to turn on preferShadowPath to prefer marshalling config paths.
typedVal.Value.(*gpb.TypedValue_JsonIetfVal).JsonIetfVal, err = ygot.Marshal7951(val, ygot.JSONIndent(" "), &ygot.RFC7951JSONConfig{AppendModuleName: true, PreferShadowPath: preferShadowPath})
var b []byte
b, err = ygot.Marshal7951(val, ygot.JSONIndent(" "), &ygot.RFC7951JSONConfig{AppendModuleName: opt.appendModuleName, PreferShadowPath: preferShadowPath})

// Respect the encoding option.
switch opt.encoding {
case gpb.Encoding_JSON:
typedVal = &gpb.TypedValue{Value: &gpb.TypedValue_JsonVal{JsonVal: b}}
case gpb.Encoding_JSON_IETF:
fallthrough
default:
typedVal = &gpb.TypedValue{Value: &gpb.TypedValue_JsonIetfVal{JsonIetfVal: b}}
}
}

if err != nil && opt.setFallback && path.Origin != "openconfig" {
Expand All @@ -544,7 +554,7 @@ func populateSetRequest(req *gpb.SetRequest, path *gpb.Path, val interface{}, op
}

var modifyTypedValueFn func(*gpb.TypedValue) error
if !isLeaf && compressInfo != nil && len(compressInfo.PostRelPath) > 0 {
if !isLeaf && compressInfo != nil && len(compressInfo.PostRelPath) > 0 && len(typedVal.GetJsonIetfVal()) > 0 {
// When the path struct points to a node that's compressed out,
// then we know that the type is a node lower than it should be
// as far as the JSON is concerned.
Expand Down
15 changes: 14 additions & 1 deletion ygnmi/ygnmi.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,15 @@ type opt struct {
setFallback bool
sampleInterval uint64
datapointValidator ValidateFn
appendModuleName bool
ft FunctionalTranslator
}

// resolveOpts applies all the options and returns a struct containing the result.
func resolveOpts(opts []Option) *opt {
o := &opt{
encoding: gpb.Encoding_PROTO,
encoding: gpb.Encoding_PROTO,
appendModuleName: true,
}
for _, opt := range opts {
opt(o)
Expand Down Expand Up @@ -333,6 +335,17 @@ func WithDatapointValidator(fn ValidateFn) Option {
}
}

// WithSkipModuleNames creates an option that avoids prepending the module name to
// elements that are defined within a different YANG module than their parent.
//
// By default, the module name is prepended to the element name, e.g. "openconfig-interfaces:interface".
// Use this option to disable this behavior.
func WithSkipModuleNames() Option {
return func(o *opt) {
o.appendModuleName = false
}
}

// WithFT creates an option to set a functional translator that intercepts and translates gNMI
// subscriptions and notifications.
//
Expand Down
66 changes: 66 additions & 0 deletions ygnmi/ygnmi_preferconfig_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 66 additions & 0 deletions ygnmi/ygnmi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ func getSampleInnerSingleKeyedMapIncomplete(t *testing.T) map[string]*exampleoc.
return sk.SingleKey
}

func getSampleParent(t *testing.T) *exampleoc.Parent {
model := &exampleoc.Parent{}
model.GetOrCreateChild().SetOne("foo")
model.GetOrCreateChild().SetTwo("bar")
model.GetOrCreateChild().SetThree(exampleoc.Child_Three_ONE)
return model
}

func TestLookup(t *testing.T) {
fakeGNMI, c := newClient(t)
leafPath := testutil.GNMIPath(t, "/remote-container/state/a-leaf")
Expand Down Expand Up @@ -3786,6 +3794,64 @@ func TestUpdate(t *testing.T) {
Target: "dut",
},
},
}, {
desc: "simple parent and json encoding",
op: func(c *ygnmi.Client) (*ygnmi.Result, error) {
return ygnmi.Update(context.Background(), c, exampleocpath.Root().Parent().Config(), getSampleParent(t), ygnmi.WithEncoding(gpb.Encoding_JSON))
},
wantRequest: &gpb.SetRequest{
Prefix: &gpb.Path{
Target: "dut",
},
Update: []*gpb.Update{{
Path: testutil.GNMIPath(t, "/parent"),
Val: &gpb.TypedValue{Value: &gpb.TypedValue_JsonVal{JsonVal: []byte(`{
"openconfig-simple:child": {
"config": {
"one": "foo",
"three": "ONE"
},
"state": {
"two": "bar"
}
}
}`)}},
}},
},
stubResponse: &gpb.SetResponse{
Prefix: &gpb.Path{
Target: "dut",
},
},
}, {
desc: "simple parent without module name",
op: func(c *ygnmi.Client) (*ygnmi.Result, error) {
return ygnmi.Update(context.Background(), c, exampleocpath.Root().Parent().Config(), getSampleParent(t), ygnmi.WithSkipModuleNames())
},
wantRequest: &gpb.SetRequest{
Prefix: &gpb.Path{
Target: "dut",
},
Update: []*gpb.Update{{
Path: testutil.GNMIPath(t, "/parent"),
Val: &gpb.TypedValue{Value: &gpb.TypedValue_JsonIetfVal{JsonIetfVal: []byte(`{
"child": {
"config": {
"one": "foo",
"three": "ONE"
},
"state": {
"two": "bar"
}
}
}`)}},
}},
},
stubResponse: &gpb.SetResponse{
Prefix: &gpb.Path{
Target: "dut",
},
},
}, {
desc: "leaf and prefer proto",
op: func(c *ygnmi.Client) (*ygnmi.Result, error) {
Expand Down
Loading