openconfig / gnmic

gNMIc is a gNMI CLI client and collector
https://gnmic.openconfig.net
Apache License 2.0
171 stars 55 forks source link

question: what is the actual json document used in a grpc request #117

Closed nskalis closed 1 year ago

nskalis commented 1 year ago

Hi, and thank you for making gnmic available.

I have a question to ask you; if I issue a GET request for example

> /usr/local/sbin/gnmic --address x.x.x.x:57400 --username xxx --password xxx --insecure get --path /state/system/platform  --encoding json --print-request
Get Request:
{
  "paths": [
    "state/system/platform"
  ],
  "encoding": "JSON",
  "data-type": "ALL"
}
Get Response:
[
  {
    "source": "x.x.x.x:57400",
    "timestamp": 1683010732292365649,
    "time": "2023-05-02T08:58:52.292365649+02:00",
    "updates": [
      {
        "Path": "state/system/platform",
        "values": {
          "state/system/platform": "7750 SR-7s"
        }
      }
    ]
  }
]

The --print-request flag prints the following out:

2023/05/02 09:01:42.640292 /home/runner/work/gnmic/gnmic/app/get.go:125: [gnmic] sending gNMI GetRequest: prefix='<nil>', path='[elem:{name:"state"} elem:{name:"system"} elem:{name:"platform"}]', type='ALL', encoding='JSON', models='[]', extension='[]' to x.x.x.x:57400

The body of the request is not actually encoded as json based on tcpdump (but in protobuf), the response is decoded in json.

Would you be so kind to advise how the actual json document in the request looks like? In other words, what the json_format (from protobuf) would print out?


I tried and failed with

  1. {"path": [{"elem": [{"name": "state"}, {"name": "system"}, {"name": "platform"}]}], "type": "ALL", "encoding": "JSON"
  2. {"path": [{"elem": {"name": "state"}}, {"elem": {"name": "system"}}, {"elem": {"name": "platform"}}], "type": "ALL", "encoding": "JSON"}
karimra commented 1 year ago

The request is sent as proto encoded bytes not json. If you want to print the request in json format run the same command with --format protojson:

gnmic --address x.x.x.x:57400 --username xxx --password xxx --insecure \
get \
--path /state/system/platform  \
--encoding json \
--print-request \
--format protojson
nskalis commented 1 year ago

Thank you. Then

  1. either something more is going on that I hope you can possibly advice as I am new to grpc
  2. or nokia/sros as a grpc server doesn't implement/respect fully the specification https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md see Content-Type → "content-type" "application/grpc" [("+proto" / "+json" / {custom})]

In other words, the below attempt returns 0 bytes and a HTTP 200 OK status.

echo -en '\x00\x00\x00\x00S{"path": [{"elem": [{"name": "state"}, {"name": "system"}, {"name": "platform"}]}]}' | curl --silent --noproxy '*' --insecure --http2 --http2-prior-knowledge --header "Content-Type: application/grpc+json" --header "TE: trailers" --header "Username: xxx" --header "Password: xxx" --data-binary @- --output - http://x.x.x.x:57400/gnmi.gNMI/Get 

Following the same approach with other well-known grpc servers, I get the expected json reply.

Assuming you're working for or you're in close relationship with Nokia, can you possibly advise if the http header content-type is honoured as per spec by the router?


Unfortunately, I believe the case is that nokia/sros doesn't support the content-type header as per the grpc specification.

< HTTP/2 200 
< content-type: application/grpc
< grpc-status: 13
< grpc-message: Unable to parse request
hellt commented 1 year ago

Hi @nskalis it is not clear what you're trying to do... Nokia SR OS supports gNMI service (as per gNMI specification) and therefore gNMI clients (such as gnmic and others) can interact with it.

nskalis commented 1 year ago

grpc is a slim extension of http2. The official page of grpc outlines the rules around it. What I wish to achieve is:

It is the simplest approach that works (in any context) with "normal" (as per spec) grpc servers.

What the gNMI specification dictates is only the structure of the body (of the http/2 request).

For now, I think I have to encode the body of the request based on the standard method outlined here https://googleapis.dev/python/protobuf/latest/google/protobuf/json_format.html for example, in protobuf.

LimeHat commented 1 year ago

What the gNMI specification dictates is only the structure of the body (of the http/2 request).

gNMI spec defines the service as a protobuf-based service

https://github.com/openconfig/reference/blob/ff092419eced6c2cf01bb747151091d684e2fc85/rpc/gnmi/gnmi-specification.md?plain=1#L85-L91 https://github.com/openconfig/gnmi/blob/master/proto/gnmi/gnmi.proto

nskalis commented 1 year ago

Depends on the way you look at it; or, only a parameter (url) in a http request.

If you use tcpdump for both approaches above, they are one and the same.

So, what gnmic CLI does is 1 command away in cURL, and 2 lines away in any http/2 client (because nokia/sros grpc server seems not to honour the http header content-type subtypes) and the body of the request has to be encoded in protobuf.

Let me organise the .proto files, and I'll let you know the outcome (if interested) in 2-3 weeks as I am working part-time on it.

nskalis commented 1 year ago

Works with protobuf encoding too. I'll request this feature from the vendor through the official channels. Thank you for being able to print out the request through gnmic.