Alerting: Handle namespace and group query string params in Ruler API (#91533)

* Handle namespace and group query string params in Ruler API

* Use the new namespace and group query params when slashes in names

* Add validation, add group handling in GMA Api

* Move constants

* Use checkForPathSeparator function

* Fix linter issue
This commit is contained in:
Konrad Lalik
2024-08-13 08:31:07 +02:00
committed by GitHub
parent d54fdba322
commit b67bcdb9b8
7 changed files with 252 additions and 82 deletions
+17 -6
View File
@@ -85,8 +85,14 @@ func (srv RulerSrv) RouteDeleteAlertRules(c *contextmodel.ReqContext, namespaceU
"namespaceUid",
namespace.UID,
}
if group != "" {
loggerCtx = append(loggerCtx, "group", group)
finalGroup, err := getRulesGroupParam(c, group)
if err != nil {
return ErrResp(http.StatusBadRequest, err, "")
}
if finalGroup != "" {
loggerCtx = append(loggerCtx, "group", finalGroup)
}
logger := srv.log.New(loggerCtx...)
@@ -97,11 +103,11 @@ func (srv RulerSrv) RouteDeleteAlertRules(c *contextmodel.ReqContext, namespaceU
err = srv.xactManager.InTransaction(c.Req.Context(), func(ctx context.Context) error {
deletionCandidates := map[ngmodels.AlertRuleGroupKey]ngmodels.RulesGroup{}
if group != "" {
if finalGroup != "" {
key := ngmodels.AlertRuleGroupKey{
OrgID: c.SignedInUser.GetOrgID(),
NamespaceUID: namespace.UID,
RuleGroup: group,
RuleGroup: finalGroup,
}
rules, err := srv.getAuthorizedRuleGroup(ctx, c, key)
if err != nil {
@@ -218,9 +224,14 @@ func (srv RulerSrv) RouteGetRulesGroupConfig(c *contextmodel.ReqContext, namespa
return toNamespaceErrorResponse(err)
}
finalRuleGroup, err := getRulesGroupParam(c, ruleGroup)
if err != nil {
return ErrResp(http.StatusBadRequest, err, "")
}
rules, err := srv.getAuthorizedRuleGroup(c.Req.Context(), c, ngmodels.AlertRuleGroupKey{
OrgID: c.SignedInUser.GetOrgID(),
RuleGroup: ruleGroup,
RuleGroup: finalRuleGroup,
NamespaceUID: namespace.UID,
})
if err != nil {
@@ -234,7 +245,7 @@ func (srv RulerSrv) RouteGetRulesGroupConfig(c *contextmodel.ReqContext, namespa
result := apimodels.RuleGroupConfigResponse{
// nolint:staticcheck
GettableRuleGroupConfig: toGettableRuleGroupConfig(ruleGroup, rules, provenanceRecords),
GettableRuleGroupConfig: toGettableRuleGroupConfig(finalRuleGroup, rules, provenanceRecords),
}
return response.JSON(http.StatusAccepted, result)
}
+47 -7
View File
@@ -68,12 +68,18 @@ func (r *LotexRuler) RouteDeleteNamespaceRulesConfig(ctx *contextmodel.ReqContex
if err != nil {
return ErrResp(500, err, "")
}
finalNamespace, err := getRulesNamespaceParam(ctx, namespace)
if err != nil {
return ErrResp(http.StatusBadRequest, err, "")
}
return r.requester.withReq(
ctx,
http.MethodDelete,
withPath(
*ctx.Req.URL,
fmt.Sprintf("%s/%s", legacyRulerPrefix, url.PathEscape(namespace)),
fmt.Sprintf("%s/%s", legacyRulerPrefix, url.PathEscape(finalNamespace)),
),
nil,
messageExtractor,
@@ -86,6 +92,17 @@ func (r *LotexRuler) RouteDeleteRuleGroupConfig(ctx *contextmodel.ReqContext, na
if err != nil {
return ErrResp(500, err, "")
}
finalNamespace, err := getRulesNamespaceParam(ctx, namespace)
if err != nil {
return ErrResp(http.StatusBadRequest, err, "")
}
finalGroup, err := getRulesGroupParam(ctx, group)
if err != nil {
return ErrResp(http.StatusBadRequest, err, "")
}
return r.requester.withReq(
ctx,
http.MethodDelete,
@@ -94,8 +111,8 @@ func (r *LotexRuler) RouteDeleteRuleGroupConfig(ctx *contextmodel.ReqContext, na
fmt.Sprintf(
"%s/%s/%s",
legacyRulerPrefix,
url.PathEscape(namespace),
url.PathEscape(group),
url.PathEscape(finalNamespace),
url.PathEscape(finalGroup),
),
),
nil,
@@ -109,6 +126,12 @@ func (r *LotexRuler) RouteGetNamespaceRulesConfig(ctx *contextmodel.ReqContext,
if err != nil {
return ErrResp(500, err, "")
}
finalNamespace, err := getRulesNamespaceParam(ctx, namespace)
if err != nil {
return ErrResp(http.StatusBadRequest, err, "")
}
return r.requester.withReq(
ctx,
http.MethodGet,
@@ -117,7 +140,7 @@ func (r *LotexRuler) RouteGetNamespaceRulesConfig(ctx *contextmodel.ReqContext,
fmt.Sprintf(
"%s/%s",
legacyRulerPrefix,
url.PathEscape(namespace),
url.PathEscape(finalNamespace),
),
),
nil,
@@ -131,6 +154,17 @@ func (r *LotexRuler) RouteGetRulegGroupConfig(ctx *contextmodel.ReqContext, name
if err != nil {
return ErrResp(500, err, "")
}
finalNamespace, err := getRulesNamespaceParam(ctx, namespace)
if err != nil {
return ErrResp(http.StatusBadRequest, err, "")
}
finalGroup, err := getRulesGroupParam(ctx, group)
if err != nil {
return ErrResp(http.StatusBadRequest, err, "")
}
return r.requester.withReq(
ctx,
http.MethodGet,
@@ -139,8 +173,8 @@ func (r *LotexRuler) RouteGetRulegGroupConfig(ctx *contextmodel.ReqContext, name
fmt.Sprintf(
"%s/%s/%s",
legacyRulerPrefix,
url.PathEscape(namespace),
url.PathEscape(group),
url.PathEscape(finalNamespace),
url.PathEscape(finalGroup),
),
),
nil,
@@ -177,7 +211,13 @@ func (r *LotexRuler) RoutePostNameRulesConfig(ctx *contextmodel.ReqContext, conf
if err != nil {
return ErrResp(500, err, "Failed marshal rule group")
}
u := withPath(*ctx.Req.URL, fmt.Sprintf("%s/%s", legacyRulerPrefix, ns))
finalNamespace, err := getRulesNamespaceParam(ctx, ns)
if err != nil {
return ErrResp(http.StatusBadRequest, err, "")
}
u := withPath(*ctx.Req.URL, fmt.Sprintf("%s/%s", legacyRulerPrefix, url.PathEscape(finalNamespace)))
return r.requester.withReq(ctx, http.MethodPost, u, bytes.NewBuffer(yml), jsonExtractor(nil), nil)
}
+31
View File
@@ -26,6 +26,11 @@ import (
"github.com/grafana/grafana/pkg/web"
)
const (
namespaceQueryTag = "QUERY_NAMESPACE"
groupQueryTag = "QUERY_GROUP"
)
var searchRegex = regexp.MustCompile(`\{(\w+)\}`)
func toMacaronPath(path string) string {
@@ -240,3 +245,29 @@ func getHash(hashSlice []string) uint64 {
hash := sum.Sum64()
return hash
}
func getRulesGroupParam(ctx *contextmodel.ReqContext, pathGroup string) (string, error) {
if pathGroup == groupQueryTag {
group := ctx.Query("group")
if group == "" {
return "", fmt.Errorf("group query parameter is empty")
}
return group, nil
}
return pathGroup, nil
}
func getRulesNamespaceParam(ctx *contextmodel.ReqContext, pathNamespace string) (string, error) {
if pathNamespace == namespaceQueryTag {
namespace := ctx.Query("namespace")
if namespace == "" {
return "", fmt.Errorf("namespace query parameter is empty")
}
return namespace, nil
}
return pathNamespace, nil
}