diff --git a/internal/dag/builder_test.go b/internal/dag/builder_test.go index 05cbcd7b3d3..b4f36b6d3ea 100644 --- a/internal/dag/builder_test.go +++ b/internal/dag/builder_test.go @@ -55,6 +55,36 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, } + kuardService2 := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kuard2", + Namespace: "projectcontour", + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{{ + Name: "http", + Protocol: "TCP", + Port: 8080, + TargetPort: intstr.FromInt(8080), + }}, + }, + } + + kuardService3 := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kuard3", + Namespace: "projectcontour", + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{{ + Name: "http", + Protocol: "TCP", + Port: 8080, + TargetPort: intstr.FromInt(8080), + }}, + }, + } + kuardServiceCustomNs := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: "kuard", @@ -276,6 +306,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ ServiceName: pointer.StringPtr("kuard"), Port: gatewayPort(8080), + Weight: 1, }}, }}, }, @@ -302,10 +333,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { Value: "/", }, }}, - ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ - ServiceName: pointer.StringPtr("blogsvc"), - Port: gatewayPort(80), - }}, + ForwardTo: httpRouteForwardTo("blogsvc", 80, 1), }}, }, } @@ -447,7 +475,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { &Listener{ Port: 80, VirtualHosts: virtualhosts( - virtualhost("test.projectcontour.io", prefixroute("/", service(kuardService))), + virtualhost("test.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardService))), ), }, ), @@ -463,7 +491,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { &Listener{ Port: 80, VirtualHosts: virtualhosts( - virtualhost("test.projectcontour.io", prefixroute("/", service(kuardService))), + virtualhost("test.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardService))), ), }, ), @@ -484,7 +512,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -493,7 +521,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { &Listener{ Port: 80, VirtualHosts: virtualhosts( - virtualhost("test.projectcontour.io", prefixroute("/", service(kuardService))), + virtualhost("test.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardService))), ), }, ), @@ -513,7 +541,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -535,7 +563,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -544,7 +572,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { &Listener{ Port: 80, VirtualHosts: virtualhosts( - virtualhost("test.projectcontour.io", prefixroute("/", service(kuardServiceCustomNs))), + virtualhost("test.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardServiceCustomNs))), ), }, ), @@ -572,16 +600,8 @@ func TestDAGInsertGatewayAPI(t *testing.T) { "test.projectcontour.io", }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ - Matches: []gatewayapi_v1alpha1.HTTPRouteMatch{{ - Path: gatewayapi_v1alpha1.HTTPPathMatch{ - Type: "Prefix", - Value: "/", - }, - }}, - ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ - ServiceName: pointer.StringPtr("kuard"), - Port: gatewayPort(8080), - }}, + Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -590,7 +610,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { &Listener{ Port: 80, VirtualHosts: virtualhosts( - virtualhost("test.projectcontour.io", prefixroute("/", service(kuardServiceCustomNs))), + virtualhost("test.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardServiceCustomNs))), ), }, ), @@ -619,22 +639,14 @@ func TestDAGInsertGatewayAPI(t *testing.T) { "test.projectcontour.io", }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ - Matches: []gatewayapi_v1alpha1.HTTPRouteMatch{{ - Path: gatewayapi_v1alpha1.HTTPPathMatch{ - Type: "Prefix", - Value: "/", - }, - }}, - ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ - ServiceName: pointer.StringPtr("kuard"), - Port: gatewayPort(8080), - }}, + Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, &gatewayapi_v1alpha1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ - Name: "basic-twp", + Name: "basic-two", Namespace: "custom", }, Spec: gatewayapi_v1alpha1.HTTPRouteSpec{ @@ -642,16 +654,8 @@ func TestDAGInsertGatewayAPI(t *testing.T) { "another.projectcontour.io", }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ - Matches: []gatewayapi_v1alpha1.HTTPRouteMatch{{ - Path: gatewayapi_v1alpha1.HTTPPathMatch{ - Type: "Prefix", - Value: "/", - }, - }}, - ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ - ServiceName: pointer.StringPtr("kuard"), - Port: gatewayPort(8080), - }}, + Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -660,8 +664,8 @@ func TestDAGInsertGatewayAPI(t *testing.T) { &Listener{ Port: 80, VirtualHosts: virtualhosts( - virtualhost("another.projectcontour.io", prefixroute("/", service(kuardServiceCustomNs))), - virtualhost("test.projectcontour.io", prefixroute("/", service(kuardServiceCustomNs))), + virtualhost("another.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardServiceCustomNs))), + virtualhost("test.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardServiceCustomNs))), ), }, ), @@ -690,7 +694,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -717,7 +721,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -758,7 +762,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -800,7 +804,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -827,10 +831,10 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }, { Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/blog"), - ForwardTo: httpRouteForwardTo("blogsvc", 80), + ForwardTo: httpRouteForwardTo("blogsvc", 80, 1), }}, }, }, @@ -840,7 +844,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { Port: 80, VirtualHosts: virtualhosts( virtualhost("test.projectcontour.io", - prefixroute("/", service(kuardService)), prefixroute("/blog", service(blogService))), + prefixrouteHTTPRoute("/", service(kuardService)), prefixrouteHTTPRoute("/blog", service(blogService))), ), }, ), @@ -867,7 +871,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -876,10 +880,10 @@ func TestDAGInsertGatewayAPI(t *testing.T) { &Listener{ Port: 80, VirtualHosts: virtualhosts( - virtualhost("test.projectcontour.io", prefixroute("/", service(kuardService))), - virtualhost("test2.projectcontour.io", prefixroute("/", service(kuardService))), - virtualhost("test3.projectcontour.io", prefixroute("/", service(kuardService))), - virtualhost("test4.projectcontour.io", prefixroute("/", service(kuardService))), + virtualhost("test.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardService))), + virtualhost("test2.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardService))), + virtualhost("test3.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardService))), + virtualhost("test4.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardService))), ), }, ), @@ -900,7 +904,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { Spec: gatewayapi_v1alpha1.HTTPRouteSpec{ Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -909,7 +913,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { &Listener{ Port: 80, VirtualHosts: virtualhosts( - virtualhost("*", prefixroute("/", service(kuardService))), + virtualhost("*", prefixrouteHTTPRoute("/", service(kuardService))), ), }, ), @@ -933,7 +937,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -942,7 +946,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { &Listener{ Port: 80, VirtualHosts: virtualhosts( - virtualhost("*.projectcontour.io", prefixroute("/", service(kuardService))), + virtualhost("*.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardService))), ), }, ), @@ -966,7 +970,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -992,7 +996,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -1018,7 +1022,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -1042,7 +1046,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { Spec: gatewayapi_v1alpha1.HTTPRouteSpec{ Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -1075,6 +1079,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ ServiceName: pointer.StringPtr("kuard"), Port: nil, + Weight: 1, }}, }}, }, @@ -1101,7 +1106,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchExact, "/blog"), - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -1111,7 +1116,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { Port: 80, VirtualHosts: virtualhosts( virtualhost("test.projectcontour.io", - exactroute("/blog", service(kuardService))), + exactrouteHTTPRoute("/blog", service(kuardService))), ), }, ), @@ -1151,7 +1156,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { Value: "/tech", }, }}, - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -1161,9 +1166,9 @@ func TestDAGInsertGatewayAPI(t *testing.T) { Port: 80, VirtualHosts: virtualhosts( virtualhost("test.projectcontour.io", - prefixroute("/", service(kuardService)), - prefixroute("/blog", service(kuardService)), - prefixroute("/tech", service(kuardService))), + prefixrouteHTTPRoute("/", service(kuardService)), + prefixrouteHTTPRoute("/blog", service(kuardService)), + prefixrouteHTTPRoute("/tech", service(kuardService))), ), }, ), @@ -1183,7 +1188,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { VirtualHost: VirtualHost{ Name: "test.projectcontour.io", ListenerName: "ingress_https", - routes: routes(prefixroute("/", service(kuardService))), + routes: routes(prefixrouteHTTPRoute("/", service(kuardService))), }, Secret: secret(sec1), }, @@ -1230,7 +1235,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { VirtualHost: VirtualHost{ Name: "test.projectcontour.io", ListenerName: "ingress_https", - routes: routes(prefixroute("/", service(blogService))), + routes: routes(prefixrouteHTTPRoute("/", service(blogService))), }, Secret: secret(sec1), }, @@ -1239,7 +1244,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { &Listener{ Port: 80, VirtualHosts: virtualhosts( - virtualhost("test.projectcontour.io", prefixroute("/", service(blogService))), + virtualhost("test.projectcontour.io", prefixrouteHTTPRoute("/", service(blogService))), ), }, ), @@ -1388,7 +1393,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { VirtualHost: VirtualHost{ Name: "test.projectcontour.io", ListenerName: "ingress_https", - routes: routes(prefixroute("/", service(blogService))), + routes: routes(prefixrouteHTTPRoute("/", service(blogService))), }, Secret: secret(sec1), }, @@ -1397,7 +1402,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { &Listener{ Port: 80, VirtualHosts: virtualhosts( - virtualhost("test.projectcontour.io", prefixroute("/", service(kuardService))), + virtualhost("test.projectcontour.io", prefixrouteHTTPRoute("/", service(kuardService))), ), }, ), @@ -1430,7 +1435,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { Values: map[string]string{"foo": "bar"}, }, }}, - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -1444,7 +1449,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { HeaderMatchConditions: []HeaderMatchCondition{ {Name: "foo", Value: "bar", MatchType: "exact", Invert: false}, }, - Clusters: clusters(service(kuardService)), + Clusters: clustersWeight(service(kuardService)), }), ), }, @@ -1486,7 +1491,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, }, }, - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -1497,14 +1502,14 @@ func TestDAGInsertGatewayAPI(t *testing.T) { VirtualHosts: virtualhosts(virtualhost("test.projectcontour.io", &Route{ PathMatchCondition: prefixString("/blog"), - Clusters: clusters(service(kuardService)), + Clusters: clustersWeight(service(kuardService)), }, &Route{ PathMatchCondition: prefixString("/tech"), HeaderMatchConditions: []HeaderMatchCondition{ {Name: "foo", Value: "bar", MatchType: "exact", Invert: false}, }, - Clusters: clusters(service(kuardService)), + Clusters: clustersWeight(service(kuardService)), }, )), }, @@ -1534,7 +1539,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { Values: map[string]string{"foo": "bar"}, }, }}, - ForwardTo: httpRouteForwardTo("kuard", 8080), + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), }}, }, }, @@ -1548,7 +1553,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { HeaderMatchConditions: []HeaderMatchCondition{ {Name: "foo", Value: "bar", MatchType: "exact", Invert: false}, }, - Clusters: clusters(service(kuardService)), + Clusters: clustersWeight(service(kuardService)), }, )), }, @@ -1581,10 +1586,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, }, }, - ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ - ServiceName: pointer.StringPtr("kuard"), - Port: gatewayPort(8080), - }}, + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), Filters: []gatewayapi_v1alpha1.HTTPRouteFilter{{ Type: gatewayapi_v1alpha1.HTTPRouteFilterRequestHeaderModifier, RequestHeaderModifier: &gatewayapi_v1alpha1.HTTPRequestHeaderFilter{ @@ -1602,7 +1604,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { VirtualHosts: virtualhosts(virtualhost("test.projectcontour.io", &Route{ PathMatchCondition: prefixString("/"), - Clusters: clusters(service(kuardService)), + Clusters: clustersWeight(service(kuardService)), RequestHeadersPolicy: &HeadersPolicy{ Set: map[string]string{ "Custom-Header-Set": "foo-bar", // Verify the header key is canonicalized. @@ -1654,6 +1656,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { Add: map[string]string{"custom-header-add": "foo-bar"}, }, }}, + Weight: 1, }}, }}, }, @@ -1698,10 +1701,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, }, }, - ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ - ServiceName: pointer.StringPtr("kuard"), - Port: gatewayPort(8080), - }}, + ForwardTo: httpRouteForwardTo("kuard", 8080, 1), Filters: []gatewayapi_v1alpha1.HTTPRouteFilter{{ Type: gatewayapi_v1alpha1.HTTPRouteFilterRequestHeaderModifier, RequestHeaderModifier: &gatewayapi_v1alpha1.HTTPRequestHeaderFilter{ @@ -1719,7 +1719,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { VirtualHosts: virtualhosts(virtualhost("test.projectcontour.io", &Route{ PathMatchCondition: prefixString("/"), - Clusters: clusters(service(kuardService)), + Clusters: clustersWeight(service(kuardService)), RequestHeadersPolicy: &HeadersPolicy{ Set: map[string]string{"Custom-Header-Set": "foo-bar"}, Add: map[string]string{}, // Invalid header should not be set. @@ -1760,6 +1760,7 @@ func TestDAGInsertGatewayAPI(t *testing.T) { ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ ServiceName: pointer.StringPtr("kuard"), Port: gatewayPort(8080), + Weight: 1, Filters: []gatewayapi_v1alpha1.HTTPRouteFilter{{ Type: gatewayapi_v1alpha1.HTTPRouteFilterRequestHeaderModifier, RequestHeaderModifier: &gatewayapi_v1alpha1.HTTPRequestHeaderFilter{ @@ -1784,6 +1785,182 @@ func TestDAGInsertGatewayAPI(t *testing.T) { }, ), }, + "different weights for multiple forwardTos": { + gateway: gatewayWithSelector, + objs: []interface{}{ + kuardService, + kuardService2, + kuardService3, + &gatewayapi_v1alpha1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "basic", + Namespace: "projectcontour", + Labels: map[string]string{ + "app": "contour", + "type": "controller", + }, + }, + Spec: gatewayapi_v1alpha1.HTTPRouteSpec{ + Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ + Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), + ForwardTo: httpRouteForwards( + httpRouteForwardTo("kuard", 8080, 5), + httpRouteForwardTo("kuard2", 8080, 10), + httpRouteForwardTo("kuard3", 8080, 15), + ), + }}, + }, + }, + }, + want: listeners( + &Listener{ + Port: 80, + VirtualHosts: virtualhosts( + virtualhost("*", prefixrouteHTTPRoute("/", + &Service{ + Weighted: WeightedService{ + Weight: 5, + ServiceName: kuardService.Name, + ServiceNamespace: kuardService.Namespace, + ServicePort: kuardService.Spec.Ports[0], + }, + }, + &Service{ + Weighted: WeightedService{ + Weight: 10, + ServiceName: kuardService2.Name, + ServiceNamespace: kuardService2.Namespace, + ServicePort: kuardService2.Spec.Ports[0], + }, + }, + &Service{ + Weighted: WeightedService{ + Weight: 15, + ServiceName: kuardService3.Name, + ServiceNamespace: kuardService3.Namespace, + ServicePort: kuardService3.Spec.Ports[0], + }, + }, + )), + ), + }, + ), + }, + "one service weight zero w/weights for other forwardTos": { + gateway: gatewayWithSelector, + objs: []interface{}{ + kuardService, + kuardService2, + kuardService3, + &gatewayapi_v1alpha1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "basic", + Namespace: "projectcontour", + Labels: map[string]string{ + "app": "contour", + "type": "controller", + }, + }, + Spec: gatewayapi_v1alpha1.HTTPRouteSpec{ + Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ + Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), + ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{ + { + ServiceName: pointer.StringPtr("kuard"), + Port: gatewayPort(8080), + Weight: 5, + }, { + ServiceName: pointer.StringPtr("kuard2"), + Port: gatewayPort(8080), + Weight: 0, + }, + { + ServiceName: pointer.StringPtr("kuard3"), + Port: gatewayPort(8080), + Weight: 15, + }, + }, + }}, + }, + }, + }, + want: listeners( + &Listener{ + Port: 80, + VirtualHosts: virtualhosts( + virtualhost("*", prefixrouteHTTPRoute("/", + &Service{ + Weighted: WeightedService{ + Weight: 5, + ServiceName: kuardService.Name, + ServiceNamespace: kuardService.Namespace, + ServicePort: kuardService.Spec.Ports[0], + }, + }, + &Service{ + Weighted: WeightedService{ + Weight: 0, + ServiceName: kuardService2.Name, + ServiceNamespace: kuardService2.Namespace, + ServicePort: kuardService2.Spec.Ports[0], + }, + }, + &Service{ + Weighted: WeightedService{ + Weight: 15, + ServiceName: kuardService3.Name, + ServiceNamespace: kuardService3.Namespace, + ServicePort: kuardService3.Spec.Ports[0], + }, + }, + )), + ), + }, + ), + }, + "weight of zero for a single forwardTo results in 503": { + gateway: gatewayWithSelector, + objs: []interface{}{ + kuardService, + kuardService2, + kuardService3, + &gatewayapi_v1alpha1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "basic", + Namespace: "projectcontour", + Labels: map[string]string{ + "app": "contour", + "type": "controller", + }, + }, + Spec: gatewayapi_v1alpha1.HTTPRouteSpec{ + Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ + Matches: httpRouteMatch(gatewayapi_v1alpha1.PathMatchPrefix, "/"), + ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ + ServiceName: pointer.StringPtr("kuard"), + Port: gatewayPort(8080), + Weight: 0, + }}, + }}, + }, + }, + }, + want: listeners( + &Listener{ + Port: 80, + VirtualHosts: virtualhosts( + virtualhost("*", directResponseRouteService("/", http.StatusServiceUnavailable, &Service{ + Weighted: WeightedService{ + Weight: 0, + ServiceName: kuardService.Name, + ServiceNamespace: kuardService.Namespace, + ServicePort: kuardService.Spec.Ports[0], + }, + })), + ), + }, + ), + }, } for name, tc := range tests { @@ -10337,6 +10514,15 @@ func directResponseRoute(prefix string, statusCode uint32) *Route { } } +func directResponseRouteService(prefix string, statusCode uint32, first *Service, rest ...*Service) *Route { + services := append([]*Service{first}, rest...) + return &Route{ + PathMatchCondition: prefixString(prefix), + DirectResponse: &DirectResponse{StatusCode: statusCode}, + Clusters: clustersWeight(services...), + } +} + func httpRouteMatch(pathType gatewayapi_v1alpha1.PathMatchType, value string) []gatewayapi_v1alpha1.HTTPRouteMatch { return []gatewayapi_v1alpha1.HTTPRouteMatch{{ Path: gatewayapi_v1alpha1.HTTPPathMatch{ @@ -10346,10 +10532,20 @@ func httpRouteMatch(pathType gatewayapi_v1alpha1.PathMatchType, value string) [] }} } -func httpRouteForwardTo(serviceName string, port int) []gatewayapi_v1alpha1.HTTPRouteForwardTo { +func httpRouteForwards(forwards ...[]gatewayapi_v1alpha1.HTTPRouteForwardTo) []gatewayapi_v1alpha1.HTTPRouteForwardTo { + var fwds []gatewayapi_v1alpha1.HTTPRouteForwardTo + + for _, f := range forwards { + fwds = append(fwds, f...) + } + return fwds +} + +func httpRouteForwardTo(serviceName string, port int, weight int32) []gatewayapi_v1alpha1.HTTPRouteForwardTo { return []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ ServiceName: pointer.StringPtr(serviceName), Port: gatewayPort(port), + Weight: weight, }} } @@ -10361,11 +10557,19 @@ func prefixroute(prefix string, first *Service, rest ...*Service) *Route { } } -func exactroute(path string, first *Service, rest ...*Service) *Route { +func prefixrouteHTTPRoute(prefix string, first *Service, rest ...*Service) *Route { + services := append([]*Service{first}, rest...) + return &Route{ + PathMatchCondition: prefixString(prefix), + Clusters: clustersWeight(services...), + } +} + +func exactrouteHTTPRoute(path string, first *Service, rest ...*Service) *Route { services := append([]*Service{first}, rest...) return &Route{ PathMatchCondition: &ExactMatchCondition{Path: path}, - Clusters: clusters(services...), + Clusters: clustersWeight(services...), } } @@ -10425,6 +10629,7 @@ func clusterHeaders(requestSet map[string]string, requestAdd map[string]string, Remove: requestRemove, HostRewrite: hostRewrite, }, + Weight: s.Weighted.Weight, }) } return c @@ -10440,6 +10645,17 @@ func clusters(services ...*Service) (c []*Cluster) { return c } +func clustersWeight(services ...*Service) (c []*Cluster) { + for _, s := range services { + c = append(c, &Cluster{ + Upstream: s, + Protocol: s.Protocol, + Weight: s.Weighted.Weight, + }) + } + return c +} + func service(s *v1.Service) *Service { return &Service{ Weighted: WeightedService{ diff --git a/internal/dag/gatewayapi_processor.go b/internal/dag/gatewayapi_processor.go index b6986aef042..aeb2387aea8 100644 --- a/internal/dag/gatewayapi_processor.go +++ b/internal/dag/gatewayapi_processor.go @@ -308,6 +308,7 @@ func (p *GatewayAPIProcessor) computeHTTPRoute(route *gatewayapi_v1alpha1.HTTPRo var clusters []*Cluster // Validate the ForwardTos. + totalWeight := int32(0) for _, forward := range rule.ForwardTo { // Verify the service is valid @@ -345,8 +346,13 @@ func (p *GatewayAPIProcessor) computeHTTPRoute(route *gatewayapi_v1alpha1.HTTPRo } } - cluster := p.cluster(headerPolicy, service) - clusters = append(clusters, cluster) + // Keep track of all the weights for this set of forwardTos. This will be + // used later to understand if all the weights are set to zero. + totalWeight += forward.Weight + + // https://github.com/projectcontour/contour/issues/3593 + service.Weighted.Weight = uint32(forward.Weight) + clusters = append(clusters, p.cluster(headerPolicy, service, uint32(forward.Weight))) } var headerPolicy *HeadersPolicy @@ -366,8 +372,9 @@ func (p *GatewayAPIProcessor) computeHTTPRoute(route *gatewayapi_v1alpha1.HTTPRo routes := p.routes(matchconditions, headerPolicy, clusters) for _, host := range hosts { for _, route := range routes { - - if len(clusters) == 0 { + // If there aren't any valid services, or the total weight of all of + // them equal zero, then return 503 responses to the caller. + if len(clusters) == 0 || totalWeight == 0 { // Configure a direct response HTTP status code of 503 so the // route still matches the configured conditions since the // service is missing or invalid. @@ -418,9 +425,10 @@ func (p *GatewayAPIProcessor) routes(matchConditions []*matchConditions, headerP } // cluster builds a *dag.Cluster for the supplied set of headerPolicy and service. -func (p *GatewayAPIProcessor) cluster(headerPolicy *HeadersPolicy, service *Service) *Cluster { +func (p *GatewayAPIProcessor) cluster(headerPolicy *HeadersPolicy, service *Service, weight uint32) *Cluster { return &Cluster{ Upstream: service, + Weight: weight, Protocol: service.Protocol, RequestHeadersPolicy: headerPolicy, } diff --git a/internal/featuretests/v3/gatewayapi_test.go b/internal/featuretests/v3/gatewayapi_test.go index c2c69c940d2..4605f0e7e46 100644 --- a/internal/featuretests/v3/gatewayapi_test.go +++ b/internal/featuretests/v3/gatewayapi_test.go @@ -17,11 +17,9 @@ import ( "testing" envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" - - "github.com/projectcontour/contour/internal/dag" - envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" envoy_discovery_v3 "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" + "github.com/projectcontour/contour/internal/dag" envoy_v3 "github.com/projectcontour/contour/internal/envoy/v3" "github.com/projectcontour/contour/internal/featuretests" "github.com/projectcontour/contour/internal/fixture" @@ -32,6 +30,41 @@ import ( gatewayapi_v1alpha1 "sigs.k8s.io/gateway-api/apis/v1alpha1" ) +var gateway = &gatewayapi_v1alpha1.Gateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "contour", + Namespace: "projectcontour", + }, + Spec: gatewayapi_v1alpha1.GatewaySpec{ + Listeners: []gatewayapi_v1alpha1.Listener{{ + Port: 80, + Protocol: "HTTP", + Routes: gatewayapi_v1alpha1.RouteBindingSelector{ + Namespaces: gatewayapi_v1alpha1.RouteNamespaces{ + From: gatewayapi_v1alpha1.RouteSelectAll, + }, + Kind: dag.KindHTTPRoute, + }, + }, { + Port: 443, + Protocol: "HTTPS", + TLS: &gatewayapi_v1alpha1.GatewayTLSConfig{ + CertificateRef: &gatewayapi_v1alpha1.LocalObjectReference{ + Group: "core", + Kind: "Secret", + Name: "tlscert", + }, + }, + Routes: gatewayapi_v1alpha1.RouteBindingSelector{ + Namespaces: gatewayapi_v1alpha1.RouteNamespaces{ + From: gatewayapi_v1alpha1.RouteSelectAll, + }, + Kind: dag.KindHTTPRoute, + }, + }}, + }, +} + func TestGateway_TLS(t *testing.T) { rh, c, done := setup(t) defer done() @@ -55,40 +88,7 @@ func TestGateway_TLS(t *testing.T) { rh.OnAdd(sec1) - rh.OnAdd(&gatewayapi_v1alpha1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "contour", - Namespace: "projectcontour", - }, - Spec: gatewayapi_v1alpha1.GatewaySpec{ - Listeners: []gatewayapi_v1alpha1.Listener{{ - Port: 80, - Protocol: "HTTP", - Routes: gatewayapi_v1alpha1.RouteBindingSelector{ - Namespaces: gatewayapi_v1alpha1.RouteNamespaces{ - From: gatewayapi_v1alpha1.RouteSelectAll, - }, - Kind: dag.KindHTTPRoute, - }, - }, { - Port: 443, - Protocol: "HTTPS", - TLS: &gatewayapi_v1alpha1.GatewayTLSConfig{ - CertificateRef: &gatewayapi_v1alpha1.LocalObjectReference{ - Group: "core", - Kind: "Secret", - Name: "tlscert", - }, - }, - Routes: gatewayapi_v1alpha1.RouteBindingSelector{ - Namespaces: gatewayapi_v1alpha1.RouteNamespaces{ - From: gatewayapi_v1alpha1.RouteSelectAll, - }, - Kind: dag.KindHTTPRoute, - }, - }}, - }, - }) + rh.OnAdd(gateway) rh.OnAdd(&gatewayapi_v1alpha1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ @@ -113,6 +113,7 @@ func TestGateway_TLS(t *testing.T) { ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ ServiceName: pointer.StringPtr("svc2"), Port: gatewayPort(80), + Weight: 1, }}, }, { Matches: []gatewayapi_v1alpha1.HTTPRouteMatch{{ @@ -124,6 +125,7 @@ func TestGateway_TLS(t *testing.T) { ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ ServiceName: pointer.StringPtr("svc1"), Port: gatewayPort(80), + Weight: 10, }}, }}, }, diff --git a/internal/featuretests/v3/routeweight_test.go b/internal/featuretests/v3/routeweight_test.go index c69954f68fe..9bfe5ce4022 100644 --- a/internal/featuretests/v3/routeweight_test.go +++ b/internal/featuretests/v3/routeweight_test.go @@ -19,12 +19,15 @@ import ( envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" contour_api_v1 "github.com/projectcontour/contour/apis/projectcontour/v1" + "github.com/projectcontour/contour/internal/dag" envoy_v3 "github.com/projectcontour/contour/internal/envoy/v3" "github.com/projectcontour/contour/internal/fixture" "github.com/projectcontour/contour/internal/protobuf" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/utils/pointer" + gatewayapi_v1alpha1 "sigs.k8s.io/gateway-api/apis/v1alpha1" ) type weightedcluster struct { @@ -32,7 +35,7 @@ type weightedcluster struct { weight uint32 } -func TestHTTPProxyRouteWithAServiceWeight(t *testing.T) { +func TestHTTPProxy_RouteWithAServiceWeight(t *testing.T) { rh, c, done := setup(t) defer done() @@ -102,6 +105,123 @@ func TestHTTPProxyRouteWithAServiceWeight(t *testing.T) { ), nil) } +func TestHTTPRoute_RouteWithAServiceWeight(t *testing.T) { + rh, c, done := setup(t) + defer done() + + rh.OnAdd(fixture.NewService("svc1"). + WithPorts(v1.ServicePort{Port: 80, TargetPort: intstr.FromInt(8080)})) + + rh.OnAdd(fixture.NewService("svc2"). + WithPorts(v1.ServicePort{Port: 80, TargetPort: intstr.FromInt(8080)})) + + rh.OnAdd(&gatewayapi_v1alpha1.Gateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "contour", + Namespace: "projectcontour", + }, + Spec: gatewayapi_v1alpha1.GatewaySpec{ + Listeners: []gatewayapi_v1alpha1.Listener{{ + Port: 80, + Protocol: "HTTP", + Routes: gatewayapi_v1alpha1.RouteBindingSelector{ + Namespaces: gatewayapi_v1alpha1.RouteNamespaces{ + From: gatewayapi_v1alpha1.RouteSelectAll, + }, + Kind: dag.KindHTTPRoute, + }, + }}, + }, + }) + + // HTTPRoute with a single weight. + route1 := &gatewayapi_v1alpha1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "basic", + Namespace: "default", + Labels: map[string]string{ + "app": "contour", + "type": "controller", + }, + }, + Spec: gatewayapi_v1alpha1.HTTPRouteSpec{ + Hostnames: []gatewayapi_v1alpha1.Hostname{ + "test.projectcontour.io", + }, + Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ + Matches: []gatewayapi_v1alpha1.HTTPRouteMatch{{ + Path: gatewayapi_v1alpha1.HTTPPathMatch{ + Type: "Prefix", + Value: "/blog", + }, + }}, + ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ + ServiceName: pointer.StringPtr("svc1"), + Port: gatewayPort(80), + Weight: 1, + }}, + }}, + }, + } + + rh.OnAdd(route1) + + assertRDS(t, c, "1", virtualhosts( + envoy_v3.VirtualHost("test.projectcontour.io", + &envoy_route_v3.Route{ + Match: routePrefix("/blog"), + Action: routecluster("default/svc1/80/da39a3ee5e"), + }, + ), + ), nil) + + // HTTPRoute with multiple weights. + route2 := &gatewayapi_v1alpha1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "basic", + Namespace: "default", + Labels: map[string]string{ + "app": "contour", + "type": "controller", + }, + }, + Spec: gatewayapi_v1alpha1.HTTPRouteSpec{ + Hostnames: []gatewayapi_v1alpha1.Hostname{ + "test.projectcontour.io", + }, + Rules: []gatewayapi_v1alpha1.HTTPRouteRule{{ + Matches: []gatewayapi_v1alpha1.HTTPRouteMatch{{ + Path: gatewayapi_v1alpha1.HTTPPathMatch{ + Type: "Prefix", + Value: "/blog", + }, + }}, + ForwardTo: []gatewayapi_v1alpha1.HTTPRouteForwardTo{{ + ServiceName: pointer.StringPtr("svc1"), + Port: gatewayPort(80), + Weight: 60, + }, { + ServiceName: pointer.StringPtr("svc2"), + Port: gatewayPort(80), + Weight: 90, + }}, + }}, + }, + } + + rh.OnUpdate(route1, route2) + assertRDS(t, c, "2", virtualhosts( + envoy_v3.VirtualHost("test.projectcontour.io", + &envoy_route_v3.Route{ + Match: routePrefix("/blog"), + Action: routeweightedcluster( + weightedcluster{"default/svc1/80/da39a3ee5e", 60}, + weightedcluster{"default/svc2/80/da39a3ee5e", 90}), + }, + ), + ), nil) +} + func routeweightedcluster(clusters ...weightedcluster) *envoy_route_v3.Route_Route { return &envoy_route_v3.Route_Route{ Route: &envoy_route_v3.RouteAction{