Skip to content

Commit 722b8dc

Browse files
committed
Refactor queryapi
Signed-off-by: SungJin1212 <[email protected]>
1 parent b804e17 commit 722b8dc

File tree

13 files changed

+282
-274
lines changed

13 files changed

+282
-274
lines changed

pkg/api/queryapi/query_api.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"github.com/prometheus/prometheus/util/annotations"
1818
"github.com/prometheus/prometheus/util/httputil"
1919
v1 "github.com/prometheus/prometheus/web/api/v1"
20+
21+
"github.com/cortexproject/cortex/pkg/util/api"
2022
)
2123

2224
type QueryAPI struct {
@@ -49,11 +51,11 @@ func NewQueryAPI(
4951
}
5052

5153
func (q *QueryAPI) RangeQueryHandler(r *http.Request) (result apiFuncResult) {
52-
start, err := ParseTime(r.FormValue("start"))
54+
start, err := api.ParseTime(r.FormValue("start"))
5355
if err != nil {
5456
return invalidParamError(err, "start")
5557
}
56-
end, err := ParseTime(r.FormValue("end"))
58+
end, err := api.ParseTime(r.FormValue("end"))
5759
if err != nil {
5860
return invalidParamError(err, "end")
5961
}
@@ -62,7 +64,7 @@ func (q *QueryAPI) RangeQueryHandler(r *http.Request) (result apiFuncResult) {
6264
return invalidParamError(errors.New("end timestamp must not be before start time"), "end")
6365
}
6466

65-
step, err := ParseDuration(r.FormValue("step"))
67+
step, err := api.ParseDuration(r.FormValue("step"))
6668
if err != nil {
6769
return invalidParamError(err, "step")
6870
}
@@ -81,7 +83,7 @@ func (q *QueryAPI) RangeQueryHandler(r *http.Request) (result apiFuncResult) {
8183
ctx := r.Context()
8284
if to := r.FormValue("timeout"); to != "" {
8385
var cancel context.CancelFunc
84-
timeout, err := ParseDuration(to)
86+
timeout, err := api.ParseDuration(to)
8587
if err != nil {
8688
return invalidParamError(err, "timeout")
8789
}
@@ -90,7 +92,7 @@ func (q *QueryAPI) RangeQueryHandler(r *http.Request) (result apiFuncResult) {
9092
defer cancel()
9193
}
9294

93-
opts, err := extractQueryOpts(r)
95+
opts, err := api.ExtractQueryOpts(r)
9496
if err != nil {
9597
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
9698
}
@@ -125,15 +127,15 @@ func (q *QueryAPI) RangeQueryHandler(r *http.Request) (result apiFuncResult) {
125127
}
126128

127129
func (q *QueryAPI) InstantQueryHandler(r *http.Request) (result apiFuncResult) {
128-
ts, err := ParseTimeParam(r, "time", q.now())
130+
ts, err := api.ParseTimeParam(r, "time", q.now())
129131
if err != nil {
130132
return invalidParamError(err, "time")
131133
}
132134

133135
ctx := r.Context()
134136
if to := r.FormValue("timeout"); to != "" {
135137
var cancel context.CancelFunc
136-
timeout, err := ParseDuration(to)
138+
timeout, err := api.ParseDuration(to)
137139
if err != nil {
138140
return invalidParamError(err, "timeout")
139141
}
@@ -142,7 +144,7 @@ func (q *QueryAPI) InstantQueryHandler(r *http.Request) (result apiFuncResult) {
142144
defer cancel()
143145
}
144146

145-
opts, err := extractQueryOpts(r)
147+
opts, err := api.ExtractQueryOpts(r)
146148
if err != nil {
147149
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
148150
}

pkg/api/queryapi/response.go

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,5 @@
11
package queryapi
22

3-
import (
4-
"fmt"
5-
"net/http"
6-
7-
"github.com/gogo/status"
8-
"github.com/weaveworks/common/httpgrpc"
9-
)
10-
11-
var (
12-
ErrEndBeforeStart = httpgrpc.Errorf(http.StatusBadRequest, "%s", "end timestamp must not be before start time")
13-
ErrNegativeStep = httpgrpc.Errorf(http.StatusBadRequest, "%s", "zero or negative query resolution step widths are not accepted. Try a positive integer")
14-
ErrStepTooSmall = httpgrpc.Errorf(http.StatusBadRequest, "%s", "exceeded maximum resolution of 11,000 points per timeseries. Try decreasing the query resolution (?step=XX)")
15-
)
16-
17-
func DecorateWithParamName(err error, field string) error {
18-
errTmpl := "invalid parameter %q; %v"
19-
if status, ok := status.FromError(err); ok {
20-
return httpgrpc.Errorf(int(status.Code()), errTmpl, field, status.Message())
21-
}
22-
return fmt.Errorf(errTmpl, field, err)
23-
}
24-
253
// Response defines the Prometheus response format.
264
type Response struct {
275
Status string `json:"status"`

pkg/api/queryapi/util.go

Lines changed: 0 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,12 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"math"
87
"net/http"
9-
"strconv"
10-
"time"
118

12-
"github.com/prometheus/common/model"
139
"github.com/prometheus/prometheus/promql"
1410
"github.com/prometheus/prometheus/util/annotations"
15-
"github.com/weaveworks/common/httpgrpc"
16-
)
17-
18-
var (
19-
// MinTime is the default timestamp used for the start of optional time ranges.
20-
// Exposed to let downstream projects reference it.
21-
//
22-
// Historical note: This should just be time.Unix(math.MinInt64/1000, 0).UTC(),
23-
// but it was set to a higher value in the past due to a misunderstanding.
24-
// The value is still low enough for practical purposes, so we don't want
25-
// to change it now, avoiding confusion for importers of this variable.
26-
MinTime = time.Unix(math.MinInt64/1000+62135596801, 0).UTC()
27-
28-
// MaxTime is the default timestamp used for the end of optional time ranges.
29-
// Exposed to let downstream projects to reference it.
30-
//
31-
// Historical note: This should just be time.Unix(math.MaxInt64/1000, 0).UTC(),
32-
// but it was set to a lower value in the past due to a misunderstanding.
33-
// The value is still high enough for practical purposes, so we don't want
34-
// to change it now, avoiding confusion for importers of this variable.
35-
MaxTime = time.Unix(math.MaxInt64/1000-62135596801, 999999999).UTC()
36-
37-
minTimeFormatted = MinTime.Format(time.RFC3339Nano)
38-
maxTimeFormatted = MaxTime.Format(time.RFC3339Nano)
3911
)
4012

41-
const (
42-
nanosecondsInMillisecond = int64(time.Millisecond / time.Nanosecond)
43-
)
44-
45-
func timeToMillis(t time.Time) int64 {
46-
return t.UnixNano() / nanosecondsInMillisecond
47-
}
48-
49-
func extractQueryOpts(r *http.Request) (promql.QueryOpts, error) {
50-
var duration time.Duration
51-
52-
if strDuration := r.FormValue("lookback_delta"); strDuration != "" {
53-
parsedDuration, err := ParseDuration(strDuration)
54-
if err != nil {
55-
return nil, fmt.Errorf("error parsing lookback delta duration: %w", err)
56-
}
57-
duration = parsedDuration
58-
}
59-
60-
return promql.NewPrometheusQueryOpts(r.FormValue("stats") == "all", duration), nil
61-
}
62-
6313
const (
6414
statusSuccess = "success"
6515
statusError = "error"
@@ -129,79 +79,3 @@ func invalidParamError(err error, parameter string) apiFuncResult {
12979
errorBadData, fmt.Errorf("invalid parameter %q: %w", parameter, err),
13080
}, nil, nil}
13181
}
132-
133-
func ParseTime(s string) (time.Time, error) {
134-
if t, err := strconv.ParseFloat(s, 64); err == nil {
135-
s, ns := math.Modf(t)
136-
ns = math.Round(ns*1000) / 1000
137-
return time.Unix(int64(s), int64(ns*float64(time.Second))).UTC(), nil
138-
}
139-
if t, err := time.Parse(time.RFC3339Nano, s); err == nil {
140-
return t, nil
141-
}
142-
143-
// Stdlib's time parser can only handle 4 digit years. As a workaround until
144-
// that is fixed we want to at least support our own boundary times.
145-
// Context: https://github.com/prometheus/client_golang/issues/614
146-
// Upstream issue: https://github.com/golang/go/issues/20555
147-
switch s {
148-
case minTimeFormatted:
149-
return MinTime, nil
150-
case maxTimeFormatted:
151-
return MaxTime, nil
152-
}
153-
return time.Time{}, fmt.Errorf("cannot parse %q to a valid timestamp", s)
154-
}
155-
156-
func ParseTimeMillis(s string) (int64, error) {
157-
t, err := ParseTime(s)
158-
if err != nil {
159-
return 0, httpgrpc.Errorf(http.StatusBadRequest, err.Error())
160-
}
161-
162-
return timeToMillis(t), nil
163-
}
164-
165-
func ParseDuration(s string) (time.Duration, error) {
166-
if d, err := strconv.ParseFloat(s, 64); err == nil {
167-
ts := d * float64(time.Second)
168-
if ts > float64(math.MaxInt64) || ts < float64(math.MinInt64) {
169-
return 0, fmt.Errorf("cannot parse %q to a valid duration. It overflows int64", s)
170-
}
171-
return time.Duration(ts), nil
172-
}
173-
if d, err := model.ParseDuration(s); err == nil {
174-
return time.Duration(d), nil
175-
}
176-
return 0, fmt.Errorf("cannot parse %q to a valid duration", s)
177-
}
178-
179-
func ParseDurationMillis(s string) (int64, error) {
180-
d, err := ParseDuration(s)
181-
if err != nil {
182-
return 0, httpgrpc.Errorf(http.StatusBadRequest, err.Error())
183-
}
184-
185-
return int64(d / (time.Millisecond / time.Nanosecond)), nil
186-
}
187-
188-
func ParseTimeParam(r *http.Request, paramName string, defaultValue time.Time) (time.Time, error) {
189-
val := r.FormValue(paramName)
190-
if val == "" {
191-
val = strconv.FormatInt(defaultValue.Unix(), 10)
192-
}
193-
result, err := ParseTime(val)
194-
if err != nil {
195-
return time.Time{}, fmt.Errorf("invalid time value for '%s': %w", paramName, err)
196-
}
197-
return result, nil
198-
}
199-
200-
func ParseTimeParamMillis(r *http.Request, paramName string, defaultValue time.Time) (int64, error) {
201-
t, err := ParseTimeParam(r, paramName, defaultValue)
202-
if err != nil {
203-
return 0, httpgrpc.Errorf(http.StatusBadRequest, err.Error())
204-
}
205-
206-
return timeToMillis(t), nil
207-
}

pkg/querier/tripperware/instantquery/instant_query.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import (
1717
v1 "github.com/prometheus/prometheus/web/api/v1"
1818
"github.com/weaveworks/common/httpgrpc"
1919

20-
"github.com/cortexproject/cortex/pkg/api/queryapi"
2120
"github.com/cortexproject/cortex/pkg/querier/stats"
2221
"github.com/cortexproject/cortex/pkg/querier/tripperware"
22+
"github.com/cortexproject/cortex/pkg/util/api"
2323
"github.com/cortexproject/cortex/pkg/util/limiter"
2424
"github.com/cortexproject/cortex/pkg/util/spanlogger"
2525
)
@@ -63,9 +63,9 @@ func NewInstantQueryCodec(compressionStr string, defaultCodecTypeStr string) ins
6363
func (c instantQueryCodec) DecodeRequest(_ context.Context, r *http.Request, forwardHeaders []string) (tripperware.Request, error) {
6464
result := tripperware.PrometheusRequest{Headers: map[string][]string{}}
6565
var err error
66-
result.Time, err = queryapi.ParseTimeParamMillis(r, "time", c.now())
66+
result.Time, err = api.ParseTimeParamMillis(r, "time", c.now())
6767
if err != nil {
68-
return nil, queryapi.DecorateWithParamName(err, "time")
68+
return nil, api.DecorateWithParamName(err, "time")
6969
}
7070

7171
result.Query = r.FormValue("query")

pkg/querier/tripperware/query_attribute_matcher.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ import (
99
"github.com/prometheus/prometheus/promql/parser"
1010
"github.com/weaveworks/common/httpgrpc"
1111

12-
"github.com/cortexproject/cortex/pkg/api/queryapi"
1312
"github.com/cortexproject/cortex/pkg/querier/stats"
14-
"github.com/cortexproject/cortex/pkg/util"
13+
"github.com/cortexproject/cortex/pkg/util/api"
1514
"github.com/cortexproject/cortex/pkg/util/validation"
1615
)
1716

@@ -29,7 +28,7 @@ func rejectQueryOrSetPriority(r *http.Request, now time.Time, lookbackDelta time
2928
if err != nil {
3029
return httpgrpc.Errorf(http.StatusBadRequest, "%s", err.Error())
3130
}
32-
minTime, maxTime := util.FindMinMaxTime(r, expr, lookbackDelta, now)
31+
minTime, maxTime := api.FindMinMaxTime(r, expr, lookbackDelta, now)
3332

3433
if queryReject := limits.QueryRejection(userStr); queryReject.Enabled && query != "" {
3534
for _, attribute := range queryReject.QueryAttributes {
@@ -173,8 +172,8 @@ func matchAttributeForMetadataQuery(attribute validation.QueryAttribute, op stri
173172
}
174173
}
175174

176-
startTime, _ := queryapi.ParseTimeMillis(r.FormValue("start"))
177-
endTime, _ := queryapi.ParseTimeMillis(r.FormValue("end"))
175+
startTime, _ := api.ParseTimeMillis(r.FormValue("start"))
176+
endTime, _ := api.ParseTimeMillis(r.FormValue("end"))
178177

179178
if attribute.TimeWindow.Start != 0 || attribute.TimeWindow.End != 0 {
180179
matched = true
@@ -238,7 +237,7 @@ func isWithinTimeRangeAttribute(limit validation.TimeRangeLimit, startTime, endT
238237

239238
func isWithinQueryStepLimit(queryStepLimit validation.QueryStepLimit, r *http.Request) bool {
240239

241-
step, err := queryapi.ParseDurationMillis(r.FormValue("step"))
240+
step, err := api.ParseDurationMillis(r.FormValue("step"))
242241
if err != nil {
243242
return false
244243
}

pkg/querier/tripperware/queryrange/query_range.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ import (
1616
"github.com/prometheus/common/model"
1717
"github.com/weaveworks/common/httpgrpc"
1818

19-
"github.com/cortexproject/cortex/pkg/api/queryapi"
2019
"github.com/cortexproject/cortex/pkg/querier/stats"
2120
"github.com/cortexproject/cortex/pkg/querier/tripperware"
21+
"github.com/cortexproject/cortex/pkg/util/api"
2222
"github.com/cortexproject/cortex/pkg/util/limiter"
2323
"github.com/cortexproject/cortex/pkg/util/spanlogger"
2424
)
@@ -96,33 +96,33 @@ func (c prometheusCodec) MergeResponse(ctx context.Context, req tripperware.Requ
9696
func (c prometheusCodec) DecodeRequest(_ context.Context, r *http.Request, forwardHeaders []string) (tripperware.Request, error) {
9797
result := tripperware.PrometheusRequest{Headers: map[string][]string{}}
9898
var err error
99-
result.Start, err = queryapi.ParseTimeMillis(r.FormValue("start"))
99+
result.Start, err = api.ParseTimeMillis(r.FormValue("start"))
100100
if err != nil {
101-
return nil, queryapi.DecorateWithParamName(err, "start")
101+
return nil, api.DecorateWithParamName(err, "start")
102102
}
103103

104-
result.End, err = queryapi.ParseTimeMillis(r.FormValue("end"))
104+
result.End, err = api.ParseTimeMillis(r.FormValue("end"))
105105
if err != nil {
106-
return nil, queryapi.DecorateWithParamName(err, "end")
106+
return nil, api.DecorateWithParamName(err, "end")
107107
}
108108

109109
if result.End < result.Start {
110-
return nil, queryapi.ErrEndBeforeStart
110+
return nil, api.ErrEndBeforeStart
111111
}
112112

113-
result.Step, err = queryapi.ParseDurationMillis(r.FormValue("step"))
113+
result.Step, err = api.ParseDurationMillis(r.FormValue("step"))
114114
if err != nil {
115-
return nil, queryapi.DecorateWithParamName(err, "step")
115+
return nil, api.DecorateWithParamName(err, "step")
116116
}
117117

118118
if result.Step <= 0 {
119-
return nil, queryapi.ErrNegativeStep
119+
return nil, api.ErrNegativeStep
120120
}
121121

122122
// For safety, limit the number of returned points per timeseries.
123123
// This is sufficient for 60s resolution for a week or 1h resolution for a year.
124124
if (result.End-result.Start)/result.Step > 11000 {
125-
return nil, queryapi.ErrStepTooSmall
125+
return nil, api.ErrStepTooSmall
126126
}
127127

128128
result.Query = r.FormValue("query")

pkg/querier/tripperware/queryrange/query_range_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ import (
2020
"github.com/weaveworks/common/httpgrpc"
2121
"github.com/weaveworks/common/user"
2222

23-
"github.com/cortexproject/cortex/pkg/api/queryapi"
2423
"github.com/cortexproject/cortex/pkg/cortexpb"
2524
"github.com/cortexproject/cortex/pkg/querier/tripperware"
25+
"github.com/cortexproject/cortex/pkg/util/api"
2626
)
2727

2828
func sortPrometheusResponseHeader(headers []*tripperware.PrometheusResponseHeader) {
@@ -56,19 +56,19 @@ func TestRequest(t *testing.T) {
5656
},
5757
{
5858
url: "api/v1/query_range?start=123&end=0",
59-
expectedErr: queryapi.ErrEndBeforeStart,
59+
expectedErr: api.ErrEndBeforeStart,
6060
},
6161
{
6262
url: "api/v1/query_range?start=123&end=456&step=baz",
6363
expectedErr: httpgrpc.Errorf(http.StatusBadRequest, "invalid parameter \"step\"; cannot parse \"baz\" to a valid duration"),
6464
},
6565
{
6666
url: "api/v1/query_range?start=123&end=456&step=-1",
67-
expectedErr: queryapi.ErrNegativeStep,
67+
expectedErr: api.ErrNegativeStep,
6868
},
6969
{
7070
url: "api/v1/query_range?start=0&end=11001&step=1",
71-
expectedErr: queryapi.ErrStepTooSmall,
71+
expectedErr: api.ErrStepTooSmall,
7272
},
7373
} {
7474
tc := tc

0 commit comments

Comments
 (0)