mirror of https://github.com/grafana/grafana
api: use alerting headers (#95118)
* api: use alerting headers * improve code, add integration test * better comment * fixed test * merged testspull/93813/head^2
parent
d9bc4f7395
commit
3a719a2cfd
@ -0,0 +1,57 @@ |
|||||||
|
package clientmiddleware |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend" |
||||||
|
"github.com/grafana/grafana/pkg/services/contexthandler" |
||||||
|
ngalertmodels "github.com/grafana/grafana/pkg/services/ngalert/models" |
||||||
|
) |
||||||
|
|
||||||
|
func NewUseAlertHeadersMiddleware() backend.HandlerMiddleware { |
||||||
|
return backend.HandlerMiddlewareFunc(func(next backend.Handler) backend.Handler { |
||||||
|
return &UseAlertHeadersMiddleware{ |
||||||
|
BaseHandler: backend.NewBaseHandler(next), |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
type UseAlertHeadersMiddleware struct { |
||||||
|
backend.BaseHandler |
||||||
|
} |
||||||
|
|
||||||
|
var alertHeaders = []string{ |
||||||
|
"X-Rule-Name", |
||||||
|
"X-Rule-Folder", |
||||||
|
"X-Rule-Source", |
||||||
|
"X-Rule-Type", |
||||||
|
"X-Rule-Version", |
||||||
|
ngalertmodels.FromAlertHeaderName, |
||||||
|
} |
||||||
|
|
||||||
|
func applyAlertHeaders(ctx context.Context, req *backend.QueryDataRequest) { |
||||||
|
reqCtx := contexthandler.FromContext(ctx) |
||||||
|
if reqCtx == nil || reqCtx.Req == nil { |
||||||
|
return |
||||||
|
} |
||||||
|
incomingHeaders := reqCtx.Req.Header |
||||||
|
|
||||||
|
for _, key := range alertHeaders { |
||||||
|
incomingValue := incomingHeaders.Get(key) |
||||||
|
if incomingValue != "" { |
||||||
|
// FromAlert must be set directly, because we need
|
||||||
|
// to keep the incorrect capitalization for backwards-compatibility
|
||||||
|
// reasons. otherwise Go would normalize it to "Fromalert"
|
||||||
|
if key == ngalertmodels.FromAlertHeaderName { |
||||||
|
req.Headers[key] = incomingValue |
||||||
|
} else { |
||||||
|
req.SetHTTPHeader(key, incomingValue) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (m *UseAlertHeadersMiddleware) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { |
||||||
|
applyAlertHeaders(ctx, req) |
||||||
|
return m.BaseHandler.QueryData(ctx, req) |
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
package clientmiddleware |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend" |
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/handlertest" |
||||||
|
"github.com/grafana/grafana/pkg/services/user" |
||||||
|
"github.com/stretchr/testify/require" |
||||||
|
) |
||||||
|
|
||||||
|
func TestUserAlertingHeadersMiddleware(t *testing.T) { |
||||||
|
testQueryDataReq := func(t *testing.T, req *http.Request) *backend.QueryDataRequest { |
||||||
|
cdt := handlertest.NewHandlerMiddlewareTest(t, |
||||||
|
WithReqContext(req, &user.SignedInUser{}), |
||||||
|
handlertest.WithMiddlewares(NewUseAlertHeadersMiddleware()), |
||||||
|
) |
||||||
|
|
||||||
|
pluginCtx := backend.PluginContext{ |
||||||
|
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}, |
||||||
|
} |
||||||
|
|
||||||
|
_, err := cdt.MiddlewareHandler.QueryData(req.Context(), &backend.QueryDataRequest{ |
||||||
|
PluginContext: pluginCtx, |
||||||
|
Headers: map[string]string{}, |
||||||
|
}) |
||||||
|
require.NoError(t, err) |
||||||
|
return cdt.QueryDataReq |
||||||
|
} |
||||||
|
|
||||||
|
t.Run("Handle non-alerting case without problems", func(t *testing.T) { |
||||||
|
req, err := http.NewRequest(http.MethodGet, "/some/thing", nil) |
||||||
|
require.NoError(t, err) |
||||||
|
outReq := testQueryDataReq(t, req) |
||||||
|
|
||||||
|
// special marker
|
||||||
|
require.Equal(t, "", outReq.Headers["FromAlert"]) |
||||||
|
|
||||||
|
// the normal http headers
|
||||||
|
require.Equal(t, "", outReq.GetHTTPHeader("X-Rule-Name")) |
||||||
|
require.Equal(t, "", outReq.GetHTTPHeader("X-Rule-Folder")) |
||||||
|
require.Equal(t, "", outReq.GetHTTPHeader("X-Rule-Source")) |
||||||
|
require.Equal(t, "", outReq.GetHTTPHeader("X-Rule-Type")) |
||||||
|
require.Equal(t, "", outReq.GetHTTPHeader("X-Rule-Version")) |
||||||
|
}) |
||||||
|
|
||||||
|
t.Run("Use Alerting headers when they exist", func(t *testing.T) { |
||||||
|
req, err := http.NewRequest(http.MethodGet, "/some/thing", nil) |
||||||
|
require.NoError(t, err) |
||||||
|
req.Header.Set("Fromalert", "true") |
||||||
|
req.Header.Set("X-Rule-Name", "n1") |
||||||
|
req.Header.Set("X-Rule-Folder", "f1") |
||||||
|
req.Header.Set("X-Rule-Source", "s1") |
||||||
|
req.Header.Set("X-Rule-Type", "t1") |
||||||
|
req.Header.Set("X-Rule-Version", "v1") |
||||||
|
|
||||||
|
outReq := testQueryDataReq(t, req) |
||||||
|
|
||||||
|
// special marker
|
||||||
|
require.Equal(t, "true", outReq.Headers["FromAlert"]) |
||||||
|
|
||||||
|
// normal http headers
|
||||||
|
require.Equal(t, "n1", outReq.GetHTTPHeader("X-Rule-Name")) |
||||||
|
require.Equal(t, "f1", outReq.GetHTTPHeader("X-Rule-Folder")) |
||||||
|
require.Equal(t, "s1", outReq.GetHTTPHeader("X-Rule-Source")) |
||||||
|
require.Equal(t, "t1", outReq.GetHTTPHeader("X-Rule-Type")) |
||||||
|
require.Equal(t, "v1", outReq.GetHTTPHeader("X-Rule-Version")) |
||||||
|
}) |
||||||
|
} |
Loading…
Reference in new issue