Merge pull request #777 from h-r-k-matsumoto/update-istio-v1alpha3

Update HTTPMatchRequest to match Istio's definitions
This commit is contained in:
Stefan Prodan
2021-01-15 13:34:29 +02:00
committed by GitHub
8 changed files with 826 additions and 31 deletions
+227 -8
View File
@@ -172,15 +172,23 @@ spec:
description: URI match conditions
type: array
items:
type: object
properties:
uri:
type: object
authority:
oneOf:
- required: ["exact"]
- required: ["prefix"]
- required: ["suffix"]
- required: ["regex"]
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
@@ -188,12 +196,223 @@ spec:
prefix:
format: string
type: string
suffix:
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
gateways:
description:
Names of gateways where the rule should be
applied.
items:
format: string
type: string
type: array
headers:
additionalProperties:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
type: object
ignoreUriCase:
description:
Flag to specify whether the URI matching should
be case-insensitive.
type: boolean
method:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
name:
description: The name assigned to a match.
format: string
type: string
port:
description:
Specifies the ports on the host that is being
addressed.
type: integer
queryParams:
additionalProperties:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
description: Query parameters for matching.
type: object
scheme:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
sourceLabels:
additionalProperties:
format: string
type: string
type: object
sourceNamespace:
description:
Source namespace constraining the applicability
of a rule to workloads in that namespace.
format: string
type: string
uri:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
withoutHeaders:
additionalProperties:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
description:
withoutHeader has the same syntax with the
header, but has opposite meaning.
type: object
type: object
retries:
description: Retry policy for HTTP requests
type: object
+227 -8
View File
@@ -172,15 +172,23 @@ spec:
description: URI match conditions
type: array
items:
type: object
properties:
uri:
type: object
authority:
oneOf:
- required: ["exact"]
- required: ["prefix"]
- required: ["suffix"]
- required: ["regex"]
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
@@ -188,12 +196,223 @@ spec:
prefix:
format: string
type: string
suffix:
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
gateways:
description:
Names of gateways where the rule should be
applied.
items:
format: string
type: string
type: array
headers:
additionalProperties:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
type: object
ignoreUriCase:
description:
Flag to specify whether the URI matching should
be case-insensitive.
type: boolean
method:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
name:
description: The name assigned to a match.
format: string
type: string
port:
description:
Specifies the ports on the host that is being
addressed.
type: integer
queryParams:
additionalProperties:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
description: Query parameters for matching.
type: object
scheme:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
sourceLabels:
additionalProperties:
format: string
type: string
type: object
sourceNamespace:
description:
Source namespace constraining the applicability
of a rule to workloads in that namespace.
format: string
type: string
uri:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
withoutHeaders:
additionalProperties:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
description:
withoutHeader has the same syntax with the
header, but has opposite meaning.
type: object
type: object
retries:
description: Retry policy for HTTP requests
type: object
+227 -8
View File
@@ -172,15 +172,23 @@ spec:
description: URI match conditions
type: array
items:
type: object
properties:
uri:
type: object
authority:
oneOf:
- required: ["exact"]
- required: ["prefix"]
- required: ["suffix"]
- required: ["regex"]
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
@@ -188,12 +196,223 @@ spec:
prefix:
format: string
type: string
suffix:
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
gateways:
description:
Names of gateways where the rule should be
applied.
items:
format: string
type: string
type: array
headers:
additionalProperties:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
type: object
ignoreUriCase:
description:
Flag to specify whether the URI matching should
be case-insensitive.
type: boolean
method:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
name:
description: The name assigned to a match.
format: string
type: string
port:
description:
Specifies the ports on the host that is being
addressed.
type: integer
queryParams:
additionalProperties:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
description: Query parameters for matching.
type: object
scheme:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
sourceLabels:
additionalProperties:
format: string
type: string
type: object
sourceNamespace:
description:
Source namespace constraining the applicability
of a rule to workloads in that namespace.
format: string
type: string
uri:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
withoutHeaders:
additionalProperties:
oneOf:
- not:
anyOf:
- required:
- exact
- required:
- prefix
- required:
- regex
- required:
- exact
- required:
- prefix
- required:
- regex
properties:
exact:
format: string
type: string
prefix:
format: string
type: string
regex:
description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax).
format: string
type: string
type: object
description:
withoutHeader has the same syntax with the
header, but has opposite meaning.
type: object
type: object
retries:
description: Retry policy for HTTP requests
type: object
@@ -394,6 +394,11 @@ type HeaderOperations struct {
//
// HTTPMatchRequest CANNOT be empty.
type HTTPMatchRequest struct {
// The name assigned to a match. The match's name will be
// concatenated with the parent route's name and will be logged in
// the access logs for requests matching this route.
Name string `json:"name,omitempty"`
// URI to match
// values are case-sensitive and formatted as follows:
//
@@ -467,6 +472,35 @@ type HTTPMatchRequest struct {
// at the top of the VirtualService (if any) are overridden. The gateway match is
// independent of sourceLabels.
Gateways []string `json:"gateways,omitempty"`
// Query parameters for matching.
//
// Ex:
// - For a query parameter like "?key=true", the map key would be "key" and
// the string match could be defined as `exact: "true"`.
// - For a query parameter like "?key", the map key would be "key" and the
// string match could be defined as `exact: ""`.
// - For a query parameter like "?key=123", the map key would be "key" and the
// string match could be defined as `regex: "\d+$"`. Note that this
// configuration will only match values like "123" but not "a123" or "123a".
//
// **Note:** `prefix` matching is currently not supported.
QueryParams map[string]v1alpha1.StringMatch `json:"queryParams,omitempty"`
// Flag to specify whether the URI matching should be case-insensitive.
//
// **Note:** The case will be ignored only in the case of `exact` and `prefix`
// URI matches.
IgnoreUriCase bool `json:"ignoreUriCase,omitempty"`
// withoutHeader has the same syntax with the header, but has opposite meaning.
// If a header is matched with a matching rule among withoutHeader, the traffic becomes not matched one.
WithoutHeaders map[string]v1alpha1.StringMatch `json:"withoutHeaders,omitempty"`
// Source namespace constraining the applicability of a rule to workloads in that namespace.
// If the VirtualService has a list of gateways specified in the top-level `gateways` field,
// it must include the reserved gateway `mesh` for this field to be applicable.
SourceNamespace string `json:"sourceNamespace,omitempty"`
}
type DestinationWeight struct {
@@ -329,6 +329,20 @@ func (in *HTTPMatchRequest) DeepCopyInto(out *HTTPMatchRequest) {
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.QueryParams != nil {
in, out := &in.QueryParams, &out.QueryParams
*out = make(map[string]v1alpha1.StringMatch, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.WithoutHeaders != nil {
in, out := &in.WithoutHeaders, &out.WithoutHeaders
*out = make(map[string]v1alpha1.StringMatch, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
+15 -4
View File
@@ -440,15 +440,26 @@ func (ir *IstioRouter) Finalize(canary *flaggerv1.Canary) error {
// mergeMatchConditions appends the URI match rules to canary conditions
func mergeMatchConditions(canary, defaults []istiov1alpha3.HTTPMatchRequest) []istiov1alpha3.HTTPMatchRequest {
for i := range canary {
if len(defaults) == 0 {
return canary
}
merged := make([]istiov1alpha3.HTTPMatchRequest, len(canary)*len(defaults))
num := 0
for _, c := range canary {
for _, d := range defaults {
if d.Uri != nil {
canary[i].Uri = d.Uri
merged[num] = *d.DeepCopy()
if c.Headers != nil {
merged[num].Headers = c.Headers
}
if c.SourceLabels != nil {
merged[num].SourceLabels = c.SourceLabels
}
num++
}
}
return canary
return merged
}
// makeDestination returns a an destination weight for the specified host
+72
View File
@@ -27,6 +27,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
istiov1alpha1 "github.com/fluxcd/flagger/pkg/apis/istio/common/v1alpha1"
istiov1alpha3 "github.com/fluxcd/flagger/pkg/apis/istio/v1alpha3"
)
@@ -492,3 +493,74 @@ func TestIstioRouter_Finalize(t *testing.T) {
}
}
}
func TestIstioRouter_Match(t *testing.T) {
mocks := newFixture(nil)
router := &IstioRouter{
logger: mocks.logger,
flaggerClient: mocks.flaggerClient,
istioClient: mocks.meshClient,
kubeClient: mocks.kubeClient,
}
// service.match is not exists, analysis match is exists
err := router.Reconcile(mocks.abtest)
require.NoError(t, err)
// test insert
vs, err := mocks.meshClient.NetworkingV1alpha3().VirtualServices("default").Get(context.TODO(), "abtest", metav1.GetOptions{})
require.NoError(t, err)
assert.Len(t, vs.Spec.Http, 2)
assert.Len(t, vs.Spec.Http[0].Match, 1) // check for abtest-canary
require.Equal(t, vs.Spec.Http[0].Match[0].Headers["x-user-type"].Exact, "test")
assert.Len(t, vs.Spec.Http[1].Match, 0) // check for abtest-primary
// Test Case that is service.match exists and multiple analysis.match
mocks.abtest.Spec.Service.Match = []istiov1alpha3.HTTPMatchRequest{
{
Name: "podinfo",
Uri: &istiov1alpha1.StringMatch{
Prefix: "/podinfo",
},
Method: &istiov1alpha1.StringMatch{
Exact: "GET",
},
IgnoreUriCase: true,
},
}
mocks.abtest.Spec.Analysis.Match = []istiov1alpha3.HTTPMatchRequest{
{
Headers: map[string]istiov1alpha1.StringMatch{
"x-user-type": {
Exact: "test",
},
"x-auth-test": {
Exact: "test",
},
},
},
{
Headers: map[string]istiov1alpha1.StringMatch{
"x-session-id": {
Exact: "test",
},
},
},
}
// apply changes
err = router.Reconcile(mocks.abtest)
require.NoError(t, err)
vs, err = mocks.meshClient.NetworkingV1alpha3().VirtualServices("default").Get(context.TODO(), "abtest", metav1.GetOptions{})
require.NoError(t, err)
assert.Len(t, vs.Spec.Http, 2)
assert.Len(t, vs.Spec.Http[0].Match, 2) // check for abtest-canary
require.Equal(t, vs.Spec.Http[0].Match[0].Uri.Prefix, "/podinfo")
require.Equal(t, vs.Spec.Http[0].Match[0].Headers["x-user-type"].Exact, "test")
require.Equal(t, vs.Spec.Http[0].Match[0].Headers["x-auth-test"].Exact, "test")
require.Equal(t, vs.Spec.Http[0].Match[1].Uri.Prefix, "/podinfo")
require.Equal(t, vs.Spec.Http[0].Match[1].Headers["x-session-id"].Exact, "test")
assert.Len(t, vs.Spec.Http[1].Match, 1) // check for abtest-primary
require.Equal(t, vs.Spec.Http[1].Match[0].Uri.Prefix, "/podinfo")
}
+10 -3
View File
@@ -116,9 +116,16 @@ func newTestCanary() *flaggerv1.Canary {
},
},
Match: []istiov1alpha3.HTTPMatchRequest{
{Uri: &istiov1alpha1.StringMatch{
Prefix: "/podinfo",
}},
{
Name: "podinfo",
Uri: &istiov1alpha1.StringMatch{
Prefix: "/podinfo",
},
Method: &istiov1alpha1.StringMatch{
Exact: "GET",
},
IgnoreUriCase: true,
},
},
Retries: &istiov1alpha3.HTTPRetry{
Attempts: 10,