Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 41 additions & 14 deletions internal/provider/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ import (
)

const (
DefaultMaxRetries int = 2
DefaultBackoffMinDelay int = 4
DefaultBackoffMaxDelay int = 60
DefaultBackoffDelayFactor float64 = 3
GnmiTimeout = 15 * time.Second
DefaultMaxRetries int = 2
DefaultBackoffMinDelay int = 4
DefaultBackoffMaxDelay int = 60
DefaultBackoffDelayFactor float64 = 3
DefaultGnmiTimeout time.Duration = 15 * time.Second // Configurable gNMI timeout
DefaultConnectTimeout time.Duration = 30 * time.Second // Configurable connection timeout
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain what the issue you try to slove and why we have two timeout ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

)

type SetOperationType string
Expand All @@ -60,6 +61,10 @@ type Client struct {
BackoffMaxDelay int
// Backoff delay factor
BackoffDelayFactor float64
// Connection timeout - configurable by user
ConnectTimeout time.Duration
// gNMI operation timeout - configurable by user
GnmiTimeout time.Duration
}

type Device struct {
Expand All @@ -73,16 +78,21 @@ type SetOperation struct {
Operation SetOperationType
}

func NewClient(reuseConnection bool) Client {
func NewClient(reuseConnection bool, options ...interface{}) Client {
devices := make(map[string]*Device)
return Client{

// Set default values
client := Client{
Devices: devices,
ReuseConnection: reuseConnection,
MaxRetries: DefaultMaxRetries,
BackoffMinDelay: DefaultBackoffMinDelay,
BackoffMaxDelay: DefaultBackoffMaxDelay,
BackoffDelayFactor: DefaultBackoffDelayFactor,
ConnectTimeout: DefaultConnectTimeout, // Default 30 seconds
GnmiTimeout: DefaultGnmiTimeout, // Default 15 seconds
}
return client
}

func (c *Client) AddTarget(ctx context.Context, device, host, username, password, certificate, key, caCertificate string, verifyCertificate, Tls bool) error {
Expand All @@ -106,7 +116,11 @@ func (c *Client) AddTarget(ctx context.Context, device, host, username, password
}

if c.ReuseConnection {
err = t.CreateGNMIClient(ctx)
// Create connection context with configurable timeout
connectCtx, cancel := context.WithTimeout(ctx, c.ConnectTimeout)
defer cancel()
tflog.Debug(ctx, fmt.Sprintf("Creating gNMI client with connection timeout: %v", c.ConnectTimeout))
err = t.CreateGNMIClient(connectCtx)
if err != nil {
return fmt.Errorf("Unable to create gNMI client: %w", err)
}
Expand Down Expand Up @@ -146,7 +160,12 @@ func (c *Client) Set(ctx context.Context, device string, operations ...SetOperat
for attempts := 0; ; attempts++ {
c.Devices[device].SetMutex.Lock()
if !c.ReuseConnection {
err = target.CreateGNMIClient(ctx)
// Create connection context with configurable timeout
connectCtx, cancel := context.WithTimeout(ctx, c.ConnectTimeout)
tflog.Debug(ctx, fmt.Sprintf("Creating gNMI client with connection timeout: %v", c.ConnectTimeout))
err = target.CreateGNMIClient(connectCtx)
cancel() // Clean up timeout context immediately

if err != nil {
if ok := c.Backoff(ctx, attempts); !ok {
return nil, fmt.Errorf("Unable to create gNMI client: %w", err)
Expand All @@ -156,9 +175,10 @@ func (c *Client) Set(ctx context.Context, device string, operations ...SetOperat
}
}
}
tCtx, cancel := context.WithTimeout(ctx, GnmiTimeout)
// Use configurable gNMI timeout
tCtx, cancel := context.WithTimeout(ctx, c.GnmiTimeout)
defer cancel()
tflog.Debug(ctx, fmt.Sprintf("gNMI set request: %s", setReq.String()))
tflog.Debug(ctx, fmt.Sprintf("gNMI set request (timeout: %v): %s", c.GnmiTimeout, setReq.String()))
setResp, err = target.Set(tCtx, setReq)
tflog.Debug(ctx, fmt.Sprintf("gNMI set response: %s", setResp.String()))
c.Devices[device].SetMutex.Unlock()
Expand Down Expand Up @@ -195,7 +215,12 @@ func (c *Client) Get(ctx context.Context, device, path string) (*gnmi.GetRespons
for attempts := 0; ; attempts++ {
tflog.Debug(ctx, fmt.Sprintf("gNMI get request: %s", getReq.String()))
if !c.ReuseConnection {
err = target.CreateGNMIClient(ctx)
// Create connection context with configurable timeout
connectCtx, cancel := context.WithTimeout(ctx, c.ConnectTimeout)
tflog.Debug(ctx, fmt.Sprintf("Creating gNMI client with connection timeout: %v", c.ConnectTimeout))
err = target.CreateGNMIClient(connectCtx)
cancel() // Clean up timeout context immediately

if err != nil {
if ok := c.Backoff(ctx, attempts); !ok {
return nil, fmt.Errorf("Unable to create gNMI client: %w", err)
Expand All @@ -205,16 +230,18 @@ func (c *Client) Get(ctx context.Context, device, path string) (*gnmi.GetRespons
}
}
}
tCtx, cancel := context.WithTimeout(ctx, GnmiTimeout)
// Use configurable gNMI timeout
tCtx, cancel := context.WithTimeout(ctx, c.GnmiTimeout)
defer cancel()
tflog.Debug(ctx, fmt.Sprintf("gNMI get request (timeout: %v)", c.GnmiTimeout))
getResp, err = target.Get(tCtx, getReq)
if !c.ReuseConnection {
target.Close()
}
tflog.Debug(ctx, fmt.Sprintf("gNMI get response: %s", getResp.String()))
if err != nil {
if ok := c.Backoff(ctx, attempts); !ok {
return nil, fmt.Errorf(("Get request failed, got error: %w"), err)
return nil, fmt.Errorf("Get request failed, got error: %w", err)
} else {
tflog.Error(ctx, fmt.Sprintf("gNMI get request failed: %s, retries: %v", err, attempts))
continue
Expand Down