Skip to content

Commit 3c29b43

Browse files
srbhaakamailgarber-akamaiezilber-akamaiyec-akamai
authored
ACLP Alerting go SDK (#824)
* DI-27070 Add support for ACLP alerting * Fix lint * Fix deprecation formatting * Fix lint * fixed review comments * fixed review comments * Delete request_helpers.go * fixed review comments * fixed review comments * fix format * formatting issues fixed * Fixed test failures * reverted change to go.mod * fixed review comments * Added new test cases * Fixed review comments * Ran make tidy * fixed review comments from ye-chen and copilot * Apply suggestion from @yec-akamai Co-authored-by: Ye Chen <[email protected]> * fixed fixtures and other review comments * fixed comments and lint errors * fix fixtures * fix alert channel type * import resort --------- Co-authored-by: Lena Garber <[email protected]> Co-authored-by: ezilber-akamai <[email protected]> Co-authored-by: Ye Chen <[email protected]> Co-authored-by: Ye Chen <[email protected]>
1 parent 56cd69e commit 3c29b43

11 files changed

+1944
-19
lines changed

alert_channels.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package linodego
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"time"
7+
8+
"github.com/linode/linodego/internal/parseabletime"
9+
)
10+
11+
type AlertNotificationType string
12+
13+
const (
14+
EmailAlertNotification AlertNotificationType = "email"
15+
)
16+
17+
type AlertChannelType string
18+
19+
const (
20+
SystemAlertChannel AlertChannelType = "system"
21+
UserAlertChannel AlertChannelType = "user"
22+
)
23+
24+
// AlertChannelEnvelope represents a single alert channel entry returned inside alert definition
25+
type AlertChannelEnvelope struct {
26+
ID int `json:"id"`
27+
Label string `json:"label"`
28+
Type string `json:"type"`
29+
URL string `json:"url"`
30+
}
31+
32+
// AlertChannel represents a Monitor Channel object.
33+
type AlertChannel struct {
34+
Alerts []AlertChannelEnvelope `json:"alerts"`
35+
ChannelType AlertNotificationType `json:"channel_type"`
36+
Content ChannelContent `json:"content"`
37+
Created *time.Time `json:"-"`
38+
CreatedBy string `json:"created_by"`
39+
Updated *time.Time `json:"-"`
40+
UpdatedBy string `json:"updated_by"`
41+
ID int `json:"id"`
42+
Label string `json:"label"`
43+
Type AlertChannelType `json:"type"`
44+
}
45+
46+
type EmailChannelContent struct {
47+
EmailAddresses []string `json:"email_addresses"`
48+
}
49+
50+
// ChannelContent represents the content block for an AlertChannel, which varies by channel type.
51+
type ChannelContent struct {
52+
Email *EmailChannelContent `json:"email"`
53+
// Other channel types like 'webhook', 'slack' could be added here as optional fields.
54+
}
55+
56+
// UnmarshalJSON implements the json.Unmarshaler interface
57+
func (a *AlertChannel) UnmarshalJSON(b []byte) error {
58+
type Mask AlertChannel
59+
60+
p := struct {
61+
*Mask
62+
63+
Updated *parseabletime.ParseableTime `json:"updated"`
64+
Created *parseabletime.ParseableTime `json:"created"`
65+
}{
66+
Mask: (*Mask)(a),
67+
}
68+
69+
if err := json.Unmarshal(b, &p); err != nil {
70+
return err
71+
}
72+
73+
a.Updated = (*time.Time)(p.Updated)
74+
a.Created = (*time.Time)(p.Created)
75+
76+
return nil
77+
}
78+
79+
// ListAlertChannels gets a paginated list of Alert Channels.
80+
func (c *Client) ListAlertChannels(ctx context.Context, opts *ListOptions) ([]AlertChannel, error) {
81+
endpoint := formatAPIPath("monitor/alert-channels")
82+
return getPaginatedResults[AlertChannel](ctx, c, endpoint, opts)
83+
}

monitor_alert_definitions.go

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
package linodego
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"time"
7+
8+
"github.com/linode/linodego/internal/parseabletime"
9+
)
10+
11+
// AlertDefinition represents an ACLP Alert Definition object
12+
type AlertDefinition struct {
13+
ID int `json:"id"`
14+
Label string `json:"label"`
15+
Severity int `json:"severity"`
16+
Type string `json:"type"`
17+
ServiceType string `json:"service_type"`
18+
Status string `json:"status"`
19+
HasMoreResources bool `json:"has_more_resources"`
20+
RuleCriteria RuleCriteria `json:"rule_criteria"`
21+
TriggerConditions TriggerConditions `json:"trigger_conditions"`
22+
AlertChannels []AlertChannelEnvelope `json:"alert_channels"`
23+
Created *time.Time `json:"-"`
24+
Updated *time.Time `json:"-"`
25+
UpdatedBy string `json:"updated_by"`
26+
CreatedBy string `json:"created_by"`
27+
EntityIDs []any `json:"entity_ids"`
28+
Description string `json:"description"`
29+
Class string `json:"class"`
30+
}
31+
32+
// Backwards-compatible alias
33+
34+
// MonitorAlertDefinition represents an ACLP Alert Definition object
35+
//
36+
// Deprecated: AlertDefinition should be used in all new implementations.
37+
type MonitorAlertDefinition = AlertDefinition
38+
39+
// TriggerConditions represents the trigger conditions for an alert.
40+
type TriggerConditions struct {
41+
CriteriaCondition string `json:"criteria_condition,omitempty"`
42+
EvaluationPeriodSeconds int `json:"evaluation_period_seconds,omitempty"`
43+
PollingIntervalSeconds int `json:"polling_interval_seconds,omitempty"`
44+
TriggerOccurrences int `json:"trigger_occurrences,omitempty"`
45+
}
46+
47+
// RuleCriteria represents the rule criteria for an alert.
48+
type RuleCriteria struct {
49+
Rules []Rule `json:"rules,omitempty"`
50+
}
51+
52+
// Rule represents a single rule for an alert.
53+
type Rule struct {
54+
AggregateFunction string `json:"aggregate_function"`
55+
DimensionFilters []DimensionFilter `json:"dimension_filters"`
56+
Label string `json:"label"`
57+
Metric string `json:"metric"`
58+
Operator string `json:"operator"`
59+
Threshold float64 `json:"threshold"`
60+
Unit string `json:"unit"`
61+
}
62+
63+
// DimensionFilter represents a single dimension filter used inside a Rule.
64+
type DimensionFilter struct {
65+
DimensionLabel string `json:"dimension_label"`
66+
Label string `json:"label"`
67+
Operator string `json:"operator"`
68+
Value string `json:"value"`
69+
}
70+
71+
// RuleCriteriaOptions represents the rule criteria options for an alert.
72+
type RuleCriteriaOptions struct {
73+
Rules []RuleOptions `json:"rules,omitempty"`
74+
}
75+
76+
// RuleOptions represents a single rule option for an alert.
77+
type RuleOptions struct {
78+
AggregateFunction string `json:"aggregate_function,omitempty"`
79+
DimensionFilters []DimensionFilterOptions `json:"dimension_filters,omitempty"`
80+
Metric string `json:"metric,omitempty"`
81+
Operator string `json:"operator,omitempty"`
82+
Threshold float64 `json:"threshold,omitempty"`
83+
}
84+
85+
// DimensionFilterOptions represents a single dimension filter option used inside a Rule.
86+
type DimensionFilterOptions struct {
87+
DimensionLabel string `json:"dimension_label,omitempty"`
88+
Operator string `json:"operator,omitempty"`
89+
Value string `json:"value,omitempty"`
90+
}
91+
92+
// AlertType represents the type of alert: "user" or "system"
93+
type AlertType string
94+
95+
const (
96+
AlertTypeUser AlertType = "user"
97+
AlertTypeSystem AlertType = "system"
98+
)
99+
100+
// Severity represents the severity level of an alert.
101+
// 0 = Severe, 1 = Medium, 2 = Low, 3 = Info
102+
type Severity int
103+
104+
const (
105+
SeveritySevere Severity = 0
106+
SeverityMedium Severity = 1
107+
SeverityLow Severity = 2
108+
SeverityInfo Severity = 3
109+
)
110+
111+
// CriteriaCondition represents supported criteria conditions
112+
type CriteriaCondition string
113+
114+
const (
115+
CriteriaConditionAll CriteriaCondition = "ALL"
116+
)
117+
118+
// AlertDefinitionCreateOptions are the options used to create a new alert definition.
119+
type AlertDefinitionCreateOptions struct {
120+
Label string `json:"label"` // mandatory
121+
Severity int `json:"severity"` // mandatory
122+
ChannelIDs []int `json:"channel_ids"` // mandatory
123+
RuleCriteria RuleCriteriaOptions `json:"rule_criteria"` // optional
124+
TriggerConditions TriggerConditions `json:"trigger_conditions"` // optional
125+
EntityIDs []string `json:"entity_ids,omitempty"` // optional
126+
Description string `json:"description,omitempty"` // optional
127+
}
128+
129+
// AlertDefinitionUpdateOptions are the options used to update an alert definition.
130+
type AlertDefinitionUpdateOptions struct {
131+
Label string `json:"label"` // mandatory
132+
Severity int `json:"severity"` // mandatory
133+
ChannelIDs []int `json:"channel_ids"` // mandatory
134+
RuleCriteria RuleCriteriaOptions `json:"rule_criteria"` // optional
135+
TriggerConditions TriggerConditions `json:"trigger_conditions"` // optional
136+
EntityIDs []string `json:"entity_ids,omitempty"` // optional
137+
Description string `json:"description,omitempty"` // optional
138+
}
139+
140+
// UnmarshalJSON implements the json.Unmarshaler interface
141+
func (i *AlertDefinition) UnmarshalJSON(b []byte) error {
142+
type Mask AlertDefinition
143+
144+
p := struct {
145+
*Mask
146+
147+
Created *parseabletime.ParseableTime `json:"created"`
148+
Updated *parseabletime.ParseableTime `json:"updated"`
149+
}{
150+
Mask: (*Mask)(i),
151+
}
152+
153+
if err := json.Unmarshal(b, &p); err != nil {
154+
return err
155+
}
156+
157+
i.Created = (*time.Time)(p.Created)
158+
i.Updated = (*time.Time)(p.Updated)
159+
160+
return nil
161+
}
162+
163+
// ListMonitorAlertDefinitions returns a paginated list of ACLP Monitor Alert Definitions by service type.
164+
func (c *Client) ListMonitorAlertDefinitions(
165+
ctx context.Context,
166+
serviceType string,
167+
opts *ListOptions,
168+
) ([]AlertDefinition, error) {
169+
var endpoint string
170+
if serviceType != "" {
171+
endpoint = formatAPIPath("monitor/services/%s/alert-definitions", serviceType)
172+
} else {
173+
endpoint = formatAPIPath("monitor/alert-definitions")
174+
}
175+
176+
return getPaginatedResults[AlertDefinition](ctx, c, endpoint, opts)
177+
}
178+
179+
// ListAllMonitorAlertDefinitions returns a paginated list of all ACLP Monitor Alert Definitions under this account.
180+
func (c *Client) ListAllMonitorAlertDefinitions(
181+
ctx context.Context,
182+
opts *ListOptions,
183+
) ([]AlertDefinition, error) {
184+
endpoint := formatAPIPath("monitor/alert-definitions")
185+
return getPaginatedResults[AlertDefinition](ctx, c, endpoint, opts)
186+
}
187+
188+
// GetMonitorAlertDefinition gets an ACLP Monitor Alert Definition.
189+
func (c *Client) GetMonitorAlertDefinition(
190+
ctx context.Context,
191+
serviceType string,
192+
alertID int,
193+
) (*MonitorAlertDefinition, error) {
194+
e := formatAPIPath("monitor/services/%s/alert-definitions/%d", serviceType, alertID)
195+
return doGETRequest[AlertDefinition](ctx, c, e)
196+
}
197+
198+
// CreateMonitorAlertDefinition creates an ACLP Monitor Alert Definition.
199+
func (c *Client) CreateMonitorAlertDefinition(
200+
ctx context.Context,
201+
serviceType string,
202+
opts AlertDefinitionCreateOptions,
203+
) (*MonitorAlertDefinition, error) {
204+
e := formatAPIPath("monitor/services/%s/alert-definitions", serviceType)
205+
return doPOSTRequest[AlertDefinition](ctx, c, e, opts)
206+
}
207+
208+
// CreateMonitorAlertDefinitionWithIdempotency creates an ACLP Monitor Alert Definition
209+
// and optionally sends an Idempotency-Key header to make the request idempotent.
210+
func (c *Client) CreateMonitorAlertDefinitionWithIdempotency(
211+
ctx context.Context,
212+
serviceType string,
213+
opts AlertDefinitionCreateOptions,
214+
idempotencyKey string,
215+
) (*MonitorAlertDefinition, error) {
216+
e := formatAPIPath("monitor/services/%s/alert-definitions", serviceType)
217+
218+
var result AlertDefinition
219+
220+
req := c.R(ctx).SetResult(&result)
221+
222+
if idempotencyKey != "" {
223+
req.SetHeader("Idempotency-Key", idempotencyKey)
224+
}
225+
226+
body, err := json.Marshal(opts)
227+
if err != nil {
228+
return nil, err
229+
}
230+
231+
req.SetBody(string(body))
232+
233+
r, err := coupleAPIErrors(req.Post(e))
234+
if err != nil {
235+
return nil, err
236+
}
237+
238+
return r.Result().(*AlertDefinition), nil
239+
}
240+
241+
// UpdateMonitorAlertDefinition updates an ACLP Monitor Alert Definition.
242+
func (c *Client) UpdateMonitorAlertDefinition(
243+
ctx context.Context,
244+
serviceType string,
245+
alertID int,
246+
opts AlertDefinitionUpdateOptions,
247+
) (*AlertDefinition, error) {
248+
e := formatAPIPath("monitor/services/%s/alert-definitions/%d", serviceType, alertID)
249+
return doPUTRequest[AlertDefinition](ctx, c, e, opts)
250+
}
251+
252+
// DeleteMonitorAlertDefinition deletes an ACLP Monitor Alert Definition.
253+
func (c *Client) DeleteMonitorAlertDefinition(ctx context.Context, serviceType string, alertID int) error {
254+
e := formatAPIPath("monitor/services/%s/alert-definitions/%d", serviceType, alertID)
255+
return doDELETERequest(ctx, c, e)
256+
}

monitor_dashboards.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const (
2828
ServiceTypeDBaaS ServiceType = "dbaas"
2929
ServiceTypeACLB ServiceType = "aclb"
3030
ServiceTypeNodeBalancer ServiceType = "nodebalancer"
31-
ServiceTypeObjectStorage ServiceType = "objectstorage"
31+
ServiceTypeObjectStorage ServiceType = "object_storage"
3232
ServiceTypeVPC ServiceType = "vpc"
3333
ServiceTypeFirewallService ServiceType = "firewall"
3434
ServiceTypeNetLoadBalancer ServiceType = "netloadbalancer"

0 commit comments

Comments
 (0)