From 261e0223a76118efd8cc3c3239f9ca3dc874f45c Mon Sep 17 00:00:00 2001 From: Sven Rebhan <36194019+srebhan@users.noreply.github.com> Date: Fri, 30 Jun 2023 20:49:26 +0200 Subject: [PATCH] fix(inputs.opcua): Ensure we are connected after reconnect (#13514) --- plugins/common/opcua/client.go | 44 ++++++++++++++--------------- plugins/inputs/opcua/read_client.go | 23 +++++++-------- 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/plugins/common/opcua/client.go b/plugins/common/opcua/client.go index 3a844440d..412d108c9 100644 --- a/plugins/common/opcua/client.go +++ b/plugins/common/opcua/client.go @@ -18,6 +18,20 @@ type OpcUAWorkarounds struct { AdditionalValidStatusCodes []string `toml:"additional_valid_status_codes"` } +type ConnectionState opcua.ConnState + +const ( + Closed ConnectionState = ConnectionState(opcua.Closed) + Connected ConnectionState = ConnectionState(opcua.Connected) + Connecting ConnectionState = ConnectionState(opcua.Connecting) + Disconnected ConnectionState = ConnectionState(opcua.Disconnected) + Reconnecting ConnectionState = ConnectionState(opcua.Reconnecting) +) + +func (c ConnectionState) String() string { + return opcua.ConnState(c).String() +} + type OpcUAClientConfig struct { Endpoint string `toml:"endpoint"` SecurityPolicy string `toml:"security_policy"` @@ -73,29 +87,15 @@ func (o *OpcUAClientConfig) CreateClient(log telegraf.Logger) (*OpcUAClient, err Log: log, } c.Log.Debug("Initialising OpcUAClient") - c.State = Disconnected err = c.setupWorkarounds() return c, err } -// ConnectionState used for constants -type ConnectionState int - -const ( - // Disconnected constant State 0 - Disconnected ConnectionState = iota - // Connecting constant State 1 - Connecting - // Connected constant State 2 - Connected -) - type OpcUAClient struct { Config *OpcUAClientConfig Log telegraf.Logger - State ConnectionState Client *opcua.Client opts []opcua.Option @@ -164,10 +164,7 @@ func (o *OpcUAClient) Connect() error { switch u.Scheme { case "opc.tcp": - o.State = Connecting - - err = o.SetupOptions() - if err != nil { + if err := o.SetupOptions(); err != nil { return err } @@ -184,11 +181,8 @@ func (o *OpcUAClient) Connect() error { ctx, cancel := context.WithTimeout(context.Background(), time.Duration(o.Config.ConnectTimeout)) defer cancel() if err := o.Client.Connect(ctx); err != nil { - o.State = Disconnected return fmt.Errorf("error in Client Connection: %w", err) } - - o.State = Connected o.Log.Debug("Connected to OPC UA Server") default: @@ -206,7 +200,6 @@ func (o *OpcUAClient) Disconnect(ctx context.Context) error { switch u.Scheme { case "opc.tcp": - o.State = Disconnected // We can't do anything about failing to close a connection err := o.Client.CloseWithContext(ctx) o.Client = nil @@ -215,3 +208,10 @@ func (o *OpcUAClient) Disconnect(ctx context.Context) error { return fmt.Errorf("invalid controller") } } + +func (o *OpcUAClient) State() ConnectionState { + if o.Client == nil { + return Disconnected + } + return ConnectionState(o.Client.State()) +} diff --git a/plugins/inputs/opcua/read_client.go b/plugins/inputs/opcua/read_client.go index 605916d0e..4bbb566c3 100644 --- a/plugins/inputs/opcua/read_client.go +++ b/plugins/inputs/opcua/read_client.go @@ -90,29 +90,26 @@ func (o *ReadClient) Connect() error { } func (o *ReadClient) ensureConnected() error { - if o.State == opcua.Disconnected { - err := o.Connect() - if err != nil { - return err - } + if o.State() == opcua.Disconnected { + return o.Connect() } - return nil } func (o *ReadClient) CurrentValues() ([]telegraf.Metric, error) { - err := o.ensureConnected() - if err != nil { + if err := o.ensureConnected(); err != nil { return nil, err } - err = o.read() - if err != nil && o.State == opcua.Connected { + if state := o.State(); state != opcua.Connected { + return nil, fmt.Errorf("not connected, in state %q", state) + } + + if err := o.read(); err != nil { // We do not return the disconnect error, as this would mask the // original problem, but we do log it - disconnectErr := o.Disconnect(context.Background()) - if disconnectErr != nil { - o.Log.Debug("Error while disconnecting: ", disconnectErr) + if derr := o.Disconnect(context.Background()); derr != nil { + o.Log.Debug("Error while disconnecting: ", derr) } return nil, err