-
-
Notifications
You must be signed in to change notification settings - Fork 70
/
alerts.go
135 lines (106 loc) · 3.52 KB
/
alerts.go
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
package grabana
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"github.com/K-Phoen/grabana/alert"
"github.com/K-Phoen/grabana/alertmanager"
"github.com/K-Phoen/sdk"
)
// ErrAlertNotFound is returned when the requested alert can not be found.
var ErrAlertNotFound = errors.New("alert not found")
type alertRef struct {
Namespace string
RuleGroup string
}
// ConfigureAlertManager updates the alert manager configuration.
func (client *Client) ConfigureAlertManager(ctx context.Context, manager *alertmanager.Manager) error {
buf, err := manager.MarshalIndentJSON()
if err != nil {
return err
}
resp, err := client.sendJSON(ctx, http.MethodPost, "/api/alertmanager/grafana/config/api/v1/alerts", buf)
if err != nil {
return err
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusAccepted {
return client.httpError(resp)
}
return nil
}
// AddAlert creates an alert group within a given namespace.
func (client *Client) AddAlert(ctx context.Context, namespace string, alertDefinition alert.Alert, datasourcesMap map[string]string) error {
// Find out which datasource the alert depends on, and inject its UID into the sdk definition
datasource := defaultDatasourceKey
if alertDefinition.Datasource != "" {
datasource = alertDefinition.Datasource
}
datasourceUID := datasourcesMap[datasource]
if datasourceUID == "" {
return fmt.Errorf("could not infer datasource UID from its name: %s", datasource)
}
alertDefinition.HookDatasourceUID(datasourceUID)
// Before we can add this alert, we need to delete any other alert that might exist for this dashboard and panel
if err := client.DeleteAlertGroup(ctx, namespace, alertDefinition.Builder.Name); err != nil && !errors.Is(err, ErrAlertNotFound) {
return fmt.Errorf("could not delete existing alerts: %w", err)
}
buf, err := json.Marshal(alertDefinition.Builder)
if err != nil {
return err
}
// Save the alert!
resp, err := client.sendJSON(ctx, http.MethodPost, "/api/ruler/grafana/api/v1/rules/"+url.PathEscape(namespace), buf)
if err != nil {
return err
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusAccepted {
return client.httpError(resp)
}
return nil
}
// DeleteAlertGroup deletes an alert group.
func (client *Client) DeleteAlertGroup(ctx context.Context, namespace string, groupName string) error {
deleteURL := fmt.Sprintf("/api/ruler/grafana/api/v1/rules/%s/%s", url.PathEscape(namespace), url.PathEscape(groupName))
resp, err := client.delete(ctx, deleteURL)
if err != nil {
return err
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode == http.StatusNotFound {
return ErrAlertNotFound
}
if resp.StatusCode != http.StatusAccepted {
return client.httpError(resp)
}
return nil
}
// listAlertsForDashboard fetches a list of alerts linked to the given dashboard.
func (client *Client) listAlertsForDashboard(ctx context.Context, dashboardUID string) ([]alertRef, error) {
resp, err := client.get(ctx, "/api/ruler/grafana/api/v1/rules?dashboard_uid="+url.QueryEscape(dashboardUID))
if err != nil {
return nil, err
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return nil, client.httpError(resp)
}
var alerts map[string][]sdk.Alert
if err := decodeJSON(resp.Body, &alerts); err != nil {
return nil, err
}
var refs []alertRef
for namespace := range alerts {
for _, a := range alerts[namespace] {
refs = append(refs, alertRef{
Namespace: namespace,
RuleGroup: a.Name,
})
}
}
return refs, nil
}