|
|
|
@ -2,26 +2,57 @@ package api |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"fmt" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/api/response" |
|
|
|
|
"github.com/grafana/grafana/pkg/models" |
|
|
|
|
"github.com/grafana/grafana/pkg/services/datasources" |
|
|
|
|
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" |
|
|
|
|
"github.com/prometheus/client_golang/prometheus" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
GrafanaBackend = "grafana" |
|
|
|
|
ProxyBackend = "proxy" // metric cardinality is too high to enumerate all non-grafana backends
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// ForkedRuler will validate and proxy requests to the correct backend type depending on the datasource.
|
|
|
|
|
type ForkedRuler struct { |
|
|
|
|
LotexRuler, GrafanaRuler RulerApiService |
|
|
|
|
DatasourceCache datasources.CacheService |
|
|
|
|
|
|
|
|
|
// metrics
|
|
|
|
|
duration *prometheus.HistogramVec |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewForkedRuler implements a set of routes that proxy to various Cortex Ruler-compatible backends.
|
|
|
|
|
func NewForkedRuler(datasourceCache datasources.CacheService, lotex, grafana RulerApiService) *ForkedRuler { |
|
|
|
|
return &ForkedRuler{ |
|
|
|
|
func NewForkedRuler(datasourceCache datasources.CacheService, lotex, grafana RulerApiService, reg prometheus.Registerer) *ForkedRuler { |
|
|
|
|
r := &ForkedRuler{ |
|
|
|
|
LotexRuler: lotex, |
|
|
|
|
GrafanaRuler: grafana, |
|
|
|
|
DatasourceCache: datasourceCache, |
|
|
|
|
duration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ |
|
|
|
|
Namespace: "grafana", |
|
|
|
|
Name: "alerting_ruler_api_duration_seconds", |
|
|
|
|
Help: "Histogram of latencies affecting the Unified Alerting Ruler API", |
|
|
|
|
Buckets: prometheus.DefBuckets, |
|
|
|
|
}, []string{"backend", "status"}), |
|
|
|
|
} |
|
|
|
|
if reg != nil { |
|
|
|
|
reg.MustRegister( |
|
|
|
|
r.duration, |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
return r |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (r *ForkedRuler) instrument(backend string, fn func() response.Response) response.Response { |
|
|
|
|
start := time.Now() |
|
|
|
|
resp := fn() |
|
|
|
|
r.duration. |
|
|
|
|
WithLabelValues(backend, fmt.Sprint(resp.Status())). |
|
|
|
|
Observe(time.Since(start).Seconds()) |
|
|
|
|
return resp |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (r *ForkedRuler) RouteDeleteNamespaceRulesConfig(ctx *models.ReqContext) response.Response { |
|
|
|
@ -31,9 +62,9 @@ func (r *ForkedRuler) RouteDeleteNamespaceRulesConfig(ctx *models.ReqContext) re |
|
|
|
|
} |
|
|
|
|
switch t { |
|
|
|
|
case apimodels.GrafanaBackend: |
|
|
|
|
return r.GrafanaRuler.RouteDeleteNamespaceRulesConfig(ctx) |
|
|
|
|
return r.instrument(GrafanaBackend, func() response.Response { return r.GrafanaRuler.RouteDeleteNamespaceRulesConfig(ctx) }) |
|
|
|
|
case apimodels.LoTexRulerBackend: |
|
|
|
|
return r.LotexRuler.RouteDeleteNamespaceRulesConfig(ctx) |
|
|
|
|
return r.instrument(ProxyBackend, func() response.Response { return r.LotexRuler.RouteDeleteNamespaceRulesConfig(ctx) }) |
|
|
|
|
default: |
|
|
|
|
return response.Error(400, fmt.Sprintf("unexpected backend type (%v)", t), nil) |
|
|
|
|
} |
|
|
|
@ -46,9 +77,9 @@ func (r *ForkedRuler) RouteDeleteRuleGroupConfig(ctx *models.ReqContext) respons |
|
|
|
|
} |
|
|
|
|
switch t { |
|
|
|
|
case apimodels.GrafanaBackend: |
|
|
|
|
return r.GrafanaRuler.RouteDeleteRuleGroupConfig(ctx) |
|
|
|
|
return r.instrument(GrafanaBackend, func() response.Response { return r.GrafanaRuler.RouteDeleteRuleGroupConfig(ctx) }) |
|
|
|
|
case apimodels.LoTexRulerBackend: |
|
|
|
|
return r.LotexRuler.RouteDeleteRuleGroupConfig(ctx) |
|
|
|
|
return r.instrument(ProxyBackend, func() response.Response { return r.LotexRuler.RouteDeleteRuleGroupConfig(ctx) }) |
|
|
|
|
default: |
|
|
|
|
return response.Error(400, fmt.Sprintf("unexpected backend type (%v)", t), nil) |
|
|
|
|
} |
|
|
|
@ -61,9 +92,9 @@ func (r *ForkedRuler) RouteGetNamespaceRulesConfig(ctx *models.ReqContext) respo |
|
|
|
|
} |
|
|
|
|
switch t { |
|
|
|
|
case apimodels.GrafanaBackend: |
|
|
|
|
return r.GrafanaRuler.RouteGetNamespaceRulesConfig(ctx) |
|
|
|
|
return r.instrument(GrafanaBackend, func() response.Response { return r.GrafanaRuler.RouteGetNamespaceRulesConfig(ctx) }) |
|
|
|
|
case apimodels.LoTexRulerBackend: |
|
|
|
|
return r.LotexRuler.RouteGetNamespaceRulesConfig(ctx) |
|
|
|
|
return r.instrument(ProxyBackend, func() response.Response { return r.LotexRuler.RouteGetNamespaceRulesConfig(ctx) }) |
|
|
|
|
default: |
|
|
|
|
return response.Error(400, fmt.Sprintf("unexpected backend type (%v)", t), nil) |
|
|
|
|
} |
|
|
|
@ -76,9 +107,9 @@ func (r *ForkedRuler) RouteGetRulegGroupConfig(ctx *models.ReqContext) response. |
|
|
|
|
} |
|
|
|
|
switch t { |
|
|
|
|
case apimodels.GrafanaBackend: |
|
|
|
|
return r.GrafanaRuler.RouteGetRulegGroupConfig(ctx) |
|
|
|
|
return r.instrument(GrafanaBackend, func() response.Response { return r.GrafanaRuler.RouteGetRulegGroupConfig(ctx) }) |
|
|
|
|
case apimodels.LoTexRulerBackend: |
|
|
|
|
return r.LotexRuler.RouteGetRulegGroupConfig(ctx) |
|
|
|
|
return r.instrument(ProxyBackend, func() response.Response { return r.LotexRuler.RouteGetRulegGroupConfig(ctx) }) |
|
|
|
|
default: |
|
|
|
|
return response.Error(400, fmt.Sprintf("unexpected backend type (%v)", t), nil) |
|
|
|
|
} |
|
|
|
@ -91,9 +122,9 @@ func (r *ForkedRuler) RouteGetRulesConfig(ctx *models.ReqContext) response.Respo |
|
|
|
|
} |
|
|
|
|
switch t { |
|
|
|
|
case apimodels.GrafanaBackend: |
|
|
|
|
return r.GrafanaRuler.RouteGetRulesConfig(ctx) |
|
|
|
|
return r.instrument(GrafanaBackend, func() response.Response { return r.GrafanaRuler.RouteGetRulesConfig(ctx) }) |
|
|
|
|
case apimodels.LoTexRulerBackend: |
|
|
|
|
return r.LotexRuler.RouteGetRulesConfig(ctx) |
|
|
|
|
return r.instrument(ProxyBackend, func() response.Response { return r.LotexRuler.RouteGetRulesConfig(ctx) }) |
|
|
|
|
default: |
|
|
|
|
return response.Error(400, fmt.Sprintf("unexpected backend type (%v)", t), nil) |
|
|
|
|
} |
|
|
|
@ -120,9 +151,9 @@ func (r *ForkedRuler) RoutePostNameRulesConfig(ctx *models.ReqContext, conf apim |
|
|
|
|
|
|
|
|
|
switch backendType { |
|
|
|
|
case apimodels.GrafanaBackend: |
|
|
|
|
return r.GrafanaRuler.RoutePostNameRulesConfig(ctx, conf) |
|
|
|
|
return r.instrument(GrafanaBackend, func() response.Response { return r.GrafanaRuler.RoutePostNameRulesConfig(ctx, conf) }) |
|
|
|
|
case apimodels.LoTexRulerBackend: |
|
|
|
|
return r.LotexRuler.RoutePostNameRulesConfig(ctx, conf) |
|
|
|
|
return r.instrument(ProxyBackend, func() response.Response { return r.LotexRuler.RoutePostNameRulesConfig(ctx, conf) }) |
|
|
|
|
default: |
|
|
|
|
return response.Error(400, fmt.Sprintf("unexpected backend type (%v)", backendType), nil) |
|
|
|
|
} |
|
|
|
|