mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-02-19 15:30:17 +00:00
adds query params support for vmauth urlPrefix (#1226)
* adds query params support for vmauth urlPrefix * Update app/vmauth/example_config.yml * Update app/vmauth/example_config.yml Co-authored-by: Aliaksandr Valialkin <valyala@gmail.com>
This commit is contained in:
parent
b0bd2c0d61
commit
7d249d787d
3 changed files with 44 additions and 4 deletions
|
@ -11,6 +11,14 @@ users:
|
||||||
password: "***"
|
password: "***"
|
||||||
url_prefix: "http://localhost:8428"
|
url_prefix: "http://localhost:8428"
|
||||||
|
|
||||||
|
# The user for querying local single-node VictoriaMetrics with extra_label team=dev.
|
||||||
|
# All the requests to http://vmauth:8427 with the given Basic Auth (username:password)
|
||||||
|
# will be routed to http://localhost:8428 with extra_label=team=dev query arg.
|
||||||
|
# For example, http://vmauth:8427/api/v1/query is routed to http://localhost:8428/api/v1/query?extra_label=team=dev
|
||||||
|
- username: "local-single-node"
|
||||||
|
password: "***"
|
||||||
|
url_prefix: "http://localhost:8428?extra_label=team=dev"
|
||||||
|
|
||||||
# The user for querying account 123 in VictoriaMetrics cluster
|
# The user for querying account 123 in VictoriaMetrics cluster
|
||||||
# See https://victoriametrics.github.io/Cluster-VictoriaMetrics.html#url-format
|
# See https://victoriametrics.github.io/Cluster-VictoriaMetrics.html#url-format
|
||||||
# All the requests to http://vmauth:8427 with the given Basic Auth (username:password)
|
# All the requests to http://vmauth:8427 with the given Basic Auth (username:password)
|
||||||
|
@ -28,4 +36,3 @@ users:
|
||||||
- username: "cluster-insert-account-42"
|
- username: "cluster-insert-account-42"
|
||||||
password: "***"
|
password: "***"
|
||||||
url_prefix: "http://vminsert:8480/insert/42/prometheus"
|
url_prefix: "http://vminsert:8480/insert/42/prometheus"
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,32 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func mergeURLs(uiURL string, requestURI *url.URL) (string, error) {
|
||||||
|
prefixURL, err := url.Parse(uiURL)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("BUG - cannot parse userInfo url: %q, err: %w", uiURL, err)
|
||||||
|
}
|
||||||
|
prefixURL.Path += requestURI.Path
|
||||||
|
requestParams := requestURI.Query()
|
||||||
|
// fast path
|
||||||
|
if len(requestParams) == 0 {
|
||||||
|
return prefixURL.String(), nil
|
||||||
|
}
|
||||||
|
// merge query parameters from requests.
|
||||||
|
userInfoParams := prefixURL.Query()
|
||||||
|
for k, v := range requestParams {
|
||||||
|
// skip clashed query params from original request
|
||||||
|
if exist := userInfoParams.Get(k); len(exist) > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for i := range v {
|
||||||
|
userInfoParams.Add(k, v[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prefixURL.RawQuery = userInfoParams.Encode()
|
||||||
|
return prefixURL.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
func createTargetURL(ui *UserInfo, uOrig *url.URL) (string, error) {
|
func createTargetURL(ui *UserInfo, uOrig *url.URL) (string, error) {
|
||||||
u, err := url.Parse(uOrig.String())
|
u, err := url.Parse(uOrig.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -20,12 +46,12 @@ func createTargetURL(ui *UserInfo, uOrig *url.URL) (string, error) {
|
||||||
for _, e := range ui.URLMap {
|
for _, e := range ui.URLMap {
|
||||||
for _, sp := range e.SrcPaths {
|
for _, sp := range e.SrcPaths {
|
||||||
if sp.match(u.Path) {
|
if sp.match(u.Path) {
|
||||||
return e.URLPrefix + u.RequestURI(), nil
|
return mergeURLs(e.URLPrefix, u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(ui.URLPrefix) > 0 {
|
if len(ui.URLPrefix) > 0 {
|
||||||
return ui.URLPrefix + u.RequestURI(), nil
|
return mergeURLs(ui.URLPrefix, u)
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("missing route for %q", u)
|
return "", fmt.Errorf("missing route for %q", u)
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ func TestCreateTargetURLSuccess(t *testing.T) {
|
||||||
}, "/../../aaa", "https://sss:3894/x/y/aaa")
|
}, "/../../aaa", "https://sss:3894/x/y/aaa")
|
||||||
f(&UserInfo{
|
f(&UserInfo{
|
||||||
URLPrefix: "https://sss:3894/x/y",
|
URLPrefix: "https://sss:3894/x/y",
|
||||||
}, "/./asd/../../aaa?a=d&s=s/../d", "https://sss:3894/x/y/aaa?a=d&s=s/../d")
|
}, "/./asd/../../aaa?a=d&s=s/../d", "https://sss:3894/x/y/aaa?a=d&s=s%2F..%2Fd")
|
||||||
|
|
||||||
// Complex routing with `url_map`
|
// Complex routing with `url_map`
|
||||||
ui := &UserInfo{
|
ui := &UserInfo{
|
||||||
|
@ -77,6 +77,13 @@ func TestCreateTargetURLSuccess(t *testing.T) {
|
||||||
f(ui, "/api/v1/label/foo/values", "http://vmselect/0/prometheus/api/v1/label/foo/values")
|
f(ui, "/api/v1/label/foo/values", "http://vmselect/0/prometheus/api/v1/label/foo/values")
|
||||||
f(ui, "/api/v1/write", "http://vminsert/0/prometheus/api/v1/write")
|
f(ui, "/api/v1/write", "http://vminsert/0/prometheus/api/v1/write")
|
||||||
f(ui, "/api/v1/foo/bar", "http://default-server/api/v1/foo/bar")
|
f(ui, "/api/v1/foo/bar", "http://default-server/api/v1/foo/bar")
|
||||||
|
f(&UserInfo{
|
||||||
|
URLPrefix: "http://foo.bar?extra_label=team=dev",
|
||||||
|
}, "/api/v1/query", "http://foo.bar/api/v1/query?extra_label=team=dev")
|
||||||
|
f(&UserInfo{
|
||||||
|
URLPrefix: "http://foo.bar?extra_label=team=mobile",
|
||||||
|
}, "/api/v1/query?extra_label=team=dev", "http://foo.bar/api/v1/query?extra_label=team%3Dmobile")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateTargetURLFailure(t *testing.T) {
|
func TestCreateTargetURLFailure(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue