Skip to content

Commit 704693a

Browse files
committed
feat(inputs.gnmi_listener): Add plugin
1 parent 5eece8e commit 704693a

28 files changed

Lines changed: 2112 additions & 0 deletions
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//go:build !custom || inputs || inputs.gnmi_listener
2+
3+
package all
4+
5+
import _ "github.com/influxdata/telegraf/plugins/inputs/gnmi_listener" // register plugin
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# gNMI (gRPC Network Management Interface) dial-out Input Plugin
2+
3+
This plugin consumes telemetry data based on [gNMI][gnmi] messages sent by
4+
network devices in dial-out mode. This plugin supports a list of vendor
5+
protocols such as [Nokia dial-out telemetry][nokia].
6+
7+
⭐ Telegraf v1.39.0
8+
🏷️ network
9+
💻 all
10+
11+
[gnmi]: https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md
12+
[nokia]: https://infocenter.nokia.com/public/7750SR222R1A/index.jsp?topic=%2Fcom.nokia.System_Mgmt_Guide%2Fdial-out_teleme-ai9exj5ye3.html
13+
14+
## Service Input <!-- @/docs/includes/service_input.md -->
15+
16+
This plugin is a service input. Normal plugins gather metrics determined by the
17+
interval setting. Service plugins start a service to listen and wait for
18+
metrics or events to occur. Service plugins have two key differences from
19+
normal plugins:
20+
21+
1. The global or plugin specific `interval` setting may not apply
22+
2. The CLI options of `--test`, `--test-wait`, and `--once` may not produce
23+
output for this plugin
24+
25+
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
26+
27+
Plugins support additional global and plugin configuration settings for tasks
28+
such as modifying metrics, tags, and fields, creating aliases, and configuring
29+
plugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details.
30+
31+
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
32+
33+
## Configuration
34+
35+
```toml @sample.conf
36+
# gNMI dial-out telemetry plugin
37+
[[inputs.gnmi_listener]]
38+
## Address and port of the gNMI GRPC server
39+
address = "localhost:57400"
40+
41+
## Protocol to use, available options:
42+
## nokia -- Nokia SR OS dial-out protocol
43+
# protocol = "nokia"
44+
45+
## Emit a metric for "delete" messages
46+
# emit_delete_metrics = false
47+
48+
## Enable to get the canonical path as field-name
49+
# canonical_field_names = false
50+
51+
## Remove leading slashes and dots in field-name
52+
# trim_field_names = false
53+
54+
## Prefix tags from path keys with the path element
55+
# prefix_tag_key_with_path = false
56+
57+
## Guess the path-tag if an update does not contain a prefix-path
58+
## Supported values are
59+
## none -- do not add a 'path' tag
60+
## common path -- use the common path elements of all fields in an update
61+
## subscription -- use the subscription path
62+
# path_guessing_strategy = "none"
63+
64+
## Vendor specific options
65+
## This defines what vendor specific options to load.
66+
## * Juniper Header Extension (juniper_header): some sensors are directly managed by
67+
## Linecard, which adds the Juniper GNMI Header Extension. Enabling this
68+
## allows the decoding of the Extension header if present. Currently this knob
69+
## adds component, component_id & sub_component_id as additional tags
70+
# vendor_specific = []
71+
72+
## YANG model paths for decoding IETF JSON payloads
73+
## Model files are loaded recursively from the given directories. Disabled if
74+
## no models are specified.
75+
# yang_model_paths = []
76+
## Used for TLS server certificate authentication
77+
# tls_cert = "/path/to/certfile"
78+
## Used for TLS server certificate authentication
79+
# tls_key = "/path/to/keyfile"
80+
## Password for encrypted key files
81+
# tls_key_pwd = ""
82+
## CA certificates used for verifying client certificates
83+
# tls_allowed_cacerts = []
84+
## List of ciphers to accept, by default all secure ciphers will be accepted
85+
## See https://pkg.go.dev/crypto/tls#pkg-constants for supported values.
86+
## Use "all", "secure" and "insecure" to add all support ciphers, secure
87+
## suites or insecure suites respectively.
88+
# tls_cipher_suites = ["secure"]
89+
## Minimal TLS version to accept by the server
90+
# tls_min_version = "TLS12"
91+
## Maximum TLS version to accept by the server
92+
# tls_max_version = ""
93+
## Whitelist for certificate DNS names to accept
94+
# tls_allowed_dns_names = []
95+
```
96+
97+
### Supported Nokia devices
98+
99+
The `nokia` protocol supports Nokia SR OS devices with dial-out telemetry such
100+
as the following platforms:
101+
102+
- 7250 Interconnect Router (IXR)
103+
- 7450 Ethernet Service Switch (ESS)
104+
- 7750 Service Router (SR)
105+
- 7950 Extensible Routing System (XRS)
106+
- Virtualized Service Router (VSR)
107+
108+
See [server implementation](nokia/README.md) for details.
109+
110+
## Metrics
111+
112+
Each GNMI message will emit a different measurement. Leaf entries in a
113+
GNMI SubscribeResponse Update message will produce a field reading in the
114+
measurement. GNMI PathElement keys for leaves will attach tags to the field(s).
115+
116+
## Example Output
117+
118+
```text
119+
gnmi,path=openconfig-interfaces:/interfaces/interface/state/counters,host=linux,name=MgmtEth0/RP0/CPU0/0,source=10.49.234.115,descr/description=Foo in-multicast-pkts=0i,out-multicast-pkts=0i,out-errors=0i,out-discards=0i,in-broadcast-pkts=0i,out-broadcast-pkts=0i,in-discards=0i,in-unknown-protos=0i,in-errors=0i,out-unicast-pkts=0i,in-octets=0i,out-octets=0i,last-clear="2019-05-22T16:53:21Z",in-unicast-pkts=0i 1559145777425000000
120+
gnmi,path=openconfig-interfaces:/interfaces/interface/state/counters,host=linux,name=GigabitEthernet0/0/0/0,source=10.49.234.115,descr/description=Bar out-multicast-pkts=0i,out-broadcast-pkts=0i,in-errors=0i,out-errors=0i,in-discards=0i,out-octets=0i,in-unknown-protos=0i,in-unicast-pkts=0i,in-octets=0i,in-multicast-pkts=0i,in-broadcast-pkts=0i,last-clear="2019-05-22T16:54:50Z",out-unicast-pkts=0i,out-discards=0i 1559145777425000000
121+
```
122+
123+
## Troubleshooting
124+
125+
### Missing `path` tag
126+
127+
Some devices (e.g. Arista) omit the prefix and specify the path in the update
128+
if there is only one value reported. This leads to a missing `path` tag for
129+
the resulting metrics. In those cases you should set `path_guessing_strategy`
130+
to `subscription` to use the subscription path as `path` tag.
131+
132+
Other devices might omit the prefix in updates altogether. Here setting
133+
`path_guessing_strategy` to `common path` can help to infer the `path` tag by
134+
using the part of the path that is common to all values in the update.
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//go:generate ../../../tools/config_includer/generator
2+
//go:generate ../../../tools/readme_config_includer/generator
3+
package gnmilistener
4+
5+
import (
6+
_ "embed"
7+
"fmt"
8+
"net"
9+
10+
"google.golang.org/grpc"
11+
"google.golang.org/grpc/credentials"
12+
13+
"github.com/influxdata/telegraf"
14+
common_gnmi "github.com/influxdata/telegraf/plugins/common/gnmi"
15+
common_tls "github.com/influxdata/telegraf/plugins/common/tls"
16+
"github.com/influxdata/telegraf/plugins/inputs"
17+
"github.com/influxdata/telegraf/plugins/inputs/gnmi_listener/nokia"
18+
)
19+
20+
//go:embed sample.conf
21+
var sampleConfig string
22+
23+
type serverImplementation interface {
24+
Register(*grpc.Server)
25+
}
26+
27+
type GNMIListener struct {
28+
Address string `toml:"address"`
29+
Protocol string `toml:"protocol"`
30+
Log telegraf.Logger `toml:"-"`
31+
common_gnmi.HandlerConfig
32+
common_tls.ServerConfig
33+
34+
options []grpc.ServerOption
35+
server *grpc.Server
36+
handler *common_gnmi.Handler
37+
addr string
38+
}
39+
40+
func (*GNMIListener) SampleConfig() string {
41+
return sampleConfig
42+
}
43+
44+
func (g *GNMIListener) Init() error {
45+
// Defaults
46+
if g.Address == "" {
47+
g.Address = "localhost:57400"
48+
}
49+
50+
// Check user settings
51+
switch g.Protocol {
52+
case "":
53+
g.Protocol = "nokia"
54+
case "nokia":
55+
// Do nothing, those are valid
56+
default:
57+
return fmt.Errorf("invalid 'protocol' %q", g.Protocol)
58+
}
59+
60+
// Fill the server options depending on the user settings
61+
if tlsCfg, err := g.ServerConfig.TLSConfig(); err != nil {
62+
return fmt.Errorf("creating TLS configuration failed: %w", err)
63+
} else if tlsCfg != nil {
64+
g.options = append(g.options, grpc.Creds(credentials.NewTLS(tlsCfg)))
65+
}
66+
67+
if g.Log.Level().Includes(telegraf.Trace) {
68+
g.options = append(g.options, grpc.InTapHandle(g.logCalls))
69+
}
70+
71+
// Create a response handler
72+
h, err := g.HandlerConfig.Handler(g.Log, common_gnmi.WithDefaultName("gnmi"))
73+
if err != nil {
74+
return fmt.Errorf("creating response handler failed: %w", err)
75+
}
76+
g.handler = h
77+
78+
return nil
79+
}
80+
81+
func (g *GNMIListener) Start(acc telegraf.Accumulator) error {
82+
// Create the protocol implementation
83+
var impl serverImplementation
84+
switch g.Protocol {
85+
case "nokia":
86+
impl = nokia.New(acc, g.handler, g.Log)
87+
default:
88+
return fmt.Errorf("invalid 'protocol' %q", g.Protocol)
89+
}
90+
91+
// Create a listener or wrap it for debugging
92+
listener, err := net.Listen("tcp", g.Address)
93+
if err != nil {
94+
return fmt.Errorf("listening on %q failed: %w", g.Address, err)
95+
}
96+
g.addr = listener.Addr().String()
97+
98+
// Start the server
99+
g.server = grpc.NewServer(g.options...)
100+
impl.Register(g.server)
101+
go func() {
102+
if err := g.server.Serve(listener); err != nil {
103+
g.Log.Errorf("Stopping GRPC server on %q due to error: %v", g.addr, err)
104+
}
105+
}()
106+
107+
return nil
108+
}
109+
110+
func (g *GNMIListener) Stop() {
111+
if g.server != nil {
112+
g.server.GracefulStop()
113+
}
114+
}
115+
116+
func (*GNMIListener) Gather(telegraf.Accumulator) error {
117+
return nil
118+
}
119+
120+
func init() {
121+
inputs.Add("gnmi_listener", func() telegraf.Input {
122+
return &GNMIListener{}
123+
})
124+
}

0 commit comments

Comments
 (0)