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

(cherry picked from commit 347273cdea)
This commit is contained in:
Domas
2021-06-01 11:25:16 +03:00
committed by GitHub
parent a96a58a305
commit a108647836
3 changed files with 29 additions and 13 deletions
+7 -2
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
}
+18 -10
View File
@@ -91,7 +91,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)
@@ -122,7 +122,7 @@ func (p *AlertingProxy) withReq(
return ErrResp(status, errors.New(errMessage), "")
}
t, err := extractor(resp.Body())
t, err := extractor(resp)
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
@@ -135,9 +135,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)
@@ -146,18 +150,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 {
@@ -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: {