fix(inputs.jti_openconfig_telemetry): Reauthenticate connection (#13647)
This commit is contained in:
parent
f5afcc169c
commit
0496741f4a
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
|
|
@ -44,10 +45,20 @@ type OpenConfigTelemetry struct {
|
||||||
Log telegraf.Logger
|
Log telegraf.Logger
|
||||||
|
|
||||||
sensorsConfig []sensorConfig
|
sensorsConfig []sensorConfig
|
||||||
grpcClientConns []*grpc.ClientConn
|
grpcClientConns []grpcConnection
|
||||||
wg *sync.WaitGroup
|
wg *sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type grpcConnection struct {
|
||||||
|
connection *grpc.ClientConn
|
||||||
|
cancel context.CancelFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *grpcConnection) Close() {
|
||||||
|
g.connection.Close()
|
||||||
|
g.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Regex to match and extract data points from path value in received key
|
// Regex to match and extract data points from path value in received key
|
||||||
keyPathRegex = regexp.MustCompile(`/([^/]*)\[([A-Za-z0-9\-/]*=[^\[]*)]`)
|
keyPathRegex = regexp.MustCompile(`/([^/]*)\[([A-Za-z0-9\-/]*=[^\[]*)]`)
|
||||||
|
|
@ -250,34 +261,49 @@ func (m *OpenConfigTelemetry) collectData(
|
||||||
defer m.wg.Done()
|
defer m.wg.Done()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
stream, err := c.TelemetrySubscribe(ctx,
|
stream, err := c.TelemetrySubscribe(
|
||||||
&telemetry.SubscriptionRequest{PathList: sensor.pathList})
|
ctx,
|
||||||
|
&telemetry.SubscriptionRequest{PathList: sensor.pathList},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rpcStatus, _ := status.FromError(err)
|
rpcStatus, _ := status.FromError(err)
|
||||||
// If service is currently unavailable and may come back later, retry
|
if rpcStatus.Code() == codes.Unauthenticated {
|
||||||
if rpcStatus.Code() != codes.Unavailable {
|
if m.Username != "" && m.Password != "" && m.ClientID != "" {
|
||||||
acc.AddError(fmt.Errorf("could not subscribe to %q: %w", grpcServer, err))
|
err := m.authenticate(ctx, grpcServer, grpcClientConn)
|
||||||
|
if err == nil {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
acc.AddError(fmt.Errorf("could not re-authenticate: %w", err))
|
||||||
|
}
|
||||||
|
} else if rpcStatus.Code() != codes.Unavailable {
|
||||||
|
// If service is currently unavailable and may come back later, retry
|
||||||
|
acc.AddError(fmt.Errorf("could not subscribe to %s on %q: %w", sensor.measurementName, grpcServer, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retry with delay. If delay is not provided, use default
|
// Retry with delay. If delay is not provided, use default
|
||||||
if time.Duration(m.RetryDelay) > 0 {
|
if time.Duration(m.RetryDelay) > 0 {
|
||||||
m.Log.Debugf("Retrying %s with timeout %v", grpcServer, time.Duration(m.RetryDelay))
|
m.Log.Debugf("Retrying %s from %s with timeout %v", sensor.measurementName, grpcServer, time.Duration(m.RetryDelay))
|
||||||
time.Sleep(time.Duration(m.RetryDelay))
|
time.Sleep(time.Duration(m.RetryDelay))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.Log.Debugf("Sucessfully subscribed to %s on %s", sensor.measurementName, grpcServer)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
r, err := stream.Recv()
|
r, err := stream.Recv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If we encounter error in the stream, break so we can retry
|
// If we encounter error in the stream, break so we can retry
|
||||||
// the connection
|
// the connection
|
||||||
acc.AddError(fmt.Errorf("failed to read from %q: %w", grpcServer, err))
|
acc.AddError(fmt.Errorf("failed to read from %s from %s: %w", sensor.measurementName, grpcServer, err))
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Log.Debugf("Received from %s: %v", grpcServer, r)
|
m.Log.Debugf("Received from %s on %s: %v", sensor.measurementName, grpcServer, r)
|
||||||
|
|
||||||
// Create a point and add to batch
|
// Create a point and add to batch
|
||||||
tags := make(map[string]string)
|
tags := make(map[string]string)
|
||||||
|
|
@ -288,7 +314,7 @@ func (m *OpenConfigTelemetry) collectData(
|
||||||
dgroups := m.extractData(r, grpcServer)
|
dgroups := m.extractData(r, grpcServer)
|
||||||
|
|
||||||
// Print final data collection
|
// Print final data collection
|
||||||
m.Log.Debugf("Available collection for %s is: %v", grpcServer, dgroups)
|
m.Log.Debugf("Available collection for %s on %s: %v", sensor.measurementName, grpcServer, dgroups)
|
||||||
|
|
||||||
timestamp := time.Now()
|
timestamp := time.Now()
|
||||||
// Iterate through data groups and add them
|
// Iterate through data groups and add them
|
||||||
|
|
@ -315,6 +341,28 @@ func (m *OpenConfigTelemetry) collectData(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *OpenConfigTelemetry) authenticate(ctx context.Context, server string, grpcClientConn *grpc.ClientConn) error {
|
||||||
|
lc := authentication.NewLoginClient(grpcClientConn)
|
||||||
|
loginReply, err := lc.LoginCheck(
|
||||||
|
ctx,
|
||||||
|
&authentication.LoginRequest{
|
||||||
|
UserName: m.Username,
|
||||||
|
Password: m.Password,
|
||||||
|
ClientId: m.ClientID,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not initiate login check for %s: %w", server, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the user is authenticated. Bail if auth error
|
||||||
|
if !loginReply.Result {
|
||||||
|
return fmt.Errorf("failed to authenticate the user for %s", server)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *OpenConfigTelemetry) Start(acc telegraf.Accumulator) error {
|
func (m *OpenConfigTelemetry) Start(acc telegraf.Accumulator) error {
|
||||||
// Build sensors config
|
// Build sensors config
|
||||||
if m.splitSensorConfig() == 0 {
|
if m.splitSensorConfig() == 0 {
|
||||||
|
|
@ -337,17 +385,28 @@ func (m *OpenConfigTelemetry) Start(acc telegraf.Accumulator) error {
|
||||||
// Connect to given list of servers and start collecting data
|
// Connect to given list of servers and start collecting data
|
||||||
var grpcClientConn *grpc.ClientConn
|
var grpcClientConn *grpc.ClientConn
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
ctx := context.Background()
|
|
||||||
m.wg = &wg
|
m.wg = &wg
|
||||||
|
|
||||||
for _, server := range m.Servers {
|
for _, server := range m.Servers {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
if len(m.Username) > 0 {
|
||||||
|
ctx = metadata.AppendToOutgoingContext(
|
||||||
|
ctx,
|
||||||
|
"username", m.Username,
|
||||||
|
"password", m.Password,
|
||||||
|
"clientid", m.ClientID,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Extract device address and port
|
// Extract device address and port
|
||||||
grpcServer, grpcPort, err := net.SplitHostPort(server)
|
grpcServer, grpcPort, err := net.SplitHostPort(server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.Log.Errorf("Invalid server address: %s", err.Error())
|
m.Log.Errorf("Invalid server address: %s", err.Error())
|
||||||
|
cancel()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
grpcClientConn, err = grpc.Dial(server, opt)
|
grpcClientConn, err = grpc.DialContext(ctx, server, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.Log.Errorf("Failed to connect to %s: %s", server, err.Error())
|
m.Log.Errorf("Failed to connect to %s: %s", server, err.Error())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -355,21 +414,15 @@ func (m *OpenConfigTelemetry) Start(acc telegraf.Accumulator) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to the list of client connections
|
// Add to the list of client connections
|
||||||
m.grpcClientConns = append(m.grpcClientConns, grpcClientConn)
|
connection := grpcConnection{
|
||||||
|
connection: grpcClientConn,
|
||||||
|
cancel: cancel,
|
||||||
|
}
|
||||||
|
m.grpcClientConns = append(m.grpcClientConns, connection)
|
||||||
|
|
||||||
if m.Username != "" && m.Password != "" && m.ClientID != "" {
|
if m.Username != "" && m.Password != "" && m.ClientID != "" {
|
||||||
lc := authentication.NewLoginClient(grpcClientConn)
|
if err := m.authenticate(ctx, server, grpcClientConn); err != nil {
|
||||||
loginReply, loginErr := lc.LoginCheck(ctx,
|
m.Log.Errorf("error authenticating to %s: %w", grpcServer, err)
|
||||||
&authentication.LoginRequest{UserName: m.Username,
|
|
||||||
Password: m.Password, ClientId: m.ClientID})
|
|
||||||
if loginErr != nil {
|
|
||||||
m.Log.Errorf("Could not initiate login check for %s: %v", server, loginErr)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the user is authenticated. Bail if auth error
|
|
||||||
if !loginReply.Result {
|
|
||||||
m.Log.Errorf("Failed to authenticate the user for %s", server)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue