Coder Social home page Coder Social logo

karimra / gnmic Goto Github PK

View Code? Open in Web Editor NEW
216.0 17.0 32.0 7.95 MB

gNMIc is a gNMI CLI client and collector

Home Page: https://gnmic.kmrd.dev

License: Apache License 2.0

Go 94.95% Shell 4.97% Dockerfile 0.07% Smarty 0.01%
openconfig gnmi networking telemetry rpcs yang gnmi-cli-client gnmi-messages golang

gnmic's People

Contributors

bewing avatar dwiesner avatar fgvdeput avatar fluepke avatar gaetanf avatar gliptak avatar hansthienpondt avatar hellt avatar jhujhiti avatar karimra avatar leongwang avatar melkypie avatar neoul avatar paneu avatar steiler avatar sulrich avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gnmic's Issues

stderr logging with --log

Set log flag to true in case no log-file is specified and debug is true.
Meaning --debug implies an implicit --log if there is no --log-file

address staticcheck errors

I've introduced staticcheck in Testing pipeline; it found some issues - https://github.com/karimra/gnmiClient/runs/789172646?check_suite_focus=true

  • cmd/get.go:148:6: func stringInList is unused (U1000)
  • cmd/root.go:82:4: grpclog.SetLogger is deprecated: use SetLoggerV2. (SA1019)
  • cmd/path.go:58:28: should use make(chan string) instead (S1019)
  • cmd/root.go:186:22: grpc.WithTimeout is deprecated: use DialContext instead of Dial and context.WithTimeout instead. - [ ] Will be supported throughout 1.x. (SA1019)
  • cmd/root.go:368:66: syscall.SIGKILL cannot be trapped (did you mean syscall.SIGTERM?) (SA1016)
  • cmd/root.go:418:9: assigning the result of this type assertion to a variable (switch targetsInt := targetsInt.(type)) could eliminate type assertions in switch cases (S1034)
  • cmd/root.go:420:38: could eliminate this type assertion
  • cmd/root.go:424:16: could eliminate this type assertion
  • cmd/root.go:446:10: assigning the result of this type assertion to a variable (switch t := t.(type)) could eliminate type assertions in switch cases (S1034)
  • cmd/root.go:448:30: could eliminate this type assertion
  • cmd/set.go:189:16: should use String() instead of fmt.Sprintf (S1025)
  • cmd/set.go:196:16: should use String() instead of fmt.Sprintf (S1025)
  • cmd/subscribe.go:107:7: ineffective break statement. Did you mean to break out of the outer loop? (SA4011)
  • cmd/version.go:41:3: redundant return statement (S1023)

make --path flag mandatory

--path flag should be marked mandatory to prevent full datastore retrieval if the flag is omitted (can happen if the path is considered to be an argument)

with a required `--path` flag it is impossible to set paths in a config file

Recently we added a requirement condition for path cli flags to avoid getting entire state when this flag is missing on the CLI.

But that has a side effect of not being able to set paths in a config file:

❯ go run . --config ~/.gnmic.yml get
Error: required flag(s) "path" not set

I propose we remove the required condition on the flag and instead check the value of the paths := viper.GetStringSlice("get-path") for emptiness

set command should stop if no replace/updates/deletes have been added to a request

currently if the file is not present by a referenced path, the empty set request is crafted and an empty struct is printed:

❯ go run . -a 0.tcp.eu.ngrok.io:4444 --insecure -u admin -p admin --config /dev/null set --update-path "/configure/port[port-id=1/1/c1/1]/description" --update-file port_descr.json
gnmic 2020/07/08 11:55:17.985379 error reading data from file 'port_descr.json': open port_descr.json: no such file or directory
gnmic 2020/07/08 11:55:18.148917 sending gNMI SetRequest: prefix='', delete='[]', replace='[]', update='[]', extension='[]' to 0.tcp.eu.ngrok.io:4444
{
  "source": "0.tcp.eu.ngrok.io:14852",
  "time": "1970-01-01T01:00:00+01:00"
}

get cmd panic

Get cmd panics in case there is both nil and non nil update values in the response

sample interval is not set when subs are defined in a file

subscribe interval is not set when the subs is defined in a file and not from CLI:

example of a request sent via file:

gnmic 2020/07/11 21:38:04.395276 sending gNMI SubscribeRequest: subscribe='subscribe:{prefix:{}  subscription:{path:{elem:{name:"state"}  elem:{name:"port"  key:{key:"port-id"  value:"1/1/c1/1"}}  elem:{name:"statistics"}  elem:{name:"out-octets"}}}  qos:{marking:20}}', mode='STREAM', encoding='JSON', to 0.tcp.eu.ngrok.io:x

the same sub request made via CLI:

gnmic 2020/07/11 21:37:08.030590 sending gNMI SubscribeRequest: subscribe='subscribe:{prefix:{}  subscription:{path:{elem:{name:"state"}  elem:{name:"port"  key:{key:"port-id"  value:"1/1/c1/1"}}  elem:{name:"statistics"}  elem:{name:"out-octets"}}  sample_interval:10000000000}  qos:{marking:20}}', mode='STREAM', encoding='JSON', to 0.tcp.eu.ngrok.io:x

add auto completion for flags with enum values

when in prompt mode, add auto completion for flags with enum values like:
--encoding [json, bytes, proto, ascii, json_ietf],
--formt [protojson, prototext, json, event, proto]
get --type [all, config, state, operational]
subscribe --mode [once, stream, poll]
subscribe --stream-mode [on-change, sample, target-defined]

textproto output fails for Get RPC

❯ gnmiClient --insecure get --path /state/system/version --format textproto
panic: reflect.Value.Interface: cannot return value obtained from unexported field or method

goroutine 19 [running]:
reflect.valueInterface(0x16ea640, 0xc00020afc0, 0x36, 0x16ea601, 0xc00020afc0, 0x36)
	/usr/local/go/src/reflect/value.go:1014 +0x1bc
reflect.Value.Interface(...)
	/usr/local/go/src/reflect/value.go:1003
github.com/gogo/protobuf/proto.(*TextMarshaler).writeAny(0x1e6b97c, 0xc0001e1f40, 0x17bc740, 0xc00020afc0, 0x1b9, 0xc0001c1600, 0x19569c0, 0x17bc740)
	/home/karim/go/pkg/mod/github.com/gogo/[email protected]/proto/text.go:592 +0x1ec
github.com/gogo/protobuf/proto.(*TextMarshaler).writeStruct(0x1e6b97c, 0xc0001e1f40, 0x17d4a80, 0xc00020afc0, 0x199, 0x199, 0x21006d0)
	/home/karim/go/pkg/mod/github.com/gogo/[email protected]/proto/text.go:453 +0x94a
github.com/gogo/protobuf/proto.(*TextMarshaler).Marshal(0x1e6b97c, 0x1934460, 0xc000304000, 0x1942380, 0xc00020afc0, 0x9, 0x0)
	/home/karim/go/pkg/mod/github.com/gogo/[email protected]/proto/text.go:894 +0x295
github.com/gogo/protobuf/proto.(*TextMarshaler).Text(0x1e6b97c, 0x1942380, 0xc00020afc0, 0x7ffeefbff994, 0x9)
	/home/karim/go/pkg/mod/github.com/gogo/[email protected]/proto/text.go:906 +0x6e
github.com/gogo/protobuf/proto.MarshalTextString(...)
	/home/karim/go/pkg/mod/github.com/gogo/[email protected]/proto/text.go:922
github.com/karimra/gnmiClient/cmd.printGetResponse(0x0, 0x0, 0xc00020afc0)
	/home/karim/github.com/karimra/gnmiClient/cmd/get.go:181 +0x9dd
github.com/karimra/gnmiClient/cmd.glob..func2.1(0xc0001dca40, 0xc0001e8680, 0xc0001e86c0, 0xc0001e2400, 0x0, 0x0, 0x0, 0xc0001e8670, 0x1, 0x1, ...)
	/home/karim/github.com/karimra/gnmiClient/cmd/get.go:156 +0x4ba
created by github.com/karimra/gnmiClient/cmd.glob..func2
	/home/karim/github.com/karimra/gnmiClient/cmd/get.go:97 +0x538

update-path/update-value doesn't take into account Encoding value json_ietf

I try to gnmic client to update some values on SRLinux platform, which supports json_ietf encoding.

Here is a simple example with hostname change:

gnmic --config gnmiClient_srl.yaml set --update-path /system/name/host-name --update-value new_hostname

Debug message:

sending gNMI SetRequest: prefix='<nil>', delete='[]', replace='[]', update='[path:{elem:{name:"system"} elem:{name:"name"} elem:{name:"host-name"}} val:{json_val:"\"new_hostname\""}]', extension='[]' to 192.168.1.1:57400

error sending set request: failed sending SetRequest to '192.168.1.1:57400': rpc error: code = InvalidArgument desc = Field type (0) is not supported

If i try to change hostname using another method, everything is successfully changed
Method-1:

gnmic --config gnmiClient_srl.yaml set --update /system/name/host-name:::json_ietf:::IXR-6-4

Method-2

gnmic --config gnmiClient_srl.yaml set --update-path / --update-file change_name.json

Complete log for all combinations
log.txt

should log message for GetRequest specify the request in its entirety?

Currently only the path information is output to the log:

2020/06/03 21:07:55.469675 sending gnmi GetRequest 'path:{elem:{name:"state"} elem:{name:"system"} elem:{name:"version"}}' to 10.2.0.11:57400

It seems valuable to display the missing elements like DataType, Encoding, etc

named subscriptions

Support subscribing using the cli mode with named subscriptions already defined in a config file.
e.g: gnmic subscribe --name sub1

improve installation script

Currently the installation script has the following limitations:

  • always download the latest version
  • cant be told to download a specific version

The proposal is to base the installer script either on the Helm installer or leverage godownloader

add support for multiple ModelName

ModelName is a repeated object in GetResponse and Subscribe. Long term plan should be to support multiple names (comma separated for instance)

race condition happens when using ONCE subscriptions

Sometime ONCE response is not printed out to stdout:

The output shows two consecutive runs:

❯ go run . -a r1 --insecure -u admin -p admin --config /dev/null sub --path /state/system/version --mode ONCE
file_output 2020/07/07 15:42:45.454581 initialized file output: {"Cfg":{"FileName":"","FileType":"stdout"}}
gnmic 2020/07/07 15:42:45.553653 target '0.tcp.eu.ngrok.io:14852' initialized
gnmic 2020/07/07 15:42:45.555383 sending gNMI SubscribeRequest: subscribe='subscribe:{prefix:{}  subscription:{path:{elem:{name:"state"}  elem:{name:"system"}  elem:{name:"version"}}}  qos:{marking:20}  mode:ONCE}', mode='ONCE', encoding='JSON', to 0.tcp.eu.ngrok.io:14852
{
  "source": "0.tcp.eu.ngrok.io:14852",
  "subscription-name": "default",
  "timestamp": 1594129419152003783,
  "time": "2020-07-07T15:43:39.152003783+02:00",
  "prefix": "state/system/version",
  "updates": [
    {
      "Path": "version-number",
      "values": {
        "version-number": "B-20.5.R1"
      }
    },
    {
      "Path": "version-string",
      "values": {
        "version-string": "TiMOS-B-20.5.R1 both/x86_64 Nokia 7750 SR Copyright (c) 2000-2020 Nokia.\r\nAll rights reserved. All use subject to applicable license agreements.\r\nBuilt on Wed May 13 14:08:50 PDT 2020 by builder in /builds/c/205B/R1/panos/main/sros"
      }
    }
  ]
}
file_output 2020/07/07 15:42:45.753384 closing file '/dev/stdout' output



❯ go run . -a r2 --insecure -u admin -p admin --config /dev/null sub --path /state/system/version --mode ONCE
file_output 2020/07/07 15:42:49.217199 initialized file output: {"Cfg":{"FileName":"","FileType":"stdout"}}
gnmic 2020/07/07 15:42:49.352015 target '0.tcp.eu.ngrok.io:14852' initialized
gnmic 2020/07/07 15:42:49.353721 sending gNMI SubscribeRequest: subscribe='subscribe:{prefix:{}  subscription:{path:{elem:{name:"state"}  elem:{name:"system"}  elem:{name:"version"}}}  qos:{marking:20}  mode:ONCE}', mode='ONCE', encoding='JSON', to 0.tcp.eu.ngrok.io:14852
file_output 2020/07/07 15:42:49.528603 closing file '/dev/stdout' output

If make this a regular method call iso of goroutine, I do not see the race condition:
https://github.com/karimra/gnmic/blob/collector/collector/collector.go#L185

How crucial is it to have it a goroutine here? Since the o.Write() inside of t.Export is async anyway?

hide internal type information?

It seems that having the internal type of the value does not benefit the user. Any reasons to keep it?

In the output below I am referring to (*gnmi.TypedValue_JsonVal)

root@eve-ng:~# gnmiClient -a 10.1.0.11:57400 -u admin -p admin --insecure get --path /state/system/platform
timestamp: 1587670793967241885
prefix:
alias:
state/system/platform: (*gnmi.TypedValue_JsonVal) "7750 SR-1s"

inline update with --update-value is broken

inline update without type specified in the --update-path should be a valid case, yet its not

$ go run . -a 10.0.0.10:123 -u admin -p admin --debug set --update-path /test --update-value val1
2020/04/23 22:47:45 deletes(0)=[]
2020/04/23 22:47:45 updates(0)=
2020/04/23 22:47:45 replaces(0)=
2020/04/23 22:47:45 delimiter=:::
2020/04/23 22:47:45 updates-paths(1)=[/test]
2020/04/23 22:47:45 replaces-paths(0)=[]
2020/04/23 22:47:45 updates-files(0)=[]
2020/04/23 22:47:45 replaces-files(0)=[]
2020/04/23 22:47:45 updates-values(1)=[val1]
2020/04/23 22:47:45 replaces-values(0)=[]
Error: unknown type '', must be one of: [json json_ietf string int uint bool decimal float bytes ascii]

timestamp in datetime format

Proposal:

Make timestamp info more readable for CLI users by either

  1. display the timestamp info both in nanoseconds and a datetime by default
  2. implement a flag that will enable this behavior

support set cmd from file with json_ietf encoding

Currently the set command if provided with --update-file or --replace-file creates the set Values as JsonVal.
Using [-e | --encoding] it's possible to control the value type, jsonVal vs jsonIetfVal

implement lstrip for comma separated paths

If a user chooses to use multiple paths by comma separating them like

gnmiClient -a 10.2.0.11 -u admin -p nokiasr0s --insecure get \
    --path "/state/system/version,\
           /state/system/version/version-number"

the the code should strip the whitespaces after splitting by comma, otherwise the full state is retrieved

gracefully handle empty json responses

As seen with IOS XR:

*gnmi.TypedValue : json_ietf_val:""
jsonData: []
gnmic 2020/07/10 17:17:45.420801 /home/karim/github.com/karimra/gnmic/cmd/get.go:124: unexpected end of JSON input

openconfig per-interface filter not working

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.