Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### Fixed

- Populate policy_id when importing fleet policies and integrations ([#646](https://github.com/elastic/terraform-provider-elasticstack/pull/646))
- Fix alerting rule update crash when backend responds with HTTP 4xx. ([#649](https://github.com/elastic/terraform-provider-elasticstack/pull/649))

## [0.11.3] - 2024-05-16

Expand Down
20 changes: 17 additions & 3 deletions internal/clients/kibana/alerting.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func ruleResponseToModel(spaceID string, res *alerting.RuleResponseProperties) *
Name: res.Name,
Consumer: res.Consumer,
NotifyWhen: string(unwrapOptionalField(res.NotifyWhen)),

Params: res.Params,
RuleTypeID: res.RuleTypeId,
Schedule: models.AlertingRuleSchedule{
Expand Down Expand Up @@ -62,7 +63,12 @@ func ruleActionsToActionsInner(ruleActions []models.AlertingRuleAction) []alerti
return actions
}

func CreateAlertingRule(ctx context.Context, apiClient *clients.ApiClient, rule models.AlertingRule) (*models.AlertingRule, diag.Diagnostics) {
type ApiClient interface {
GetAlertingClient() (alerting.AlertingAPI, error)
SetAlertingAuthContext(context.Context) context.Context
}

func CreateAlertingRule(ctx context.Context, apiClient ApiClient, rule models.AlertingRule) (*models.AlertingRule, diag.Diagnostics) {
client, err := apiClient.GetAlertingClient()
if err != nil {
return nil, diag.FromErr(err)
Expand Down Expand Up @@ -105,7 +111,7 @@ func CreateAlertingRule(ctx context.Context, apiClient *clients.ApiClient, rule
return ruleResponseToModel(rule.SpaceID, ruleRes), utils.CheckHttpError(res, "Unabled to create alerting rule")
}

func UpdateAlertingRule(ctx context.Context, apiClient *clients.ApiClient, rule models.AlertingRule) (*models.AlertingRule, diag.Diagnostics) {
func UpdateAlertingRule(ctx context.Context, apiClient ApiClient, rule models.AlertingRule) (*models.AlertingRule, diag.Diagnostics) {
client, err := apiClient.GetAlertingClient()
if err != nil {
return nil, diag.FromErr(err)
Expand All @@ -124,18 +130,26 @@ func UpdateAlertingRule(ctx context.Context, apiClient *clients.ApiClient, rule
Tags: rule.Tags,
Throttle: *alerting.NewNullableString(rule.Throttle),
}

req := client.UpdateRule(ctxWithAuth, rule.RuleID, rule.SpaceID).KbnXsrf("true").UpdateRuleRequest(reqModel)

ruleRes, res, err := req.Execute()
if err != nil && res == nil {
return nil, diag.FromErr(err)
}
rule.RuleID = ruleRes.Id

if ruleRes != nil {
rule.RuleID = ruleRes.Id
}

defer res.Body.Close()

if diags := utils.CheckHttpError(res, "Unable to update alerting rule"); diags.HasError() {
return nil, diags
}

shouldBeEnabled := rule.Enabled != nil && *rule.Enabled

if shouldBeEnabled && !ruleRes.Enabled {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're assuming here that anything where ruleRes == nil will be caught by utils.CheckHttpError above? I wonder if it's worth having an explicit check as well?

Copy link
Contributor Author

@dimuon dimuon May 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're assuming here that anything where ruleRes == nil will be caught by utils.CheckHttpError above?

I'm not sure actually - CheckHttpError just checks HTTP status code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added logic to explicitly handle an empty response with HTTP 200.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry - the new logic just returns an error in case of an empty response for Create/Update call, HTTP status code doesn't make any diff in this case.
Still in reality, CheckHttpError should handle the cases when something goes wrong based on the HTTP status code. The new logic just makes sure that crash won't happen.

res, err := client.EnableRule(ctxWithAuth, rule.RuleID, rule.SpaceID).KbnXsrf("true").Execute()
if err != nil && res == nil {
Expand Down
278 changes: 278 additions & 0 deletions internal/clients/kibana/alerting_api_stub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
package kibana

import (
"context"
"net/http"

"github.com/elastic/terraform-provider-elasticstack/generated/alerting"
)

type FakeAlertingAPI struct {
RuleResponseProperties *alerting.RuleResponseProperties
HttpResponse *http.Response
Error error
}

// The method stubs are generated initially by the VS Code Quick Fix for the below Blank Identifier definition.
// https://stackoverflow.com/a/77393824
var _ alerting.AlertingAPI = (*FakeAlertingAPI)(nil)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use gomock or similar to generate a proper mock implementation rather than this?


// CreateRule implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) CreateRule(ctx context.Context, spaceId string, ruleId string) alerting.ApiCreateRuleRequest {
return alerting.ApiCreateRuleRequest{ApiService: f}
}

// CreateRuleExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) CreateRuleExecute(r alerting.ApiCreateRuleRequest) (*alerting.RuleResponseProperties, *http.Response, error) {
return f.RuleResponseProperties, f.HttpResponse, f.Error
}

// DeleteRule implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) DeleteRule(ctx context.Context, ruleId string, spaceId string) alerting.ApiDeleteRuleRequest {
panic("unimplemented")
}

// DeleteRuleExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) DeleteRuleExecute(r alerting.ApiDeleteRuleRequest) (*http.Response, error) {
panic("unimplemented")
}

// DisableRule implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) DisableRule(ctx context.Context, ruleId string, spaceId string) alerting.ApiDisableRuleRequest {
panic("unimplemented")
}

// DisableRuleExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) DisableRuleExecute(r alerting.ApiDisableRuleRequest) (*http.Response, error) {
panic("unimplemented")
}

// EnableRule implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) EnableRule(ctx context.Context, ruleId string, spaceId string) alerting.ApiEnableRuleRequest {
panic("unimplemented")
}

// EnableRuleExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) EnableRuleExecute(r alerting.ApiEnableRuleRequest) (*http.Response, error) {
panic("unimplemented")
}

// FindRules implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) FindRules(ctx context.Context, spaceId string) alerting.ApiFindRulesRequest {
panic("unimplemented")
}

// FindRulesExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) FindRulesExecute(r alerting.ApiFindRulesRequest) (*alerting.FindRules200Response, *http.Response, error) {
panic("unimplemented")
}

// GetAlertingHealth implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) GetAlertingHealth(ctx context.Context, spaceId string) alerting.ApiGetAlertingHealthRequest {
panic("unimplemented")
}

// GetAlertingHealthExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) GetAlertingHealthExecute(r alerting.ApiGetAlertingHealthRequest) (*alerting.GetAlertingHealth200Response, *http.Response, error) {
panic("unimplemented")
}

// GetRule implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) GetRule(ctx context.Context, ruleId string, spaceId string) alerting.ApiGetRuleRequest {
panic("unimplemented")
}

// GetRuleExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) GetRuleExecute(r alerting.ApiGetRuleRequest) (*alerting.RuleResponseProperties, *http.Response, error) {
panic("unimplemented")
}

// GetRuleTypes implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) GetRuleTypes(ctx context.Context, spaceId string) alerting.ApiGetRuleTypesRequest {
panic("unimplemented")
}

// GetRuleTypesExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) GetRuleTypesExecute(r alerting.ApiGetRuleTypesRequest) ([]alerting.GetRuleTypes200ResponseInner, *http.Response, error) {
panic("unimplemented")
}

// LegacyCreateAlert implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyCreateAlert(ctx context.Context, alertId string, spaceId string) alerting.ApiLegacyCreateAlertRequest {
panic("unimplemented")
}

// LegacyCreateAlertExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyCreateAlertExecute(r alerting.ApiLegacyCreateAlertRequest) (*alerting.AlertResponseProperties, *http.Response, error) {
panic("unimplemented")
}

// LegacyDisableAlert implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyDisableAlert(ctx context.Context, spaceId string, alertId string) alerting.ApiLegacyDisableAlertRequest {
panic("unimplemented")
}

// LegacyDisableAlertExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyDisableAlertExecute(r alerting.ApiLegacyDisableAlertRequest) (*http.Response, error) {
panic("unimplemented")
}

// LegacyEnableAlert implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyEnableAlert(ctx context.Context, spaceId string, alertId string) alerting.ApiLegacyEnableAlertRequest {
panic("unimplemented")
}

// LegacyEnableAlertExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyEnableAlertExecute(r alerting.ApiLegacyEnableAlertRequest) (*http.Response, error) {
panic("unimplemented")
}

// LegacyFindAlerts implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyFindAlerts(ctx context.Context, spaceId string) alerting.ApiLegacyFindAlertsRequest {
panic("unimplemented")
}

// LegacyFindAlertsExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyFindAlertsExecute(r alerting.ApiLegacyFindAlertsRequest) (*alerting.LegacyFindAlerts200Response, *http.Response, error) {
panic("unimplemented")
}

// LegacyGetAlert implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyGetAlert(ctx context.Context, spaceId string, alertId string) alerting.ApiLegacyGetAlertRequest {
panic("unimplemented")
}

// LegacyGetAlertExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyGetAlertExecute(r alerting.ApiLegacyGetAlertRequest) (*alerting.AlertResponseProperties, *http.Response, error) {
panic("unimplemented")
}

// LegacyGetAlertTypes implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyGetAlertTypes(ctx context.Context, spaceId string) alerting.ApiLegacyGetAlertTypesRequest {
panic("unimplemented")
}

// LegacyGetAlertTypesExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyGetAlertTypesExecute(r alerting.ApiLegacyGetAlertTypesRequest) ([]alerting.LegacyGetAlertTypes200ResponseInner, *http.Response, error) {
panic("unimplemented")
}

// LegacyGetAlertingHealth implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyGetAlertingHealth(ctx context.Context, spaceId string) alerting.ApiLegacyGetAlertingHealthRequest {
panic("unimplemented")
}

// LegacyGetAlertingHealthExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyGetAlertingHealthExecute(r alerting.ApiLegacyGetAlertingHealthRequest) (*alerting.LegacyGetAlertingHealth200Response, *http.Response, error) {
panic("unimplemented")
}

// LegacyMuteAlertInstance implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyMuteAlertInstance(ctx context.Context, spaceId string, alertId string, alertInstanceId string) alerting.ApiLegacyMuteAlertInstanceRequest {
panic("unimplemented")
}

// LegacyMuteAlertInstanceExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyMuteAlertInstanceExecute(r alerting.ApiLegacyMuteAlertInstanceRequest) (*http.Response, error) {
panic("unimplemented")
}

// LegacyMuteAllAlertInstances implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyMuteAllAlertInstances(ctx context.Context, spaceId string, alertId string) alerting.ApiLegacyMuteAllAlertInstancesRequest {
panic("unimplemented")
}

// LegacyMuteAllAlertInstancesExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyMuteAllAlertInstancesExecute(r alerting.ApiLegacyMuteAllAlertInstancesRequest) (*http.Response, error) {
panic("unimplemented")
}

// LegacyUnmuteAlertInstance implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyUnmuteAlertInstance(ctx context.Context, spaceId string, alertId string, alertInstanceId string) alerting.ApiLegacyUnmuteAlertInstanceRequest {
panic("unimplemented")
}

// LegacyUnmuteAlertInstanceExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyUnmuteAlertInstanceExecute(r alerting.ApiLegacyUnmuteAlertInstanceRequest) (*http.Response, error) {
panic("unimplemented")
}

// LegacyUnmuteAllAlertInstances implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyUnmuteAllAlertInstances(ctx context.Context, spaceId string, alertId string) alerting.ApiLegacyUnmuteAllAlertInstancesRequest {
panic("unimplemented")
}

// LegacyUnmuteAllAlertInstancesExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyUnmuteAllAlertInstancesExecute(r alerting.ApiLegacyUnmuteAllAlertInstancesRequest) (*http.Response, error) {
panic("unimplemented")
}

// LegacyUpdateAlert implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyUpdateAlert(ctx context.Context, spaceId string, alertId string) alerting.ApiLegacyUpdateAlertRequest {
panic("unimplemented")
}

// LegacyUpdateAlertExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegacyUpdateAlertExecute(r alerting.ApiLegacyUpdateAlertRequest) (*alerting.AlertResponseProperties, *http.Response, error) {
panic("unimplemented")
}

// LegaryDeleteAlert implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegaryDeleteAlert(ctx context.Context, spaceId string, alertId string) alerting.ApiLegaryDeleteAlertRequest {
panic("unimplemented")
}

// LegaryDeleteAlertExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) LegaryDeleteAlertExecute(r alerting.ApiLegaryDeleteAlertRequest) (*http.Response, error) {
panic("unimplemented")
}

// MuteAlert implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) MuteAlert(ctx context.Context, alertId string, ruleId string, spaceId string) alerting.ApiMuteAlertRequest {
panic("unimplemented")
}

// MuteAlertExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) MuteAlertExecute(r alerting.ApiMuteAlertRequest) (*http.Response, error) {
panic("unimplemented")
}

// MuteAllAlerts implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) MuteAllAlerts(ctx context.Context, ruleId string, spaceId string) alerting.ApiMuteAllAlertsRequest {
panic("unimplemented")
}

// MuteAllAlertsExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) MuteAllAlertsExecute(r alerting.ApiMuteAllAlertsRequest) (*http.Response, error) {
panic("unimplemented")
}

// UnmuteAlert implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) UnmuteAlert(ctx context.Context, alertId string, ruleId string, spaceId string) alerting.ApiUnmuteAlertRequest {
panic("unimplemented")
}

// UnmuteAlertExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) UnmuteAlertExecute(r alerting.ApiUnmuteAlertRequest) (*http.Response, error) {
panic("unimplemented")
}

// UnmuteAllAlerts implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) UnmuteAllAlerts(ctx context.Context, ruleId string, spaceId string) alerting.ApiUnmuteAllAlertsRequest {
panic("unimplemented")
}

// UnmuteAllAlertsExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) UnmuteAllAlertsExecute(r alerting.ApiUnmuteAllAlertsRequest) (*http.Response, error) {
panic("unimplemented")
}

// UpdateRule implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) UpdateRule(ctx context.Context, ruleId string, spaceId string) alerting.ApiUpdateRuleRequest {
return alerting.ApiUpdateRuleRequest{ApiService: f}
}

// UpdateRuleExecute implements alerting.AlertingAPI.
func (f *FakeAlertingAPI) UpdateRuleExecute(r alerting.ApiUpdateRuleRequest) (*alerting.RuleResponseProperties, *http.Response, error) {
return f.RuleResponseProperties, f.HttpResponse, f.Error
}
Loading