dnscontrol/pkg/cloudflare-go/notifications.go
Tom Limoncelli 7fd6a74e0c
CLOUDFLAREAPI: CF_REDIRECT/CF_TEMP_REDIRECT should dtrt using Single Redirects (#3002)
Co-authored-by: Josh Zhang <jzhang1@stackoverflow.com>
2024-06-18 17:38:50 -04:00

447 lines
15 KiB
Go

package cloudflare
import (
"context"
"fmt"
"net/http"
"time"
"github.com/goccy/go-json"
)
// NotificationMechanismData holds a single public facing mechanism data
// integation.
type NotificationMechanismData struct {
Name string `json:"name"`
ID string `json:"id"`
}
// NotificationMechanismIntegrations is a list of all the integrations of a
// certain mechanism type e.g. all email integrations.
type NotificationMechanismIntegrations []NotificationMechanismData
// NotificationPolicy represents the notification policy created along with
// the destinations.
type NotificationPolicy struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Enabled bool `json:"enabled"`
AlertType string `json:"alert_type"`
Mechanisms map[string]NotificationMechanismIntegrations `json:"mechanisms"`
Created time.Time `json:"created"`
Modified time.Time `json:"modified"`
Conditions map[string]interface{} `json:"conditions"`
Filters map[string][]string `json:"filters"`
}
// NotificationPoliciesResponse holds the response for listing all
// notification policies for an account.
type NotificationPoliciesResponse struct {
Response
ResultInfo
Result []NotificationPolicy
}
// NotificationPolicyResponse holds the response type when a single policy
// is retrieved.
type NotificationPolicyResponse struct {
Response
Result NotificationPolicy
}
// NotificationWebhookIntegration describes the webhook information along
// with its status.
type NotificationWebhookIntegration struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
URL string `json:"url"`
CreatedAt time.Time `json:"created_at"`
LastSuccess *time.Time `json:"last_success"`
LastFailure *time.Time `json:"last_failure"`
}
// NotificationWebhookResponse describes a single webhook retrieved.
type NotificationWebhookResponse struct {
Response
ResultInfo
Result NotificationWebhookIntegration
}
// NotificationWebhooksResponse describes a list of webhooks retrieved.
type NotificationWebhooksResponse struct {
Response
ResultInfo
Result []NotificationWebhookIntegration
}
// NotificationUpsertWebhooks describes a valid webhook request.
type NotificationUpsertWebhooks struct {
Name string `json:"name"`
URL string `json:"url"`
Secret string `json:"secret"`
}
// NotificationPagerDutyResource describes a PagerDuty integration.
type NotificationPagerDutyResource struct {
ID string `json:"id"`
Name string `json:"name"`
}
// NotificationPagerDutyResponse describes the PagerDuty integration
// retrieved.
type NotificationPagerDutyResponse struct {
Response
ResultInfo
Result NotificationPagerDutyResource
}
// NotificationResource describes the id of an inserted/updated/deleted
// resource.
type NotificationResource struct {
ID string
}
// SaveResponse is returned when a resource is inserted/updated/deleted.
type SaveResponse struct {
Response
Result NotificationResource
}
// NotificationMechanismMetaData represents the state of the delivery
// mechanism.
type NotificationMechanismMetaData struct {
Eligible bool `json:"eligible"`
Ready bool `json:"ready"`
Type string `json:"type"`
}
// NotificationMechanisms are the different possible delivery mechanisms.
type NotificationMechanisms struct {
Email NotificationMechanismMetaData `json:"email"`
PagerDuty NotificationMechanismMetaData `json:"pagerduty"`
Webhooks NotificationMechanismMetaData `json:"webhooks,omitempty"`
}
// NotificationEligibilityResponse describes the eligible mechanisms that
// can be configured for a notification.
type NotificationEligibilityResponse struct {
Response
Result NotificationMechanisms
}
// NotificationsGroupedByProduct are grouped by products.
type NotificationsGroupedByProduct map[string][]NotificationAlertWithDescription
// NotificationAlertWithDescription represents the alert/notification
// available.
type NotificationAlertWithDescription struct {
DisplayName string `json:"display_name"`
Type string `json:"type"`
Description string `json:"description"`
}
// NotificationAvailableAlertsResponse describes the available
// alerts/notifications grouped by products.
type NotificationAvailableAlertsResponse struct {
Response
Result NotificationsGroupedByProduct
}
// NotificationHistory describes the history
// of notifications sent for an account.
type NotificationHistory struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
AlertBody string `json:"alert_body"`
AlertType string `json:"alert_type"`
Mechanism string `json:"mechanism"`
MechanismType string `json:"mechanism_type"`
Sent time.Time `json:"sent"`
}
// NotificationHistoryResponse describes the notification history
// response for an account for a specific time period.
type NotificationHistoryResponse struct {
Response
ResultInfo `json:"result_info"`
Result []NotificationHistory
}
// ListNotificationPolicies will return the notification policies
// created by a user for a specific account.
//
// API Reference: https://api.cloudflare.com/#notification-policies-properties
func (api *API) ListNotificationPolicies(ctx context.Context, accountID string) (NotificationPoliciesResponse, error) {
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/policies", accountID)
res, err := api.makeRequestContext(ctx, http.MethodGet, baseURL, nil)
if err != nil {
return NotificationPoliciesResponse{}, err
}
var r NotificationPoliciesResponse
err = json.Unmarshal(res, &r)
if err != nil {
return r, err
}
return r, nil
}
// GetNotificationPolicy returns a specific created by a user, given the account
// id and the policy id.
//
// API Reference: https://api.cloudflare.com/#notification-policies-properties
func (api *API) GetNotificationPolicy(ctx context.Context, accountID, policyID string) (NotificationPolicyResponse, error) {
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/policies/%s", accountID, policyID)
res, err := api.makeRequestContext(ctx, http.MethodGet, baseURL, nil)
if err != nil {
return NotificationPolicyResponse{}, err
}
var r NotificationPolicyResponse
err = json.Unmarshal(res, &r)
if err != nil {
return r, err
}
return r, nil
}
// CreateNotificationPolicy creates a notification policy for an account.
//
// API Reference: https://api.cloudflare.com/#notification-policies-create-notification-policy
func (api *API) CreateNotificationPolicy(ctx context.Context, accountID string, policy NotificationPolicy) (SaveResponse, error) {
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/policies", accountID)
res, err := api.makeRequestContext(ctx, http.MethodPost, baseURL, policy)
if err != nil {
return SaveResponse{}, err
}
return unmarshalNotificationSaveResponse(res)
}
// UpdateNotificationPolicy updates a notification policy, given the
// account id and the policy id and returns the policy id.
//
// API Reference: https://api.cloudflare.com/#notification-policies-update-notification-policy
func (api *API) UpdateNotificationPolicy(ctx context.Context, accountID string, policy *NotificationPolicy) (SaveResponse, error) {
if policy == nil {
return SaveResponse{}, fmt.Errorf("policy cannot be nil")
}
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/policies/%s", accountID, policy.ID)
res, err := api.makeRequestContext(ctx, http.MethodPut, baseURL, policy)
if err != nil {
return SaveResponse{}, err
}
return unmarshalNotificationSaveResponse(res)
}
// DeleteNotificationPolicy deletes a notification policy for an account.
//
// API Reference: https://api.cloudflare.com/#notification-policies-delete-notification-policy
func (api *API) DeleteNotificationPolicy(ctx context.Context, accountID, policyID string) (SaveResponse, error) {
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/policies/%s", accountID, policyID)
res, err := api.makeRequestContext(ctx, http.MethodDelete, baseURL, nil)
if err != nil {
return SaveResponse{}, err
}
return unmarshalNotificationSaveResponse(res)
}
// ListNotificationWebhooks will return the webhook destinations configured
// for an account.
//
// API Reference: https://api.cloudflare.com/#notification-webhooks-list-webhooks
func (api *API) ListNotificationWebhooks(ctx context.Context, accountID string) (NotificationWebhooksResponse, error) {
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/destinations/webhooks", accountID)
res, err := api.makeRequestContext(ctx, http.MethodGet, baseURL, nil)
if err != nil {
return NotificationWebhooksResponse{}, err
}
var r NotificationWebhooksResponse
err = json.Unmarshal(res, &r)
if err != nil {
return r, err
}
return r, nil
}
// CreateNotificationWebhooks will help connect a webhooks destination.
// A test message will be sent to the webhooks endpoint during creation.
// If added successfully, the webhooks can be setup as a destination mechanism
// while creating policies.
//
// Notifications will be posted to this URL.
//
// API Reference: https://api.cloudflare.com/#notification-webhooks-create-webhook
func (api *API) CreateNotificationWebhooks(ctx context.Context, accountID string, webhooks *NotificationUpsertWebhooks) (SaveResponse, error) {
if webhooks == nil {
return SaveResponse{}, fmt.Errorf("webhooks cannot be nil")
}
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/destinations/webhooks", accountID)
res, err := api.makeRequestContext(ctx, http.MethodPost, baseURL, webhooks)
if err != nil {
return SaveResponse{}, err
}
return unmarshalNotificationSaveResponse(res)
}
// GetNotificationWebhooks will return a specific webhook destination,
// given the account and webhooks ids.
//
// API Reference: https://api.cloudflare.com/#notification-webhooks-get-webhook
func (api *API) GetNotificationWebhooks(ctx context.Context, accountID, webhookID string) (NotificationWebhookResponse, error) {
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/destinations/webhooks/%s", accountID, webhookID)
res, err := api.makeRequestContext(ctx, http.MethodGet, baseURL, nil)
if err != nil {
return NotificationWebhookResponse{}, err
}
var r NotificationWebhookResponse
err = json.Unmarshal(res, &r)
if err != nil {
return r, err
}
return r, nil
}
// UpdateNotificationWebhooks will update a particular webhook's name,
// given the account and webhooks ids.
//
// The webhook url and secret cannot be updated.
//
// API Reference: https://api.cloudflare.com/#notification-webhooks-update-webhook
func (api *API) UpdateNotificationWebhooks(ctx context.Context, accountID, webhookID string, webhooks *NotificationUpsertWebhooks) (SaveResponse, error) {
if webhooks == nil {
return SaveResponse{}, fmt.Errorf("webhooks cannot be nil")
}
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/destinations/webhooks/%s", accountID, webhookID)
res, err := api.makeRequestContext(ctx, http.MethodPut, baseURL, webhooks)
if err != nil {
return SaveResponse{}, err
}
return unmarshalNotificationSaveResponse(res)
}
// DeleteNotificationWebhooks will delete a webhook, given the account and
// webhooks ids. Deleting the webhooks will remove it from any connected
// notification policies.
//
// API Reference: https://api.cloudflare.com/#notification-webhooks-delete-webhook
func (api *API) DeleteNotificationWebhooks(ctx context.Context, accountID, webhookID string) (SaveResponse, error) {
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/destinations/webhooks/%s", accountID, webhookID)
res, err := api.makeRequestContext(ctx, http.MethodDelete, baseURL, nil)
if err != nil {
return SaveResponse{}, err
}
return unmarshalNotificationSaveResponse(res)
}
// ListPagerDutyNotificationDestinations will return the pagerduty
// destinations configured for an account.
//
// API Reference: https://api.cloudflare.com/#notification-destinations-with-pagerduty-list-pagerduty-services
func (api *API) ListPagerDutyNotificationDestinations(ctx context.Context, accountID string) (NotificationPagerDutyResponse, error) {
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/destinations/pagerduty", accountID)
res, err := api.makeRequestContext(ctx, http.MethodGet, baseURL, nil)
if err != nil {
return NotificationPagerDutyResponse{}, err
}
var r NotificationPagerDutyResponse
err = json.Unmarshal(res, &r)
if err != nil {
return r, err
}
return r, nil
}
// GetEligibleNotificationDestinations will return the types of
// destinations an account is eligible to configure.
//
// API Reference: https://api.cloudflare.com/#notification-mechanism-eligibility-properties
func (api *API) GetEligibleNotificationDestinations(ctx context.Context, accountID string) (NotificationEligibilityResponse, error) {
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/destinations/eligible", accountID)
res, err := api.makeRequestContext(ctx, http.MethodGet, baseURL, nil)
if err != nil {
return NotificationEligibilityResponse{}, err
}
var r NotificationEligibilityResponse
err = json.Unmarshal(res, &r)
if err != nil {
return r, err
}
return r, nil
}
// GetAvailableNotificationTypes will return the alert types available for
// a given account.
//
// API Reference: https://api.cloudflare.com/#notification-mechanism-eligibility-properties
func (api *API) GetAvailableNotificationTypes(ctx context.Context, accountID string) (NotificationAvailableAlertsResponse, error) {
baseURL := fmt.Sprintf("/accounts/%s/alerting/v3/available_alerts", accountID)
res, err := api.makeRequestContext(ctx, http.MethodGet, baseURL, nil)
if err != nil {
return NotificationAvailableAlertsResponse{}, err
}
var r NotificationAvailableAlertsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return r, err
}
return r, nil
}
// TimeRange is an object for filtering the alert history based on timestamp.
type TimeRange struct {
Since string `json:"since,omitempty" url:"since,omitempty"`
Before string `json:"before,omitempty" url:"before,omitempty"`
}
// AlertHistoryFilter is an object for filtering the alert history response from the api.
type AlertHistoryFilter struct {
TimeRange
PaginationOptions
}
// ListNotificationHistory will return the history of alerts sent for
// a given account. The time period varies based on zone plan.
// Free, Biz, Pro = 30 days
// Ent = 90 days
//
// API Reference: https://api.cloudflare.com/#notification-history-list-history
func (api *API) ListNotificationHistory(ctx context.Context, accountID string, alertHistoryFilter AlertHistoryFilter) ([]NotificationHistory, ResultInfo, error) {
uri := buildURI(fmt.Sprintf("/accounts/%s/alerting/v3/history", accountID), alertHistoryFilter)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return []NotificationHistory{}, ResultInfo{}, err
}
var r NotificationHistoryResponse
err = json.Unmarshal(res, &r)
if err != nil {
return []NotificationHistory{}, ResultInfo{}, err
}
return r.Result, r.ResultInfo, nil
}
// unmarshal will unmarshal bytes and return a SaveResponse.
func unmarshalNotificationSaveResponse(res []byte) (SaveResponse, error) {
var r SaveResponse
err := json.Unmarshal(res, &r)
if err != nil {
return r, err
}
return r, nil
}