Skip to content

Commit 5ada433

Browse files
Ahmet OeztuerkAhmet Oeztuerk
authored andcommitted
use contexts properly with timeout
timeouts could cause the code to exit, and started before the action was taken. create contexts with timeouts when necessary, and use them in prometheusClient and golang net.http API calls
1 parent 747c932 commit 5ada433

5 files changed

Lines changed: 54 additions & 29 deletions

File tree

internal/helper/prometheus.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package helper
22

33
import (
4+
"context"
45
"crypto/tls"
56
"fmt"
67
"io"
@@ -93,7 +94,7 @@ func NewAPIClientV1(address *url.URL) (v1.API, error) {
9394
}
9495

9596
// DoAPIRequest does the http handling for an api request
96-
func DoAPIRequest(url *url.URL) ([]byte, error) {
97+
func DoAPIRequest(ctx context.Context, url *url.URL) ([]byte, error) {
9798
transport := http.DefaultTransport.(*http.Transport).Clone()
9899
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: InsecureSkipVerify}
99100

@@ -107,7 +108,13 @@ func DoAPIRequest(url *url.URL) ([]byte, error) {
107108
httpClient.Jar.SetCookies(url, Cookies)
108109
}
109110

110-
resp, err := httpClient.Get(url.String())
111+
// Create request with context to support timeout
112+
req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil)
113+
if err != nil {
114+
return nil, err
115+
}
116+
117+
resp, err := httpClient.Do(req)
111118
if err != nil {
112119
return nil, err
113120
}

internal/mode/ping.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type buildInfo struct {
2626
}
2727

2828
// Ping will fetch build information from the prometheus server
29-
func Ping(address *url.URL, collection *check_x.PerformanceDataCollection) (check_x.State, string, error) {
29+
func Ping(ctx context.Context, address *url.URL, collection *check_x.PerformanceDataCollection) (check_x.State, string, error) {
3030
if address == nil {
3131
err := fmt.Errorf("address to query is null")
3232
return check_x.Unknown, fmt.Sprintf("Error: %s", err.Error()), err
@@ -44,7 +44,7 @@ func Ping(address *url.URL, collection *check_x.PerformanceDataCollection) (chec
4444

4545
query := `prometheus_build_info{job="prometheus"}`
4646
startTime := time.Now()
47-
result, _, err := apiClient.Query(context.TODO(), query, time.Now())
47+
result, _, err := apiClient.Query(ctx, query, time.Now())
4848
endTime := time.Now()
4949
if err != nil {
5050
return check_x.Unknown, fmt.Sprintf("Error when querying API: %s", err.Error()), err

internal/mode/query.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
)
1818

1919
// Query allows the user to test data in the prometheus server
20-
func Query(address *url.URL, query, warning, critical, alias, search, replace, emptyQueryMessage string, emptyQueryStatus check_x.State, collection *check_x.PerformanceDataCollection) (check_x.State, string, error) {
20+
func Query(ctx context.Context, address *url.URL, query, warning, critical, alias, search, replace, emptyQueryMessage string, emptyQueryStatus check_x.State, collection *check_x.PerformanceDataCollection) (check_x.State, string, error) {
2121
if address == nil {
2222
err := fmt.Errorf("address to query is null")
2323
return check_x.Unknown, fmt.Sprintf("Error: %s", err.Error()), err
@@ -51,7 +51,7 @@ func Query(address *url.URL, query, warning, critical, alias, search, replace, e
5151
return check_x.Unknown, fmt.Sprintf("Error creating apiClient: %s", err.Error()), err
5252
}
5353

54-
result, _, err := apiClient.Query(context.TODO(), query, time.Now())
54+
result, _, err := apiClient.Query(ctx, query, time.Now())
5555
if err != nil {
5656
return check_x.Unknown, fmt.Sprintf("Error when querying: %s", err.Error()), err
5757
}

internal/mode/targetsHealth.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package mode
22

33
import (
4+
"context"
45
"encoding/json"
56
"fmt"
67
"net/url"
@@ -36,13 +37,13 @@ type targets struct {
3637
} `json:"data"`
3738
}
3839

39-
func getTargets(address *url.URL) (*targets, error) {
40-
u, err := url.Parse(address.String())
40+
func getTargets(ctx context.Context, address *url.URL) (*targets, error) {
41+
url, err := url.Parse(address.String())
4142
if err != nil {
4243
return nil, err
4344
}
44-
u.Path = path.Join(u.Path, "/api/v1/targets")
45-
jsonBytes, err := helper.DoAPIRequest(u)
45+
url.Path = path.Join(url.Path, "/api/v1/targets")
46+
jsonBytes, err := helper.DoAPIRequest(ctx, url)
4647
if err != nil {
4748
return nil, err
4849
}
@@ -55,7 +56,7 @@ func getTargets(address *url.URL) (*targets, error) {
5556
}
5657

5758
// TargetsHealth tests the health of the targets
58-
func TargetsHealth(address *url.URL, label, warning, critical string, collection *check_x.PerformanceDataCollection) (check_x.State, string, error) {
59+
func TargetsHealth(ctx context.Context, address *url.URL, label, warning, critical string, collection *check_x.PerformanceDataCollection) (check_x.State, string, error) {
5960
if address == nil {
6061
err := fmt.Errorf("address to query is null")
6162
return check_x.Unknown, fmt.Sprintf("Error: %s", err.Error()), err
@@ -76,7 +77,7 @@ func TargetsHealth(address *url.URL, label, warning, critical string, collection
7677
return check_x.Unknown, fmt.Sprintf("Error creating critThreshold from '%s' : %s", critical, err.Error()), err
7778
}
7879

79-
targets, err := getTargets(address)
80+
targets, err := getTargets(ctx, address)
8081
if err != nil {
8182
return check_x.Unknown, fmt.Sprintf("Error getting targets out of address: %s : %s", address.String(), err.Error()), err
8283
}

pkg/checker/checker.go

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,6 @@ var (
4141
emptyQueryStatus check_x.State
4242
)
4343

44-
func startTimeout() {
45-
if timeout != 0 {
46-
check_x.StartTimeout(time.Duration(timeout) * time.Second)
47-
}
48-
}
49-
5044
// This function is intended to be used for single-use cli mode
5145
// It will be called from main executable function as it returns int
5246
func CheckMain(args []string) int {
@@ -71,10 +65,10 @@ func GenerateStdout(state check_x.State, msg string, collection *check_x.Perform
7165
// It can be used as a library import
7266
func Check(args []string) (check_x.State, string, *check_x.PerformanceDataCollection, error) {
7367

74-
var state check_x.State
75-
var msg string
68+
state := check_x.Unknown
69+
msg := "Cli action did not run yet"
7670
var collection = check_x.NewPerformanceDataCollection()
77-
var err error
71+
var err error = nil
7872

7973
cmd := &cli.Command{
8074
Name: "check_prometheus",
@@ -118,8 +112,15 @@ func Check(args []string) (check_x.State, string, *check_x.PerformanceDataCollec
118112
Usage: "Returns the build informations",
119113
Description: `This check requires that the prometheus server itself is listed as target. Following query will be used: 'prometheus_build_info{job="prometheus"}'`,
120114
Action: func(ctx context.Context, cmd *cli.Command) error {
121-
startTimeout()
122-
state, msg, err = mode.Ping(address, &collection)
115+
var ctxPing context.Context
116+
var ctxPingCancel context.CancelFunc
117+
if timeout == 0 {
118+
ctxPing = context.WithoutCancel(ctx)
119+
} else {
120+
ctxPing, ctxPingCancel = context.WithTimeout(ctx, time.Duration(timeout)*time.Second)
121+
defer ctxPingCancel()
122+
}
123+
state, msg, err = mode.Ping(ctxPing, address, &collection)
123124
return err
124125
},
125126
Flags: []cli.Flag{
@@ -193,9 +194,17 @@ func Check(args []string) (check_x.State, string, *check_x.PerformanceDataCollec
193194
--> UNKNOWN - The given States do not contain an State
194195
195196
`,
196-
Action: func(c context.Context, cmd *cli.Command) error {
197-
startTimeout()
198-
state, msg, err = mode.Query(address, queryDecoded, warning, critical, alias, search, replace, emptyQueryMessage, emptyQueryStatus, &collection)
197+
Action: func(ctx context.Context, cmd *cli.Command) error {
198+
var ctxQuery context.Context
199+
var ctxQueryCancel context.CancelFunc
200+
if timeout == 0 {
201+
ctxQuery = context.WithoutCancel(ctx)
202+
} else {
203+
ctxQuery, ctxQueryCancel = context.WithTimeout(ctx, time.Duration(timeout)*time.Second)
204+
defer ctxQueryCancel()
205+
}
206+
207+
state, msg, err = mode.Query(ctxQuery, address, queryDecoded, warning, critical, alias, search, replace, emptyQueryMessage, emptyQueryStatus, &collection)
199208
return err
200209
},
201210
Flags: []cli.Flag{
@@ -360,9 +369,17 @@ func Check(args []string) (check_x.State, string, *check_x.PerformanceDataCollec
360369
HideHelp: false,
361370
Usage: "Returns the health of the targets",
362371
Description: `The warning and critical thresholds are appied on the health_rate. The health_rate is calculted: sum(healthy) / sum(targets).`,
363-
Action: func(c context.Context, cmd *cli.Command) error {
364-
startTimeout()
365-
state, msg, err = mode.TargetsHealth(address, label, warning, critical, &collection)
372+
Action: func(ctx context.Context, cmd *cli.Command) error {
373+
var ctxTargetsHealth context.Context
374+
var ctxTargetsHealthCancel context.CancelFunc
375+
if timeout == 0 {
376+
ctxTargetsHealth = context.WithoutCancel(ctx)
377+
} else {
378+
ctxTargetsHealth, ctxTargetsHealthCancel = context.WithTimeout(ctx, time.Duration(timeout)*time.Second)
379+
defer ctxTargetsHealthCancel()
380+
}
381+
382+
state, msg, err = mode.TargetsHealth(ctxTargetsHealth, address, label, warning, critical, &collection)
366383
return err
367384
},
368385
Flags: []cli.Flag{

0 commit comments

Comments
 (0)