internal/clients/kibana/slo.go (170 lines of code) (raw):
package kibana
import (
"context"
"fmt"
"net/http"
"github.com/elastic/terraform-provider-elasticstack/generated/slo"
"github.com/elastic/terraform-provider-elasticstack/internal/clients"
"github.com/elastic/terraform-provider-elasticstack/internal/models"
"github.com/elastic/terraform-provider-elasticstack/internal/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
)
func GetSlo(ctx context.Context, apiClient *clients.ApiClient, id, spaceID string) (*models.Slo, diag.Diagnostics) {
client, err := apiClient.GetSloClient()
if err != nil {
return nil, diag.FromErr(err)
}
ctxWithAuth := apiClient.SetSloAuthContext(ctx)
req := client.GetSloOp(ctxWithAuth, spaceID, id).KbnXsrf("true")
sloRes, res, err := req.Execute()
if res == nil {
return nil, diag.FromErr(err)
}
if res.StatusCode == http.StatusNotFound {
return nil, nil
}
if err != nil {
return nil, diag.FromErr(err)
}
defer res.Body.Close()
return sloResponseToModel(spaceID, sloRes), utils.CheckHttpError(res, "Unable to get slo with ID "+string(id))
}
func DeleteSlo(ctx context.Context, apiClient *clients.ApiClient, sloId string, spaceId string) diag.Diagnostics {
client, err := apiClient.GetSloClient()
if err != nil {
return diag.FromErr(err)
}
ctxWithAuth := apiClient.SetSloAuthContext(ctx)
req := client.DeleteSloOp(ctxWithAuth, sloId, spaceId).KbnXsrf("true")
res, err := req.Execute()
if err != nil && res == nil {
return diag.FromErr(err)
}
defer res.Body.Close()
return utils.CheckHttpError(res, "Unable to delete slo with ID "+string(sloId))
}
func UpdateSlo(ctx context.Context, apiClient *clients.ApiClient, s models.Slo, supportsGroupByList bool) (*models.Slo, diag.Diagnostics) {
client, err := apiClient.GetSloClient()
if err != nil {
return nil, diag.FromErr(err)
}
ctxWithAuth := apiClient.SetSloAuthContext(ctx)
indicator, err := responseIndicatorToCreateSloRequestIndicator(s.Indicator)
if err != nil {
return nil, diag.FromErr(err)
}
reqModel := slo.UpdateSloRequest{
Name: &s.Name,
Description: &s.Description,
Indicator: &indicator,
TimeWindow: &s.TimeWindow,
BudgetingMethod: (*slo.BudgetingMethod)(&s.BudgetingMethod),
Objective: &s.Objective,
Settings: s.Settings,
GroupBy: transformGroupBy(s.GroupBy, supportsGroupByList),
Tags: s.Tags,
}
req := client.UpdateSloOp(ctxWithAuth, s.SpaceID, s.SloID).KbnXsrf("true").UpdateSloRequest(reqModel)
slo, res, err := req.Execute()
if err != nil {
return nil, diag.FromErr(err)
}
defer res.Body.Close()
if diags := utils.CheckHttpError(res, "unable to update slo with id "+s.SloID); diags.HasError() {
return nil, diags
}
return sloResponseToModel(s.SpaceID, slo), diag.Diagnostics{}
}
func CreateSlo(ctx context.Context, apiClient *clients.ApiClient, s models.Slo, supportsGroupByList bool) (*models.Slo, diag.Diagnostics) {
client, err := apiClient.GetSloClient()
if err != nil {
return nil, diag.FromErr(err)
}
ctxWithAuth := apiClient.SetSloAuthContext(ctx)
indicator, err := responseIndicatorToCreateSloRequestIndicator(s.Indicator)
if err != nil {
return nil, diag.FromErr(err)
}
reqModel := slo.CreateSloRequest{
Name: s.Name,
Description: s.Description,
Indicator: indicator,
TimeWindow: s.TimeWindow,
BudgetingMethod: slo.BudgetingMethod(s.BudgetingMethod),
Objective: s.Objective,
Settings: s.Settings,
GroupBy: transformGroupBy(s.GroupBy, supportsGroupByList),
Tags: s.Tags,
}
// Explicitly set SLO object id if provided, otherwise we'll use the autogenerated ID from the Kibana API response
if s.SloID != "" {
reqModel.Id = &s.SloID
}
req := client.CreateSloOp(ctxWithAuth, s.SpaceID).KbnXsrf("true").CreateSloRequest(reqModel)
sloRes, res, err := req.Execute()
if err != nil {
return nil, diag.FromErr(err)
}
defer res.Body.Close()
if diags := utils.CheckHttpError(res, "unable to create slo with id "+s.SloID); diags.HasError() {
return nil, diags
}
s.SloID = sloRes.Id
return &s, diag.Diagnostics{}
}
func responseIndicatorToCreateSloRequestIndicator(s slo.SloResponseIndicator) (slo.CreateSloRequestIndicator, error) {
var ret slo.CreateSloRequestIndicator
ind := s.GetActualInstance()
switch ind := ind.(type) {
case *slo.IndicatorPropertiesApmAvailability:
ret.IndicatorPropertiesApmAvailability = ind
case *slo.IndicatorPropertiesApmLatency:
ret.IndicatorPropertiesApmLatency = ind
case *slo.IndicatorPropertiesCustomKql:
ret.IndicatorPropertiesCustomKql = ind
case *slo.IndicatorPropertiesCustomMetric:
ret.IndicatorPropertiesCustomMetric = ind
case *slo.IndicatorPropertiesHistogram:
ret.IndicatorPropertiesHistogram = ind
default:
return ret, fmt.Errorf("unknown indicator type: %T", ind)
}
return ret, nil
}
func sloResponseToModel(spaceID string, res *slo.SloResponse) *models.Slo {
if res == nil {
return nil
}
return &models.Slo{
SloID: res.Id,
SpaceID: spaceID,
Name: res.Name,
Description: res.Description,
BudgetingMethod: res.BudgetingMethod,
Indicator: res.Indicator,
TimeWindow: res.TimeWindow,
Objective: res.Objective,
Settings: &res.Settings,
GroupBy: transformGroupByFromResponse(res.GroupBy),
Tags: res.Tags,
}
}
func transformGroupBy(groupBy []string, supportsGroupByList bool) *slo.SloResponseGroupBy {
if groupBy == nil {
return nil
}
if !supportsGroupByList && len(groupBy) > 0 {
return &slo.SloResponseGroupBy{
String: &groupBy[0],
}
}
return &slo.SloResponseGroupBy{ArrayOfString: &groupBy}
}
func transformGroupByFromResponse(groupBy slo.SloResponseGroupBy) []string {
if groupBy.String != nil {
return []string{*groupBy.String}
}
if groupBy.ArrayOfString == nil {
return nil
}
return *groupBy.ArrayOfString
}