mirror of
https://github.com/status-im/consul.git
synced 2025-01-12 14:55:02 +00:00
connect: change router syntax for matching query parameters to resemble the syntax for matching paths and headers for consistency. (#6163)
This is a breaking change, but only in the context of the beta series.
This commit is contained in:
parent
880d149c19
commit
85cf2706e6
agent
config
structs
xds
api
command/config/write
website/source/docs/agent/config-entries
@ -3121,16 +3121,16 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
||||
"path_prefix": "/foo",
|
||||
"query_param": [
|
||||
{
|
||||
"name": "hack1"
|
||||
"name": "hack1",
|
||||
"present": true
|
||||
},
|
||||
{
|
||||
"name": "hack2",
|
||||
"value": "1"
|
||||
"exact": "1"
|
||||
},
|
||||
{
|
||||
"name": "hack3",
|
||||
"value": "a.*z",
|
||||
"regex": true
|
||||
"regex": "a.*z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -3205,15 +3205,15 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
||||
query_param = [
|
||||
{
|
||||
name = "hack1"
|
||||
present = true
|
||||
},
|
||||
{
|
||||
name = "hack2"
|
||||
value = "1"
|
||||
exact = "1"
|
||||
},
|
||||
{
|
||||
name = "hack3"
|
||||
value = "a.*z"
|
||||
regex = true
|
||||
regex = "a.*z"
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -3286,16 +3286,16 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
||||
PathPrefix: "/foo",
|
||||
QueryParam: []structs.ServiceRouteHTTPMatchQueryParam{
|
||||
{
|
||||
Name: "hack1",
|
||||
Name: "hack1",
|
||||
Present: true,
|
||||
},
|
||||
{
|
||||
Name: "hack2",
|
||||
Value: "1",
|
||||
Exact: "1",
|
||||
},
|
||||
{
|
||||
Name: "hack3",
|
||||
Value: "a.*z",
|
||||
Regex: true,
|
||||
Regex: "a.*z",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -124,6 +124,20 @@ func (e *ServiceRouterConfigEntry) Validate() error {
|
||||
if qm.Name == "" {
|
||||
return fmt.Errorf("Route[%d] QueryParam[%d] missing required Name field", i, j)
|
||||
}
|
||||
|
||||
qmParts := 0
|
||||
if qm.Present {
|
||||
qmParts++
|
||||
}
|
||||
if qm.Exact != "" {
|
||||
qmParts++
|
||||
}
|
||||
if qm.Regex != "" {
|
||||
qmParts++
|
||||
}
|
||||
if qmParts != 1 {
|
||||
return fmt.Errorf("Route[%d] QueryParam[%d] should only contain one of Present, Exact, or Regex", i, j)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,9 +243,10 @@ type ServiceRouteHTTPMatchHeader struct {
|
||||
}
|
||||
|
||||
type ServiceRouteHTTPMatchQueryParam struct {
|
||||
Name string
|
||||
Value string `json:",omitempty"`
|
||||
Regex bool `json:",omitempty"`
|
||||
Name string
|
||||
Present bool `json:",omitempty"`
|
||||
Exact string `json:",omitempty"`
|
||||
Regex string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// ServiceRouteDestination describes how to proxy the actual matching request
|
||||
|
@ -960,11 +960,68 @@ func TestServiceRouterConfigEntry(t *testing.T) {
|
||||
{
|
||||
name: "route with no name query param",
|
||||
entry: makerouter(routeMatch(httpMatchParam(ServiceRouteHTTPMatchQueryParam{
|
||||
Value: "foo",
|
||||
Exact: "foo",
|
||||
}))),
|
||||
validateErr: "missing required Name field",
|
||||
},
|
||||
|
||||
{
|
||||
name: "route with query param exact match",
|
||||
entry: makerouter(routeMatch(httpMatchParam(ServiceRouteHTTPMatchQueryParam{
|
||||
Name: "foo",
|
||||
Exact: "bar",
|
||||
}))),
|
||||
},
|
||||
{
|
||||
name: "route with query param regex match",
|
||||
entry: makerouter(routeMatch(httpMatchParam(ServiceRouteHTTPMatchQueryParam{
|
||||
Name: "foo",
|
||||
Regex: "bar",
|
||||
}))),
|
||||
},
|
||||
{
|
||||
name: "route with query param present match",
|
||||
entry: makerouter(routeMatch(httpMatchParam(ServiceRouteHTTPMatchQueryParam{
|
||||
Name: "foo",
|
||||
Present: true,
|
||||
}))),
|
||||
},
|
||||
{
|
||||
name: "route with query param exact and regex match",
|
||||
entry: makerouter(routeMatch(httpMatchParam(ServiceRouteHTTPMatchQueryParam{
|
||||
Name: "foo",
|
||||
Exact: "bar",
|
||||
Regex: "bar",
|
||||
}))),
|
||||
validateErr: "should only contain one of Present, Exact, or Regex",
|
||||
},
|
||||
{
|
||||
name: "route with query param exact and present match",
|
||||
entry: makerouter(routeMatch(httpMatchParam(ServiceRouteHTTPMatchQueryParam{
|
||||
Name: "foo",
|
||||
Exact: "bar",
|
||||
Present: true,
|
||||
}))),
|
||||
validateErr: "should only contain one of Present, Exact, or Regex",
|
||||
},
|
||||
{
|
||||
name: "route with query param regex and present match",
|
||||
entry: makerouter(routeMatch(httpMatchParam(ServiceRouteHTTPMatchQueryParam{
|
||||
Name: "foo",
|
||||
Regex: "bar",
|
||||
Present: true,
|
||||
}))),
|
||||
validateErr: "should only contain one of Present, Exact, or Regex",
|
||||
},
|
||||
{
|
||||
name: "route with query param exact, regex, and present match",
|
||||
entry: makerouter(routeMatch(httpMatchParam(ServiceRouteHTTPMatchQueryParam{
|
||||
Name: "foo",
|
||||
Exact: "bar",
|
||||
Regex: "bar",
|
||||
Present: true,
|
||||
}))),
|
||||
validateErr: "should only contain one of Present, Exact, or Regex",
|
||||
},
|
||||
////////////////
|
||||
{
|
||||
name: "route with no match and prefix rewrite",
|
||||
@ -1033,7 +1090,7 @@ func TestServiceRouterConfigEntry(t *testing.T) {
|
||||
entry: makerouter(ServiceRoute{
|
||||
Match: httpMatchParam(ServiceRouteHTTPMatchQueryParam{
|
||||
Name: "foo",
|
||||
Value: "bar",
|
||||
Exact: "bar",
|
||||
}),
|
||||
Destination: &ServiceRouteDestination{
|
||||
Service: "other",
|
||||
|
@ -171,15 +171,15 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||
query_param = [
|
||||
{
|
||||
name = "hack1"
|
||||
present = true
|
||||
},
|
||||
{
|
||||
name = "hack2"
|
||||
value = "1"
|
||||
exact = "1"
|
||||
},
|
||||
{
|
||||
name = "hack3"
|
||||
value = "a.*z"
|
||||
regex = true
|
||||
regex = "a.*z"
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -249,15 +249,15 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||
QueryParam = [
|
||||
{
|
||||
Name = "hack1"
|
||||
Present = true
|
||||
},
|
||||
{
|
||||
Name = "hack2"
|
||||
Value = "1"
|
||||
Exact = "1"
|
||||
},
|
||||
{
|
||||
Name = "hack3"
|
||||
Value = "a.*z"
|
||||
Regex = true
|
||||
Regex = "a.*z"
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -326,16 +326,16 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||
PathPrefix: "/foo",
|
||||
QueryParam: []ServiceRouteHTTPMatchQueryParam{
|
||||
{
|
||||
Name: "hack1",
|
||||
Name: "hack1",
|
||||
Present: true,
|
||||
},
|
||||
{
|
||||
Name: "hack2",
|
||||
Value: "1",
|
||||
Exact: "1",
|
||||
},
|
||||
{
|
||||
Name: "hack3",
|
||||
Value: "a.*z",
|
||||
Regex: true,
|
||||
Regex: "a.*z",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -256,9 +256,19 @@ func makeRouteMatchForDiscoveryRoute(discoveryRoute *structs.DiscoveryRoute, pro
|
||||
em.QueryParameters = make([]*envoyroute.QueryParameterMatcher, 0, len(match.HTTP.QueryParam))
|
||||
for _, qm := range match.HTTP.QueryParam {
|
||||
eq := &envoyroute.QueryParameterMatcher{
|
||||
Name: qm.Name,
|
||||
Value: qm.Value,
|
||||
Regex: makeBoolValue(qm.Regex),
|
||||
Name: qm.Name,
|
||||
}
|
||||
|
||||
switch {
|
||||
case qm.Exact != "":
|
||||
eq.Value = qm.Exact
|
||||
case qm.Regex != "":
|
||||
eq.Value = qm.Regex
|
||||
eq.Regex = makeBoolValue(true)
|
||||
case qm.Present:
|
||||
eq.Value = ""
|
||||
default:
|
||||
continue // skip this impossible situation
|
||||
}
|
||||
|
||||
em.QueryParameters = append(em.QueryParameters, eq)
|
||||
|
@ -192,19 +192,25 @@ func TestRoutesFromSnapshot(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Match: httpMatchParam(structs.ServiceRouteHTTPMatchQueryParam{
|
||||
Name: "secretparam",
|
||||
Value: "exact",
|
||||
Name: "secretparam1",
|
||||
Exact: "exact",
|
||||
}),
|
||||
Destination: toService("prm-exact"),
|
||||
},
|
||||
{
|
||||
Match: httpMatchParam(structs.ServiceRouteHTTPMatchQueryParam{
|
||||
Name: "secretparam",
|
||||
Value: "regex",
|
||||
Regex: true,
|
||||
Name: "secretparam2",
|
||||
Regex: "regex",
|
||||
}),
|
||||
Destination: toService("prm-regex"),
|
||||
},
|
||||
{
|
||||
Match: httpMatchParam(structs.ServiceRouteHTTPMatchQueryParam{
|
||||
Name: "secretparam3",
|
||||
Present: true,
|
||||
}),
|
||||
Destination: toService("prm-present"),
|
||||
},
|
||||
{
|
||||
Match: nil,
|
||||
Destination: toService("nil-match"),
|
||||
|
@ -125,9 +125,8 @@
|
||||
"prefix": "/",
|
||||
"queryParameters": [
|
||||
{
|
||||
"name": "secretparam",
|
||||
"value": "exact",
|
||||
"regex": false
|
||||
"name": "secretparam1",
|
||||
"value": "exact"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -140,7 +139,7 @@
|
||||
"prefix": "/",
|
||||
"queryParameters": [
|
||||
{
|
||||
"name": "secretparam",
|
||||
"name": "secretparam2",
|
||||
"value": "regex",
|
||||
"regex": true
|
||||
}
|
||||
@ -150,6 +149,19 @@
|
||||
"cluster": "prm-regex.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
},
|
||||
{
|
||||
"match": {
|
||||
"prefix": "/",
|
||||
"queryParameters": [
|
||||
{
|
||||
"name": "secretparam3"
|
||||
}
|
||||
]
|
||||
},
|
||||
"route": {
|
||||
"cluster": "prm-present.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
},
|
||||
{
|
||||
"match": {
|
||||
"prefix": "/"
|
||||
|
@ -49,9 +49,10 @@ type ServiceRouteHTTPMatchHeader struct {
|
||||
}
|
||||
|
||||
type ServiceRouteHTTPMatchQueryParam struct {
|
||||
Name string
|
||||
Value string `json:",omitempty"`
|
||||
Regex bool `json:",omitempty"`
|
||||
Name string
|
||||
Present bool `json:",omitempty"`
|
||||
Exact string `json:",omitempty"`
|
||||
Regex string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type ServiceRouteDestination struct {
|
||||
|
@ -200,7 +200,7 @@ func TestAPI_ConfigEntry_DiscoveryChain(t *testing.T) {
|
||||
{Name: "x-debug", Exact: "1"},
|
||||
},
|
||||
QueryParam: []ServiceRouteHTTPMatchQueryParam{
|
||||
{Name: "debug", Value: "1"},
|
||||
{Name: "debug", Exact: "1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -265,15 +265,15 @@ func TestParseConfigEntry(t *testing.T) {
|
||||
query_param = [
|
||||
{
|
||||
name = "hack1"
|
||||
present = true
|
||||
},
|
||||
{
|
||||
name = "hack2"
|
||||
value = "1"
|
||||
exact = "1"
|
||||
},
|
||||
{
|
||||
name = "hack3"
|
||||
value = "a.*z"
|
||||
regex = true
|
||||
regex = "a.*z"
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -343,15 +343,15 @@ func TestParseConfigEntry(t *testing.T) {
|
||||
QueryParam = [
|
||||
{
|
||||
Name = "hack1"
|
||||
Present = true
|
||||
},
|
||||
{
|
||||
Name = "hack2"
|
||||
Value = "1"
|
||||
Exact = "1"
|
||||
},
|
||||
{
|
||||
Name = "hack3"
|
||||
Value = "a.*z"
|
||||
Regex = true
|
||||
Regex = "a.*z"
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -420,16 +420,16 @@ func TestParseConfigEntry(t *testing.T) {
|
||||
PathPrefix: "/foo",
|
||||
QueryParam: []api.ServiceRouteHTTPMatchQueryParam{
|
||||
{
|
||||
Name: "hack1",
|
||||
Name: "hack1",
|
||||
Present: true,
|
||||
},
|
||||
{
|
||||
Name: "hack2",
|
||||
Value: "1",
|
||||
Exact: "1",
|
||||
},
|
||||
{
|
||||
Name: "hack3",
|
||||
Value: "a.*z",
|
||||
Regex: true,
|
||||
Regex: "a.*z",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -84,7 +84,7 @@ routes = [
|
||||
query_param = [
|
||||
{
|
||||
name = "x-debug"
|
||||
value = "1"
|
||||
exact = "1"
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -176,16 +176,22 @@ routes = [
|
||||
- `Name` `(string: <required>)` - The name of the query parameter to
|
||||
match on.
|
||||
|
||||
- `Value` `(string: <required>)` - String to match against the query
|
||||
parameter value. The behavior changes with the definition of the
|
||||
`Regex` field.
|
||||
|
||||
- `Regex` `(bool: false)` - Controls how the `Value` field is used. If
|
||||
`Regex` is `false` then `Value` matches exactly. If `Regex` is
|
||||
`true` then `Value` matches as a regular expression pattern.
|
||||
- `Present` `(bool: false)` - Match if the query parameter with the given name
|
||||
is present with any value.
|
||||
|
||||
The syntax when using the Envoy proxy is [documented
|
||||
here](https://en.cppreference.com/w/cpp/regex/ecmascript).
|
||||
At most only one of `Exact`, `Regex`, or `Present` may be configured.
|
||||
|
||||
- `Exact` `(string: "")` - Match if the query parameter with the given
|
||||
name is this value.
|
||||
|
||||
At most only one of `Exact`, `Regex`, or `Present` may be configured.
|
||||
|
||||
- `Regex` `(string: "")` - Match if the query parameter with the given
|
||||
name matches this pattern.
|
||||
|
||||
The syntax when using the Envoy proxy is [documented here](https://en.cppreference.com/w/cpp/regex/ecmascript).
|
||||
|
||||
At most only one of `Exact`, `Regex`, or `Present` may be configured.
|
||||
|
||||
- `Destination` `(ServiceRouteDestination: <optional>)` - Controls how to
|
||||
proxy the actual matching request to a service.
|
||||
|
Loading…
x
Reference in New Issue
Block a user