API_V1: Extract time param parsing logic (#6860)

* extract API time param parsing logic in a func

Signed-off-by: blalov <boiskila@gmail.com>
This commit is contained in:
Boyko 2020-03-06 12:33:01 +02:00 committed by GitHub
parent 1dbd799354
commit 84b00564f4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 50 deletions

View file

@ -318,18 +318,10 @@ func (api *API) options(r *http.Request) apiFuncResult {
}
func (api *API) query(r *http.Request) apiFuncResult {
var ts time.Time
if t := r.FormValue("time"); t != "" {
var err error
ts, err = parseTime(t)
if err != nil {
err = errors.Wrapf(err, "invalid parameter 'time'")
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
} else {
ts = api.now()
ts, err := parseTimeParam(r, "time", api.now())
if err != nil {
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
ctx := r.Context()
if to := r.FormValue("timeout"); to != "" {
var cancel context.CancelFunc
@ -512,26 +504,13 @@ func (api *API) series(r *http.Request) apiFuncResult {
return apiFuncResult{nil, &apiError{errorBadData, errors.New("no match[] parameter provided")}, nil, nil}
}
var start time.Time
if t := r.FormValue("start"); t != "" {
var err error
start, err = parseTime(t)
if err != nil {
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
} else {
start = minTime
start, err := parseTimeParam(r, "start", minTime)
if err != nil {
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
var end time.Time
if t := r.FormValue("end"); t != "" {
var err error
end, err = parseTime(t)
if err != nil {
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
} else {
end = maxTime
end, err := parseTimeParam(r, "end", maxTime)
if err != nil {
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
var matcherSets [][]*labels.Matcher
@ -1320,26 +1299,13 @@ func (api *API) deleteSeries(r *http.Request) apiFuncResult {
return apiFuncResult{nil, &apiError{errorBadData, errors.New("no match[] parameter provided")}, nil, nil}
}
var start time.Time
if t := r.FormValue("start"); t != "" {
var err error
start, err = parseTime(t)
if err != nil {
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
} else {
start = minTime
start, err := parseTimeParam(r, "start", minTime)
if err != nil {
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
var end time.Time
if t := r.FormValue("end"); t != "" {
var err error
end, err = parseTime(t)
if err != nil {
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
} else {
end = maxTime
end, err := parseTimeParam(r, "end", maxTime)
if err != nil {
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
for _, s := range r.Form["match[]"] {
@ -1474,6 +1440,18 @@ func (api *API) respondError(w http.ResponseWriter, apiErr *apiError, data inter
}
}
func parseTimeParam(r *http.Request, paramName string, defaultValue time.Time) (time.Time, error) {
val := r.FormValue(paramName)
if val == "" {
return defaultValue, nil
}
result, err := parseTime(val)
if err != nil {
return time.Time{}, errors.Wrapf(err, "Invalid time value for '%s'", paramName)
}
return result, nil
}
func parseTime(s string) (time.Time, error) {
if t, err := strconv.ParseFloat(s, 64); err == nil {
s, ns := math.Modf(t)

View file

@ -17,7 +17,6 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@ -41,6 +40,7 @@ import (
"github.com/prometheus/common/promlog"
"github.com/prometheus/common/route"
"github.com/pkg/errors"
"github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/pkg/gate"
"github.com/prometheus/prometheus/pkg/labels"
@ -2172,6 +2172,68 @@ func TestRespondError(t *testing.T) {
}
}
func TestParseTimeParam(t *testing.T) {
type resultType struct {
asTime time.Time
asError func() error
}
ts, err := parseTime("1582468023986")
testutil.Ok(t, err)
var tests = []struct {
paramName string
paramValue string
defaultValue time.Time
result resultType
}{
{ // When data is valid.
paramName: "start",
paramValue: "1582468023986",
defaultValue: minTime,
result: resultType{
asTime: ts,
asError: nil,
},
},
{ // When data is empty string.
paramName: "end",
paramValue: "",
defaultValue: maxTime,
result: resultType{
asTime: maxTime,
asError: nil,
},
},
{ // When data is not valid.
paramName: "foo",
paramValue: "baz",
defaultValue: maxTime,
result: resultType{
asTime: time.Time{},
asError: func() error {
_, err := parseTime("baz")
return errors.Wrapf(err, "Invalid time value for '%s'", "foo")
},
},
},
}
for _, test := range tests {
req, err := http.NewRequest("GET", "localhost:42/foo?"+test.paramName+"="+test.paramValue, nil)
testutil.Ok(t, err)
result := test.result
asTime, err := parseTimeParam(req, test.paramName, test.defaultValue)
if err != nil {
testutil.ErrorEqual(t, result.asError(), err)
} else {
testutil.Assert(t, asTime.Equal(result.asTime), "time as return value: %s not parsed correctly. Expected %s. Actual %s", test.paramValue, result.asTime, asTime)
}
}
}
func TestParseTime(t *testing.T) {
ts, err := time.Parse(time.RFC3339Nano, "2015-06-03T13:21:58.555Z")
if err != nil {