Skip to content

Commit 9b96787

Browse files
committed
time param on endpoint should be optional
1 parent d4c17d3 commit 9b96787

File tree

5 files changed

+56
-20
lines changed

5 files changed

+56
-20
lines changed

pkg/cortex/modules.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ func (t *Cortex) initQueryFrontendTripperware() (serv services.Service, err erro
459459
queryRangeMiddlewares,
460460
instantQueryMiddlewares,
461461
queryrange.PrometheusCodec,
462-
instantquery.InstantQueryCodec,
462+
instantquery.Codec,
463463
)
464464

465465
return services.NewIdleService(nil, func(_ error) error {

pkg/querier/tripperware/instantquery/instant_query.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ import (
88
"net/http"
99
"net/url"
1010
"sort"
11+
"strconv"
1112
"strings"
13+
"time"
1214

1315
jsoniter "github.com/json-iterator/go"
1416
"github.com/opentracing/opentracing-go"
1517
otlog "github.com/opentracing/opentracing-go/log"
18+
"github.com/pkg/errors"
1619
"github.com/prometheus/common/model"
1720
"github.com/prometheus/prometheus/model/timestamp"
1821
"github.com/weaveworks/common/httpgrpc"
@@ -26,8 +29,8 @@ import (
2629
)
2730

2831
var (
29-
InstantQueryCodec tripperware.Codec = instantQueryCodec{}
30-
json = jsoniter.Config{
32+
Codec tripperware.Codec = newInstantQueryCodec()
33+
json = jsoniter.Config{
3134
EscapeHTML: false, // No HTML in our responses.
3235
SortMapKeys: true,
3336
ValidateJsonRawMessage: true,
@@ -102,6 +105,11 @@ func (r *PrometheusRequest) WithStats(stats string) tripperware.Request {
102105

103106
type instantQueryCodec struct {
104107
tripperware.Codec
108+
now func() time.Time
109+
}
110+
111+
func newInstantQueryCodec() instantQueryCodec {
112+
return instantQueryCodec{now: time.Now}
105113
}
106114

107115
func (resp *PrometheusInstantQueryResponse) HTTPHeaders() map[string][]string {
@@ -118,10 +126,10 @@ func (resp *PrometheusInstantQueryResponse) HTTPHeaders() map[string][]string {
118126
return nil
119127
}
120128

121-
func (instantQueryCodec) DecodeRequest(_ context.Context, r *http.Request, forwardHeaders []string) (tripperware.Request, error) {
129+
func (c instantQueryCodec) DecodeRequest(_ context.Context, r *http.Request, forwardHeaders []string) (tripperware.Request, error) {
122130
result := PrometheusRequest{Headers: map[string][]string{}}
123131
var err error
124-
result.Time, err = util.ParseTime(r.FormValue("time"))
132+
result.Time, err = parseTimeParam(r, "time", c.now().Unix())
125133
if err != nil {
126134
return nil, decorateWithParamName(err, "time")
127135
}
@@ -443,3 +451,15 @@ func (s *PrometheusInstantQueryData) MarshalJSON() ([]byte, error) {
443451
return s.Result.GetRawBytes(), nil
444452
}
445453
}
454+
455+
func parseTimeParam(r *http.Request, paramName string, defaultValue int64) (int64, error) {
456+
val := r.FormValue(paramName)
457+
if val == "" {
458+
val = strconv.FormatInt(defaultValue, 10)
459+
}
460+
result, err := util.ParseTime(val)
461+
if err != nil {
462+
return 0, errors.Wrapf(err, "Invalid time value for '%s'", paramName)
463+
}
464+
return result, nil
465+
}

pkg/querier/tripperware/instantquery/instant_query_middlewares.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ func Middlewares(
1212
) ([]tripperware.Middleware, error) {
1313
var m []tripperware.Middleware
1414

15-
m = append(m, tripperware.ShardByMiddleware(log, limits, InstantQueryCodec))
15+
m = append(m, tripperware.ShardByMiddleware(log, limits, Codec))
1616
return m, nil
1717
}

pkg/querier/tripperware/instantquery/instant_query_test.go

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,30 @@ import (
88
"net/http"
99
"strconv"
1010
"testing"
11+
"time"
1112

1213
"github.com/stretchr/testify/assert"
1314
"github.com/stretchr/testify/require"
14-
"github.com/weaveworks/common/httpgrpc"
1515
"github.com/weaveworks/common/user"
1616

1717
"github.com/cortexproject/cortex/pkg/querier/tripperware"
1818
)
1919

2020
func TestRequest(t *testing.T) {
21+
now := time.Now()
22+
codec := instantQueryCodec{now: func() time.Time {
23+
return now
24+
}}
2125

2226
for _, tc := range []struct {
2327
url string
28+
expectedUrl string
2429
expected tripperware.Request
2530
expectedErr error
2631
}{
2732
{
28-
url: "/api/v1/query?query=sum%28container_memory_rss%29+by+%28namespace%29&stats=all&time=1536673680",
33+
url: "/api/v1/query?query=sum%28container_memory_rss%29+by+%28namespace%29&stats=all&time=1536673680",
34+
expectedUrl: "/api/v1/query?query=sum%28container_memory_rss%29+by+%28namespace%29&stats=all&time=1536673680",
2935
expected: &PrometheusRequest{
3036
Path: "/api/v1/query",
3137
Time: 1536673680 * 1e3,
@@ -37,7 +43,8 @@ func TestRequest(t *testing.T) {
3743
},
3844
},
3945
{
40-
url: "/api/v1/query?query=sum%28container_memory_rss%29+by+%28namespace%29&time=1536673680",
46+
url: "/api/v1/query?query=sum%28container_memory_rss%29+by+%28namespace%29&time=1536673680",
47+
expectedUrl: "/api/v1/query?query=sum%28container_memory_rss%29+by+%28namespace%29&time=1536673680",
4148
expected: &PrometheusRequest{
4249
Path: "/api/v1/query",
4350
Time: 1536673680 * 1e3,
@@ -49,8 +56,17 @@ func TestRequest(t *testing.T) {
4956
},
5057
},
5158
{
52-
url: "/api/v1/query?query=sum%28container_memory_rss%29+by+%28namespace%29&stats=all",
53-
expectedErr: httpgrpc.Errorf(http.StatusBadRequest, "invalid parameter \"time\"; cannot parse \"\" to a valid timestamp"),
59+
url: "/api/v1/query?query=sum%28container_memory_rss%29+by+%28namespace%29",
60+
expectedUrl: fmt.Sprintf("%s%d", "/api/v1/query?query=sum%28container_memory_rss%29+by+%28namespace%29&time=", now.Unix()),
61+
expected: &PrometheusRequest{
62+
Path: "/api/v1/query",
63+
Time: now.Unix() * 1e3,
64+
Query: "sum(container_memory_rss) by (namespace)",
65+
Stats: "",
66+
Headers: map[string][]string{
67+
"Test-Header": {"test"},
68+
},
69+
},
5470
},
5571
} {
5672
t.Run(tc.url, func(t *testing.T) {
@@ -63,16 +79,16 @@ func TestRequest(t *testing.T) {
6379
// Get a deep copy of the request with Context changed to ctx
6480
r = r.Clone(ctx)
6581

66-
req, err := InstantQueryCodec.DecodeRequest(ctx, r, []string{"Test-Header"})
82+
req, err := codec.DecodeRequest(ctx, r, []string{"Test-Header"})
6783
if err != nil {
6884
require.EqualValues(t, tc.expectedErr, err)
6985
return
7086
}
7187
require.EqualValues(t, tc.expected, req)
7288

73-
rdash, err := InstantQueryCodec.EncodeRequest(context.Background(), req)
89+
rdash, err := codec.EncodeRequest(context.Background(), req)
7490
require.NoError(t, err)
75-
require.EqualValues(t, tc.url, rdash.RequestURI)
91+
require.EqualValues(t, tc.expectedUrl, rdash.RequestURI)
7692
})
7793
}
7894
}
@@ -106,7 +122,7 @@ func TestResponse(t *testing.T) {
106122
Header: http.Header{"Content-Type": []string{"application/json"}},
107123
Body: io.NopCloser(bytes.NewBuffer([]byte(tc.body))),
108124
}
109-
resp, err := InstantQueryCodec.DecodeResponse(context.Background(), response, nil)
125+
resp, err := Codec.DecodeResponse(context.Background(), response, nil)
110126
require.NoError(t, err)
111127

112128
// Reset response, as the above call will have consumed the body reader.
@@ -116,7 +132,7 @@ func TestResponse(t *testing.T) {
116132
Body: io.NopCloser(bytes.NewBuffer([]byte(tc.body))),
117133
ContentLength: int64(len(tc.body)),
118134
}
119-
resp2, err := InstantQueryCodec.EncodeResponse(context.Background(), resp)
135+
resp2, err := Codec.EncodeResponse(context.Background(), resp)
120136
require.NoError(t, err)
121137
assert.Equal(t, response, resp2)
122138
})
@@ -199,16 +215,16 @@ func TestMergeResponse(t *testing.T) {
199215
Header: http.Header{"Content-Type": []string{"application/json"}},
200216
Body: io.NopCloser(bytes.NewBuffer([]byte(r))),
201217
}
202-
dr, err := InstantQueryCodec.DecodeResponse(context.Background(), hr, nil)
218+
dr, err := Codec.DecodeResponse(context.Background(), hr, nil)
203219
require.NoError(t, err)
204220
resps = append(resps, dr)
205221
}
206-
resp, err := InstantQueryCodec.MergeResponse(resps...)
222+
resp, err := Codec.MergeResponse(resps...)
207223
assert.Equal(t, err, tc.expectedErr)
208224
if err != nil {
209225
return
210226
}
211-
dr, err := InstantQueryCodec.EncodeResponse(context.Background(), resp)
227+
dr, err := Codec.EncodeResponse(context.Background(), resp)
212228
assert.Equal(t, err, tc.expectedErr)
213229
contents, err := io.ReadAll(dr.Body)
214230
assert.Equal(t, err, tc.expectedErr)

pkg/querier/tripperware/instantquery/shard_by_query_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ import (
88
)
99

1010
func Test_shardQuery(t *testing.T) {
11-
tripperware.TestQueryShardQuery(t, InstantQueryCodec, queryrange.ShardedPrometheusCodec)
11+
tripperware.TestQueryShardQuery(t, Codec, queryrange.ShardedPrometheusCodec)
1212
}

0 commit comments

Comments
 (0)