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:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user