Skip to content

Commit 0d12938

Browse files
authored
Add Uptime Checks and Alerts Support (#593)
* Add uptime checks and alerts support * typo * Alert -> UptimeAlert, Fix "GetState" * GetUptimeCheckState -> GetState, Regions -> map[string]UptimeRegion
1 parent c871e00 commit 0d12938

File tree

3 files changed

+940
-0
lines changed

3 files changed

+940
-0
lines changed

godo.go

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ type Client struct {
8282
StorageActions StorageActionsService
8383
Tags TagsService
8484
Tokens TokensService
85+
UptimeChecks UptimeChecksService
8586
VPCs VPCsService
8687

8788
// Optional function called after every successful request made to the DO APIs
@@ -252,6 +253,7 @@ func NewClient(httpClient *http.Client) *Client {
252253
c.StorageActions = &StorageActionsServiceOp{client: c}
253254
c.Tags = &TagsServiceOp{client: c}
254255
c.Tokens = &TokensServiceOp{client: c}
256+
c.UptimeChecks = &UptimeChecksServiceOp{client: c}
255257
c.VPCs = &VPCsServiceOp{client: c}
256258

257259
c.headers = make(map[string]string)

uptime.go

+342
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
package godo
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
"path"
8+
)
9+
10+
const uptimeChecksBasePath = "/v2/uptime/checks"
11+
12+
// UptimeChecksService is an interface for creating and managing Uptime checks with the DigitalOcean API.
13+
// See: https://docs.digitalocean.com/reference/api/api-reference/#tag/Uptime
14+
type UptimeChecksService interface {
15+
List(context.Context, *ListOptions) ([]UptimeCheck, *Response, error)
16+
Get(context.Context, string) (*UptimeCheck, *Response, error)
17+
GetState(context.Context, string) (*UptimeCheckState, *Response, error)
18+
Create(context.Context, *CreateUptimeCheckRequest) (*UptimeCheck, *Response, error)
19+
Update(context.Context, string, *UpdateUptimeCheckRequest) (*UptimeCheck, *Response, error)
20+
Delete(context.Context, string) (*Response, error)
21+
GetAlert(context.Context, string, string) (*UptimeAlert, *Response, error)
22+
ListAlerts(context.Context, string, *ListOptions) ([]UptimeAlert, *Response, error)
23+
CreateAlert(context.Context, string, *CreateUptimeAlertRequest) (*UptimeAlert, *Response, error)
24+
UpdateAlert(context.Context, string, string, *UpdateUptimeAlertRequest) (*UptimeAlert, *Response, error)
25+
DeleteAlert(context.Context, string, string) (*Response, error)
26+
}
27+
28+
// UptimeChecksServiceOp handles communication with Uptime Check methods of the DigitalOcean API.
29+
type UptimeChecksServiceOp struct {
30+
client *Client
31+
}
32+
33+
// UptimeCheck represents a DigitalOcean UptimeCheck configuration.
34+
type UptimeCheck struct {
35+
ID string `json:"id"`
36+
Name string `json:"name"`
37+
Type string `json:"type"`
38+
Target string `json:"target"`
39+
Regions []string `json:"regions"`
40+
Enabled bool `json:"enabled"`
41+
}
42+
43+
// UptimeAlert represents a DigitalOcean Uptime Alert configuration.
44+
type UptimeAlert struct {
45+
ID string `json:"id"`
46+
Name string `json:"name"`
47+
Type string `json:"type"`
48+
Threshold int `json:"threshold"`
49+
Comparison string `json:"comparison"`
50+
Notifications *Notifications `json:"notifications"`
51+
Period string `json:"period"`
52+
}
53+
54+
// Notifications represents a DigitalOcean Notifications configuration.
55+
type Notifications struct {
56+
Email []string `json:"email"`
57+
Slack []SlackDetails `json:"slack"`
58+
}
59+
60+
// UptimeCheckState represents a DigitalOcean Uptime Check's state configuration.
61+
type UptimeCheckState struct {
62+
Regions map[string]UptimeRegion `json:"regions"`
63+
PreviousOutage UptimePreviousOutage `json:"previous_outage"`
64+
}
65+
66+
type UptimeRegion struct {
67+
Status string `json:"status"`
68+
StatusChangedAt string `json:"status_changed_at"`
69+
ThirtyDayUptimePercentage float32 `json:"thirty_day_uptime_percentage"`
70+
}
71+
72+
// UptimePreviousOutage represents a DigitalOcean Uptime Check's previous outage configuration.
73+
type UptimePreviousOutage struct {
74+
Region string `json:"region"`
75+
StartedAt string `json:"started_at"`
76+
EndedAt string `json:"ended_at"`
77+
DurationSeconds int `json:"duration_seconds"`
78+
}
79+
80+
// CreateUptimeCheckRequest represents the request to create a new uptime check.
81+
type CreateUptimeCheckRequest struct {
82+
Name string `json:"name"`
83+
Type string `json:"type"`
84+
Target string `json:"target"`
85+
Regions []string `json:"regions"`
86+
Enabled bool `json:"enabled"`
87+
}
88+
89+
// UpdateUptimeCheckRequest represents the request to update uptime check information.
90+
type UpdateUptimeCheckRequest struct {
91+
Name string `json:"name"`
92+
Type string `json:"type"`
93+
Target string `json:"target"`
94+
Regions []string `json:"regions"`
95+
Enabled bool `json:"enabled"`
96+
}
97+
98+
// CreateUptimeUptimeAlertRequest represents the request to create a new Uptime Alert.
99+
type CreateUptimeAlertRequest struct {
100+
Name string `json:"name"`
101+
Type string `json:"type"`
102+
Threshold int `json:"threshold"`
103+
Comparison string `json:"comparison"`
104+
Notifications *Notifications `json:"notifications"`
105+
Period string `json:"period"`
106+
}
107+
108+
// UpdateUptimeAlertRequest represents the request to create a new alert.
109+
type UpdateUptimeAlertRequest struct {
110+
Name string `json:"name"`
111+
Type string `json:"type"`
112+
Threshold int `json:"threshold"`
113+
Comparison string `json:"comparison"`
114+
Notifications *Notifications `json:"notifications"`
115+
Period string `json:"period"`
116+
}
117+
118+
type uptimeChecksRoot struct {
119+
UptimeChecks []UptimeCheck `json:"checks"`
120+
Links *Links `json:"links"`
121+
Meta *Meta `json:"meta"`
122+
}
123+
124+
type uptimeCheckStateRoot struct {
125+
UptimeCheckState UptimeCheckState `json:"state"`
126+
}
127+
128+
type uptimeAlertsRoot struct {
129+
UptimeAlerts []UptimeAlert `json:"alerts"`
130+
Links *Links `json:"links"`
131+
Meta *Meta `json:"meta"`
132+
}
133+
134+
type uptimeCheckRoot struct {
135+
UptimeCheck *UptimeCheck `json:"check"`
136+
}
137+
138+
type uptimeAlertRoot struct {
139+
UptimeAlert *UptimeAlert `json:"alert"`
140+
}
141+
142+
var _ UptimeChecksService = &UptimeChecksServiceOp{}
143+
144+
// List Checks.
145+
func (p *UptimeChecksServiceOp) List(ctx context.Context, opts *ListOptions) ([]UptimeCheck, *Response, error) {
146+
path, err := addOptions(uptimeChecksBasePath, opts)
147+
if err != nil {
148+
return nil, nil, err
149+
}
150+
151+
req, err := p.client.NewRequest(ctx, http.MethodGet, path, nil)
152+
if err != nil {
153+
return nil, nil, err
154+
}
155+
156+
root := new(uptimeChecksRoot)
157+
resp, err := p.client.Do(ctx, req, root)
158+
if err != nil {
159+
return nil, resp, err
160+
}
161+
if l := root.Links; l != nil {
162+
resp.Links = l
163+
}
164+
if m := root.Meta; m != nil {
165+
resp.Meta = m
166+
}
167+
168+
return root.UptimeChecks, resp, err
169+
}
170+
171+
// GetState of uptime check.
172+
func (p *UptimeChecksServiceOp) GetState(ctx context.Context, uptimeCheckID string) (*UptimeCheckState, *Response, error) {
173+
path := path.Join(uptimeChecksBasePath, uptimeCheckID, "/state")
174+
175+
req, err := p.client.NewRequest(ctx, http.MethodGet, path, nil)
176+
if err != nil {
177+
return nil, nil, err
178+
}
179+
180+
root := new(uptimeCheckStateRoot)
181+
resp, err := p.client.Do(ctx, req, root)
182+
if err != nil {
183+
return nil, resp, err
184+
}
185+
186+
return &root.UptimeCheckState, resp, err
187+
}
188+
189+
// Get retrieves a single uptime check by its ID.
190+
func (p *UptimeChecksServiceOp) Get(ctx context.Context, uptimeCheckID string) (*UptimeCheck, *Response, error) {
191+
path := path.Join(uptimeChecksBasePath, uptimeCheckID)
192+
193+
req, err := p.client.NewRequest(ctx, http.MethodGet, path, nil)
194+
if err != nil {
195+
return nil, nil, err
196+
}
197+
198+
root := new(uptimeCheckRoot)
199+
resp, err := p.client.Do(ctx, req, root)
200+
if err != nil {
201+
return nil, resp, err
202+
}
203+
204+
return root.UptimeCheck, resp, err
205+
}
206+
207+
// Create a new uptime check.
208+
func (p *UptimeChecksServiceOp) Create(ctx context.Context, cr *CreateUptimeCheckRequest) (*UptimeCheck, *Response, error) {
209+
req, err := p.client.NewRequest(ctx, http.MethodPost, uptimeChecksBasePath, cr)
210+
if err != nil {
211+
return nil, nil, err
212+
}
213+
214+
root := new(uptimeCheckRoot)
215+
resp, err := p.client.Do(ctx, req, root)
216+
if err != nil {
217+
return nil, resp, err
218+
}
219+
220+
return root.UptimeCheck, resp, err
221+
}
222+
223+
// Update an uptime check.
224+
func (p *UptimeChecksServiceOp) Update(ctx context.Context, uptimeCheckID string, ur *UpdateUptimeCheckRequest) (*UptimeCheck, *Response, error) {
225+
path := path.Join(uptimeChecksBasePath, uptimeCheckID)
226+
req, err := p.client.NewRequest(ctx, http.MethodPut, path, ur)
227+
if err != nil {
228+
return nil, nil, err
229+
}
230+
231+
root := new(uptimeCheckRoot)
232+
resp, err := p.client.Do(ctx, req, root)
233+
if err != nil {
234+
return nil, resp, err
235+
}
236+
237+
return root.UptimeCheck, resp, err
238+
}
239+
240+
// Delete an existing uptime check.
241+
func (p *UptimeChecksServiceOp) Delete(ctx context.Context, uptimeCheckID string) (*Response, error) {
242+
path := path.Join(uptimeChecksBasePath, uptimeCheckID)
243+
req, err := p.client.NewRequest(ctx, http.MethodDelete, path, nil)
244+
if err != nil {
245+
return nil, err
246+
}
247+
248+
return p.client.Do(ctx, req, nil)
249+
}
250+
251+
// alerts
252+
253+
// ListAlerts lists alerts for a check.
254+
func (p *UptimeChecksServiceOp) ListAlerts(ctx context.Context, uptimeCheckID string, opts *ListOptions) ([]UptimeAlert, *Response, error) {
255+
fullPath := path.Join(uptimeChecksBasePath, uptimeCheckID, "/alerts")
256+
path, err := addOptions(fullPath, opts)
257+
if err != nil {
258+
return nil, nil, err
259+
}
260+
261+
req, err := p.client.NewRequest(ctx, http.MethodGet, path, nil)
262+
if err != nil {
263+
return nil, nil, err
264+
}
265+
266+
root := new(uptimeAlertsRoot)
267+
resp, err := p.client.Do(ctx, req, root)
268+
if err != nil {
269+
return nil, resp, err
270+
}
271+
if l := root.Links; l != nil {
272+
resp.Links = l
273+
}
274+
if m := root.Meta; m != nil {
275+
resp.Meta = m
276+
}
277+
278+
return root.UptimeAlerts, resp, err
279+
}
280+
281+
// CreateAlert creates a new check alert.
282+
func (p *UptimeChecksServiceOp) CreateAlert(ctx context.Context, uptimeCheckID string, cr *CreateUptimeAlertRequest) (*UptimeAlert, *Response, error) {
283+
fullPath := path.Join(uptimeChecksBasePath, uptimeCheckID, "/alerts")
284+
req, err := p.client.NewRequest(ctx, http.MethodPost, fullPath, cr)
285+
if err != nil {
286+
return nil, nil, err
287+
}
288+
289+
root := new(uptimeAlertRoot)
290+
resp, err := p.client.Do(ctx, req, root)
291+
if err != nil {
292+
return nil, resp, err
293+
}
294+
295+
return root.UptimeAlert, resp, err
296+
}
297+
298+
// GetAlert retrieves a single uptime check alert by its ID.
299+
func (p *UptimeChecksServiceOp) GetAlert(ctx context.Context, uptimeCheckID string, alertID string) (*UptimeAlert, *Response, error) {
300+
path := fmt.Sprintf("v2/uptime/checks/%s/alerts/%s", uptimeCheckID, alertID)
301+
302+
req, err := p.client.NewRequest(ctx, http.MethodGet, path, nil)
303+
if err != nil {
304+
return nil, nil, err
305+
}
306+
307+
root := new(uptimeAlertRoot)
308+
resp, err := p.client.Do(ctx, req, root)
309+
if err != nil {
310+
return nil, resp, err
311+
}
312+
313+
return root.UptimeAlert, resp, err
314+
}
315+
316+
// UpdateAlert updates an check's alert.
317+
func (p *UptimeChecksServiceOp) UpdateAlert(ctx context.Context, uptimeCheckID string, alertID string, ur *UpdateUptimeAlertRequest) (*UptimeAlert, *Response, error) {
318+
path := path.Join(uptimeChecksBasePath, uptimeCheckID, "/alerts/", alertID)
319+
req, err := p.client.NewRequest(ctx, http.MethodPut, path, ur)
320+
if err != nil {
321+
return nil, nil, err
322+
}
323+
324+
root := new(uptimeAlertRoot)
325+
resp, err := p.client.Do(ctx, req, root)
326+
if err != nil {
327+
return nil, resp, err
328+
}
329+
330+
return root.UptimeAlert, resp, err
331+
}
332+
333+
// DeleteAlert deletes an existing check's alert.
334+
func (p *UptimeChecksServiceOp) DeleteAlert(ctx context.Context, uptimeCheckID string, alertID string) (*Response, error) {
335+
path := path.Join(uptimeChecksBasePath, uptimeCheckID, "/alerts/", alertID)
336+
req, err := p.client.NewRequest(ctx, http.MethodDelete, path, nil)
337+
if err != nil {
338+
return nil, err
339+
}
340+
341+
return p.client.Do(ctx, req, nil)
342+
}

0 commit comments

Comments
 (0)