Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.

Commit d46efa2

Browse files
authored
Fix misrouting of /_license (and others) to ClickHouse (#1225)
In ElasticSearch there's a `GET /:index` endpoint. Quesma supports that endpoint, however a `GET /_license` request erroneously matched to that endpoint, routing it into ClickHouse instead of a fallback to ElasticSearch. Previously a couple similar endpoints (such as `/_nodes`, `/_xpack`, `/_stats`) were hardcoded to be routed to Elastic, however that list was not exhaustive and was prone to become obsolete if Elastic introduced a new endpoint. This PR changes the routing logic - now if an index name starts with `_` (forbidden index name in Elastic and indicative of an endpoint name) it is assumed that it is an internal path and should be routed to Elastic.
1 parent 459ace6 commit d46efa2

File tree

7 files changed

+41
-39
lines changed

7 files changed

+41
-39
lines changed

ci/it/testcases/test_transparent_proxy.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func (a *TransparentProxyIntegrationTestcase) RunTests(ctx context.Context, t *t
3333
t.Run("test basic request", func(t *testing.T) { a.testBasicRequest(ctx, t) })
3434
t.Run("test if cat health request reaches elasticsearch", func(t *testing.T) { a.testIfCatHealthRequestReachesElasticsearch(ctx, t) })
3535
t.Run("test if index creation works", func(t *testing.T) { a.testIfIndexCreationWorks(ctx, t) })
36+
t.Run("test internal endpoints", func(t *testing.T) { a.testInternalEndpoints(ctx, t) })
3637
return nil
3738
}
3839

@@ -64,3 +65,13 @@ func (a *TransparentProxyIntegrationTestcase) testIfIndexCreationWorks(ctx conte
6465
assert.Contains(t, string(bodyBytes), "index_1")
6566
assert.Contains(t, string(bodyBytes), "index_2")
6667
}
68+
69+
func (a *TransparentProxyIntegrationTestcase) testInternalEndpoints(ctx context.Context, t *testing.T) {
70+
for _, internalPath := range InternalPaths {
71+
t.Run(internalPath, func(t *testing.T) {
72+
resp, _ := a.RequestToQuesma(ctx, t, "GET", internalPath, nil)
73+
assert.Equal(t, http.StatusOK, resp.StatusCode)
74+
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
75+
})
76+
}
77+
}

ci/it/testcases/test_wildcard_clickhouse.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func (a *WildcardClickhouseTestcase) RunTests(ctx context.Context, t *testing.T)
3333
t.Run("test basic request", func(t *testing.T) { a.testBasicRequest(ctx, t) })
3434
t.Run("test ingest+query works", func(t *testing.T) { a.testIngestQueryWorks(ctx, t) })
3535
t.Run("test clickhouse table autodiscovery", func(t *testing.T) { a.testClickHouseTableAutodiscovery(ctx, t) })
36+
t.Run("test internal endpoints", func(t *testing.T) { a.testInternalEndpoints(ctx, t) })
3637
return nil
3738
}
3839

@@ -94,3 +95,18 @@ func (a *WildcardClickhouseTestcase) testClickHouseTableAutodiscovery(ctx contex
9495
// assert.Contains(t, string(bodyBytes), "Charlie")
9596
// assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
9697
}
98+
99+
// For full list, run "rg -o 'new Route\([^/{}"]*("/_[^/{}"]*(/[^{}/"]*)?")' | cut -d'"' -f2 | sort | uniq"
100+
// on the ES codebase.
101+
var InternalPaths = []string{"/_nodes", "/_xpack", "/_stats", "/_all/_stats", "/_license", "/_cat", "/_cat/health", "/_cluster/stats", "/_data_stream/_stats"}
102+
103+
func (a *WildcardClickhouseTestcase) testInternalEndpoints(ctx context.Context, t *testing.T) {
104+
for _, internalPath := range InternalPaths {
105+
t.Run(internalPath, func(t *testing.T) {
106+
resp, _ := a.RequestToQuesma(ctx, t, "GET", internalPath, nil)
107+
assert.Equal(t, http.StatusOK, resp.StatusCode)
108+
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Quesma-Source"))
109+
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
110+
})
111+
}
112+
}

ci/it/testcases/test_wildcard_disabled.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func (a *WildcardDisabledTestcase) RunTests(ctx context.Context, t *testing.T) e
3535
t.Run("test ingest is disabled", func(t *testing.T) { a.testIngestIsDisabled(ctx, t) })
3636
t.Run("test explicit index query enabled", func(t *testing.T) { a.testExplicitIndexQueryIsEnabled(ctx, t) })
3737
t.Run("test explicit index ingest enabled", func(t *testing.T) { a.testExplicitIndexIngestIsEnabled(ctx, t) })
38+
t.Run("test internal endpoints", func(t *testing.T) { a.testInternalEndpoints(ctx, t) })
3839
return nil
3940
}
4041

@@ -99,3 +100,14 @@ func (a *WildcardDisabledTestcase) testExplicitIndexIngestIsEnabled(ctx context.
99100
assert.Equal(t, "Clickhouse", resp.Header.Get("X-Quesma-Source"))
100101
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
101102
}
103+
104+
func (a *WildcardDisabledTestcase) testInternalEndpoints(ctx context.Context, t *testing.T) {
105+
for _, internalPath := range InternalPaths {
106+
t.Run(internalPath, func(t *testing.T) {
107+
resp, _ := a.RequestToQuesma(ctx, t, "GET", internalPath, nil)
108+
assert.Equal(t, http.StatusOK, resp.StatusCode)
109+
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Quesma-Source"))
110+
assert.Equal(t, "Elasticsearch", resp.Header.Get("X-Elastic-Product"))
111+
})
112+
}
113+
}

quesma/elasticsearch/index.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,17 @@ import (
1010

1111
const (
1212
internalIndexPrefix = "."
13+
internalPathPrefix = "_"
1314
)
1415

1516
func IsIndexPattern(index string) bool {
1617
return strings.ContainsAny(index, "*,")
1718
}
1819

1920
func IsInternalIndex(index string) bool {
20-
return strings.HasPrefix(index, internalIndexPrefix)
21+
return strings.HasPrefix(index, internalIndexPrefix) || strings.HasPrefix(index, internalPathPrefix)
2122
}
2223

23-
// InternalPaths is a list of paths that are considered internal and should not handled by Quesma
24-
var InternalPaths = []string{"/_nodes", "/_xpack"}
25-
2624
func IsValidIndexName(name string) error {
2725
const maxIndexNameLength = 256
2826

quesma/frontend_connectors/elasticsearch_query.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package frontend_connectors
55

66
import (
77
"context"
8-
"github.com/QuesmaOrg/quesma/quesma/elasticsearch"
98
"github.com/QuesmaOrg/quesma/quesma/processors/es_to_ch_common"
109
"github.com/QuesmaOrg/quesma/quesma/quesma/config"
1110
quesma_api "github.com/QuesmaOrg/quesma/quesma/v2/core"
@@ -28,15 +27,6 @@ func NewElasticsearchQueryFrontendConnector(endpoint string, cfg *config.QuesmaC
2827
}
2928
router := quesma_api.NewPathRouter()
3029

31-
internalPaths := append(elasticsearch.InternalPaths, "/_stats")
32-
33-
for _, esInternalPath := range internalPaths {
34-
router.Register(esInternalPath, quesma_api.Always(), func(ctx context.Context, req *quesma_api.Request, writer http.ResponseWriter) (*quesma_api.Result, error) {
35-
metadata := quesma_api.MakeNewMetadata()
36-
metadata[es_to_ch_common.Bypass] = true
37-
return &quesma_api.Result{Meta: metadata, GenericResult: req.OriginalRequest}, nil
38-
})
39-
}
4030
//TODO: Somehow this messes up the router, so we need to fix it
4131
//router.Register(IndexPath, quesma_api.IsHTTPMethod("GET"), func(ctx context.Context, req *quesma_api.Request, writer http.ResponseWriter) (*quesma_api.Result, error) {
4232
// return &quesma_api.Result{Meta: metadata, GenericResult: req.OriginalRequest}, nil

quesma/quesma/router_test.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,6 @@ func configureRouter(cfg *config.QuesmaConfiguration, sr schema.Registry, lm *cl
4646

4747
router := quesma_api.NewPathRouter()
4848

49-
// These are the endpoints that are not supported by Quesma
50-
// These will redirect to the elastic cluster.
51-
for _, path := range elasticsearch.InternalPaths {
52-
router.Register(path, quesma_api.Never(), func(ctx context.Context, req *quesma_api.Request, _ http.ResponseWriter) (*quesma_api.Result, error) {
53-
return nil, nil
54-
})
55-
}
56-
5749
// These are the endpoints that are supported by Quesma
5850

5951
// Warning:

quesma/quesma/router_v2.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"errors"
88
"github.com/QuesmaOrg/quesma/quesma/backend_connectors"
99
"github.com/QuesmaOrg/quesma/quesma/clickhouse"
10-
"github.com/QuesmaOrg/quesma/quesma/elasticsearch"
1110
"github.com/QuesmaOrg/quesma/quesma/ingest"
1211
"github.com/QuesmaOrg/quesma/quesma/logger"
1312
"github.com/QuesmaOrg/quesma/quesma/painful"
@@ -32,14 +31,6 @@ func ConfigureIngestRouterV2(cfg *config.QuesmaConfiguration, dependencies quesm
3231

3332
router := quesma_api.NewPathRouter()
3433

35-
// These are the endpoints that are not supported by Quesma
36-
// These will redirect to the elastic cluster.
37-
for _, path := range elasticsearch.InternalPaths {
38-
router.Register(path, quesma_api.Never(), func(ctx context.Context, req *quesma_api.Request, _ http.ResponseWriter) (*quesma_api.Result, error) {
39-
return nil, nil
40-
})
41-
}
42-
4334
router.Register(routes.ExecutePainlessScriptPath, and(method("POST"), matchAgainstIndexNameInScriptRequestBody(tableResolver)), func(ctx context.Context, req *quesma_api.Request, _ http.ResponseWriter) (*quesma_api.Result, error) {
4435

4536
var scriptRequest painful.ScriptRequest
@@ -120,14 +111,6 @@ func ConfigureSearchRouterV2(cfg *config.QuesmaConfiguration, dependencies quesm
120111

121112
router := quesma_api.NewPathRouter()
122113

123-
// These are the endpoints that are not supported by Quesma
124-
// These will redirect to the elastic cluster.
125-
for _, path := range elasticsearch.InternalPaths {
126-
router.Register(path, quesma_api.Never(), func(ctx context.Context, req *quesma_api.Request, _ http.ResponseWriter) (*quesma_api.Result, error) {
127-
return nil, nil
128-
})
129-
}
130-
131114
// These are the endpoints that are supported by Quesma
132115

133116
// Warning:

0 commit comments

Comments
 (0)