38603b1a9e
- The util/converter Prometheus response json parse was not checking for errors while parsing. It now does. In particular, if `[dataproxy]/response_limit` is set in Grafana's config, it will now recognize the limit error. - Fixes #73747 - Adds `jsonitere` package, which wraps json-iterator/go's Iterator's Methods with methods that return errors, so errcheck linting can be relied upon - Impact: - If something was sending malformed JSON to the prometheus or loki datasources, the previous code might have accepted that and partially processed the data - Before there may have been partial data with no error, where as no there may be errors but they will have no partial results, just the error.
136 lines
4.1 KiB
Go
136 lines
4.1 KiB
Go
package prometheus
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/grafana/pkg/api/dtos"
|
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
"github.com/grafana/grafana/pkg/services/datasources"
|
|
"github.com/grafana/grafana/pkg/services/org"
|
|
"github.com/grafana/grafana/pkg/services/user"
|
|
"github.com/grafana/grafana/pkg/tests/testinfra"
|
|
)
|
|
|
|
func TestIntegrationPrometheus(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
|
DisableAnonymous: true,
|
|
})
|
|
|
|
grafanaListeningAddr, testEnv := testinfra.StartGrafanaEnv(t, dir, path)
|
|
ctx := context.Background()
|
|
|
|
u := testinfra.CreateUser(t, testEnv.SQLStore, user.CreateUserCommand{
|
|
DefaultOrgRole: string(org.RoleAdmin),
|
|
Password: "admin",
|
|
Login: "admin",
|
|
})
|
|
|
|
var outgoingRequest *http.Request
|
|
outgoingServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
outgoingRequest = r
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
}))
|
|
t.Cleanup(outgoingServer.Close)
|
|
|
|
jsonData := simplejson.NewFromAny(map[string]interface{}{
|
|
"httpMethod": "post",
|
|
"httpHeaderName1": "X-CUSTOM-HEADER",
|
|
"customQueryParameters": "q1=1&q2=2",
|
|
})
|
|
secureJSONData := map[string]string{
|
|
"basicAuthPassword": "basicAuthPassword",
|
|
"httpHeaderValue1": "custom-header-value",
|
|
}
|
|
|
|
uid := "prometheus"
|
|
_, err := testEnv.Server.HTTPServer.DataSourcesService.AddDataSource(ctx, &datasources.AddDataSourceCommand{
|
|
OrgID: u.OrgID,
|
|
Access: datasources.DS_ACCESS_PROXY,
|
|
Name: "Prometheus",
|
|
Type: datasources.DS_PROMETHEUS,
|
|
UID: uid,
|
|
URL: outgoingServer.URL,
|
|
BasicAuth: true,
|
|
BasicAuthUser: "basicAuthUser",
|
|
JsonData: jsonData,
|
|
SecureJsonData: secureJSONData,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
t.Run("When calling /api/ds/query should set expected headers on outgoing HTTP request", func(t *testing.T) {
|
|
query := simplejson.NewFromAny(map[string]interface{}{
|
|
"datasource": map[string]interface{}{
|
|
"uid": uid,
|
|
},
|
|
"expr": "1",
|
|
"instantQuery": true,
|
|
})
|
|
buf1 := &bytes.Buffer{}
|
|
err = json.NewEncoder(buf1).Encode(dtos.MetricRequest{
|
|
From: "1668078080000",
|
|
To: "1668081680000",
|
|
Queries: []*simplejson.Json{query},
|
|
})
|
|
require.NoError(t, err)
|
|
u := fmt.Sprintf("http://admin:admin@%s/api/ds/query", grafanaListeningAddr)
|
|
// nolint:gosec
|
|
resp, err := http.Post(u, "application/json", buf1)
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() {
|
|
_ = resp.Body.Close()
|
|
})
|
|
|
|
require.NotNil(t, outgoingRequest)
|
|
require.Equal(t, "/api/v1/query_range?q1=1&q2=2", outgoingRequest.URL.String())
|
|
require.Equal(t, "custom-header-value", outgoingRequest.Header.Get("X-CUSTOM-HEADER"))
|
|
username, pwd, ok := outgoingRequest.BasicAuth()
|
|
require.True(t, ok)
|
|
require.Equal(t, "basicAuthUser", username)
|
|
require.Equal(t, "basicAuthPassword", pwd)
|
|
})
|
|
|
|
t.Run("When calling /api/ds/query should set expected headers on outgoing HTTP request", func(t *testing.T) {
|
|
query := simplejson.NewFromAny(map[string]interface{}{
|
|
"datasource": map[string]interface{}{
|
|
"uid": uid,
|
|
},
|
|
"expr": "up",
|
|
"instantQuery": true,
|
|
})
|
|
buf1 := &bytes.Buffer{}
|
|
err = json.NewEncoder(buf1).Encode(dtos.MetricRequest{
|
|
From: "now-1h",
|
|
To: "now",
|
|
Queries: []*simplejson.Json{query},
|
|
})
|
|
require.NoError(t, err)
|
|
u := fmt.Sprintf("http://admin:admin@%s/api/ds/query", grafanaListeningAddr)
|
|
// nolint:gosec
|
|
resp, err := http.Post(u, "application/json", buf1)
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() {
|
|
_ = resp.Body.Close()
|
|
})
|
|
|
|
require.NotNil(t, outgoingRequest)
|
|
require.Equal(t, "/api/v1/query_range", outgoingRequest.URL.Path)
|
|
require.Contains(t, outgoingRequest.URL.String(), "?q1=1&q2=2")
|
|
require.Equal(t, "custom-header-value", outgoingRequest.Header.Get("X-CUSTOM-HEADER"))
|
|
username, pwd, ok := outgoingRequest.BasicAuth()
|
|
require.True(t, ok)
|
|
require.Equal(t, "basicAuthUser", username)
|
|
require.Equal(t, "basicAuthPassword", pwd)
|
|
})
|
|
}
|