Alerting: check upstream response content type in lotex proxy (#34760)

This commit is contained in:
Domas 2021-05-27 14:12:29 +03:00 committed by GitHub
parent 5660bb585f
commit 347273cdea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 13 deletions

View File

@ -14,6 +14,7 @@ import (
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/promql/parser"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/util"
)
@ -112,9 +113,13 @@ func instantQueryResults(resp instantQueryResponse) (eval.Results, error) {
}
}
func instantQueryResultsExtractor(b []byte) (interface{}, error) {
func instantQueryResultsExtractor(r *response.NormalResponse) (interface{}, error) {
contentType := r.Header().Get("Content-Type")
if !strings.Contains(contentType, "json") {
return nil, fmt.Errorf("unexpected content type from upstream. expected JSON, got %v", contentType)
}
var resp instantQueryResponse
err := json.Unmarshal(b, &resp)
err := json.Unmarshal(r.Body(), &resp)
if err != nil {
return nil, err
}

View File

@ -88,7 +88,7 @@ func (p *AlertingProxy) withReq(
method string,
u *url.URL,
body io.Reader,
extractor func([]byte) (interface{}, error),
extractor func(*response.NormalResponse) (interface{}, error),
headers map[string]string,
) response.Response {
req, err := http.NewRequest(method, u.String(), body)
@ -119,7 +119,7 @@ func (p *AlertingProxy) withReq(
return response.Error(status, errMessage, nil)
}
t, err := extractor(resp.Body())
t, err := extractor(resp)
if err != nil {
return response.Error(500, err.Error(), nil)
}
@ -132,9 +132,13 @@ func (p *AlertingProxy) withReq(
return response.JSON(status, b)
}
func yamlExtractor(v interface{}) func([]byte) (interface{}, error) {
return func(b []byte) (interface{}, error) {
decoder := yaml.NewDecoder(bytes.NewReader(b))
func yamlExtractor(v interface{}) func(*response.NormalResponse) (interface{}, error) {
return func(resp *response.NormalResponse) (interface{}, error) {
contentType := resp.Header().Get("Content-Type")
if !strings.Contains(contentType, "yaml") {
return nil, fmt.Errorf("unexpected content type from upstream. expected YAML, got %v", contentType)
}
decoder := yaml.NewDecoder(bytes.NewReader(resp.Body()))
decoder.KnownFields(true)
err := decoder.Decode(v)
@ -143,18 +147,22 @@ func yamlExtractor(v interface{}) func([]byte) (interface{}, error) {
}
}
func jsonExtractor(v interface{}) func([]byte) (interface{}, error) {
func jsonExtractor(v interface{}) func(*response.NormalResponse) (interface{}, error) {
if v == nil {
// json unmarshal expects a pointer
v = &map[string]interface{}{}
}
return func(b []byte) (interface{}, error) {
return v, json.Unmarshal(b, v)
return func(resp *response.NormalResponse) (interface{}, error) {
contentType := resp.Header().Get("Content-Type")
if !strings.Contains(contentType, "json") {
return nil, fmt.Errorf("unexpected content type from upstream. expected JSON, got %v", contentType)
}
return v, json.Unmarshal(resp.Body(), v)
}
}
func messageExtractor(b []byte) (interface{}, error) {
return map[string]string{"message": string(b)}, nil
func messageExtractor(resp *response.NormalResponse) (interface{}, error) {
return map[string]string{"message": string(resp.Body())}, nil
}
func validateCondition(c ngmodels.Condition, user *models.SignedInUser, skipCache bool, datasourceCache datasources.CacheService) error {

View File

@ -77,7 +77,10 @@ async function rulerGetRequest<T>(url: string, empty: T): Promise<T> {
} catch (e) {
if (e?.status === 404 || e?.data?.message?.includes('group does not exist')) {
return empty;
} else if (e?.status === 500 && e?.data?.message?.includes('mapping values are not allowed in this context')) {
} else if (
e?.status === 500 &&
e?.data?.message?.includes('unexpected content type from upstream. expected YAML, got text/html')
) {
throw {
...e,
data: {