-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathclient.go
More file actions
153 lines (119 loc) · 3.77 KB
/
client.go
File metadata and controls
153 lines (119 loc) · 3.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package client
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"github.com/NETWAYS/check_prometheus/internal/alert"
"github.com/NETWAYS/go-check"
"github.com/prometheus/client_golang/api"
v1 "github.com/prometheus/client_golang/api/prometheus/v1"
)
type Client struct {
URL string
Client api.Client
API v1.API
RoundTripper http.RoundTripper
}
func NewClient(url string, rt http.RoundTripper) *Client {
return &Client{
URL: url,
RoundTripper: rt,
}
}
func (c *Client) Connect() error {
cfg, err := api.NewClient(api.Config{
Address: c.URL,
RoundTripper: c.RoundTripper,
})
if err != nil {
return fmt.Errorf("error creating client: %w", err)
}
c.Client = cfg
c.API = v1.NewAPI(c.Client)
return nil
}
func (c *Client) GetStatus(ctx context.Context, endpoint string) (returncode int, statuscode int, body string, err error) {
// Parses the response from the Prometheus /healthy and /ready endpoint
// Return: Exit Status Code, HTTP Status Code, HTTP Body, Error
// Building the final URL with the endpoint parameter
u, _ := url.JoinPath(c.URL, "/-/", endpoint)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if err != nil {
e := fmt.Sprintf("could not create request: %s", err)
return check.Unknown, 0, e, err
}
// Making the request with the preconfigured Client
// So that we can reuse the preconfigured Roundtripper
resp, b, err := c.Client.Do(ctx, req)
if err != nil {
e := fmt.Sprintf("could not get status: %s", err)
return check.Unknown, 0, e, err
}
defer resp.Body.Close()
// Getting the response body
respBody := strings.TrimSpace(string(b))
// What we expect from the Prometheus Server
statusOk := "is Healthy."
if endpoint == "ready" {
statusOk = "is Ready."
}
if resp.StatusCode == http.StatusOK && strings.Contains(respBody, statusOk) {
return check.OK, resp.StatusCode, respBody, err
}
if resp.StatusCode != http.StatusOK {
return check.Critical, resp.StatusCode, respBody, err
}
return check.Unknown, resp.StatusCode, respBody, err
}
func (c *Client) GetAlertmanagerAlerts(ctx context.Context) ([]alert.AlertmanagerAlert, error) {
u, _ := url.JoinPath(c.URL, "/api/v2/alerts")
req, errReq := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if errReq != nil {
return []alert.AlertmanagerAlert{}, fmt.Errorf("could not create request: %w", errReq)
}
// Making the request with the preconfigured Client
// So that we can reuse the preconfigured Roundtripper
resp, b, errDo := c.Client.Do(ctx, req)
if errDo != nil {
return []alert.AlertmanagerAlert{}, fmt.Errorf("could not get status: %w", errDo)
}
defer resp.Body.Close()
var alerts []alert.AlertmanagerAlert
errJSON := json.Unmarshal(b, &alerts)
if errJSON != nil {
return []alert.AlertmanagerAlert{}, fmt.Errorf("could not parse alerts: %w", errJSON)
}
return alerts, nil
}
type headersRoundTripper struct {
headers map[string]string
rt http.RoundTripper
}
// NewHeadersRoundTripper adds the given headers to a request
func NewHeadersRoundTripper(headers map[string]string, rt http.RoundTripper) http.RoundTripper {
return &headersRoundTripper{headers, rt}
}
func (rt *headersRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
// RoundTrip should not modify the request, except for
// consuming and closing the Request's Body.
req = cloneRequest(req)
for key, value := range rt.headers {
req.Header.Add(key, value)
}
return rt.rt.RoundTrip(req)
}
// cloneRequest returns a clone of the provided *http.Request
func cloneRequest(r *http.Request) *http.Request {
// Shallow copy of the struct.
r2 := new(http.Request)
*r2 = *r
// Deep copy of the Header.
r2.Header = make(http.Header)
for k, s := range r.Header {
r2.Header[k] = s
}
return r2
}