feat(inputs.gnmi): Support Juniper GNMI Extension Header (#13116)

This commit is contained in:
David Roy 2023-04-27 17:30:21 +02:00 committed by GitHub
parent f297d3e6c3
commit a868add749
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 565 additions and 11 deletions

View File

@ -70,6 +70,14 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
# prefix = ""
# target = ""
## Vendor specific options
## This defines what vendor specific options to load.
## * Juniper Header Extension (juniper_header): some sensors are directly managed by
## Linecard, which adds the Juniper GNMI Header Extension. Enabling this
## allows the decoding of the Extension header if present. Currently this knob
## adds component, component_id & sub_component_id as additionnal tags
# vendor_specific = []
## Define additional aliases to map encoding paths to measurement names
# [inputs.gnmi.aliases]
# ifcounters = "openconfig:/interfaces/interface/state/counters"

View File

@ -0,0 +1,380 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.30.0
// protoc v3.12.4
// source: GnmiJuniperTelemetryHeaderExtension.proto
package jnpr_gnmi_extention
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type StreamType int32
const (
StreamType_INITIAL_SYNC StreamType = 0
StreamType_ONCHANGE StreamType = 1
StreamType_PERIODIC StreamType = 2
)
// Enum value maps for StreamType.
var (
StreamType_name = map[int32]string{
0: "INITIAL_SYNC",
1: "ONCHANGE",
2: "PERIODIC",
}
StreamType_value = map[string]int32{
"INITIAL_SYNC": 0,
"ONCHANGE": 1,
"PERIODIC": 2,
}
)
func (x StreamType) Enum() *StreamType {
p := new(StreamType)
*p = x
return p
}
func (x StreamType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (StreamType) Descriptor() protoreflect.EnumDescriptor {
return file_GnmiJuniperTelemetryHeaderExtension_proto_enumTypes[0].Descriptor()
}
func (StreamType) Type() protoreflect.EnumType {
return &file_GnmiJuniperTelemetryHeaderExtension_proto_enumTypes[0]
}
func (x StreamType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use StreamType.Descriptor instead.
func (StreamType) EnumDescriptor() ([]byte, []int) {
return file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescGZIP(), []int{0}
}
// Present as first gNMI update in all packets
type GnmiJuniperTelemetryHeaderExtension struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// router name:export IP address
SystemId string `protobuf:"bytes,1,opt,name=system_id,json=systemId,proto3" json:"system_id,omitempty"`
// line card / RE (slot number)
ComponentId uint32 `protobuf:"varint,2,opt,name=component_id,json=componentId,proto3" json:"component_id,omitempty"`
// PFE (if applicable)
SubComponentId uint32 `protobuf:"varint,3,opt,name=sub_component_id,json=subComponentId,proto3" json:"sub_component_id,omitempty"`
// Internal sensor name
SensorName string `protobuf:"bytes,4,opt,name=sensor_name,json=sensorName,proto3" json:"sensor_name,omitempty"`
// Sensor path in the subscribe request
SubscribedPath string `protobuf:"bytes,5,opt,name=subscribed_path,json=subscribedPath,proto3" json:"subscribed_path,omitempty"`
// Internal sensor path in junos
StreamedPath string `protobuf:"bytes,6,opt,name=streamed_path,json=streamedPath,proto3" json:"streamed_path,omitempty"`
Component string `protobuf:"bytes,7,opt,name=component,proto3" json:"component,omitempty"`
// Sequence number, monotonically increasing for each
SequenceNumber uint64 `protobuf:"varint,8,opt,name=sequence_number,json=sequenceNumber,proto3" json:"sequence_number,omitempty"`
// Payload get timestamp in milliseconds
PayloadGetTimestamp int64 `protobuf:"varint,9,opt,name=payload_get_timestamp,json=payloadGetTimestamp,proto3" json:"payload_get_timestamp,omitempty"`
// Stream creation timestamp in milliseconds
StreamCreationTimestamp int64 `protobuf:"varint,10,opt,name=stream_creation_timestamp,json=streamCreationTimestamp,proto3" json:"stream_creation_timestamp,omitempty"`
// [Deprecated] Event timestamp in milliseconds
//
// Deprecated: Marked as deprecated in GnmiJuniperTelemetryHeaderExtension.proto.
EventTimestamp int64 `protobuf:"varint,11,opt,name=event_timestamp,json=eventTimestamp,proto3" json:"event_timestamp,omitempty"`
// Export timestamp in milliseconds
ExportTimestamp int64 `protobuf:"varint,12,opt,name=export_timestamp,json=exportTimestamp,proto3" json:"export_timestamp,omitempty"`
// Subsequence number
SubSequenceNumber uint64 `protobuf:"varint,13,opt,name=sub_sequence_number,json=subSequenceNumber,proto3" json:"sub_sequence_number,omitempty"`
// End of marker
Eom bool `protobuf:"varint,14,opt,name=eom,proto3" json:"eom,omitempty"`
// Event publish timestamp in milliseconds
EventPublishTimestamp int64 `protobuf:"varint,15,opt,name=event_publish_timestamp,json=eventPublishTimestamp,proto3" json:"event_publish_timestamp,omitempty"`
// Stream type of packet
StreamId StreamType `protobuf:"varint,16,opt,name=stream_id,json=streamId,proto3,enum=StreamType" json:"stream_id,omitempty"`
}
func (x *GnmiJuniperTelemetryHeaderExtension) Reset() {
*x = GnmiJuniperTelemetryHeaderExtension{}
if protoimpl.UnsafeEnabled {
mi := &file_GnmiJuniperTelemetryHeaderExtension_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GnmiJuniperTelemetryHeaderExtension) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GnmiJuniperTelemetryHeaderExtension) ProtoMessage() {}
func (x *GnmiJuniperTelemetryHeaderExtension) ProtoReflect() protoreflect.Message {
mi := &file_GnmiJuniperTelemetryHeaderExtension_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GnmiJuniperTelemetryHeaderExtension.ProtoReflect.Descriptor instead.
func (*GnmiJuniperTelemetryHeaderExtension) Descriptor() ([]byte, []int) {
return file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescGZIP(), []int{0}
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetSystemId() string {
if x != nil {
return x.SystemId
}
return ""
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetComponentId() uint32 {
if x != nil {
return x.ComponentId
}
return 0
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetSubComponentId() uint32 {
if x != nil {
return x.SubComponentId
}
return 0
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetSensorName() string {
if x != nil {
return x.SensorName
}
return ""
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetSubscribedPath() string {
if x != nil {
return x.SubscribedPath
}
return ""
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetStreamedPath() string {
if x != nil {
return x.StreamedPath
}
return ""
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetComponent() string {
if x != nil {
return x.Component
}
return ""
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetSequenceNumber() uint64 {
if x != nil {
return x.SequenceNumber
}
return 0
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetPayloadGetTimestamp() int64 {
if x != nil {
return x.PayloadGetTimestamp
}
return 0
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetStreamCreationTimestamp() int64 {
if x != nil {
return x.StreamCreationTimestamp
}
return 0
}
// Deprecated: Marked as deprecated in GnmiJuniperTelemetryHeaderExtension.proto.
func (x *GnmiJuniperTelemetryHeaderExtension) GetEventTimestamp() int64 {
if x != nil {
return x.EventTimestamp
}
return 0
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetExportTimestamp() int64 {
if x != nil {
return x.ExportTimestamp
}
return 0
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetSubSequenceNumber() uint64 {
if x != nil {
return x.SubSequenceNumber
}
return 0
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetEom() bool {
if x != nil {
return x.Eom
}
return false
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetEventPublishTimestamp() int64 {
if x != nil {
return x.EventPublishTimestamp
}
return 0
}
func (x *GnmiJuniperTelemetryHeaderExtension) GetStreamId() StreamType {
if x != nil {
return x.StreamId
}
return StreamType_INITIAL_SYNC
}
var File_GnmiJuniperTelemetryHeaderExtension_proto protoreflect.FileDescriptor
var file_GnmiJuniperTelemetryHeaderExtension_proto_rawDesc = []byte{
0x0a, 0x29, 0x47, 0x6e, 0x6d, 0x69, 0x4a, 0x75, 0x6e, 0x69, 0x70, 0x65, 0x72, 0x54, 0x65, 0x6c,
0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65,
0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb1, 0x05, 0x0a, 0x23,
0x47, 0x6e, 0x6d, 0x69, 0x4a, 0x75, 0x6e, 0x69, 0x70, 0x65, 0x72, 0x54, 0x65, 0x6c, 0x65, 0x6d,
0x65, 0x74, 0x72, 0x79, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73,
0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x64,
0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e,
0x74, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f,
0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x73,
0x75, 0x62, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a,
0x0b, 0x73, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27,
0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x74,
0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
0x62, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1c, 0x0a, 0x09,
0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52,
0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65,
0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x08, 0x20,
0x01, 0x28, 0x04, 0x52, 0x0e, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x4e, 0x75, 0x6d,
0x62, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x67,
0x65, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01,
0x28, 0x03, 0x52, 0x13, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x47, 0x65, 0x74, 0x54, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x17, 0x73, 0x74, 0x72, 0x65,
0x61, 0x6d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x12, 0x2b, 0x0a, 0x0f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01,
0x52, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x12, 0x29, 0x0a, 0x10, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x6f,
0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x0a, 0x13, 0x73,
0x75, 0x62, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62,
0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x73, 0x75, 0x62, 0x53, 0x65, 0x71,
0x75, 0x65, 0x6e, 0x63, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x65,
0x6f, 0x6d, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x65, 0x6f, 0x6d, 0x12, 0x36, 0x0a,
0x17, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x74,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15,
0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x28, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f,
0x69, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0b, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x2a,
0x3a, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a,
0x0c, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x00, 0x12,
0x0c, 0x0a, 0x08, 0x4f, 0x4e, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x01, 0x12, 0x0c, 0x0a,
0x08, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x49, 0x43, 0x10, 0x02, 0x42, 0x17, 0x5a, 0x15, 0x2e,
0x3b, 0x6a, 0x6e, 0x70, 0x72, 0x5f, 0x67, 0x6e, 0x6d, 0x69, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e,
0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescOnce sync.Once
file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescData = file_GnmiJuniperTelemetryHeaderExtension_proto_rawDesc
)
func file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescGZIP() []byte {
file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescOnce.Do(func() {
file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescData = protoimpl.X.CompressGZIP(file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescData)
})
return file_GnmiJuniperTelemetryHeaderExtension_proto_rawDescData
}
var file_GnmiJuniperTelemetryHeaderExtension_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_GnmiJuniperTelemetryHeaderExtension_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_GnmiJuniperTelemetryHeaderExtension_proto_goTypes = []interface{}{
(StreamType)(0), // 0: StreamType
(*GnmiJuniperTelemetryHeaderExtension)(nil), // 1: GnmiJuniperTelemetryHeaderExtension
}
var file_GnmiJuniperTelemetryHeaderExtension_proto_depIdxs = []int32{
0, // 0: GnmiJuniperTelemetryHeaderExtension.stream_id:type_name -> StreamType
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_GnmiJuniperTelemetryHeaderExtension_proto_init() }
func file_GnmiJuniperTelemetryHeaderExtension_proto_init() {
if File_GnmiJuniperTelemetryHeaderExtension_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_GnmiJuniperTelemetryHeaderExtension_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GnmiJuniperTelemetryHeaderExtension); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_GnmiJuniperTelemetryHeaderExtension_proto_rawDesc,
NumEnums: 1,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_GnmiJuniperTelemetryHeaderExtension_proto_goTypes,
DependencyIndexes: file_GnmiJuniperTelemetryHeaderExtension_proto_depIdxs,
EnumInfos: file_GnmiJuniperTelemetryHeaderExtension_proto_enumTypes,
MessageInfos: file_GnmiJuniperTelemetryHeaderExtension_proto_msgTypes,
}.Build()
File_GnmiJuniperTelemetryHeaderExtension_proto = out.File
file_GnmiJuniperTelemetryHeaderExtension_proto_rawDesc = nil
file_GnmiJuniperTelemetryHeaderExtension_proto_goTypes = nil
file_GnmiJuniperTelemetryHeaderExtension_proto_depIdxs = nil
}

View File

@ -18,6 +18,7 @@ import (
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/internal/choice"
internaltls "github.com/influxdata/telegraf/plugins/common/tls"
"github.com/influxdata/telegraf/plugins/inputs"
)
@ -36,6 +37,9 @@ device model and the following response data:
%+v
This message is only printed once.`
// Currently supported GNMI Extensions
var supportedExtensions = []string{"juniper_header"}
// gNMI plugin instance
type GNMI struct {
Addresses []string `toml:"addresses"`
@ -47,6 +51,7 @@ type GNMI struct {
Prefix string `toml:"prefix"`
Target string `toml:"target"`
UpdatesOnly bool `toml:"updates_only"`
VendorSpecific []string `toml:"vendor_specific"`
Username string `toml:"username"`
Password string `toml:"password"`
Redial config.Duration `toml:"redial"`
@ -187,7 +192,15 @@ func (c *GNMI) Start(acc telegraf.Accumulator) error {
for _, addr := range c.Addresses {
go func(addr string) {
defer c.wg.Done()
h := newHandler(addr, c.internalAliases, c.TagSubscriptions, int(c.MaxMsgSize), c.Log, c.Trace)
confHandler := configHandler{
aliases: c.internalAliases,
subscriptions: c.TagSubscriptions,
maxSize: int(c.MaxMsgSize),
log: c.Log,
trace: c.Trace,
vendorExt: c.VendorSpecific,
}
h := newHandler(addr, confHandler)
for ctx.Err() == nil {
if err := h.subscribeGNMI(ctx, acc, tlscfg, request); err != nil && ctx.Err() == nil {
acc.AddError(err)
@ -304,6 +317,14 @@ func init() {
inputs.Add("cisco_telemetry_gnmi", New)
}
func (c *GNMI) Init() error {
// Check vendor_specific options configured by user
if err := choice.CheckSlice(c.VendorSpecific, supportedExtensions); err != nil {
return fmt.Errorf("unsupported vendor_specific option: %w", err)
}
return nil
}
func (s *Subscription) buildFullPath(c *GNMI) error {
var err error
if s.fullPath, err = xpath.ToGNMIPath(s.Path); err != nil {

View File

@ -13,14 +13,17 @@ import (
"time"
gnmiLib "github.com/openconfig/gnmi/proto/gnmi"
gnmiExt "github.com/openconfig/gnmi/proto/gnmi_ext"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/plugins/inputs"
jnprHeader "github.com/influxdata/telegraf/plugins/inputs/gnmi/extensions/jnpr_gnmi_extention"
"github.com/influxdata/telegraf/plugins/parsers/influx"
"github.com/influxdata/telegraf/testutil"
)
@ -903,6 +906,91 @@ func TestNotification(t *testing.T) {
),
},
},
{
name: "Juniper Extension",
plugin: &GNMI{
Log: testutil.Logger{},
Encoding: "proto",
VendorSpecific: []string{"juniper_header"},
Redial: config.Duration(1 * time.Second),
Subscriptions: []Subscription{
{
Name: "type",
Origin: "openconfig-platform",
Path: "/components/component[name=CHASSIS0:FPC0]/state",
SubscriptionMode: "sample",
SampleInterval: config.Duration(1 * time.Second),
},
},
},
server: &MockServer{
SubscribeF: func(server gnmiLib.GNMI_SubscribeServer) error {
if err := server.Send(&gnmiLib.SubscribeResponse{Response: &gnmiLib.SubscribeResponse_SyncResponse{SyncResponse: true}}); err != nil {
return err
}
response := &gnmiLib.SubscribeResponse{
Response: &gnmiLib.SubscribeResponse_Update{
Update: &gnmiLib.Notification{
Timestamp: 1668771585733542546,
Prefix: &gnmiLib.Path{
Elem: []*gnmiLib.PathElem{
{Name: "openconfig-platform:components"},
{Name: "component", Key: map[string]string{"name": "CHASSIS0:FPC0"}},
{Name: "state"},
},
Target: "OC-YANG",
},
Update: []*gnmiLib.Update{
{
Path: &gnmiLib.Path{
Elem: []*gnmiLib.PathElem{
{Name: "type"},
}},
Val: &gnmiLib.TypedValue{
Value: &gnmiLib.TypedValue_StringVal{StringVal: "LINECARD"},
},
},
},
},
},
Extension: []*gnmiExt.Extension{{
Ext: &gnmiExt.Extension_RegisteredExt{
RegisteredExt: &gnmiExt.RegisteredExtension{
// Juniper Header Extension
//EID_JUNIPER_TELEMETRY_HEADER = 1;
Id: 1,
Msg: func(jnprExt *jnprHeader.GnmiJuniperTelemetryHeaderExtension) []byte {
b, err := proto.Marshal(jnprExt)
if err != nil {
return nil
}
return b
}(&jnprHeader.GnmiJuniperTelemetryHeaderExtension{ComponentId: 15, SubComponentId: 1, Component: "PICD"}),
},
},
}},
}
return server.Send(response)
},
},
expected: []telegraf.Metric{
testutil.MustMetric(
"type",
map[string]string{
"path": "openconfig-platform:/components/component/state",
"source": "127.0.0.1",
"name": "CHASSIS0:FPC0",
"component_id": "15",
"sub_component_id": "1",
"component": "PICD",
},
map[string]interface{}{
"type": "LINECARD",
},
time.Unix(0, 0),
),
},
},
}
for _, tt := range tests {

View File

@ -12,34 +12,52 @@ import (
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal/choice"
"github.com/influxdata/telegraf/metric"
jnprHeader "github.com/influxdata/telegraf/plugins/inputs/gnmi/extensions/jnpr_gnmi_extention"
gnmiLib "github.com/openconfig/gnmi/proto/gnmi"
gnmiExt "github.com/openconfig/gnmi/proto/gnmi_ext"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
)
const eidJuniperTelemetryHeader = 1
type handler struct {
address string
aliases map[string]string
tagsubs []TagSubscription
maxMsgSize int
emptyNameWarnShown bool
vendorExt []string
tagStore *tagStore
trace bool
log telegraf.Logger
}
func newHandler(addr string, aliases map[string]string, subs []TagSubscription, maxsize int, l telegraf.Logger, trace bool) *handler {
// Allow to convey additionnal configuration elements
type configHandler struct {
aliases map[string]string
subscriptions []TagSubscription
maxSize int
log telegraf.Logger
trace bool
vendorExt []string
}
func newHandler(addr string, confHandler configHandler) *handler {
return &handler{
address: addr,
aliases: aliases,
tagsubs: subs,
maxMsgSize: maxsize,
tagStore: newTagStore(subs),
trace: trace,
log: l,
aliases: confHandler.aliases,
tagsubs: confHandler.subscriptions,
maxMsgSize: confHandler.maxSize,
vendorExt: confHandler.vendorExt,
tagStore: newTagStore(confHandler.subscriptions),
trace: confHandler.trace,
log: confHandler.log,
}
}
@ -98,21 +116,52 @@ func (h *handler) subscribeGNMI(ctx context.Context, acc telegraf.Accumulator, t
h.log.Debugf("update_%v: %s", t, string(buf))
}
}
if response, ok := reply.Response.(*gnmiLib.SubscribeResponse_Update); ok {
h.handleSubscribeResponseUpdate(acc, response)
h.handleSubscribeResponseUpdate(acc, response, reply.GetExtension())
}
}
return nil
}
// Handle SubscribeResponse_Update message from gNMI and parse contained telemetry data
func (h *handler) handleSubscribeResponseUpdate(acc telegraf.Accumulator, response *gnmiLib.SubscribeResponse_Update) {
func (h *handler) handleSubscribeResponseUpdate(acc telegraf.Accumulator, response *gnmiLib.SubscribeResponse_Update, extension []*gnmiExt.Extension) {
var prefix, prefixAliasPath string
grouper := metric.NewSeriesGrouper()
timestamp := time.Unix(0, response.Update.Timestamp)
prefixTags := make(map[string]string)
// iter on each extension
for _, ext := range extension {
currentExt := ext.GetRegisteredExt().Msg
if currentExt == nil {
break
}
// extension ID
switch ext.GetRegisteredExt().Id {
// Juniper Header extention
//EID_JUNIPER_TELEMETRY_HEADER = 1;
case eidJuniperTelemetryHeader:
// Decode it only if user requested it
if choice.Contains("juniper_header", h.vendorExt) {
juniperHeader := &jnprHeader.GnmiJuniperTelemetryHeaderExtension{}
// unmarshal extention
err := proto.Unmarshal(currentExt, juniperHeader)
if err != nil {
h.log.Errorf("unmarshal gnmi Juniper Header extention failed: %w", err)
break
}
// Add only relevant Tags from the Juniper Header extention.
// These are requiered for aggregation
prefixTags["component_id"] = fmt.Sprint(juniperHeader.GetComponentId())
prefixTags["component"] = fmt.Sprint(juniperHeader.GetComponent())
prefixTags["sub_component_id"] = fmt.Sprint(juniperHeader.GetSubComponentId())
}
default:
continue
}
}
if response.Update.Prefix != nil {
var err error
if prefix, prefixAliasPath, err = handlePath(response.Update.Prefix, prefixTags, h.aliases, ""); err != nil {

View File

@ -34,6 +34,14 @@
# prefix = ""
# target = ""
## Vendor specific options
## This defines what vendor specific options to load.
## * Juniper Header Extension (juniper_header): some sensors are directly managed by
## Linecard, which adds the Juniper GNMI Header Extension. Enabling this
## allows the decoding of the Extension header if present. Currently this knob
## adds component, component_id & sub_component_id as additionnal tags
# vendor_specific = []
## Define additional aliases to map encoding paths to measurement names
# [inputs.gnmi.aliases]
# ifcounters = "openconfig:/interfaces/interface/state/counters"