karimra / gnmic

gNMIc is a gNMI CLI client and collector
https://gnmic.kmrd.dev
Apache License 2.0
217 stars 32 forks source link

openconfig per-interface filter not working #110

Closed svautour closed 4 years ago

svautour commented 4 years ago

This works: gnmic -a 172.16.18.4:57400 -u svautour -p xxxxx --skip-verify --mode STREAM --stream-mode ON_CHANGE sub --path /state/router[router-name=Base]/interface[interface-name=*]/if-oper-status

This works: gnmic -a 172.16.18.9:57400 -u svautour -p xxxx --skip-verify --encoding JSON_IETF --log --timeout 30s get --path "openconfig-interfaces:interfaces/interface"

This works: gnmic -a 172.16.18.9:57400 -u svautour -p xxx --skip-verify --encoding JSON_IETF --log --timeout 30s --model openconfig-interfaces get --path "interfaces/interface"

This however does not work:

svautour@covengcore2:~$ gnmic -a 172.16.18.9:57400 -u svautour -p xxx --skip-verify --encoding JSON_IETF --log --timeout 30s --model openconfig-interfaces get --path "interfaces/interface[name=Loopback0]" gnmic 2020/08/06 17:00:17.026960 sending gNMI GetRequest: prefix='', path='[elem:{name:"interfaces"} elem:{name:"interface" key:{key:"name" value:"Loopback0"}}]', type='ALL', encoding='JSON_IETF', models='[name:"openconfig-interfaces" organization:"OpenConfig working group" version:"1.0.2"]', extension='[]' to 172.16.18.9:57400 gnmic 2020/08/06 17:00:17.044347 failed sending GetRequest to 172.16.18.9:57400: failed sending GetRequest to '172.16.18.9:57400': rpc error: code = Internal desc = gNMI get-request: rpc error: code = Internal desc = lexical error: invalid char in json text. {"openconfig-interfaces:interf (right here) ------^

When I pull back all interfaces I get:

---snip--- "interfaces/interface": [ { "config": { "description": "this is lo0 intf", "enabled": true, "name": "Loopback0", "type": "iana-if-type:softwareLoopback" }, "name": "Loopback0", "state": { ---snip---

I should be able to filter on the name key.

hellt commented 4 years ago

Hi @svautour,

  1. what device and SW version are you running gnmic against? Is it IOS-XR?
  2. the issue might be related to the way the underlying R code of the network OS treating the JSON payload (ref).

I have tested the same request (apart from using --models, since UseModels functionality is not supported on the device I tested against):

[root@0002-eve-2-labvm ~]# gnmic -a 10.2.0.21:6030 -u admin -p admin --insecure  get --path "/interfaces/interface[name=Ethernet1]" -e JSON_IETF  --log
gnmic 2020/08/07 00:55:21.127141 sending gNMI GetRequest: prefix='<nil>', path='[elem:{name:"interfaces"} elem:{name:"interface" key:{key:"name" value:"Ethernet1"}}]', type='ALL', encoding='JSON_IETF', models='[]', extension='[]' to 10.2.0.21:6030
{
  "source": "10.2.0.21:6030",
  "time": "1970-01-01T02:00:00+02:00",
  "updates": [
    {
      "Path": "/interfaces/interface[name=Ethernet1]",
      "values": {
        "interfaces/interface": {
          "openconfig-if-ethernet:ethernet": {
            "arista-intf-augments:pfc": {
              "priorities": {
                "priority": [
                  {
                    "index": 0,
                    "state": {
                      "in-frames": "0",
                      "index": 0,
                      "out-frames": "0"
                    }
                  },

May I suggest you test it without --models? If the router OS requires model to be set (like in the case of IOS-XR) then prepend the path with the target: --path "openconfig-interfaces:interfaces/interface[name=Loopback0]"

svautour commented 4 years ago

Hello,

Thanks for the feedback and sorry for the late reply. I was on vacation. Yes this is an IOS-XR device.

I have tried may variations including the one you suggest. This works:

gnmic -a 172.16.18.9:57400 -u svautour --skip-verify --encoding JSON_IETF --log --timeout 30s get --path "openconfig-interfaces:interfaces/interface"

This fails:

svautour@covengcore2:~$ gnmic -a 172.16.18.9:57400 -u svautour --skip-verify --encoding JSON_IETF --log --timeout 30s get --path "openconfig-interfaces:interfaces/interface[name=Loopback0]" password: gnmic 2020/08/18 12:13:59.991018 sending gNMI GetRequest: prefix='', path='[origin:"openconfig-interfaces" elem:{name:"interfaces"} elem:{name:"interface" key:{key:"name" value:"Loopback0"}}]', type='ALL', encoding='JSON_IETF', models='[]', extension='[]' to 172.16.18.9:57400 gnmic 2020/08/18 12:14:00.009193 failed sending GetRequest to 172.16.18.9:57400: failed sending GetRequest to '172.16.18.9:57400': rpc error: code = Internal desc = gNMI get-request: rpc error: code = Internal desc = lexical error: invalid char in json text. {"openconfig-interfaces:interf (right here) ------^

It only fails when I try to filter for 1 interface. Based on the error I thought maybe it was the client. Doesn't look like it. I can't try it against a Nokia router as I don't have a Nokia router with openconfig enabled.

I do have a GNMI client from Cisco and to make this work I have to configure the payload like this:

prefix: {} path: { origin: "openconfig-interfaces" elem: { name: "interfaces" } elem: { name: "interface" key { key: "name" value: "\"Loopback0\"" } } }

Note the interface has to be in double quotes and you use the \ to escape them. Is there a way to do this with the gnmic client?

Great client BTW. It's the first I've come across that I can use against both Cisco and Nokia, with or without TLS!

Thanks, Serge

karimra commented 4 years ago

Hi @svautour

To add double quotes to the interface name, you can try specifying the path flag this way: --path openconfig-interfaces:interfaces/interface[name="Loopback0"] or --path "openconfig-interfaces:interfaces/interface[name=\"Loopback0\"]"

To get more details about the request you can also add --print-request and --format prototext to the command.

I agree that the log message wording is a little misleading here.

svautour commented 4 years ago

Hello,

I have tried both of these but get the same error:

svautour@covengcore2:~$ gnmic -a 172.16.18.9:57400 -u svautour --skip-verify --encoding JSON_IETF --log --timeout 30s get --path "openconfig-interfaces:interfaces/interface[name=\"Loopback0\"]" Error: invalid argument "openconfig-interfaces:interfaces/interface[name=\"Loopback0\"]" for "--path" flag: parse error on line 1, column 48: bare " in non-quoted-field

svautour@covengcore2:~$ gnmic -a 172.16.18.9:57400 -u svautour --skip-verify --encoding JSON_IETF --log --timeout 30s get --path openconfig-interfaces:interfaces/interface[name=\"Loopback0\"] Error: invalid argument "openconfig-interfaces:interfaces/interface[name=\"Loopback0\"]" for "--path" flag: parse error on line 1, column 48: bare " in non-quoted-field

I believe this time the error is from the client.

BTW, I just upgraded to version 0.2.1 and still get the same problem.

Here's the output with the 2 other switches. Not much help:

root@covengcore2:~# gnmic -a 172.16.18.9:57400 -u svautour --skip-verify --encoding JSON_IETF --log --timeout 30s --print-request --format prototext get --path "openconfig-interfaces:interfaces/interface[name=Loopback0]" password: Get Request: path: { origin: "openconfig-interfaces" elem: { name: "interfaces" } elem: { name: "interface" key: { key: "name" value: "Loopback0" } } } encoding: JSON_IETF

gnmic 2020/08/24 18:46:25.934609 sending gNMI GetRequest: prefix='', path='[origin:"openconfig-interfaces" elem:{name:"interfaces"} elem:{name:"interface" key:{key:"name" value:"Loopback0"}}]', type='ALL', encoding='JSON_IETF', models='[]', extension='[]' to 172.16.18.9:57400 gnmic 2020/08/24 18:46:25.967293 failed sending GetRequest to 172.16.18.9:57400: failed sending GetRequest to '172.16.18.9:57400': rpc error: code = Internal desc = gNMI get-request: rpc error: code = Internal desc = lexical error: invalid char in json text. {"openconfig-interfaces:interf (right here) ------^

Thanks, Serge

karimra commented 4 years ago

Hi @svautour

I believe there are 2 \ missing in the first command around "Loopback0" to escape the double-quotes. svautour@covengcore2:~$ gnmic -a 172.16.18.9:57400 -u svautour --skip-verify --encoding JSON_IETF --log --timeout 30s get --path "openconfig-interfaces:interfaces/interface[name=\"Loopback0\"]"

I will try to get my hands on an IOS-XR device to give this a try as well.

svautour commented 4 years ago

My bad. Those \ didn't come across in the post. Here's what I used:

svautour@covengcore2:~$ gnmic -a 172.16.18.9:57400 -u svautour --skip-verify --encoding JSON_IETF --log --timeout 30s --print-request --format prototext get --path "openconfig-interfaces:interfaces/interface[name=\"Loopback0\"]" Error: invalid argument "openconfig-interfaces:interfaces/interface[name=\"Loopback0\"]" for "--path" flag: parse error on line 1, column 48: bare " in non-quoted-field

svautour@covengcore2:~$ gnmic -a 172.16.18.9:57400 -u svautour --skip-verify --encoding JSON_IETF --log --timeout 30s --print-request --format prototext get --path openconfig-interfaces:interfaces/interface[name=\"Loopback0\"] Error: invalid argument "openconfig-interfaces:interfaces/interface[name=\"Loopback0\"]" for "--path" flag: parse error on line 1, column 48: bare " in non-quoted-field

These are coming from the client as I am not even getting prompted for a password.

Thanks, Serge

karimra commented 4 years ago

Hi @svautour

I think I got what the issue is.

The --path flag is defined as StringSlice meaning both these syntaxes are accepted:

The package used to parse flags (spf13/pflag) relies on Go's encoding/csv package to parse this kind of flags. encoding/csv reader has an option to allow quotes in unquoted fields called LazyQuotes which spf13/pflag does not set.

A quick fix would be to let go of the second syntax (--path /path/1,/path/2) to avoid parsing via encoding/csv, then sweep through the other flags defined the same way and change them as well.

But first I want to confirm that the issue is really coming from the missing quotes around "Loopback0" by doing some tests on an IOS-XR device.

karimra commented 4 years ago

Hi @svautour

So seems like IOS-XR really wants a quoted interface name ( probably the same for all yang list keys ). Added the fix in this branch #119 So no more comma separated --path It works well on my side in the sandbox that @hellt shared (thanks!) Are you able to try it out by building the binary on your side ? Or it's ok for you to wait till next release ?

hellt commented 4 years ago

@svautour if you want to test it within your environment and don't want to bother building from the source, you can tell us what OS you are running (linux/mac) and I will share the binary with that fix with you

svautour commented 4 years ago

Hello,

Excellent! Thank you so much.

I don't mind waiting for the next release. I also don't mind testing for you if you can provide a simple install process like the one I followed when I first installed it. I am running it on Ubuntu 18.04.

Thanks again, Serge

hellt commented 4 years ago

@svautour here you can find the binary in zip archive gnmic.zip

the path with the quoted list key can be formatted as follows:

--path 'openconfig-interfaces:interfaces/interface[name="Loopback0"]'
svautour commented 4 years ago

Looks good. Thanks!

`svautour@covengcore2:/usr/local/bin$ gnmic -a 172.16.18.9:57400 -u svautour --insecure --encoding JSON_IETF --log --timeout 30s --print-request --format prototext get --path "openconfig-interfaces:interfaces/interface[name=\"Loopback0\"]"
password: Get Request: path: { origin: "openconfig-interfaces" elem: { name: "interfaces" } elem: { name: "interface" key: { key: "name" value: "\"Loopback0\"" } } } encoding: JSON_IETF

gnmic 2020/08/31 15:05:55.659271 sending gNMI GetRequest: prefix='', path='[origin:"openconfig-interfaces" elem:{name:"interfaces"} elem:{name:"interface" key:{key:"name" value:"\"Loopback0\""}}]', type='ALL', encoding='JSON_IETF', models='[]', extension='[]' to 172.16.18.9:57400 Get Response: notification: { timestamp: 1598886691909359922 update: { path: { origin: "openconfig-interfaces" elem: { name: "interfaces" } elem: { name: "interface" key: { key: "name" value: "\"Loopback0\"" } } } val: { json_ietf_val: "[{\"name\":\"Loopback0\",\"config\":{\"name\":\"Loopback0\",\"type\":\"iana-if-type:softwareLoopback\",\"enabled\":true,\"description\":\"this is lo0 intf\"},\"state\":{\"name\":\"Loopback0\",\"enabled\":true,\"type\":\"iana-if-type:softwareLoopback\",\"admin-status\":\"UP\",\"oper-status\":\"UP\",\"mtu\":1500,\"last-change\":959804,\"description\":\"this is lo0 intf\",\"ifindex\":206},\"subinterfaces\":{\"subinterface\":[{\"index\":0,\"openconfig-if-ip:ipv4\":{\"addresses\":{\"address\":[{\"ip\":\"67.70.219.110\",\"config\":{\"ip\":\"67.70.219.110\",\"prefix-length\":32},\"state\":{\"ip\":\"67.70.219.110\",\"prefix-length\":32,\"origin\":\"STATIC\"}}]},\"state\":{\"counters\":{\"in-octets\":\"0\",\"in-pkts\":\"0\",\"out-octets\":\"0\",\"out-pkts\":\"0\"}}},\"openconfig-if-ip:ipv6\":{\"state\":{\"counters\":{\"in-octets\":\"0\",\"in-pkts\":\"0\",\"out-octets\":\"0\",\"out-pkts\":\"0\"}}}}]}}]" } } } error: {}`

Note that even though I posted the above as code it still doesn't come across right. The interface is specified with:

--path "openconfig-interfaces:interfaces/interface[name=\"Loopback0\"]"

karimra commented 4 years ago

Thanks for testing this @svautour , I will merge the PR