Git Product home page Git Product logo

gnmic's Introduction

github release Github all releases Go Report Doc build


gnmic (pronoun.: gee·en·em·eye·see) is a gNMI CLI client that provides full support for Capabilities, Get, Set and Subscribe RPCs with collector capabilities.

Documentation available at https://gnmic.kmrd.dev

Features

  • Full support for gNMI RPCs
    Every gNMI RPC has a corresponding command with all of the RPC options configurable by means of the local and global flags.
  • Flexible collector deployment
    gnmic can be deployed as a gNMI collector that supports multiple output types (NATS, Kafka, Prometheus, InfluxDB,...).
    The collector can be deployed either as a single instance, as part of a cluster, or used to form data pipelines.
  • Support gRPC tunnel based dialout telemetry
    gnmic can be deployed as a gNMI collector with an embedded tunnel server.
  • gNMI data manipulation
    gnmic collector has data transformation capabilities that can be used to adapt the collected data to your specific use case.
  • Dynamic targets loading
    gnmic support target loading at runtime based on input from external systems.
  • YANG-based path suggestions
    Your CLI magically becomes a YANG browser when gnmic is executed in prompt mode. In this mode the flags that take XPATH values will get auto-suggestions based on the provided YANG modules. In other words - voodoo magic 🤯
  • Multi-target operations
    Commands can operate on multiple gNMI targets for bulk configuration/retrieval/subscription.
  • Multiple configuration sources
    gnmic supports flags, environment variables as well as file based configurations.
  • Inspect raw gNMI messages
    With the prototext output format you can see the actual gNMI messages being sent/received. Its like having a gNMI looking glass!
  • (In)secure gRPC connection
    gNMI client supports both TLS and non-TLS transports so you can start using it in a lab environment without having to care about the PKI.
  • Dial-out telemetry
    The dial-out telemetry server is provided for Nokia SR OS.
  • Pre-built multi-platform binaries
    Statically linked binaries made in our release pipeline are available for major operating systems and architectures. Making installation a breeze!
  • Extensive and friendly documentation
    You won't be in need to dive into the source code to understand how gnimc works, our documentation site has you covered.

Quick start guide

Installation

bash -c "$(curl -sL https://get-gnmic.kmrd.dev)"

Capabilities request

gnmic -a 10.1.0.11:57400 -u admin -p admin --insecure capabilities

Get request

gnmic -a 10.1.0.11:57400 -u admin -p admin --insecure \
      get --path /state/system/platform

Set request

gnmic -a 10.1.0.11:57400 -u admin -p admin --insecure \
      set --update-path /configure/system/name \
          --update-value gnmic_demo

Subscribe request

gnmic -a 10.1.0.11:57400 -u admin -p admin --insecure \
      sub --path "/state/port[port-id=1/1/c1/1]/statistics/in-packets"

Prompt mode

The prompt mode is an interactive mode of the gnmic CLI client for user convenience.

# clone repository with YANG models (Openconfig example)
git clone https://github.com/openconfig/public
cd public

# Start gnmic in prompt mode and read in all the modules:

gnmic --file release/models \
      --dir third_party \
      --exclude ietf-interfaces \
      prompt

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

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

named subscriptions

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

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

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

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

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.

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

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"
}

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]

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

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

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

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)

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

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]

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"

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)

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)

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

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.