-
Notifications
You must be signed in to change notification settings - Fork 98
ACLP Alerting go SDK #824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
ACLP Alerting go SDK #824
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| package linodego | ||
|
|
||
| import ( | ||
| "context" | ||
| ) | ||
|
|
||
| // AlertChannelEnvelope represents a single alert channel entry returned inside alert definition | ||
| type AlertChannelEnvelope struct { | ||
| ID int `json:"id"` | ||
| Label string `json:"label"` | ||
| Type string `json:"type"` | ||
| URL string `json:"url"` | ||
| } | ||
|
|
||
| // AlertChannel represents a Monitor Channel object. | ||
| type AlertChannel struct { | ||
| ID int `json:"id"` | ||
| Label string `json:"label"` | ||
| ChannelType string `json:"channel_type"` | ||
| Content ChannelContent `json:"content"` | ||
| Created string `json:"created"` | ||
| CreatedBy string `json:"created_by"` | ||
| Updated string `json:"updated"` | ||
| UpdatedBy string `json:"updated_by"` | ||
| URL string `json:"url"` | ||
| } | ||
|
|
||
| // AlertChannelDetail represents the details of a Monitor Channel. | ||
| type AlertChannelDetail struct { | ||
| To string `json:"to,omitempty"` | ||
| From string `json:"from,omitempty"` | ||
| User string `json:"user,omitempty"` | ||
| Token string `json:"token,omitempty"` | ||
| URL string `json:"url,omitempty"` | ||
| } | ||
|
|
||
| // AlertChannelCreateOptions are the options used to create a new Monitor Channel. | ||
| type AlertChannelCreateOptions struct { | ||
| Label string `json:"label"` | ||
| Type string `json:"type"` | ||
| Details AlertChannelDetailOptions `json:"details"` | ||
| } | ||
|
|
||
| // AlertChannelDetailOptions are the options used to create the details of a new Monitor Channel. | ||
| type AlertChannelDetailOptions struct { | ||
| To string `json:"to,omitempty"` | ||
| } | ||
|
|
||
| // AlertingChannelCreateOptions are the options used to create a new Monitor Channel. | ||
| // | ||
| // Deprecated: AlertChannelCreateOptions should be used in all new implementations. | ||
| type AlertingChannelCreateOptions = AlertChannelCreateOptions | ||
|
|
||
| type EmailChannelContent struct { | ||
| EmailAddresses []string `json:"email_addresses"` | ||
| } | ||
|
|
||
| // ChannelContent represents the content block for an AlertChannel, which varies by channel type. | ||
| type ChannelContent struct { | ||
| Email *EmailChannelContent `json:"email,omitempty"` | ||
| // Other channel types like 'webhook', 'slack' could be added here as optional fields. | ||
| } | ||
|
|
||
| // ListAlertChannels gets a paginated list of Alert Channels. | ||
| func (c *Client) ListAlertChannels(ctx context.Context, opts *ListOptions) ([]AlertChannel, error) { | ||
| endpoint := formatAPIV4BetaPath("monitor/alert-channels") | ||
| return getPaginatedResults[AlertChannel](ctx, c, endpoint, opts) | ||
| } | ||
|
|
||
| // GetAlertChannel gets an Alert Channel by ID. | ||
| func (c *Client) GetAlertChannel(ctx context.Context, channelID int) (*AlertChannel, error) { | ||
| e := formatAPIV4BetaPath("monitor/alert-channels/%d", channelID) | ||
| return doGETRequest[AlertChannel](ctx, c, e) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,4 @@ require ( | |
|
|
||
| go 1.24.0 | ||
|
|
||
| toolchain go1.25.1 | ||
|
|
||
| retract v1.0.0 // Accidental branch push | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,218 @@ | ||
| package linodego | ||
|
|
||
| import ( | ||
| "context" | ||
| "encoding/json" | ||
| "time" | ||
|
|
||
| "github.com/linode/linodego/internal/parseabletime" | ||
| ) | ||
|
|
||
| // AlertDefinition represents an ACLP Alert Definition object | ||
| type AlertDefinition struct { | ||
| ID int `json:"id"` | ||
| Label string `json:"label"` | ||
| Severity int `json:"severity"` | ||
| Type string `json:"type"` | ||
| ServiceType string `json:"service_type"` | ||
| Status string `json:"status"` | ||
| HasMoreResources bool `json:"has_more_resources"` | ||
| Rule *Rule `json:"rule"` | ||
| RuleCriteria *RuleCriteria `json:"rule_criteria"` | ||
| TriggerConditions *TriggerConditions `json:"trigger_conditions"` | ||
| AlertChannels []AlertChannelEnvelope `json:"alert_channels"` | ||
| Created *time.Time `json:"-"` | ||
| Updated *time.Time `json:"-"` | ||
| UpdatedBy string `json:"updated_by"` | ||
| CreatedBy string `json:"created_by"` | ||
| EntityIDs []string `json:"entity_ids"` | ||
| Description string `json:"description"` | ||
| Class string `json:"class"` | ||
| } | ||
|
|
||
| // Backwards-compatible alias | ||
|
|
||
| // MonitorAlertDefinition represents an ACLP Alert Definition object | ||
| // | ||
| // Deprecated: AlertDefinition should be used in all new implementations. | ||
| type MonitorAlertDefinition = AlertDefinition | ||
|
|
||
| // TriggerConditions represents the trigger conditions for an alert. | ||
| type TriggerConditions struct { | ||
| CriteriaCondition string `json:"criteria_condition,omitempty"` | ||
| EvaluationPeriodSeconds int `json:"evaluation_period_seconds,omitempty"` | ||
| PollingIntervalSeconds int `json:"polling_interval_seconds,omitempty"` | ||
| TriggerOccurrences int `json:"trigger_occurrences,omitempty"` | ||
| } | ||
|
|
||
| // RuleCriteria represents the rule criteria for an alert. | ||
| type RuleCriteria struct { | ||
| Rules []Rule `json:"rules,omitempty"` | ||
| } | ||
|
|
||
| // Rule represents a single rule for an alert. | ||
| type Rule struct { | ||
| AggregateFunction string `json:"aggregate_function,omitempty"` | ||
| DimensionFilters []DimensionFilter `json:"dimension_filters,omitempty"` | ||
| Label string `json:"label,omitempty"` | ||
| Metric string `json:"metric,omitempty"` | ||
| Operator string `json:"operator,omitempty"` | ||
| Threshold *float64 `json:"threshold,omitempty"` | ||
| Unit *string `json:"unit,omitempty"` | ||
| } | ||
|
|
||
| // DimensionFilter represents a single dimension filter used inside a Rule. | ||
| type DimensionFilter struct { | ||
| DimensionLabel string `json:"dimension_label"` | ||
| Label string `json:"label"` | ||
| Operator string `json:"operator"` | ||
| Value any `json:"value"` | ||
| } | ||
|
|
||
| // AlertType represents the type of alert: "user" or "system" | ||
| type AlertType string | ||
|
|
||
| const ( | ||
| AlertTypeUser AlertType = "user" | ||
| AlertTypeSystem AlertType = "system" | ||
| ) | ||
|
|
||
| // Severity represents the severity level of an alert. | ||
| // 0 = Severe, 1 = Medium, 2 = Low, 3 = Info | ||
| type Severity int | ||
|
|
||
| const ( | ||
| SeveritySevere Severity = 0 | ||
| SeverityMedium Severity = 1 | ||
| SeverityLow Severity = 2 | ||
| SeverityInfo Severity = 3 | ||
| ) | ||
|
|
||
| // CriteriaCondition represents supported criteria conditions | ||
| type CriteriaCondition string | ||
|
|
||
| const ( | ||
| CriteriaConditionAll CriteriaCondition = "ALL" | ||
| ) | ||
|
|
||
| // AlertDefinitionCreateOptions are the options used to create a new alert definition. | ||
| type AlertDefinitionCreateOptions struct { | ||
| ServiceType string `json:"service_type"` // mandatory | ||
| Label string `json:"label"` // mandatory | ||
| Severity int `json:"severity"` // mandatory | ||
| ChannelIDs []int `json:"channel_ids"` // mandatory | ||
| RuleCriteria *RuleCriteria `json:"rule_criteria,omitempty"` // optional | ||
| TriggerConditions *TriggerConditions `json:"trigger_conditions,omitempty"` // optional | ||
| EntityIDs []string `json:"entity_ids,omitempty"` // optional | ||
| Description string `json:"description,omitempty"` // optional | ||
| } | ||
|
|
||
| // AlertDefinitionUpdateOptions are the options used to update an alert definition. | ||
| type AlertDefinitionUpdateOptions struct { | ||
| ServiceType string `json:"service_type"` // mandatory, must not be empty | ||
| AlertID int `json:"alert_id"` // mandatory, must not be zero | ||
| Label string `json:"label,omitempty"` // optional | ||
| Severity int `json:"severity,omitempty"` // optional, should be int to match AlertDefinition | ||
| Description string `json:"description,omitempty"` // optional | ||
| RuleCriteria *RuleCriteria `json:"rule_criteria,omitempty"` // optional | ||
| TriggerConditions *TriggerConditions `json:"trigger_conditions,omitempty"` // optional | ||
| EntityIDs []string `json:"entity_ids,omitempty"` // optional | ||
| ChannelIDs []int `json:"channel_ids,omitempty"` // optional | ||
| } | ||
|
|
||
| // UnmarshalJSON implements the json.Unmarshaler interface | ||
| func (i *AlertDefinition) UnmarshalJSON(b []byte) error { | ||
| type Mask AlertDefinition | ||
|
|
||
| p := struct { | ||
| *Mask | ||
|
|
||
| Created *parseabletime.ParseableTime `json:"created"` | ||
| Updated *parseabletime.ParseableTime `json:"updated"` | ||
| }{ | ||
| Mask: (*Mask)(i), | ||
| } | ||
|
|
||
| if err := json.Unmarshal(b, &p); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| i.Created = (*time.Time)(p.Created) | ||
| i.Updated = (*time.Time)(p.Updated) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // ListMonitorAlertDefinitions gets a paginated list of ACLP Monitor Alert Definitions. | ||
| func (c *Client) ListMonitorAlertDefinitions(ctx context.Context, serviceType string, opts *ListOptions) ([]AlertDefinition, error) { | ||
| var endpoint string | ||
| if serviceType != "" { | ||
| endpoint = formatAPIV4BetaPath("monitor/services/%s/alert-definitions", serviceType) | ||
| } else { | ||
| endpoint = formatAPIV4BetaPath("monitor/alert-definitions") | ||
| } | ||
|
|
||
| return getPaginatedResults[AlertDefinition](ctx, c, endpoint, opts) | ||
| } | ||
|
|
||
| // GetMonitorAlertDefinition gets an ACLP Monitor Alert Definition. | ||
| func (c *Client) GetMonitorAlertDefinition(ctx context.Context, serviceType string, alertID int) (*AlertDefinition, error) { | ||
| e := formatAPIV4BetaPath("monitor/services/%s/alert-definitions/%d", serviceType, alertID) | ||
| return doGETRequest[AlertDefinition](ctx, c, e) | ||
| } | ||
|
|
||
| // CreateMonitorAlertDefinition creates an ACLP Monitor Alert Definition. | ||
| func (c *Client) CreateMonitorAlertDefinition(ctx context.Context, serviceType string, opts AlertDefinitionCreateOptions) (*AlertDefinition, error) { | ||
| e := formatAPIV4BetaPath("monitor/services/%s/alert-definitions", serviceType) | ||
| return doPOSTRequest[AlertDefinition](ctx, c, e, opts) | ||
| } | ||
|
|
||
| // CreateMonitorAlertDefinitionWithIdempotency creates an ACLP Monitor Alert Definition | ||
| // and optionally sends an Idempotency-Key header to make the request idempotent. | ||
| func (c *Client) CreateMonitorAlertDefinitionWithIdempotency( | ||
| ctx context.Context, | ||
| serviceType string, | ||
| opts AlertDefinitionCreateOptions, | ||
| idempotencyKey string, | ||
| ) (*AlertDefinition, error) { | ||
| e := formatAPIV4BetaPath("monitor/services/%s/alert-definitions", serviceType) | ||
|
|
||
| var result AlertDefinition | ||
|
|
||
| req := c.R(ctx).SetResult(&result) | ||
|
|
||
| if idempotencyKey != "" { | ||
| req.SetHeader("Idempotency-Key", idempotencyKey) | ||
| } | ||
|
|
||
| body, err := json.Marshal(opts) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| req.SetBody(string(body)) | ||
|
|
||
| r, err := coupleAPIErrors(req.Post(e)) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return r.Result().(*AlertDefinition), nil | ||
| } | ||
|
|
||
| // UpdateMonitorAlertDefinition updates an ACLP Monitor Alert Definition. | ||
| func (c *Client) UpdateMonitorAlertDefinition( | ||
| ctx context.Context, | ||
| serviceType string, | ||
| alertID int, | ||
| opts AlertDefinitionUpdateOptions, | ||
| ) (*AlertDefinition, error) { | ||
| e := formatAPIV4BetaPath("monitor/services/%s/alert-definitions/%d", serviceType, alertID) | ||
| return doPUTRequest[AlertDefinition](ctx, c, e, opts) | ||
| } | ||
|
|
||
| // DeleteMonitorAlertDefinition deletes an ACLP Monitor Alert Definition. | ||
| func (c *Client) DeleteMonitorAlertDefinition(ctx context.Context, serviceType string, alertID int) error { | ||
| e := formatAPIV4BetaPath("monitor/services/%s/alert-definitions/%d", serviceType, alertID) | ||
| return doDELETERequest(ctx, c, e) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ import ( | |
| "fmt" | ||
| "net/url" | ||
| "reflect" | ||
| "strings" | ||
| ) | ||
|
|
||
| // paginatedResponse represents a single response from a paginated | ||
|
|
@@ -316,6 +317,19 @@ func formatAPIPath(format string, args ...any) string { | |
| return fmt.Sprintf(format, escapedArgs...) | ||
| } | ||
|
|
||
| // formatAPIV4BetaPath builds a fully-qualified URL for v4beta endpoints. | ||
| // We return a full URL (including scheme and host) so requests made with the | ||
| // standard client (which is pointed at /v4) will hit the /v4beta host/path | ||
| // directly. | ||
| func formatAPIV4BetaPath(format string, args ...any) string { | ||
| p := formatAPIPath(format, args...) | ||
|
|
||
| // Ensure we don't produce a double slash when joining | ||
| p = strings.TrimPrefix(p, "/") | ||
|
|
||
| return fmt.Sprintf("%s://%s/%s/%s", APIProto, APIHost, "v4beta", p) | ||
| } | ||
|
Comment on lines
+324
to
+331
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally we put the responsibility on users to configure The idea is that users will be required to acknowledge that they're using beta endpoints rather than it happening without them knowing. I'll take a note to document this a bit more explicitly π |
||
|
|
||
| func isNil(i any) bool { | ||
| if i == nil { | ||
| return true | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.