Skip to content

Commit c5bc099

Browse files
authored
gateway2: allow child policies to always set fields unset on the parent (#10548)
1 parent 815faad commit c5bc099

File tree

5 files changed

+62
-2
lines changed

5 files changed

+62
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
changelog:
2+
- type: FIX
3+
issueLink: https://github.com/solo-io/solo-projects/issues/7601
4+
resolvesIssue: false
5+
description: |
6+
When merging parent-child policies, the merging should allow child
7+
policies to augment parent policies such that fields unset on the
8+
parent can be set by the child. There is a bug when using policy
9+
override capability with route delegation that disallows this when
10+
the annotation specifies non-wildcard fields, such that even if
11+
a field is unset by the parent only the fields specified in the
12+
override annotation are merged in - which is incorrect because
13+
the annotation only applies to fields that are being overriden
14+
(set by the parent). This change fixes the bug.

projects/gateway2/translator/plugins/routeoptions/route_options_plugin_test.go

+37-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import (
55
"errors"
66
"time"
77

8+
"github.com/google/go-cmp/cmp"
89
. "github.com/onsi/ginkgo/v2"
910
. "github.com/onsi/gomega"
1011
"google.golang.org/protobuf/proto"
12+
"google.golang.org/protobuf/testing/protocmp"
1113
"google.golang.org/protobuf/types/known/durationpb"
1214
"google.golang.org/protobuf/types/known/wrapperspb"
1315
"istio.io/istio/pkg/kube/krt"
@@ -737,7 +739,7 @@ var _ = Describe("RouteOptionsPlugin", func() {
737739
var _ = DescribeTable("mergeOptionsForRoute",
738740
func(route *gwv1.HTTPRoute, dst, src *v1.RouteOptions, expectedOptions *v1.RouteOptions, expectedResult glooutils.OptionsMergeResult) {
739741
mergedOptions, result := mergeOptionsForRoute(context.TODO(), route, dst, src)
740-
Expect(proto.Equal(mergedOptions, expectedOptions)).To(BeTrue())
742+
Expect(cmp.Diff(mergedOptions, expectedOptions, protocmp.Transform())).To(BeEmpty())
741743
Expect(result).To(Equal(expectedResult))
742744
},
743745
Entry("prefer dst options by default",
@@ -890,6 +892,40 @@ var _ = DescribeTable("mergeOptionsForRoute",
890892
},
891893
glooutils.OptionsMergedFull,
892894
),
895+
Entry("override and augment dst options with annotation: specific fields",
896+
&gwv1.HTTPRoute{
897+
ObjectMeta: metav1.ObjectMeta{
898+
Annotations: map[string]string{policyOverrideAnnotation: "faults,timeout"},
899+
},
900+
},
901+
&v1.RouteOptions{
902+
Faults: &faultinjection.RouteFaults{
903+
Abort: &faultinjection.RouteAbort{
904+
HttpStatus: 500,
905+
},
906+
},
907+
Timeout: durationpb.New(5 * time.Second),
908+
},
909+
&v1.RouteOptions{
910+
PrefixRewrite: &wrapperspb.StringValue{Value: "/src"},
911+
Faults: &faultinjection.RouteFaults{
912+
Abort: &faultinjection.RouteAbort{
913+
HttpStatus: 100,
914+
},
915+
},
916+
Timeout: durationpb.New(10 * time.Second),
917+
},
918+
&v1.RouteOptions{
919+
Faults: &faultinjection.RouteFaults{
920+
Abort: &faultinjection.RouteAbort{
921+
HttpStatus: 100,
922+
},
923+
},
924+
PrefixRewrite: &wrapperspb.StringValue{Value: "/src"},
925+
Timeout: durationpb.New(10 * time.Second),
926+
},
927+
glooutils.OptionsMergedFull,
928+
),
893929
)
894930

895931
func routeOption() *solokubev1.RouteOption {

projects/gateway2/translator/testutils/inputs/delegation/route_options_multi_level_inheritance_override_partial.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ spec:
112112
- path:
113113
type: PathPrefix
114114
value: /a/1
115+
filters:
116+
- type: URLRewrite
117+
urlRewrite:
118+
path:
119+
replacePrefixMatch: /rewrite/path
120+
type: ReplacePrefixMatch
115121
backendRefs:
116122
- name: svc-a
117123
port: 8080

projects/gateway2/translator/testutils/outputs/delegation/route_options_multi_level_inheritance_override_partial.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ listeners:
3737
headerManipulation:
3838
requestHeadersToRemove:
3939
- override
40+
prefixRewrite: /rewrite/path
4041
name: httproute-route-a-a-0-0
4142
routeAction:
4243
single:

projects/gloo/pkg/utils/merge.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,10 @@ func MergeRouteOptionsWithOverrides(dst, src *v1.RouteOptions, allowedOverrides
147147
var dstFieldsOverwritten int
148148
for i := range dstValue.NumField() {
149149
dstField, srcField := dstValue.Field(i), srcValue.Field(i)
150-
if overwriteByDefault && !(allowedOverrides.Has(wildcardField) ||
150+
// Allow overrides if the field in dst is unset as merging from src into dst by default
151+
// allows src to augment dst by setting fields unset in dst, hence the override check only
152+
// applies when the field in dst is set: !isEmptyValue(dstField).
153+
if !isEmptyValue(dstField) && overwriteByDefault && !(allowedOverrides.Has(wildcardField) ||
151154
allowedOverrides.Has(strings.ToLower(dstValue.Type().Field(i).Name))) {
152155
continue
153156
}

0 commit comments

Comments
 (0)