Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Device Returns Array for Each Interface #958

Open
achurak opened this issue Mar 15, 2024 · 3 comments
Open

Device Returns Array for Each Interface #958

achurak opened this issue Mar 15, 2024 · 3 comments

Comments

@achurak
Copy link

achurak commented Mar 15, 2024

I apologize in advance if it's something obvious and I'm missing it but I'm trying to do what I think is as basic as can be, simply pull information about interfaces from a cisco device using gnmi client, however I just can't unmarshal it correctly no matter what I try.
It looks like the json that the cisco device returns is an array, something like this:

json_val: "[{\"name\":\"eth1/31\",\"config\":{\"enabled\":true,\"mtu\":1500,\"name\":\"eth1/31\",\"type\":\"ethernetCsmacd\",\"tpid\":\"TPID_0X8100\"},\"hold-time\":{\"config\":{\"down\":100}},\"subinterfaces\":{\"subinterface\":[{\"index\":0,\"config\":{\"index\":0}}]},\"ethernet\":{\"config\":{\"auto-negotiate\":true,\"enable-flow-control\":false,\"mac-address\":\"00:00:00:00:00:00\"},\"switched-vlan\":{\"config\":{\"access-vlan\":1,\"interface-mode\":\"ACCESS\",\"native-vlan\":1}}}}]"

but the generated model expects it to be a map keyed by the interface name.

Failed to unmarshal update: unmarshalContainer for schema device: jsonTree [ map[config:map[enabled:true mtu:1500 name:eth1/31 tpid:TPID_0X8100 type:ethernetCsmacd] ethernet:map[config:map[auto-negotiate:true enable-flow-cont...: got type []interface {} inside container, expect map[string]interface{}

I can even remove the [] from the string and the unmarshaling works after that (though it doesn't recognize ethernetCsmacd as a correct value for interface type but it's a different problem), but I feel like it's a super hacky workaround and there's gotta be a better/correct way of handling this.

@wenovus
Copy link
Collaborator

wenovus commented Mar 26, 2024

Hi achurak, apologies for the delayed response.

I believe you queried /interfaces/interface from the device, which correctly returns a JSON list.

However, ygot doesn't support unmarshalling directly at the list level -- you must either

  1. specify the list key interfaces/interface[name=foo], and unmarshal into the list struct, or
  2. query at /interfaces level, and unmarshal at that level. Note that this option is only available if compress=false is used. If compress=true is used then you must wrap the json_val yourself with another JSON object, and unmarshal into the struct one-level higher, which in this case is root-level struct. This is highly inconvenient, and I've opened Allow ytypes.SetNode on intermediate nodes in compressed mode #959 to track it.

@achurak
Copy link
Author

achurak commented Mar 28, 2024

@wenovus No worries, thank you for getting back to me! Correct, I queried /interfaces/interface.

  1. Do I understand correctly that the first way will only query a single interface instead of a list of all interfaces? I believe I've actually tried that and Cisco still returns an array but with a single interface/object inside it.
  2. Do I need to unmarshal it into a generic, wrap it and then unmarshal into the ygot struct?

@wenovus
Copy link
Collaborator

wenovus commented Mar 28, 2024

  1. Looking more, I think what Cisco has might be reasonable (as this is ambiguous in the gNMI spec), since in general it's possible to specify wildcards in queries, so it would be confusing if in the case that all list attributes are specified, a JSON object is returned rather than a list. One way to work around this is to loop through each JSON list element, unmarshal separately, and then call device.AppendInterface to add them one at a time.
  2. You can json.Unmarshal, wrap it inside a map[string]any keyed by "interfaces" per the YANG container name, and then json.Marshal again, and then unmarshal into the ygot struct. However I think 1. is much easier and less hacky.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants