fix(observability): remove invalid fields match and match_regex from main route in alert_config (#915)
* fix: remove invalid `match` and `match_regex` from main route in alert_config - deprecated `match` and `match_regex` in child routes - add new `matchers` field
This commit is contained in:
parent
433efa001c
commit
65c6106ea9
9 changed files with 157 additions and 111 deletions
|
|
@ -133,8 +133,6 @@ Read-Only:
|
|||
- `group_by` (List of String) The labels by which incoming alerts are grouped together. For example, multiple alerts coming in for cluster=A and alertname=LatencyHigh would be batched into a single group. To aggregate by all possible labels use the special value '...' as the sole label name, for example: group_by: ['...']. This effectively disables aggregation entirely, passing through all alerts as-is. This is unlikely to be what you want, unless you have a very low alert volume or your upstream notification system performs its own grouping.
|
||||
- `group_interval` (String) How long to wait before sending a notification about new alerts that are added to a group of alerts for which an initial notification has already been sent. (Usually ~5m or more.)
|
||||
- `group_wait` (String) How long to initially wait to send a notification for a group of alerts. Allows to wait for an inhibiting alert to arrive or collect more initial alerts for the same group. (Usually ~0s to few minutes.) .
|
||||
- `match` (Map of String) A set of equality matchers an alert has to fulfill to match the node.
|
||||
- `match_regex` (Map of String) A set of regex-matchers an alert has to fulfill to match the node.
|
||||
- `receiver` (String) The name of the receiver to route the alerts to.
|
||||
- `repeat_interval` (String) How long to wait before sending a notification again if it has already been sent successfully for an alert. (Usually ~3h or more).
|
||||
- `routes` (Attributes List) List of child routes. (see [below for nested schema](#nestedatt--alert_config--route--routes))
|
||||
|
|
@ -147,7 +145,8 @@ Read-Only:
|
|||
- `group_by` (List of String) The labels by which incoming alerts are grouped together. For example, multiple alerts coming in for cluster=A and alertname=LatencyHigh would be batched into a single group. To aggregate by all possible labels use the special value '...' as the sole label name, for example: group_by: ['...']. This effectively disables aggregation entirely, passing through all alerts as-is. This is unlikely to be what you want, unless you have a very low alert volume or your upstream notification system performs its own grouping.
|
||||
- `group_interval` (String) How long to wait before sending a notification about new alerts that are added to a group of alerts for which an initial notification has already been sent. (Usually ~5m or more.)
|
||||
- `group_wait` (String) How long to initially wait to send a notification for a group of alerts. Allows to wait for an inhibiting alert to arrive or collect more initial alerts for the same group. (Usually ~0s to few minutes.)
|
||||
- `match` (Map of String) A set of equality matchers an alert has to fulfill to match the node.
|
||||
- `match_regex` (Map of String) A set of regex-matchers an alert has to fulfill to match the node.
|
||||
- `match` (Map of String, Deprecated) A set of equality matchers an alert has to fulfill to match the node. This field is deprecated and will be removed after 10th March 2026, use `matchers` in the `routes` instead
|
||||
- `match_regex` (Map of String, Deprecated) A set of regex-matchers an alert has to fulfill to match the node. This field is deprecated and will be removed after 10th March 2026, use `matchers` in the `routes` instead
|
||||
- `matchers` (List of String) A list of matchers that an alert has to fulfill to match the node. A matcher is a string with a syntax inspired by PromQL and OpenMetrics.
|
||||
- `receiver` (String) The name of the receiver to route the alerts to.
|
||||
- `repeat_interval` (String) How long to wait before sending a notification again if it has already been sent successfully for an alert. (Usually ~3h or more).
|
||||
|
|
|
|||
|
|
@ -142,8 +142,6 @@ Optional:
|
|||
- `group_by` (List of String) The labels by which incoming alerts are grouped together. For example, multiple alerts coming in for cluster=A and alertname=LatencyHigh would be batched into a single group. To aggregate by all possible labels use the special value '...' as the sole label name, for example: group_by: ['...']. This effectively disables aggregation entirely, passing through all alerts as-is. This is unlikely to be what you want, unless you have a very low alert volume or your upstream notification system performs its own grouping.
|
||||
- `group_interval` (String) How long to wait before sending a notification about new alerts that are added to a group of alerts for which an initial notification has already been sent. (Usually ~5m or more.)
|
||||
- `group_wait` (String) How long to initially wait to send a notification for a group of alerts. Allows to wait for an inhibiting alert to arrive or collect more initial alerts for the same group. (Usually ~0s to few minutes.)
|
||||
- `match` (Map of String) A set of equality matchers an alert has to fulfill to match the node.
|
||||
- `match_regex` (Map of String) A set of regex-matchers an alert has to fulfill to match the node.
|
||||
- `repeat_interval` (String) How long to wait before sending a notification again if it has already been sent successfully for an alert. (Usually ~3h or more).
|
||||
- `routes` (Attributes List) List of child routes. (see [below for nested schema](#nestedatt--alert_config--route--routes))
|
||||
|
||||
|
|
@ -159,8 +157,9 @@ Optional:
|
|||
- `group_by` (List of String) The labels by which incoming alerts are grouped together. For example, multiple alerts coming in for cluster=A and alertname=LatencyHigh would be batched into a single group. To aggregate by all possible labels use the special value '...' as the sole label name, for example: group_by: ['...']. This effectively disables aggregation entirely, passing through all alerts as-is. This is unlikely to be what you want, unless you have a very low alert volume or your upstream notification system performs its own grouping.
|
||||
- `group_interval` (String) How long to wait before sending a notification about new alerts that are added to a group of alerts for which an initial notification has already been sent. (Usually ~5m or more.)
|
||||
- `group_wait` (String) How long to initially wait to send a notification for a group of alerts. Allows to wait for an inhibiting alert to arrive or collect more initial alerts for the same group. (Usually ~0s to few minutes.)
|
||||
- `match` (Map of String) A set of equality matchers an alert has to fulfill to match the node.
|
||||
- `match_regex` (Map of String) A set of regex-matchers an alert has to fulfill to match the node.
|
||||
- `match` (Map of String, Deprecated) A set of equality matchers an alert has to fulfill to match the node. This field is deprecated and will be removed after 10th March 2026, use `matchers` in the `routes` instead
|
||||
- `match_regex` (Map of String, Deprecated) A set of regex-matchers an alert has to fulfill to match the node. This field is deprecated and will be removed after 10th March 2026, use `matchers` in the `routes` instead
|
||||
- `matchers` (List of String) A list of matchers that an alert has to fulfill to match the node. A matcher is a string with a syntax inspired by PromQL and OpenMetrics.
|
||||
- `repeat_interval` (String) How long to wait before sending a notification again if it has already been sent successfully for an alert. (Usually ~3h or more).
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -296,16 +296,6 @@ func (d *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques
|
|||
Description: "How long to initially wait to send a notification for a group of alerts. Allows to wait for an inhibiting alert to arrive or collect more initial alerts for the same group. (Usually ~0s to few minutes.) .",
|
||||
Computed: true,
|
||||
},
|
||||
"match": schema.MapAttribute{
|
||||
Description: "A set of equality matchers an alert has to fulfill to match the node.",
|
||||
Computed: true,
|
||||
ElementType: types.StringType,
|
||||
},
|
||||
"match_regex": schema.MapAttribute{
|
||||
Description: "A set of regex-matchers an alert has to fulfill to match the node.",
|
||||
Computed: true,
|
||||
ElementType: types.StringType,
|
||||
},
|
||||
"receiver": schema.StringAttribute{
|
||||
Description: "The name of the receiver to route the alerts to.",
|
||||
Computed: true,
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import (
|
|||
)
|
||||
|
||||
// Currently, due to incorrect types in the API, the maximum recursion level for child routes is set to 1.
|
||||
// Once this is fixed, the value should be set to 10.
|
||||
// Once this is fixed, the value should be set to 10 and toRoutePayload needs to be adjusted, to support it.
|
||||
const childRouteMaxRecursionLevel = 1
|
||||
|
||||
// Ensure the implementation satisfies the expected interfaces.
|
||||
|
|
@ -118,12 +118,26 @@ var globalConfigurationTypes = map[string]attr.Type{
|
|||
}
|
||||
|
||||
// Struct corresponding to Model.AlertConfig.route
|
||||
type routeModel struct {
|
||||
type mainRouteModel struct {
|
||||
GroupBy types.List `tfsdk:"group_by"`
|
||||
GroupInterval types.String `tfsdk:"group_interval"`
|
||||
GroupWait types.String `tfsdk:"group_wait"`
|
||||
Match types.Map `tfsdk:"match"`
|
||||
Receiver types.String `tfsdk:"receiver"`
|
||||
RepeatInterval types.String `tfsdk:"repeat_interval"`
|
||||
Routes types.List `tfsdk:"routes"`
|
||||
}
|
||||
|
||||
// Struct corresponding to Model.AlertConfig.route
|
||||
// This is used to map the routes between the mainRouteModel and the last level of recursion of the routes field
|
||||
type routeModelMiddle struct {
|
||||
GroupBy types.List `tfsdk:"group_by"`
|
||||
GroupInterval types.String `tfsdk:"group_interval"`
|
||||
GroupWait types.String `tfsdk:"group_wait"`
|
||||
// Deprecated: Match is deprecated and will be removed after 10th March 2026. Use Matchers instead
|
||||
Match types.Map `tfsdk:"match"`
|
||||
// Deprecated: MatchRegex is deprecated and will be removed after 10th March 2026. Use Matchers instead
|
||||
MatchRegex types.Map `tfsdk:"match_regex"`
|
||||
Matchers types.List `tfsdk:"matchers"`
|
||||
Receiver types.String `tfsdk:"receiver"`
|
||||
RepeatInterval types.String `tfsdk:"repeat_interval"`
|
||||
Routes types.List `tfsdk:"routes"`
|
||||
|
|
@ -132,11 +146,14 @@ type routeModel struct {
|
|||
// Struct corresponding to Model.AlertConfig.route but without the recursive routes field
|
||||
// This is used to map the last level of recursion of the routes field
|
||||
type routeModelNoRoutes struct {
|
||||
GroupBy types.List `tfsdk:"group_by"`
|
||||
GroupInterval types.String `tfsdk:"group_interval"`
|
||||
GroupWait types.String `tfsdk:"group_wait"`
|
||||
Match types.Map `tfsdk:"match"`
|
||||
GroupBy types.List `tfsdk:"group_by"`
|
||||
GroupInterval types.String `tfsdk:"group_interval"`
|
||||
GroupWait types.String `tfsdk:"group_wait"`
|
||||
// Deprecated: Match is deprecated and will be removed after 10th March 2026. Use Matchers instead
|
||||
Match types.Map `tfsdk:"match"`
|
||||
// Deprecated: MatchRegex is deprecated and will be removed after 10th March 2026. Use Matchers instead
|
||||
MatchRegex types.Map `tfsdk:"match_regex"`
|
||||
Matchers types.List `tfsdk:"matchers"`
|
||||
Receiver types.String `tfsdk:"receiver"`
|
||||
RepeatInterval types.String `tfsdk:"repeat_interval"`
|
||||
}
|
||||
|
|
@ -145,8 +162,6 @@ var routeTypes = map[string]attr.Type{
|
|||
"group_by": types.ListType{ElemType: types.StringType},
|
||||
"group_interval": types.StringType,
|
||||
"group_wait": types.StringType,
|
||||
"match": types.MapType{ElemType: types.StringType},
|
||||
"match_regex": types.MapType{ElemType: types.StringType},
|
||||
"receiver": types.StringType,
|
||||
"repeat_interval": types.StringType,
|
||||
"routes": types.ListType{ElemType: getRouteListType()},
|
||||
|
|
@ -218,8 +233,9 @@ var routeDescriptions = map[string]string{
|
|||
"group_by": "The labels by which incoming alerts are grouped together. For example, multiple alerts coming in for cluster=A and alertname=LatencyHigh would be batched into a single group. To aggregate by all possible labels use the special value '...' as the sole label name, for example: group_by: ['...']. This effectively disables aggregation entirely, passing through all alerts as-is. This is unlikely to be what you want, unless you have a very low alert volume or your upstream notification system performs its own grouping.",
|
||||
"group_interval": "How long to wait before sending a notification about new alerts that are added to a group of alerts for which an initial notification has already been sent. (Usually ~5m or more.)",
|
||||
"group_wait": "How long to initially wait to send a notification for a group of alerts. Allows to wait for an inhibiting alert to arrive or collect more initial alerts for the same group. (Usually ~0s to few minutes.)",
|
||||
"match": "A set of equality matchers an alert has to fulfill to match the node.",
|
||||
"match_regex": "A set of regex-matchers an alert has to fulfill to match the node.",
|
||||
"match": "A set of equality matchers an alert has to fulfill to match the node. This field is deprecated and will be removed after 10th March 2026, use `matchers` in the `routes` instead",
|
||||
"match_regex": "A set of regex-matchers an alert has to fulfill to match the node. This field is deprecated and will be removed after 10th March 2026, use `matchers` in the `routes` instead",
|
||||
"matchers": "A list of matchers that an alert has to fulfill to match the node. A matcher is a string with a syntax inspired by PromQL and OpenMetrics.",
|
||||
"receiver": "The name of the receiver to route the alerts to.",
|
||||
"repeat_interval": "How long to wait before sending a notification again if it has already been sent successfully for an alert. (Usually ~3h or more).",
|
||||
"routes": "List of child routes.",
|
||||
|
|
@ -241,6 +257,7 @@ func getRouteListTypeAux(level, limit int) types.ObjectType {
|
|||
"group_wait": types.StringType,
|
||||
"match": types.MapType{ElemType: types.StringType},
|
||||
"match_regex": types.MapType{ElemType: types.StringType},
|
||||
"matchers": types.ListType{ElemType: types.StringType},
|
||||
"receiver": types.StringType,
|
||||
"repeat_interval": types.StringType,
|
||||
}
|
||||
|
|
@ -290,13 +307,21 @@ func getRouteNestedObjectAux(isDatasource bool, level, limit int) schema.ListNes
|
|||
},
|
||||
},
|
||||
"match": schema.MapAttribute{
|
||||
Description: routeDescriptions["match"],
|
||||
Optional: !isDatasource,
|
||||
Computed: isDatasource,
|
||||
ElementType: types.StringType,
|
||||
Description: routeDescriptions["match"],
|
||||
DeprecationMessage: "Use `matchers` in the `routes` instead.",
|
||||
Optional: !isDatasource,
|
||||
Computed: isDatasource,
|
||||
ElementType: types.StringType,
|
||||
},
|
||||
"match_regex": schema.MapAttribute{
|
||||
Description: routeDescriptions["match_regex"],
|
||||
Description: routeDescriptions["match_regex"],
|
||||
DeprecationMessage: "Use `matchers` in the `routes` instead.",
|
||||
Optional: !isDatasource,
|
||||
Computed: isDatasource,
|
||||
ElementType: types.StringType,
|
||||
},
|
||||
"matchers": schema.ListAttribute{
|
||||
Description: routeDescriptions["matchers"],
|
||||
Optional: !isDatasource,
|
||||
Computed: isDatasource,
|
||||
ElementType: types.StringType,
|
||||
|
|
@ -701,16 +726,6 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
|
|||
stringplanmodifier.UseStateForUnknown(),
|
||||
},
|
||||
},
|
||||
"match": schema.MapAttribute{
|
||||
Description: routeDescriptions["match"],
|
||||
Optional: true,
|
||||
ElementType: types.StringType,
|
||||
},
|
||||
"match_regex": schema.MapAttribute{
|
||||
Description: routeDescriptions["match_regex"],
|
||||
Optional: true,
|
||||
ElementType: types.StringType,
|
||||
},
|
||||
"receiver": schema.StringAttribute{
|
||||
Description: routeDescriptions["receiver"],
|
||||
Required: true,
|
||||
|
|
@ -1521,8 +1536,6 @@ func getMockAlertConfig(ctx context.Context) (alertConfigModel, error) {
|
|||
"group_wait": types.StringValue("30s"),
|
||||
"group_interval": types.StringValue("5m"),
|
||||
"repeat_interval": types.StringValue("4h"),
|
||||
"match": types.MapNull(types.StringType),
|
||||
"match_regex": types.MapNull(types.StringType),
|
||||
"routes": types.ListNull(getRouteListType()),
|
||||
})
|
||||
if diags.HasError() {
|
||||
|
|
@ -1735,16 +1748,6 @@ func mapRouteToAttributes(ctx context.Context, route *observability.Route) (attr
|
|||
return types.ObjectNull(routeTypes), fmt.Errorf("mapping group by: %w", core.DiagsToError(diags))
|
||||
}
|
||||
|
||||
matchModel, diags := types.MapValueFrom(ctx, types.StringType, route.Match)
|
||||
if diags.HasError() {
|
||||
return types.ObjectNull(routeTypes), fmt.Errorf("mapping match: %w", core.DiagsToError(diags))
|
||||
}
|
||||
|
||||
matchRegexModel, diags := types.MapValueFrom(ctx, types.StringType, route.MatchRe)
|
||||
if diags.HasError() {
|
||||
return types.ObjectNull(routeTypes), fmt.Errorf("mapping match regex: %w", core.DiagsToError(diags))
|
||||
}
|
||||
|
||||
childRoutes, err := mapChildRoutesToAttributes(ctx, route.Routes)
|
||||
if err != nil {
|
||||
return types.ObjectNull(routeTypes), fmt.Errorf("mapping child routes: %w", err)
|
||||
|
|
@ -1754,8 +1757,6 @@ func mapRouteToAttributes(ctx context.Context, route *observability.Route) (attr
|
|||
"group_by": groupByModel,
|
||||
"group_interval": types.StringPointerValue(route.GroupInterval),
|
||||
"group_wait": types.StringPointerValue(route.GroupWait),
|
||||
"match": matchModel,
|
||||
"match_regex": matchRegexModel,
|
||||
"receiver": types.StringPointerValue(route.Receiver),
|
||||
"repeat_interval": types.StringPointerValue(route.RepeatInterval),
|
||||
"routes": childRoutes,
|
||||
|
|
@ -1796,12 +1797,18 @@ func mapChildRoutesToAttributes(ctx context.Context, routes *[]observability.Rou
|
|||
return nullList, fmt.Errorf("mapping match regex: %w", core.DiagsToError(diags))
|
||||
}
|
||||
|
||||
matchersModel, diags := types.ListValueFrom(ctx, types.StringType, route.Matchers)
|
||||
if diags.HasError() {
|
||||
return nullList, fmt.Errorf("mapping matchers: %w", core.DiagsToError(diags))
|
||||
}
|
||||
|
||||
routeMap := map[string]attr.Value{
|
||||
"group_by": groupByModel,
|
||||
"group_interval": types.StringPointerValue(route.GroupInterval),
|
||||
"group_wait": types.StringPointerValue(route.GroupWait),
|
||||
"match": matchModel,
|
||||
"match_regex": matchRegexModel,
|
||||
"matchers": matchersModel,
|
||||
"receiver": types.StringPointerValue(route.Receiver),
|
||||
"repeat_interval": types.StringPointerValue(route.RepeatInterval),
|
||||
}
|
||||
|
|
@ -1921,7 +1928,7 @@ func toUpdateAlertConfigPayload(ctx context.Context, model *alertConfigModel) (*
|
|||
return nil, fmt.Errorf("mapping receivers: %w", err)
|
||||
}
|
||||
|
||||
routeTF := routeModel{}
|
||||
routeTF := mainRouteModel{}
|
||||
diags := model.Route.As(ctx, &routeTF, basetypes.ObjectAsOptions{})
|
||||
if diags.HasError() {
|
||||
return nil, fmt.Errorf("mapping route: %w", core.DiagsToError(diags))
|
||||
|
|
@ -2023,14 +2030,12 @@ func toReceiverPayload(ctx context.Context, model *alertConfigModel) (*[]observa
|
|||
return &receivers, nil
|
||||
}
|
||||
|
||||
func toRoutePayload(ctx context.Context, routeTF *routeModel) (*observability.UpdateAlertConfigsPayloadRoute, error) {
|
||||
func toRoutePayload(ctx context.Context, routeTF *mainRouteModel) (*observability.UpdateAlertConfigsPayloadRoute, error) {
|
||||
if routeTF == nil {
|
||||
return nil, fmt.Errorf("nil route model")
|
||||
}
|
||||
|
||||
var groupByPayload *[]string
|
||||
var matchPayload *map[string]interface{}
|
||||
var matchRegexPayload *map[string]interface{}
|
||||
var childRoutesPayload *[]observability.UpdateAlertConfigsPayloadRouteRoutesInner
|
||||
|
||||
if !routeTF.GroupBy.IsNull() && !routeTF.GroupBy.IsUnknown() {
|
||||
|
|
@ -2041,24 +2046,8 @@ func toRoutePayload(ctx context.Context, routeTF *routeModel) (*observability.Up
|
|||
}
|
||||
}
|
||||
|
||||
if !routeTF.Match.IsNull() && !routeTF.Match.IsUnknown() {
|
||||
matchMap, err := conversion.ToStringInterfaceMap(ctx, routeTF.Match)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("mapping match: %w", err)
|
||||
}
|
||||
matchPayload = &matchMap
|
||||
}
|
||||
|
||||
if !routeTF.MatchRegex.IsNull() && !routeTF.MatchRegex.IsUnknown() {
|
||||
matchRegexMap, err := conversion.ToStringInterfaceMap(ctx, routeTF.MatchRegex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("mapping match regex: %w", err)
|
||||
}
|
||||
matchRegexPayload = &matchRegexMap
|
||||
}
|
||||
|
||||
if !routeTF.Routes.IsNull() && !routeTF.Routes.IsUnknown() {
|
||||
childRoutes := []routeModel{}
|
||||
childRoutes := []routeModelMiddle{}
|
||||
diags := routeTF.Routes.ElementsAs(ctx, &childRoutes, false)
|
||||
if diags.HasError() {
|
||||
// If there is an error, we will try to map the child routes as if they are the last child routes
|
||||
|
|
@ -2070,12 +2059,13 @@ func toRoutePayload(ctx context.Context, routeTF *routeModel) (*observability.Up
|
|||
return nil, fmt.Errorf("mapping child routes: %w", core.DiagsToError(diags))
|
||||
}
|
||||
for i := range lastChildRoutes {
|
||||
childRoute := routeModel{
|
||||
childRoute := routeModelMiddle{
|
||||
GroupBy: lastChildRoutes[i].GroupBy,
|
||||
GroupInterval: lastChildRoutes[i].GroupInterval,
|
||||
GroupWait: lastChildRoutes[i].GroupWait,
|
||||
Match: lastChildRoutes[i].Match,
|
||||
MatchRegex: lastChildRoutes[i].MatchRegex,
|
||||
Matchers: lastChildRoutes[i].Matchers,
|
||||
Receiver: lastChildRoutes[i].Receiver,
|
||||
RepeatInterval: lastChildRoutes[i].RepeatInterval,
|
||||
Routes: types.ListNull(getRouteListType()),
|
||||
|
|
@ -2087,11 +2077,11 @@ func toRoutePayload(ctx context.Context, routeTF *routeModel) (*observability.Up
|
|||
childRoutesList := []observability.UpdateAlertConfigsPayloadRouteRoutesInner{}
|
||||
for i := range childRoutes {
|
||||
childRoute := childRoutes[i]
|
||||
childRoutePayload, err := toRoutePayload(ctx, &childRoute)
|
||||
childRoutePayload, err := toChildRoutePayload(ctx, &childRoute)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("mapping child route: %w", err)
|
||||
}
|
||||
childRoutesList = append(childRoutesList, *toChildRoutePayload(childRoutePayload))
|
||||
childRoutesList = append(childRoutesList, *childRoutePayload)
|
||||
}
|
||||
|
||||
childRoutesPayload = &childRoutesList
|
||||
|
|
@ -2101,28 +2091,63 @@ func toRoutePayload(ctx context.Context, routeTF *routeModel) (*observability.Up
|
|||
GroupBy: groupByPayload,
|
||||
GroupInterval: conversion.StringValueToPointer(routeTF.GroupInterval),
|
||||
GroupWait: conversion.StringValueToPointer(routeTF.GroupWait),
|
||||
Match: matchPayload,
|
||||
MatchRe: matchRegexPayload,
|
||||
Receiver: conversion.StringValueToPointer(routeTF.Receiver),
|
||||
RepeatInterval: conversion.StringValueToPointer(routeTF.RepeatInterval),
|
||||
Routes: childRoutesPayload,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toChildRoutePayload(in *observability.UpdateAlertConfigsPayloadRoute) *observability.UpdateAlertConfigsPayloadRouteRoutesInner {
|
||||
if in == nil {
|
||||
return nil
|
||||
func toChildRoutePayload(ctx context.Context, routeTF *routeModelMiddle) (*observability.UpdateAlertConfigsPayloadRouteRoutesInner, error) {
|
||||
if routeTF == nil {
|
||||
return nil, fmt.Errorf("nil route model")
|
||||
}
|
||||
|
||||
var groupByPayload, matchersPayload *[]string
|
||||
var matchPayload, matchRegexPayload *map[string]interface{}
|
||||
|
||||
if !utils.IsUndefined(routeTF.GroupBy) {
|
||||
groupByPayload = &[]string{}
|
||||
diags := routeTF.GroupBy.ElementsAs(ctx, groupByPayload, false)
|
||||
if diags.HasError() {
|
||||
return nil, fmt.Errorf("mapping group by: %w", core.DiagsToError(diags))
|
||||
}
|
||||
}
|
||||
|
||||
if !utils.IsUndefined(routeTF.Match) {
|
||||
matchMap, err := conversion.ToStringInterfaceMap(ctx, routeTF.Match)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("mapping match: %w", err)
|
||||
}
|
||||
matchPayload = &matchMap
|
||||
}
|
||||
|
||||
if !utils.IsUndefined(routeTF.MatchRegex) {
|
||||
matchRegexMap, err := conversion.ToStringInterfaceMap(ctx, routeTF.MatchRegex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("mapping match regex: %w", err)
|
||||
}
|
||||
matchRegexPayload = &matchRegexMap
|
||||
}
|
||||
|
||||
if !utils.IsUndefined(routeTF.Matchers) {
|
||||
matchersList, err := conversion.StringListToPointer(routeTF.Matchers)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("mapping match regex: %w", err)
|
||||
}
|
||||
matchersPayload = matchersList
|
||||
}
|
||||
|
||||
return &observability.UpdateAlertConfigsPayloadRouteRoutesInner{
|
||||
GroupBy: in.GroupBy,
|
||||
GroupInterval: in.GroupInterval,
|
||||
GroupWait: in.GroupWait,
|
||||
Match: in.Match,
|
||||
MatchRe: in.MatchRe,
|
||||
Receiver: in.Receiver,
|
||||
RepeatInterval: in.RepeatInterval,
|
||||
GroupBy: groupByPayload,
|
||||
GroupInterval: conversion.StringValueToPointer(routeTF.GroupInterval),
|
||||
GroupWait: conversion.StringValueToPointer(routeTF.GroupWait),
|
||||
Match: matchPayload,
|
||||
MatchRe: matchRegexPayload,
|
||||
Matchers: matchersPayload,
|
||||
Receiver: conversion.StringValueToPointer(routeTF.Receiver),
|
||||
RepeatInterval: conversion.StringValueToPointer(routeTF.RepeatInterval),
|
||||
// Routes not currently supported
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toGlobalConfigPayload(ctx context.Context, model *alertConfigModel) (*observability.UpdateAlertConfigsPayloadGlobal, error) {
|
||||
|
|
|
|||
|
|
@ -68,8 +68,6 @@ func fixtureRouteModel() basetypes.ObjectValue {
|
|||
}),
|
||||
"group_interval": types.StringValue("1m"),
|
||||
"group_wait": types.StringValue("1m"),
|
||||
"match": types.MapValueMust(types.StringType, map[string]attr.Value{"key": types.StringValue("value")}),
|
||||
"match_regex": types.MapValueMust(types.StringType, map[string]attr.Value{"key": types.StringValue("value")}),
|
||||
"receiver": types.StringValue("name"),
|
||||
"repeat_interval": types.StringValue("1m"),
|
||||
// "routes": types.ListNull(getRouteListType()),
|
||||
|
|
@ -79,10 +77,14 @@ func fixtureRouteModel() basetypes.ObjectValue {
|
|||
types.StringValue("label1"),
|
||||
types.StringValue("label2"),
|
||||
}),
|
||||
"group_interval": types.StringValue("1m"),
|
||||
"group_wait": types.StringValue("1m"),
|
||||
"match": types.MapValueMust(types.StringType, map[string]attr.Value{"key": types.StringValue("value")}),
|
||||
"match_regex": types.MapValueMust(types.StringType, map[string]attr.Value{"key": types.StringValue("value")}),
|
||||
"group_interval": types.StringValue("1m"),
|
||||
"group_wait": types.StringValue("1m"),
|
||||
"match": types.MapValueMust(types.StringType, map[string]attr.Value{"key": types.StringValue("value")}),
|
||||
"match_regex": types.MapValueMust(types.StringType, map[string]attr.Value{"key": types.StringValue("value")}),
|
||||
"matchers": types.ListValueMust(types.StringType, []attr.Value{
|
||||
types.StringValue("matcher1"),
|
||||
types.StringValue("matcher2"),
|
||||
}),
|
||||
"receiver": types.StringValue("name"),
|
||||
"repeat_interval": types.StringValue("1m"),
|
||||
}),
|
||||
|
|
@ -95,8 +97,6 @@ func fixtureNullRouteModel() basetypes.ObjectValue {
|
|||
"group_by": types.ListNull(types.StringType),
|
||||
"group_interval": types.StringNull(),
|
||||
"group_wait": types.StringNull(),
|
||||
"match": types.MapNull(types.StringType),
|
||||
"match_regex": types.MapNull(types.StringType),
|
||||
"receiver": types.StringNull(),
|
||||
"repeat_interval": types.StringNull(),
|
||||
"routes": types.ListNull(getRouteListType()),
|
||||
|
|
@ -171,8 +171,6 @@ func fixtureRoutePayload() *observability.UpdateAlertConfigsPayloadRoute {
|
|||
GroupBy: utils.Ptr([]string{"label1", "label2"}),
|
||||
GroupInterval: utils.Ptr("1m"),
|
||||
GroupWait: utils.Ptr("1m"),
|
||||
Match: &map[string]interface{}{"key": "value"},
|
||||
MatchRe: &map[string]interface{}{"key": "value"},
|
||||
Receiver: utils.Ptr("name"),
|
||||
RepeatInterval: utils.Ptr("1m"),
|
||||
Routes: &[]observability.UpdateAlertConfigsPayloadRouteRoutesInner{
|
||||
|
|
@ -182,6 +180,7 @@ func fixtureRoutePayload() *observability.UpdateAlertConfigsPayloadRoute {
|
|||
GroupWait: utils.Ptr("1m"),
|
||||
Match: &map[string]interface{}{"key": "value"},
|
||||
MatchRe: &map[string]interface{}{"key": "value"},
|
||||
Matchers: &[]string{"matcher1", "matcher2"},
|
||||
Receiver: utils.Ptr("name"),
|
||||
RepeatInterval: utils.Ptr("1m"),
|
||||
},
|
||||
|
|
@ -246,6 +245,7 @@ func fixtureRouteResponse() *observability.Route {
|
|||
GroupWait: utils.Ptr("1m"),
|
||||
Match: &map[string]string{"key": "value"},
|
||||
MatchRe: &map[string]string{"key": "value"},
|
||||
Matchers: &[]string{"matcher1", "matcher2"},
|
||||
Receiver: utils.Ptr("name"),
|
||||
RepeatInterval: utils.Ptr("1m"),
|
||||
Routes: &[]observability.RouteSerializer{
|
||||
|
|
@ -255,6 +255,7 @@ func fixtureRouteResponse() *observability.Route {
|
|||
GroupWait: utils.Ptr("1m"),
|
||||
Match: &map[string]string{"key": "value"},
|
||||
MatchRe: &map[string]string{"key": "value"},
|
||||
Matchers: &[]string{"matcher1", "matcher2"},
|
||||
Receiver: utils.Ptr("name"),
|
||||
RepeatInterval: utils.Ptr("1m"),
|
||||
},
|
||||
|
|
@ -300,13 +301,21 @@ func fixtureRouteAttributeSchema(route *schema.ListNestedAttribute, isDatasource
|
|||
},
|
||||
},
|
||||
"match": schema.MapAttribute{
|
||||
Description: routeDescriptions["match"],
|
||||
Optional: !isDatasource,
|
||||
Computed: isDatasource,
|
||||
ElementType: types.StringType,
|
||||
Description: routeDescriptions["match"],
|
||||
DeprecationMessage: "Use `matchers` in the `routes` instead.",
|
||||
Optional: !isDatasource,
|
||||
Computed: isDatasource,
|
||||
ElementType: types.StringType,
|
||||
},
|
||||
"match_regex": schema.MapAttribute{
|
||||
Description: routeDescriptions["match_regex"],
|
||||
Description: routeDescriptions["match_regex"],
|
||||
DeprecationMessage: "Use `matchers` in the `routes` instead.",
|
||||
Optional: !isDatasource,
|
||||
Computed: isDatasource,
|
||||
ElementType: types.StringType,
|
||||
},
|
||||
"matchers": schema.ListAttribute{
|
||||
Description: routeDescriptions["matchers"],
|
||||
Optional: !isDatasource,
|
||||
Computed: isDatasource,
|
||||
ElementType: types.StringType,
|
||||
|
|
@ -1484,6 +1493,7 @@ func TestGetRouteListTypeAux(t *testing.T) {
|
|||
"group_wait": types.StringType,
|
||||
"match": types.MapType{ElemType: types.StringType},
|
||||
"match_regex": types.MapType{ElemType: types.StringType},
|
||||
"matchers": types.ListType{ElemType: types.StringType},
|
||||
"receiver": types.StringType,
|
||||
"repeat_interval": types.StringType,
|
||||
},
|
||||
|
|
@ -1500,6 +1510,7 @@ func TestGetRouteListTypeAux(t *testing.T) {
|
|||
"group_wait": types.StringType,
|
||||
"match": types.MapType{ElemType: types.StringType},
|
||||
"match_regex": types.MapType{ElemType: types.StringType},
|
||||
"matchers": types.ListType{ElemType: types.StringType},
|
||||
"receiver": types.StringType,
|
||||
"repeat_interval": types.StringType,
|
||||
"routes": types.ListType{ElemType: types.ObjectType{AttrTypes: map[string]attr.Type{
|
||||
|
|
@ -1508,6 +1519,7 @@ func TestGetRouteListTypeAux(t *testing.T) {
|
|||
"group_wait": types.StringType,
|
||||
"match": types.MapType{ElemType: types.StringType},
|
||||
"match_regex": types.MapType{ElemType: types.StringType},
|
||||
"matchers": types.ListType{ElemType: types.StringType},
|
||||
"receiver": types.StringType,
|
||||
"repeat_interval": types.StringType,
|
||||
}}},
|
||||
|
|
@ -1525,6 +1537,7 @@ func TestGetRouteListTypeAux(t *testing.T) {
|
|||
"group_wait": types.StringType,
|
||||
"match": types.MapType{ElemType: types.StringType},
|
||||
"match_regex": types.MapType{ElemType: types.StringType},
|
||||
"matchers": types.ListType{ElemType: types.StringType},
|
||||
"receiver": types.StringType,
|
||||
"repeat_interval": types.StringType,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ var testConfigVarsMax = config.Variables{
|
|||
"smtp_smart_host": config.StringVariable("smtp.gmail.com:587"),
|
||||
"match": config.StringVariable("alert1"),
|
||||
"match_regex": config.StringVariable("alert1"),
|
||||
"matchers": config.StringVariable("instance =~ \".*\""),
|
||||
// logalertgroup
|
||||
"logalertgroup_for_time": config.StringVariable("60s"),
|
||||
"logalertgroup_label": config.StringVariable("label1"),
|
||||
|
|
@ -134,6 +135,7 @@ func configVarsMaxUpdated() config.Variables {
|
|||
tempConfig["webhook_configs_url"] = config.StringVariable("https://chat.googleapis.com/api")
|
||||
tempConfig["ms_teams"] = config.StringVariable("false")
|
||||
tempConfig["google_chat"] = config.StringVariable("true")
|
||||
tempConfig["matchers"] = config.StringVariable("instance =~ \"my.*\"")
|
||||
return tempConfig
|
||||
}
|
||||
|
||||
|
|
@ -529,6 +531,8 @@ func TestAccResourceMax(t *testing.T) {
|
|||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.route.routes.0.repeat_interval", testutil.ConvertConfigVariable(testConfigVarsMax["repeat_interval"])),
|
||||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.route.routes.0.match.match1", testutil.ConvertConfigVariable(testConfigVarsMax["match"])),
|
||||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.route.routes.0.match_regex.match_regex1", testutil.ConvertConfigVariable(testConfigVarsMax["match_regex"])),
|
||||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.route.routes.0.matchers.0", testutil.ConvertConfigVariable(testConfigVarsMax["matchers"])),
|
||||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.route.routes.0.matchers.#", "1"),
|
||||
|
||||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.global.opsgenie_api_key", testutil.ConvertConfigVariable(testConfigVarsMax["opsgenie_api_key"])),
|
||||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.global.opsgenie_api_url", testutil.ConvertConfigVariable(testConfigVarsMax["opsgenie_api_url"])),
|
||||
|
|
@ -692,6 +696,8 @@ func TestAccResourceMax(t *testing.T) {
|
|||
resource.TestCheckResourceAttr("data.stackit_observability_instance.instance", "alert_config.route.routes.0.repeat_interval", testutil.ConvertConfigVariable(testConfigVarsMax["repeat_interval"])),
|
||||
resource.TestCheckResourceAttr("data.stackit_observability_instance.instance", "alert_config.route.routes.0.match.match1", testutil.ConvertConfigVariable(testConfigVarsMax["match"])),
|
||||
resource.TestCheckResourceAttr("data.stackit_observability_instance.instance", "alert_config.route.routes.0.match_regex.match_regex1", testutil.ConvertConfigVariable(testConfigVarsMax["match_regex"])),
|
||||
resource.TestCheckResourceAttr("data.stackit_observability_instance.instance", "alert_config.route.routes.0.matchers.0", testutil.ConvertConfigVariable(testConfigVarsMax["matchers"])),
|
||||
resource.TestCheckResourceAttr("data.stackit_observability_instance.instance", "alert_config.route.routes.0.matchers.#", "1"),
|
||||
|
||||
resource.TestCheckResourceAttr("data.stackit_observability_instance.instance", "alert_config.global.opsgenie_api_key", testutil.ConvertConfigVariable(testConfigVarsMax["opsgenie_api_key"])),
|
||||
resource.TestCheckResourceAttr("data.stackit_observability_instance.instance", "alert_config.global.opsgenie_api_url", testutil.ConvertConfigVariable(testConfigVarsMax["opsgenie_api_url"])),
|
||||
|
|
@ -916,6 +922,8 @@ func TestAccResourceMax(t *testing.T) {
|
|||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.route.routes.0.repeat_interval", testutil.ConvertConfigVariable(testConfigVarsMax["repeat_interval"])),
|
||||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.route.routes.0.match.match1", testutil.ConvertConfigVariable(testConfigVarsMax["match"])),
|
||||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.route.routes.0.match_regex.match_regex1", testutil.ConvertConfigVariable(testConfigVarsMax["match_regex"])),
|
||||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.route.routes.0.matchers.0", testutil.ConvertConfigVariable(configVarsMaxUpdated()["matchers"])),
|
||||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.route.routes.0.matchers.#", "1"),
|
||||
|
||||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.global.opsgenie_api_key", testutil.ConvertConfigVariable(testConfigVarsMax["opsgenie_api_key"])),
|
||||
resource.TestCheckResourceAttr("stackit_observability_instance.instance", "alert_config.global.opsgenie_api_url", testutil.ConvertConfigVariable(testConfigVarsMax["opsgenie_api_url"])),
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ variable "smtp_from" {}
|
|||
variable "smtp_smart_host" {}
|
||||
variable "match" {}
|
||||
variable "match_regex" {}
|
||||
variable "matchers" {}
|
||||
|
||||
variable "logalertgroup_name" {}
|
||||
variable "logalertgroup_alert" {}
|
||||
|
|
@ -151,6 +152,9 @@ resource "stackit_observability_instance" "instance" {
|
|||
match_regex = {
|
||||
match_regex1 = var.match_regex
|
||||
}
|
||||
matchers = [
|
||||
var.matchers
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -556,7 +556,10 @@ func ConvertConfigVariable(variable config.Variable) string {
|
|||
tmpByteArray, _ := variable.MarshalJSON()
|
||||
// In case the variable is a string, the quotes should be removed
|
||||
if tmpByteArray[0] == '"' && tmpByteArray[len(tmpByteArray)-1] == '"' {
|
||||
return string(tmpByteArray[1 : len(tmpByteArray)-1])
|
||||
result := string(tmpByteArray[1 : len(tmpByteArray)-1])
|
||||
// Replace escaped quotes which where added MarshalJSON
|
||||
rawString := strings.ReplaceAll(result, `\"`, `"`)
|
||||
return rawString
|
||||
}
|
||||
return string(tmpByteArray)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@ func TestConvertConfigVariable(t *testing.T) {
|
|||
variable: config.IntegerVariable(10),
|
||||
want: "10",
|
||||
},
|
||||
{
|
||||
name: "quoted string",
|
||||
variable: config.StringVariable(`instance =~ ".*"`),
|
||||
want: `instance =~ ".*"`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue