Alerting: Foundations of historian app. (#114463)
We have two historians in alerting - alert state and notification. The intention of this app is to provide query capabilities for both. In this initial commit, the existing /history API is simply cloned to the new app. It is identical except that it will send Kubernetes-style error responses instead of Grafana-style. This approach was taken to implement the new app more iteratively - ideally we would define a new API, but this requires quite a significant overhaul of the backend code.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
package historian
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/api"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
type Historian interface {
|
||||
Query(ctx context.Context, query models.HistoryQuery) (*data.Frame, error)
|
||||
}
|
||||
|
||||
type handlers struct {
|
||||
historian Historian
|
||||
}
|
||||
|
||||
func (h handlers) GetAlertStateHistoryHandler(ctx context.Context, writer app.CustomRouteResponseWriter, request *app.CustomRouteRequest) error {
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return &apierrors.StatusError{
|
||||
ErrStatus: metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusUnauthorized,
|
||||
Message: "authentication required",
|
||||
}}
|
||||
}
|
||||
|
||||
query, err := api.ParseHistoryQuery(user.GetOrgID(), user, request.URL.Query())
|
||||
if err != nil {
|
||||
return &apierrors.StatusError{
|
||||
ErrStatus: metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusBadRequest,
|
||||
Message: err.Error(),
|
||||
}}
|
||||
}
|
||||
|
||||
frame, err := h.historian.Query(ctx, query)
|
||||
if err != nil {
|
||||
return &apierrors.StatusError{
|
||||
ErrStatus: metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: err.Error(),
|
||||
}}
|
||||
}
|
||||
|
||||
writer.Header().Add("Content-Type", "application/json")
|
||||
writer.WriteHeader(http.StatusOK)
|
||||
return json.NewEncoder(writer).Encode(frame)
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
package historian
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
type mockHistorian struct {
|
||||
queryFunc func(ctx context.Context, query models.HistoryQuery) (*data.Frame, error)
|
||||
}
|
||||
|
||||
func (m *mockHistorian) Query(ctx context.Context, query models.HistoryQuery) (*data.Frame, error) {
|
||||
if m.queryFunc != nil {
|
||||
return m.queryFunc(ctx, query)
|
||||
}
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
type mockResponseWriter struct {
|
||||
*httptest.ResponseRecorder
|
||||
headers http.Header
|
||||
}
|
||||
|
||||
func newMockResponseWriter() *mockResponseWriter {
|
||||
return &mockResponseWriter{
|
||||
ResponseRecorder: httptest.NewRecorder(),
|
||||
headers: make(http.Header),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockResponseWriter) Header() http.Header {
|
||||
return m.headers
|
||||
}
|
||||
|
||||
func TestGetAlertStateHistoryHandler(t *testing.T) {
|
||||
t.Run("returns data frame when query succeeds", func(t *testing.T) {
|
||||
now := time.Now()
|
||||
testFrame := data.NewFrame("test",
|
||||
data.NewField("Time", nil, []time.Time{now, now.Add(time.Second)}),
|
||||
data.NewField("Line", nil, []string{"alert fired", "alert resolved"}),
|
||||
)
|
||||
|
||||
mock := &mockHistorian{
|
||||
queryFunc: func(ctx context.Context, query models.HistoryQuery) (*data.Frame, error) {
|
||||
assert.Equal(t, int64(123), query.OrgID)
|
||||
assert.NotNil(t, query.SignedInUser)
|
||||
return testFrame, nil
|
||||
},
|
||||
}
|
||||
|
||||
h := handlers{historian: mock}
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{
|
||||
OrgID: 123,
|
||||
})
|
||||
|
||||
writer := newMockResponseWriter()
|
||||
req := &app.CustomRouteRequest{
|
||||
URL: &url.URL{RawQuery: ""},
|
||||
}
|
||||
|
||||
err := h.GetAlertStateHistoryHandler(ctx, writer, req)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
assert.Equal(t, "application/json", writer.headers.Get("Content-Type"))
|
||||
|
||||
var result *data.Frame
|
||||
err = json.Unmarshal(writer.Body.Bytes(), &result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "test", result.Name)
|
||||
assert.Equal(t, 2, result.Rows())
|
||||
})
|
||||
|
||||
t.Run("passes query parameters to historian", func(t *testing.T) {
|
||||
testFrame := data.NewFrame("test",
|
||||
data.NewField("Time", nil, []time.Time{time.Now()}),
|
||||
data.NewField("Line", nil, []string{"test"}),
|
||||
)
|
||||
|
||||
var capturedQuery models.HistoryQuery
|
||||
mock := &mockHistorian{
|
||||
queryFunc: func(ctx context.Context, query models.HistoryQuery) (*data.Frame, error) {
|
||||
capturedQuery = query
|
||||
return testFrame, nil
|
||||
},
|
||||
}
|
||||
|
||||
h := handlers{historian: mock}
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{OrgID: 99})
|
||||
|
||||
params := url.Values{}
|
||||
params.Set("ruleUID", "rule-123")
|
||||
params.Set("dashboardUID", "dash-456")
|
||||
params.Set("panelID", "7")
|
||||
params.Set("from", "1000")
|
||||
params.Set("to", "2000")
|
||||
params.Set("limit", "50")
|
||||
|
||||
writer := newMockResponseWriter()
|
||||
req := &app.CustomRouteRequest{
|
||||
URL: &url.URL{RawQuery: params.Encode()},
|
||||
}
|
||||
|
||||
err := h.GetAlertStateHistoryHandler(ctx, writer, req)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "rule-123", capturedQuery.RuleUID)
|
||||
assert.Equal(t, "dash-456", capturedQuery.DashboardUID)
|
||||
assert.Equal(t, int64(7), capturedQuery.PanelID)
|
||||
assert.Equal(t, time.Unix(1000, 0), capturedQuery.From)
|
||||
assert.Equal(t, time.Unix(2000, 0), capturedQuery.To)
|
||||
assert.Equal(t, 50, capturedQuery.Limit)
|
||||
})
|
||||
|
||||
t.Run("handles label matchers in query", func(t *testing.T) {
|
||||
testFrame := data.NewFrame("test",
|
||||
data.NewField("Time", nil, []time.Time{time.Now()}),
|
||||
data.NewField("Line", nil, []string{"test"}),
|
||||
)
|
||||
|
||||
var capturedQuery models.HistoryQuery
|
||||
mock := &mockHistorian{
|
||||
queryFunc: func(ctx context.Context, query models.HistoryQuery) (*data.Frame, error) {
|
||||
capturedQuery = query
|
||||
return testFrame, nil
|
||||
},
|
||||
}
|
||||
|
||||
h := handlers{historian: mock}
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{OrgID: 1})
|
||||
|
||||
params := url.Values{}
|
||||
params.Add("labels", `env=prod`)
|
||||
params.Add("labels", `region=us-west`)
|
||||
|
||||
writer := newMockResponseWriter()
|
||||
req := &app.CustomRouteRequest{
|
||||
URL: &url.URL{RawQuery: params.Encode()},
|
||||
}
|
||||
|
||||
err := h.GetAlertStateHistoryHandler(ctx, writer, req)
|
||||
|
||||
require.NoError(t, err)
|
||||
if len(capturedQuery.Labels) > 0 {
|
||||
assert.NotEmpty(t, capturedQuery.Labels)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("returns unauthorized when no user in context", func(t *testing.T) {
|
||||
h := handlers{historian: &mockHistorian{}}
|
||||
ctx := context.Background()
|
||||
|
||||
writer := newMockResponseWriter()
|
||||
req := &app.CustomRouteRequest{
|
||||
URL: &url.URL{RawQuery: ""},
|
||||
}
|
||||
|
||||
err := h.GetAlertStateHistoryHandler(ctx, writer, req)
|
||||
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "authentication required")
|
||||
})
|
||||
|
||||
t.Run("returns internal error when historian query fails", func(t *testing.T) {
|
||||
mock := &mockHistorian{
|
||||
queryFunc: func(ctx context.Context, query models.HistoryQuery) (*data.Frame, error) {
|
||||
return nil, errors.New("database connection failed")
|
||||
},
|
||||
}
|
||||
|
||||
h := handlers{historian: mock}
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{OrgID: 1})
|
||||
|
||||
writer := newMockResponseWriter()
|
||||
req := &app.CustomRouteRequest{
|
||||
URL: &url.URL{RawQuery: ""},
|
||||
}
|
||||
|
||||
err := h.GetAlertStateHistoryHandler(ctx, writer, req)
|
||||
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "database connection failed")
|
||||
})
|
||||
|
||||
t.Run("returns empty frame when no results", func(t *testing.T) {
|
||||
emptyFrame := data.NewFrame("empty")
|
||||
|
||||
mock := &mockHistorian{
|
||||
queryFunc: func(ctx context.Context, query models.HistoryQuery) (*data.Frame, error) {
|
||||
return emptyFrame, nil
|
||||
},
|
||||
}
|
||||
|
||||
h := handlers{historian: mock}
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{OrgID: 1})
|
||||
|
||||
writer := newMockResponseWriter()
|
||||
req := &app.CustomRouteRequest{
|
||||
URL: &url.URL{RawQuery: ""},
|
||||
}
|
||||
|
||||
err := h.GetAlertStateHistoryHandler(ctx, writer, req)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
var result *data.Frame
|
||||
err = json.Unmarshal(writer.Body.Bytes(), &result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Rows())
|
||||
})
|
||||
|
||||
t.Run("encodes complex data frame with multiple fields", func(t *testing.T) {
|
||||
now := time.Now()
|
||||
complexFrame := data.NewFrame("complex",
|
||||
data.NewField("Time", nil, []time.Time{now}),
|
||||
data.NewField("Line", nil, []string{"alert fired"}),
|
||||
data.NewField("Value", nil, []float64{42.5}),
|
||||
data.NewField("Labels", nil, []string{`{"env":"prod"}`}),
|
||||
)
|
||||
|
||||
mock := &mockHistorian{
|
||||
queryFunc: func(ctx context.Context, query models.HistoryQuery) (*data.Frame, error) {
|
||||
return complexFrame, nil
|
||||
},
|
||||
}
|
||||
|
||||
h := handlers{historian: mock}
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{OrgID: 1})
|
||||
|
||||
writer := newMockResponseWriter()
|
||||
req := &app.CustomRouteRequest{
|
||||
URL: &url.URL{RawQuery: ""},
|
||||
}
|
||||
|
||||
err := h.GetAlertStateHistoryHandler(ctx, writer, req)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
var result *data.Frame
|
||||
err = json.Unmarshal(writer.Body.Bytes(), &result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 4, len(result.Fields))
|
||||
assert.Equal(t, 1, result.Rows())
|
||||
})
|
||||
}
|
||||
|
||||
func TestParseHistoryQueryIntegration(t *testing.T) {
|
||||
t.Run("parses all supported query parameters", func(t *testing.T) {
|
||||
testFrame := data.NewFrame("test",
|
||||
data.NewField("Time", nil, []time.Time{time.Now()}),
|
||||
data.NewField("Line", nil, []string{"test"}),
|
||||
)
|
||||
|
||||
var capturedQuery models.HistoryQuery
|
||||
mock := &mockHistorian{
|
||||
queryFunc: func(ctx context.Context, query models.HistoryQuery) (*data.Frame, error) {
|
||||
capturedQuery = query
|
||||
return testFrame, nil
|
||||
},
|
||||
}
|
||||
|
||||
h := handlers{historian: mock}
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{OrgID: 5})
|
||||
|
||||
params := url.Values{}
|
||||
params.Set("ruleUID", "test-rule")
|
||||
params.Set("dashboardUID", "test-dash")
|
||||
params.Set("panelID", "3")
|
||||
params.Set("from", "1609459200")
|
||||
params.Set("to", "1609545600")
|
||||
params.Set("limit", "100")
|
||||
params.Set("current", "alerting")
|
||||
params.Set("previous", "normal")
|
||||
|
||||
writer := newMockResponseWriter()
|
||||
req := &app.CustomRouteRequest{
|
||||
URL: &url.URL{RawQuery: params.Encode()},
|
||||
}
|
||||
|
||||
err := h.GetAlertStateHistoryHandler(ctx, writer, req)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(5), capturedQuery.OrgID)
|
||||
assert.Equal(t, "test-rule", capturedQuery.RuleUID)
|
||||
assert.Equal(t, "test-dash", capturedQuery.DashboardUID)
|
||||
assert.Equal(t, int64(3), capturedQuery.PanelID)
|
||||
assert.Equal(t, time.Unix(1609459200, 0), capturedQuery.From)
|
||||
assert.Equal(t, time.Unix(1609545600, 0), capturedQuery.To)
|
||||
assert.Equal(t, 100, capturedQuery.Limit)
|
||||
assert.Equal(t, "alerting", capturedQuery.Current)
|
||||
assert.Equal(t, "normal", capturedQuery.Previous)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package historian
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
|
||||
"github.com/grafana/grafana/apps/alerting/historian/pkg/apis"
|
||||
historianApp "github.com/grafana/grafana/apps/alerting/historian/pkg/app"
|
||||
historianAppConfig "github.com/grafana/grafana/apps/alerting/historian/pkg/app/config"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
var (
|
||||
_ appsdkapiserver.AppInstaller = (*AlertingHistorianAppInstaller)(nil)
|
||||
)
|
||||
|
||||
type AlertingHistorianAppInstaller struct {
|
||||
appsdkapiserver.AppInstaller
|
||||
}
|
||||
|
||||
func RegisterAppInstaller(
|
||||
cfg *setting.Cfg,
|
||||
ng *ngalert.AlertNG,
|
||||
) (*AlertingHistorianAppInstaller, error) {
|
||||
if ng.IsDisabled() {
|
||||
log.New("app-registry").Info("Skipping Kubernetes Alerting Historian apiserver (historian.alerting.grafana.app): Unified Alerting is disabled")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
installer := &AlertingHistorianAppInstaller{}
|
||||
|
||||
handlers := &handlers{
|
||||
historian: ng.Api.Historian,
|
||||
}
|
||||
|
||||
appSpecificConfig := historianAppConfig.RuntimeConfig{
|
||||
GetAlertStateHistoryHandler: handlers.GetAlertStateHistoryHandler,
|
||||
}
|
||||
|
||||
provider := simple.NewAppProvider(apis.LocalManifest(), appSpecificConfig, historianApp.New)
|
||||
|
||||
appConfig := app.Config{
|
||||
KubeConfig: restclient.Config{},
|
||||
ManifestData: *apis.LocalManifest().ManifestData,
|
||||
SpecificConfig: appSpecificConfig,
|
||||
}
|
||||
|
||||
i, err := appsdkapiserver.NewDefaultAppInstaller(provider, appConfig, &apis.GoTypeAssociator{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
installer.AppInstaller = i
|
||||
return installer, nil
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/advisor"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/historian"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/rules"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/annotation"
|
||||
@@ -42,6 +43,7 @@ func ProvideAppInstallers(
|
||||
annotationAppInstaller *annotation.AnnotationAppInstaller,
|
||||
exampleAppInstaller *example.ExampleAppInstaller,
|
||||
advisorAppInstaller *advisor.AdvisorAppInstaller,
|
||||
alertingHistorianAppInstaller *historian.AlertingHistorianAppInstaller,
|
||||
) []appsdkapiserver.AppInstaller {
|
||||
installers := []appsdkapiserver.AppInstaller{
|
||||
playlistAppInstaller,
|
||||
@@ -75,6 +77,10 @@ func ProvideAppInstallers(
|
||||
if features.IsEnabledGlobally(featuremgmt.FlagGrafanaAdvisor) {
|
||||
installers = append(installers, advisorAppInstaller)
|
||||
}
|
||||
//nolint:staticcheck // not yet migrated to OpenFeature
|
||||
if features.IsEnabledGlobally(featuremgmt.FlagKubernetesAlertingHistorian) && alertingHistorianAppInstaller != nil {
|
||||
installers = append(installers, alertingHistorianAppInstaller)
|
||||
}
|
||||
|
||||
return installers
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/registry/apps/advisor"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/historian"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/rules"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/annotation"
|
||||
@@ -25,6 +26,8 @@ func TestProvideAppInstallers_Table(t *testing.T) {
|
||||
annotationAppInstaller := &annotation.AnnotationAppInstaller{}
|
||||
exampleAppInstaller := &example.ExampleAppInstaller{}
|
||||
advisorAppInstaller := &advisor.AdvisorAppInstaller{}
|
||||
historianAppInstaller := &historian.AlertingHistorianAppInstaller{}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
flags []any
|
||||
@@ -40,7 +43,7 @@ func TestProvideAppInstallers_Table(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
features := featuremgmt.WithFeatures(tt.flags...)
|
||||
got := ProvideAppInstallers(features, playlistInstaller, pluginsInstaller, nil, tt.rulesInst, correlationsAppInstaller, notificationsAppInstaller, nil, annotationAppInstaller, exampleAppInstaller, advisorAppInstaller)
|
||||
got := ProvideAppInstallers(features, playlistInstaller, pluginsInstaller, nil, tt.rulesInst, correlationsAppInstaller, notificationsAppInstaller, nil, annotationAppInstaller, exampleAppInstaller, advisorAppInstaller, historianAppInstaller)
|
||||
if tt.expectRulesApp {
|
||||
require.Contains(t, got, tt.rulesInst)
|
||||
} else {
|
||||
|
||||
@@ -3,6 +3,7 @@ package appregistry
|
||||
import (
|
||||
"github.com/google/wire"
|
||||
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/historian"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/rules"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/annotation"
|
||||
@@ -25,6 +26,7 @@ var WireSet = wire.NewSet(
|
||||
correlations.RegisterAppInstaller,
|
||||
rules.RegisterAppInstaller,
|
||||
notifications.RegisterAppInstaller,
|
||||
historian.RegisterAppInstaller,
|
||||
logsdrilldown.RegisterAppInstaller,
|
||||
annotation.RegisterAppInstaller,
|
||||
example.RegisterAppInstaller,
|
||||
|
||||
Generated
+11
-2
@@ -80,6 +80,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/registry/apis/userstorage"
|
||||
"github.com/grafana/grafana/pkg/registry/apps"
|
||||
advisor2 "github.com/grafana/grafana/pkg/registry/apps/advisor"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/historian"
|
||||
notifications2 "github.com/grafana/grafana/pkg/registry/apps/alerting/notifications"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/rules"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/annotation"
|
||||
@@ -825,7 +826,11 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v2 := appregistry.ProvideAppInstallers(featureToggles, playlistAppInstaller, appInstaller, shortURLAppInstaller, alertingRulesAppInstaller, correlationsAppInstaller, alertingNotificationsAppInstaller, logsDrilldownAppInstaller, annotationAppInstaller, exampleAppInstaller, advisorAppInstaller)
|
||||
alertingHistorianAppInstaller, err := historian.RegisterAppInstaller(cfg, alertNG)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v2 := appregistry.ProvideAppInstallers(featureToggles, playlistAppInstaller, appInstaller, shortURLAppInstaller, alertingRulesAppInstaller, correlationsAppInstaller, alertingNotificationsAppInstaller, logsDrilldownAppInstaller, annotationAppInstaller, exampleAppInstaller, advisorAppInstaller, alertingHistorianAppInstaller)
|
||||
builderMetrics := builder.ProvideBuilderMetrics(registerer)
|
||||
apiserverService, err := apiserver.ProvideService(cfg, featureToggles, routeRegisterImpl, tracingService, serverLockService, sqlStore, kvStore, middlewareHandler, scopedPluginDatasourceProvider, plugincontextProvider, pluginstoreService, dualwriteService, resourceClient, inlineSecureValueSupport, eventualRestConfigProvider, v, eventualRestConfigProvider, registerer, aggregatorRunner, v2, builderMetrics)
|
||||
if err != nil {
|
||||
@@ -1475,7 +1480,11 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v2 := appregistry.ProvideAppInstallers(featureToggles, playlistAppInstaller, appInstaller, shortURLAppInstaller, alertingRulesAppInstaller, correlationsAppInstaller, alertingNotificationsAppInstaller, logsDrilldownAppInstaller, annotationAppInstaller, exampleAppInstaller, advisorAppInstaller)
|
||||
alertingHistorianAppInstaller, err := historian.RegisterAppInstaller(cfg, alertNG)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v2 := appregistry.ProvideAppInstallers(featureToggles, playlistAppInstaller, appInstaller, shortURLAppInstaller, alertingRulesAppInstaller, correlationsAppInstaller, alertingNotificationsAppInstaller, logsDrilldownAppInstaller, annotationAppInstaller, exampleAppInstaller, advisorAppInstaller, alertingHistorianAppInstaller)
|
||||
builderMetrics := builder.ProvideBuilderMetrics(registerer)
|
||||
apiserverService, err := apiserver.ProvideService(cfg, featureToggles, routeRegisterImpl, tracingService, serverLockService, sqlStore, kvStore, middlewareHandler, scopedPluginDatasourceProvider, plugincontextProvider, pluginstoreService, dualwriteService, resourceClient, inlineSecureValueSupport, eventualRestConfigProvider, v, eventualRestConfigProvider, registerer, aggregatorRunner, v2, builderMetrics)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -3633,4 +3633,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user