2019-05-22 21:23:23 +00:00
|
|
|
package httpserver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Path contains the following path structure:
|
2022-11-29 02:49:01 +00:00
|
|
|
// /{prefix}/{tenantID}/{suffix}
|
2019-05-22 21:23:23 +00:00
|
|
|
type Path struct {
|
|
|
|
Prefix string
|
|
|
|
AuthToken string
|
|
|
|
Suffix string
|
|
|
|
}
|
|
|
|
|
|
|
|
// ParsePath parses the given path.
|
|
|
|
func ParsePath(path string) (*Path, error) {
|
|
|
|
// The path must have the following form:
|
2022-11-29 02:49:01 +00:00
|
|
|
// /{prefix}/{tenantID}/{suffix}
|
2019-05-22 21:23:23 +00:00
|
|
|
//
|
|
|
|
// - prefix must contain `select`, `insert` or `delete`.
|
2022-11-29 02:49:01 +00:00
|
|
|
// - tenantID contains `accountID[:projectID]`, where projectID is optional.
|
|
|
|
// tenantID may also contain `multitenant` string. In this case the accountID and projectID
|
2022-09-30 14:28:35 +00:00
|
|
|
// are obtained from vm_account_id and vm_project_id labels of the ingested samples.
|
2019-05-22 21:23:23 +00:00
|
|
|
// - suffix contains arbitrary suffix.
|
|
|
|
//
|
|
|
|
// prefix must be used for the routing to the appropriate service
|
|
|
|
// in the cluster - either vminsert or vmselect.
|
|
|
|
s := skipPrefixSlashes(path)
|
|
|
|
n := strings.IndexByte(s, '/')
|
|
|
|
if n < 0 {
|
2022-11-29 02:49:01 +00:00
|
|
|
return nil, fmt.Errorf("cannot find {prefix} in %q; expecting /{prefix}/{tenantID}/{suffix} format; "+
|
2024-04-18 00:54:20 +00:00
|
|
|
"see https://docs.victoriametrics.com/cluster-victoriametrics/#url-format", path)
|
2019-05-22 21:23:23 +00:00
|
|
|
}
|
|
|
|
prefix := s[:n]
|
|
|
|
|
|
|
|
s = skipPrefixSlashes(s[n+1:])
|
|
|
|
n = strings.IndexByte(s, '/')
|
|
|
|
if n < 0 {
|
2022-11-29 02:49:01 +00:00
|
|
|
return nil, fmt.Errorf("cannot find {tenantID} in %q; expecting /{prefix}/{tenantID}/{suffix} format; "+
|
2024-04-18 00:54:20 +00:00
|
|
|
"see https://docs.victoriametrics.com/cluster-victoriametrics/#url-format", path)
|
2019-05-22 21:23:23 +00:00
|
|
|
}
|
2022-11-29 02:49:01 +00:00
|
|
|
tenantID := s[:n]
|
2019-05-22 21:23:23 +00:00
|
|
|
|
|
|
|
s = skipPrefixSlashes(s[n+1:])
|
|
|
|
|
|
|
|
// Substitute double slashes with single slashes in the path, since such slashes
|
|
|
|
// may appear due improper copy-pasting of the url.
|
|
|
|
suffix := strings.Replace(s, "//", "/", -1)
|
|
|
|
|
|
|
|
p := &Path{
|
|
|
|
Prefix: prefix,
|
2022-11-29 02:49:01 +00:00
|
|
|
AuthToken: tenantID,
|
2019-05-22 21:23:23 +00:00
|
|
|
Suffix: suffix,
|
|
|
|
}
|
|
|
|
return p, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// skipPrefixSlashes remove double slashes which may appear due
|
|
|
|
// improper copy-pasting of the url
|
|
|
|
func skipPrefixSlashes(s string) string {
|
|
|
|
for len(s) > 0 && s[0] == '/' {
|
|
|
|
s = s[1:]
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|