Skip to content

Commit

Permalink
Add Uptime Checks and Alerts Support (#593)
Browse files Browse the repository at this point in the history
* Add uptime checks and alerts support

* typo

* Alert -> UptimeAlert, Fix "GetState"

* GetUptimeCheckState -> GetState, Regions -> map[string]UptimeRegion
  • Loading branch information
danaelhe authored Jan 17, 2023
1 parent c871e00 commit 0d12938
Show file tree
Hide file tree
Showing 3 changed files with 940 additions and 0 deletions.
2 changes: 2 additions & 0 deletions godo.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ type Client struct {
StorageActions StorageActionsService
Tags TagsService
Tokens TokensService
UptimeChecks UptimeChecksService
VPCs VPCsService

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

c.headers = make(map[string]string)
Expand Down
342 changes: 342 additions & 0 deletions uptime.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
package godo

import (
"context"
"fmt"
"net/http"
"path"
)

const uptimeChecksBasePath = "/v2/uptime/checks"

// UptimeChecksService is an interface for creating and managing Uptime checks with the DigitalOcean API.
// See: https://docs.digitalocean.com/reference/api/api-reference/#tag/Uptime
type UptimeChecksService interface {
List(context.Context, *ListOptions) ([]UptimeCheck, *Response, error)
Get(context.Context, string) (*UptimeCheck, *Response, error)
GetState(context.Context, string) (*UptimeCheckState, *Response, error)
Create(context.Context, *CreateUptimeCheckRequest) (*UptimeCheck, *Response, error)
Update(context.Context, string, *UpdateUptimeCheckRequest) (*UptimeCheck, *Response, error)
Delete(context.Context, string) (*Response, error)
GetAlert(context.Context, string, string) (*UptimeAlert, *Response, error)
ListAlerts(context.Context, string, *ListOptions) ([]UptimeAlert, *Response, error)
CreateAlert(context.Context, string, *CreateUptimeAlertRequest) (*UptimeAlert, *Response, error)
UpdateAlert(context.Context, string, string, *UpdateUptimeAlertRequest) (*UptimeAlert, *Response, error)
DeleteAlert(context.Context, string, string) (*Response, error)
}

// UptimeChecksServiceOp handles communication with Uptime Check methods of the DigitalOcean API.
type UptimeChecksServiceOp struct {
client *Client
}

// UptimeCheck represents a DigitalOcean UptimeCheck configuration.
type UptimeCheck struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Target string `json:"target"`
Regions []string `json:"regions"`
Enabled bool `json:"enabled"`
}

// UptimeAlert represents a DigitalOcean Uptime Alert configuration.
type UptimeAlert struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Threshold int `json:"threshold"`
Comparison string `json:"comparison"`
Notifications *Notifications `json:"notifications"`
Period string `json:"period"`
}

// Notifications represents a DigitalOcean Notifications configuration.
type Notifications struct {
Email []string `json:"email"`
Slack []SlackDetails `json:"slack"`
}

// UptimeCheckState represents a DigitalOcean Uptime Check's state configuration.
type UptimeCheckState struct {
Regions map[string]UptimeRegion `json:"regions"`
PreviousOutage UptimePreviousOutage `json:"previous_outage"`
}

type UptimeRegion struct {
Status string `json:"status"`
StatusChangedAt string `json:"status_changed_at"`
ThirtyDayUptimePercentage float32 `json:"thirty_day_uptime_percentage"`
}

// UptimePreviousOutage represents a DigitalOcean Uptime Check's previous outage configuration.
type UptimePreviousOutage struct {
Region string `json:"region"`
StartedAt string `json:"started_at"`
EndedAt string `json:"ended_at"`
DurationSeconds int `json:"duration_seconds"`
}

// CreateUptimeCheckRequest represents the request to create a new uptime check.
type CreateUptimeCheckRequest struct {
Name string `json:"name"`
Type string `json:"type"`
Target string `json:"target"`
Regions []string `json:"regions"`
Enabled bool `json:"enabled"`
}

// UpdateUptimeCheckRequest represents the request to update uptime check information.
type UpdateUptimeCheckRequest struct {
Name string `json:"name"`
Type string `json:"type"`
Target string `json:"target"`
Regions []string `json:"regions"`
Enabled bool `json:"enabled"`
}

// CreateUptimeUptimeAlertRequest represents the request to create a new Uptime Alert.
type CreateUptimeAlertRequest struct {
Name string `json:"name"`
Type string `json:"type"`
Threshold int `json:"threshold"`
Comparison string `json:"comparison"`
Notifications *Notifications `json:"notifications"`
Period string `json:"period"`
}

// UpdateUptimeAlertRequest represents the request to create a new alert.
type UpdateUptimeAlertRequest struct {
Name string `json:"name"`
Type string `json:"type"`
Threshold int `json:"threshold"`
Comparison string `json:"comparison"`
Notifications *Notifications `json:"notifications"`
Period string `json:"period"`
}

type uptimeChecksRoot struct {
UptimeChecks []UptimeCheck `json:"checks"`
Links *Links `json:"links"`
Meta *Meta `json:"meta"`
}

type uptimeCheckStateRoot struct {
UptimeCheckState UptimeCheckState `json:"state"`
}

type uptimeAlertsRoot struct {
UptimeAlerts []UptimeAlert `json:"alerts"`
Links *Links `json:"links"`
Meta *Meta `json:"meta"`
}

type uptimeCheckRoot struct {
UptimeCheck *UptimeCheck `json:"check"`
}

type uptimeAlertRoot struct {
UptimeAlert *UptimeAlert `json:"alert"`
}

var _ UptimeChecksService = &UptimeChecksServiceOp{}

// List Checks.
func (p *UptimeChecksServiceOp) List(ctx context.Context, opts *ListOptions) ([]UptimeCheck, *Response, error) {
path, err := addOptions(uptimeChecksBasePath, opts)
if err != nil {
return nil, nil, err
}

req, err := p.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}

root := new(uptimeChecksRoot)
resp, err := p.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
if l := root.Links; l != nil {
resp.Links = l
}
if m := root.Meta; m != nil {
resp.Meta = m
}

return root.UptimeChecks, resp, err
}

// GetState of uptime check.
func (p *UptimeChecksServiceOp) GetState(ctx context.Context, uptimeCheckID string) (*UptimeCheckState, *Response, error) {
path := path.Join(uptimeChecksBasePath, uptimeCheckID, "/state")

req, err := p.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}

root := new(uptimeCheckStateRoot)
resp, err := p.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}

return &root.UptimeCheckState, resp, err
}

// Get retrieves a single uptime check by its ID.
func (p *UptimeChecksServiceOp) Get(ctx context.Context, uptimeCheckID string) (*UptimeCheck, *Response, error) {
path := path.Join(uptimeChecksBasePath, uptimeCheckID)

req, err := p.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}

root := new(uptimeCheckRoot)
resp, err := p.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}

return root.UptimeCheck, resp, err
}

// Create a new uptime check.
func (p *UptimeChecksServiceOp) Create(ctx context.Context, cr *CreateUptimeCheckRequest) (*UptimeCheck, *Response, error) {
req, err := p.client.NewRequest(ctx, http.MethodPost, uptimeChecksBasePath, cr)
if err != nil {
return nil, nil, err
}

root := new(uptimeCheckRoot)
resp, err := p.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}

return root.UptimeCheck, resp, err
}

// Update an uptime check.
func (p *UptimeChecksServiceOp) Update(ctx context.Context, uptimeCheckID string, ur *UpdateUptimeCheckRequest) (*UptimeCheck, *Response, error) {
path := path.Join(uptimeChecksBasePath, uptimeCheckID)
req, err := p.client.NewRequest(ctx, http.MethodPut, path, ur)
if err != nil {
return nil, nil, err
}

root := new(uptimeCheckRoot)
resp, err := p.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}

return root.UptimeCheck, resp, err
}

// Delete an existing uptime check.
func (p *UptimeChecksServiceOp) Delete(ctx context.Context, uptimeCheckID string) (*Response, error) {
path := path.Join(uptimeChecksBasePath, uptimeCheckID)
req, err := p.client.NewRequest(ctx, http.MethodDelete, path, nil)
if err != nil {
return nil, err
}

return p.client.Do(ctx, req, nil)
}

// alerts

// ListAlerts lists alerts for a check.
func (p *UptimeChecksServiceOp) ListAlerts(ctx context.Context, uptimeCheckID string, opts *ListOptions) ([]UptimeAlert, *Response, error) {
fullPath := path.Join(uptimeChecksBasePath, uptimeCheckID, "/alerts")
path, err := addOptions(fullPath, opts)
if err != nil {
return nil, nil, err
}

req, err := p.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}

root := new(uptimeAlertsRoot)
resp, err := p.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
if l := root.Links; l != nil {
resp.Links = l
}
if m := root.Meta; m != nil {
resp.Meta = m
}

return root.UptimeAlerts, resp, err
}

// CreateAlert creates a new check alert.
func (p *UptimeChecksServiceOp) CreateAlert(ctx context.Context, uptimeCheckID string, cr *CreateUptimeAlertRequest) (*UptimeAlert, *Response, error) {
fullPath := path.Join(uptimeChecksBasePath, uptimeCheckID, "/alerts")
req, err := p.client.NewRequest(ctx, http.MethodPost, fullPath, cr)
if err != nil {
return nil, nil, err
}

root := new(uptimeAlertRoot)
resp, err := p.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}

return root.UptimeAlert, resp, err
}

// GetAlert retrieves a single uptime check alert by its ID.
func (p *UptimeChecksServiceOp) GetAlert(ctx context.Context, uptimeCheckID string, alertID string) (*UptimeAlert, *Response, error) {
path := fmt.Sprintf("v2/uptime/checks/%s/alerts/%s", uptimeCheckID, alertID)

req, err := p.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}

root := new(uptimeAlertRoot)
resp, err := p.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}

return root.UptimeAlert, resp, err
}

// UpdateAlert updates an check's alert.
func (p *UptimeChecksServiceOp) UpdateAlert(ctx context.Context, uptimeCheckID string, alertID string, ur *UpdateUptimeAlertRequest) (*UptimeAlert, *Response, error) {
path := path.Join(uptimeChecksBasePath, uptimeCheckID, "/alerts/", alertID)
req, err := p.client.NewRequest(ctx, http.MethodPut, path, ur)
if err != nil {
return nil, nil, err
}

root := new(uptimeAlertRoot)
resp, err := p.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}

return root.UptimeAlert, resp, err
}

// DeleteAlert deletes an existing check's alert.
func (p *UptimeChecksServiceOp) DeleteAlert(ctx context.Context, uptimeCheckID string, alertID string) (*Response, error) {
path := path.Join(uptimeChecksBasePath, uptimeCheckID, "/alerts/", alertID)
req, err := p.client.NewRequest(ctx, http.MethodDelete, path, nil)
if err != nil {
return nil, err
}

return p.client.Do(ctx, req, nil)
}
Loading

0 comments on commit 0d12938

Please sign in to comment.