Release 5.0.2 with error source fix for some downstream errors (#1980)
This PR fixes error source for 2 errors: - parsing of invalid json response should be downstream error as we expect to receive valid json from zabbix - no host found error should be downstream. We are bumping sdk that includes that fix https://github.com/grafana/grafana-plugin-sdk-go/pull/1246. As you can see - the invalid json parsing is now downstream error <img width="1498" alt="image" src="https://github.com/user-attachments/assets/88028dbe-0f73-47aa-8262-5729059ce12f" />
This commit is contained in:
@@ -117,23 +117,23 @@ func (ds *ZabbixDatasource) QueryData(ctx context.Context, req *backend.QueryDat
|
||||
query, err := ReadQuery(q)
|
||||
ds.logger.Debug("DS query", "query", q)
|
||||
if err != nil {
|
||||
res.Error = err
|
||||
res = backend.ErrorResponseWithErrorSource(err)
|
||||
} else if query.QueryType == MODE_METRICS {
|
||||
frames, err := zabbixDS.queryNumericItems(ctx, &query)
|
||||
if err != nil {
|
||||
res.Error = err
|
||||
res = backend.ErrorResponseWithErrorSource(err)
|
||||
} else {
|
||||
res.Frames = append(res.Frames, frames...)
|
||||
}
|
||||
} else if query.QueryType == MODE_ITEMID {
|
||||
frames, err := zabbixDS.queryItemIdData(ctx, &query)
|
||||
if err != nil {
|
||||
res.Error = err
|
||||
res = backend.ErrorResponseWithErrorSource(err)
|
||||
} else {
|
||||
res.Frames = append(res.Frames, frames...)
|
||||
}
|
||||
} else {
|
||||
res.Error = backend.DownstreamError(ErrNonMetricQueryNotSupported)
|
||||
res = backend.ErrorResponseWithErrorSource(backend.DownstreamError(ErrNonMetricQueryNotSupported))
|
||||
}
|
||||
qdr.Responses[q.RefID] = res
|
||||
}
|
||||
|
||||
@@ -118,13 +118,13 @@ func ReadQuery(query backend.DataQuery) (QueryModel, error) {
|
||||
Interval: query.Interval,
|
||||
}
|
||||
if err := json.Unmarshal(query.JSON, &model); err != nil {
|
||||
return model, fmt.Errorf("could not read query: %w", err)
|
||||
return model, backend.DownstreamError(fmt.Errorf("could not read query: %w", err))
|
||||
}
|
||||
|
||||
if model.QueryType == "" {
|
||||
queryJSON, err := simplejson.NewJson(query.JSON)
|
||||
if err != nil {
|
||||
return model, fmt.Errorf("could not read query JSON: %w", err)
|
||||
return model, backend.DownstreamError(fmt.Errorf("could not read query JSON: %w", err))
|
||||
}
|
||||
|
||||
queryType, err := queryJSON.Get("queryType").Int64()
|
||||
|
||||
@@ -125,7 +125,7 @@ func (zabbix *Zabbix) Authenticate(ctx context.Context) error {
|
||||
}
|
||||
err = zabbix.api.AuthenticateWithToken(ctx, token)
|
||||
if err != nil {
|
||||
zabbix.logger.Error("Zabbix authentication error", "error", err)
|
||||
zabbix.logger.Error("Zabbix authentication token error", "error", err)
|
||||
return err
|
||||
}
|
||||
zabbix.logger.Debug("Using API token for authentication")
|
||||
|
||||
@@ -196,7 +196,8 @@ func isDeprecatedUserParamError(err error) bool {
|
||||
func handleAPIResult(response []byte) (*simplejson.Json, error) {
|
||||
jsonResp, err := simplejson.NewJson([]byte(response))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Response is not valid JSON
|
||||
return nil, backend.DownstreamError(err)
|
||||
}
|
||||
if errJSON, isError := jsonResp.CheckGet("error"); isError {
|
||||
errMessage := fmt.Errorf("%s %s", errJSON.Get("message").MustString(), errJSON.Get("data").MustString())
|
||||
|
||||
@@ -71,3 +71,54 @@ func TestZabbixAPI(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAPIResult(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
response string
|
||||
expectedData interface{}
|
||||
expectedError string
|
||||
isDownstream bool
|
||||
}{
|
||||
{
|
||||
name: "Valid JSON with result",
|
||||
response: `{"result": {"data": "test"}}`,
|
||||
expectedData: map[string]interface{}{"data": "test"},
|
||||
},
|
||||
{
|
||||
name: "Invalid JSON",
|
||||
response: `{"result": invalid}`,
|
||||
expectedError: "invalid character 'i' looking for beginning of value",
|
||||
isDownstream: true,
|
||||
},
|
||||
{
|
||||
name: "API error response",
|
||||
response: `{"error": {"message": "Authentication failed", "data": "Session terminated"}}`,
|
||||
expectedError: "Authentication failed Session terminated",
|
||||
isDownstream: true,
|
||||
},
|
||||
{
|
||||
name: "Empty result",
|
||||
response: `{"result": []}`,
|
||||
expectedData: []interface{}{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := handleAPIResult([]byte(tt.response))
|
||||
|
||||
if tt.expectedError != "" {
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, tt.expectedError, err.Error())
|
||||
if tt.isDownstream {
|
||||
assert.True(t, backend.IsDownstreamError(err), "error should be a downstream error")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.expectedData, result.Interface())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user