Skip to content

Commit 10c38a5

Browse files
committed
Add support for HTTPOption
1 parent 3090431 commit 10c38a5

File tree

9 files changed

+556
-136
lines changed

9 files changed

+556
-136
lines changed

config/config-gateway.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,17 @@ data:
4040
# gatewayClass: GatewayClass Name
4141
# gateway: the namespace/name of Gateway
4242
# service: the namespace/name of Service for the Gateway
43+
# httpListenerName: the name of the listener for HTTP traffic in the Gateway (required)
4344
#
4445
# The gateway configuration for the default visibility.
4546
visibility: |
4647
ExternalIP:
4748
class: istio
4849
gateway: istio-system/knative-gateway
4950
service: istio-system/istio-ingressgateway
51+
httpListenerName: default
5052
ClusterLocal:
5153
class: istio
5254
gateway: istio-system/knative-local-gateway
5355
service: istio-system/knative-local-gateway
56+
httpListenerName: http2

pkg/reconciler/ingress/config/gateway.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ const (
3737

3838
// defaultGatewayClass is the gatewayclass name for the gateway.
3939
defaultGatewayClass = "istio"
40+
41+
// defaultClusterLocalHTTPListener is the name of the listener for HTTP traffic
42+
defaultClusterLocalHTTPListener = "http2"
43+
44+
// defaultExternalIPHTTPListener
45+
defaultExternalIPHTTPListener = "default"
4046
)
4147

4248
var (
@@ -54,15 +60,17 @@ var (
5460
)
5561

5662
type GatewayConfig struct {
57-
GatewayClass string
58-
Gateway *types.NamespacedName
59-
Service *types.NamespacedName
63+
GatewayClass string
64+
Gateway *types.NamespacedName
65+
Service *types.NamespacedName
66+
HTTPListenerName string
6067
}
6168

6269
type visibilityValue struct {
63-
GatewayClass string `json:"class,omitempty"`
64-
Gateway string `json:"gateway,omitempty"`
65-
Service string `json:"service,omitempty"`
70+
GatewayClass string `json:"class,omitempty"`
71+
Gateway string `json:"gateway,omitempty"`
72+
Service string `json:"service,omitempty"`
73+
HTTPListenerName string `json:"httpListenerName,omitempty"`
6674
}
6775

6876
// Gateway maps gateways to routes by matching the gateway's
@@ -82,8 +90,18 @@ func NewGatewayFromConfigMap(configMap *corev1.ConfigMap) (*Gateway, error) {
8290
// These are the defaults.
8391
return &Gateway{
8492
Gateways: map[v1alpha1.IngressVisibility]GatewayConfig{
85-
v1alpha1.IngressVisibilityExternalIP: {GatewayClass: defaultGatewayClass, Gateway: defaultIstioGateway, Service: defaultGatewayService},
86-
v1alpha1.IngressVisibilityClusterLocal: {GatewayClass: defaultGatewayClass, Gateway: defaultIstioLocalGateway, Service: defaultLocalGatewayService},
93+
v1alpha1.IngressVisibilityExternalIP: {
94+
GatewayClass: defaultGatewayClass,
95+
Gateway: defaultIstioGateway,
96+
Service: defaultGatewayService,
97+
HTTPListenerName: defaultExternalIPHTTPListener,
98+
},
99+
v1alpha1.IngressVisibilityClusterLocal: {
100+
GatewayClass: defaultGatewayClass,
101+
Gateway: defaultIstioLocalGateway,
102+
Service: defaultLocalGatewayService,
103+
HTTPListenerName: defaultClusterLocalHTTPListener,
104+
},
87105
},
88106
}, nil
89107
}
@@ -121,10 +139,14 @@ func NewGatewayFromConfigMap(configMap *corev1.ConfigMap) (*Gateway, error) {
121139
if err != nil {
122140
return nil, fmt.Errorf("visibility %q failed to parse service: %w", key, err)
123141
}
142+
if value.HTTPListenerName == "" {
143+
return nil, fmt.Errorf("visibility %q must set httpListenerName", key)
144+
}
124145
entry[key] = GatewayConfig{
125-
GatewayClass: value.GatewayClass,
126-
Gateway: gateway,
127-
Service: service,
146+
GatewayClass: value.GatewayClass,
147+
Gateway: gateway,
148+
Service: service,
149+
HTTPListenerName: value.HTTPListenerName,
128150
}
129151
}
130152
return &Gateway{Gateways: entry}, nil

pkg/reconciler/ingress/config/testdata/config-gateway.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,17 @@ data:
3535
# gatewayClass: GatewayClass Name
3636
# gateway: the namespace/name of Gateway
3737
# service: the namespace/name of Service for the Gateway
38+
# httpListenerName: the name of the listener for HTTP traffic in the Gateway (required)
3839
#
3940
# The gateway configuration for the default visibility.
4041
visibility: |
4142
ExternalIP:
4243
class: istio
4344
gateway: istio-system/knative-gateway
4445
service: istio-system/istio-ingressgateway
46+
httpListenerName: default
4547
ClusterLocal:
4648
class: istio
4749
gateway: istio-system/knative-local-gateway
4850
service: istio-system/knative-local-gateway
51+
httpListenerName: http2

pkg/reconciler/ingress/ingress.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,20 @@ func (c *Reconciler) reconcileIngress(ctx context.Context, ing *v1alpha1.Ingress
9898
for _, rule := range ing.Spec.Rules {
9999
rule := rule
100100

101-
httproutes, err := c.reconcileHTTPRoute(ctx, ing, &rule)
101+
workloadHTTPRoute, err := c.reconcileWorkloadRoute(ctx, ing, &rule)
102102
if err != nil {
103103
return err
104104
}
105105

106-
if isHTTPRouteReady(httproutes) {
106+
var redirectHTTPRoute *gatewayapi.HTTPRoute
107+
if ing.Spec.HTTPOption == v1alpha1.HTTPOptionRedirected {
108+
redirectHTTPRoute, err = c.reconcileRedirectHTTPRoute(ctx, ing, &rule)
109+
if err != nil {
110+
return err
111+
}
112+
}
113+
114+
if isHTTPRouteReady(workloadHTTPRoute) && (redirectHTTPRoute == nil || isHTTPRouteReady(redirectHTTPRoute)) {
107115
ing.Status.MarkNetworkConfigured()
108116
} else {
109117
ing.Status.MarkIngressNotReady("HTTPRouteNotReady", "Waiting for HTTPRoute becomes Ready.")

pkg/reconciler/ingress/ingress_test.go

Lines changed: 86 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ var (
5656
privateSvcIP = "5.6.7.8"
5757
publicSvc = network.GetServiceHostname(publicName, testNamespace)
5858
privateSvc = network.GetServiceHostname(privateName, testNamespace)
59+
60+
gatewayRef = gatewayapi.ParentReference{
61+
Group: (*gatewayapi.Group)(pointer.String("gateway.networking.k8s.io")),
62+
Kind: (*gatewayapi.Kind)(pointer.String("Gateway")),
63+
Namespace: (*gatewayapi.Namespace)(pointer.String("istio-system")),
64+
Name: gatewayapi.ObjectName("istio-gateway"),
65+
}
5966
)
6067

6168
var (
@@ -149,19 +156,19 @@ func TestReconcile(t *testing.T) {
149156
Name: "skip ingress marked for deletion",
150157
Key: "ns/name",
151158
Objects: []runtime.Object{
152-
ing(withBasicSpec, withGatewayAPIclass, func(i *v1alpha1.Ingress) {
159+
ing(withBasicSpec, withGatewayAPIClass, func(i *v1alpha1.Ingress) {
153160
i.SetDeletionTimestamp(&metav1.Time{Time: time.Now()})
154161
}),
155162
},
156163
}, {
157164
Name: "first reconcile basic ingress",
158165
Key: "ns/name",
159166
Objects: append([]runtime.Object{
160-
ing(withBasicSpec, withGatewayAPIclass),
167+
ing(withBasicSpec, withGatewayAPIClass),
161168
}, servicesAndEndpoints...),
162-
WantCreates: []runtime.Object{httpRoute(t, ing(withBasicSpec, withGatewayAPIclass))},
169+
WantCreates: []runtime.Object{httpRoute(t, ing(withBasicSpec, withGatewayAPIClass))},
163170
WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
164-
Object: ing(withBasicSpec, withGatewayAPIclass, func(i *v1alpha1.Ingress) {
171+
Object: ing(withBasicSpec, withGatewayAPIClass, func(i *v1alpha1.Ingress) {
165172
// These are the things we expect to change in status.
166173
i.Status.InitializeConditions()
167174
i.Status.MarkLoadBalancerReady(
@@ -188,8 +195,8 @@ func TestReconcile(t *testing.T) {
188195
Name: "reconcile ready ingress",
189196
Key: "ns/name",
190197
Objects: append([]runtime.Object{
191-
ing(withBasicSpec, withGatewayAPIclass, makeItReady, withFinalizer),
192-
httpRoute(t, ing(withBasicSpec, withGatewayAPIclass)),
198+
ing(withBasicSpec, withGatewayAPIClass, makeItReady, withFinalizer),
199+
httpRoute(t, ing(withBasicSpec, withGatewayAPIClass)),
193200
}, servicesAndEndpoints...),
194201
// no extra update
195202
}}
@@ -223,11 +230,11 @@ func TestReconcileProberNotReady(t *testing.T) {
223230
Name: "first reconcile basic ingress wth prober",
224231
Key: "ns/name",
225232
Objects: append([]runtime.Object{
226-
ing(withBasicSpec, withGatewayAPIclass),
233+
ing(withBasicSpec, withGatewayAPIClass),
227234
}, servicesAndEndpoints...),
228-
WantCreates: []runtime.Object{httpRoute(t, ing(withBasicSpec, withGatewayAPIclass))},
235+
WantCreates: []runtime.Object{httpRoute(t, ing(withBasicSpec, withGatewayAPIClass))},
229236
WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
230-
Object: ing(withBasicSpec, withGatewayAPIclass, func(i *v1alpha1.Ingress) {
237+
Object: ing(withBasicSpec, withGatewayAPIClass, func(i *v1alpha1.Ingress) {
231238
i.Status.InitializeConditions()
232239
i.Status.MarkLoadBalancerNotReady()
233240
}),
@@ -389,6 +396,47 @@ func TestReconcileTLS(t *testing.T) {
389396
Eventf(corev1.EventTypeWarning, "GatewayMissing", `Unable to update Gateway istio-system/istio-gateway`),
390397
Eventf(corev1.EventTypeWarning, "InternalError", `Gateway istio-system/istio-gateway does not exist: gateway.gateway.networking.k8s.io "istio-gateway" not found`),
391398
},
399+
}, {
400+
Name: "TLS ingress with httpOption redirected",
401+
Key: "ns/name",
402+
Objects: append([]runtime.Object{
403+
ing(withBasicSpec, withGatewayAPIClass, withHTTPOptionRedirected, withTLS(secretName)),
404+
secret(secretName, nsName),
405+
gw(defaultListener),
406+
}, servicesAndEndpoints...),
407+
WantCreates: []runtime.Object{
408+
httpRoute(t, ing(withBasicSpec, withGatewayAPIClass, withHTTPOptionRedirected, withTLS(secretName)), withSectionName("kni-")),
409+
httpRedirectRoute(t, ing(withBasicSpec, withGatewayAPIClass, withHTTPOptionRedirected, withTLS(secretName)), withSectionName("http")),
410+
rp(secret(secretName, nsName)),
411+
},
412+
WantUpdates: []clientgotesting.UpdateActionImpl{{
413+
Object: gw(defaultListener, tlsListener("secure.example.com", nsName, secretName)),
414+
}},
415+
WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
416+
Object: ing(withBasicSpec, withGatewayAPIClass, withHTTPOptionRedirected, withTLS(secretName), func(i *v1alpha1.Ingress) {
417+
// These are the things we expect to change in status.
418+
i.Status.InitializeConditions()
419+
i.Status.MarkLoadBalancerReady(
420+
[]v1alpha1.LoadBalancerIngressStatus{{
421+
DomainInternal: publicSvc,
422+
}},
423+
[]v1alpha1.LoadBalancerIngressStatus{{
424+
DomainInternal: privateSvc,
425+
}})
426+
}),
427+
}},
428+
WantPatches: []clientgotesting.PatchActionImpl{{
429+
ActionImpl: clientgotesting.ActionImpl{
430+
Namespace: "ns",
431+
},
432+
Name: "name",
433+
Patch: []byte(`{"metadata":{"finalizers":["ingresses.networking.internal.knative.dev"],"resourceVersion":""}}`),
434+
}},
435+
WantEvents: []string{
436+
Eventf(corev1.EventTypeNormal, "FinalizerUpdate", `Updated "name" finalizers`),
437+
Eventf(corev1.EventTypeNormal, "Created", "Created HTTPRoute \"example.com\""),
438+
Eventf(corev1.EventTypeNormal, "Created", "Created HTTPRoute \"example.com-redirect\""),
439+
},
392440
}}
393441

394442
table.Test(t, GatewayFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher, tr *TableRow) controller.Reconciler {
@@ -433,11 +481,11 @@ func TestReconcileProbeError(t *testing.T) {
433481
Key: "ns/name",
434482
WantErr: true,
435483
Objects: append([]runtime.Object{
436-
ing(withBasicSpec, withGatewayAPIclass),
484+
ing(withBasicSpec, withGatewayAPIClass),
437485
}, servicesAndEndpoints...),
438-
WantCreates: []runtime.Object{httpRoute(t, ing(withBasicSpec, withGatewayAPIclass))},
486+
WantCreates: []runtime.Object{httpRoute(t, ing(withBasicSpec, withGatewayAPIClass))},
439487
WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
440-
Object: ing(withBasicSpec, withGatewayAPIclass, func(i *v1alpha1.Ingress) {
488+
Object: ing(withBasicSpec, withGatewayAPIClass, func(i *v1alpha1.Ingress) {
441489
i.Status.InitializeConditions()
442490
i.Status.MarkIngressNotReady(notReconciledReason, notReconciledMessage)
443491
}),
@@ -493,20 +541,31 @@ func makeItReady(i *v1alpha1.Ingress) {
493541
func httpRoute(t *testing.T, i *v1alpha1.Ingress, opts ...HTTPRouteOption) runtime.Object {
494542
t.Helper()
495543
ingress.InsertProbe(i)
496-
ctx := (&testConfigStore{config: defaultConfig}).ToContext(context.Background())
497-
httpRoute, _ := resources.MakeHTTPRoute(ctx, i, &i.Spec.Rules[0])
544+
545+
httpRoute, _ := resources.MakeHTTPRoute(i, &i.Spec.Rules[0], gatewayRef)
498546
for _, opt := range opts {
499547
opt(httpRoute)
500548
}
501549
return httpRoute
502550
}
503551

552+
func httpRedirectRoute(t *testing.T, i *v1alpha1.Ingress, opts ...HTTPRouteOption) runtime.Object {
553+
t.Helper()
554+
ingress.InsertProbe(i)
555+
556+
httpRedirectRoute, _ := resources.MakeRedirectHTTPRoute(i, &i.Spec.Rules[0], gatewayRef)
557+
for _, opt := range opts {
558+
opt(httpRedirectRoute)
559+
}
560+
return httpRedirectRoute
561+
}
562+
504563
type HTTPRouteOption func(h *gatewayapi.HTTPRoute)
505564

506-
func withGatewayAPIclass(i *v1alpha1.Ingress) {
507-
withAnnotation(map[string]string{
508-
networking.IngressClassAnnotationKey: gatewayAPIIngressClassName,
509-
})(i)
565+
func withSectionName(sectionName string) HTTPRouteOption {
566+
return func(h *gatewayapi.HTTPRoute) {
567+
h.Spec.CommonRouteSpec.ParentRefs[0].SectionName = (*gatewayapi.SectionName)(pointer.String(sectionName))
568+
}
510569
}
511570

512571
type fakeStatusManager struct {
@@ -566,7 +625,7 @@ func defaultListener(g *gatewayapi.Gateway) {
566625
func tlsListener(hostname, nsName, secretName string) GatewayOption {
567626
return func(g *gatewayapi.Gateway) {
568627
g.Spec.Listeners = append(g.Spec.Listeners, gatewayapi.Listener{
569-
Name: gatewayapi.SectionName("kni-"),
628+
Name: "kni-",
570629
Hostname: (*gatewayapi.Hostname)(&hostname),
571630
Port: 443,
572631
Protocol: "HTTPS",
@@ -644,8 +703,8 @@ func rp(to *corev1.Secret) *gatewayapialpha.ReferenceGrant {
644703
Namespace: gatewayapialpha.Namespace(testNamespace),
645704
}},
646705
To: []gatewayapialpha.ReferenceGrantTo{{
647-
Group: gatewayapialpha.Group(""),
648-
Kind: gatewayapialpha.Kind("Secret"),
706+
Group: "",
707+
Kind: "Secret",
649708
Name: (*gatewayapialpha.ObjectName)(&to.Name),
650709
}},
651710
},
@@ -658,12 +717,14 @@ var (
658717
Gateway: &config.Gateway{
659718
Gateways: map[v1alpha1.IngressVisibility]config.GatewayConfig{
660719
v1alpha1.IngressVisibilityExternalIP: {
661-
Service: &types.NamespacedName{Namespace: "istio-system", Name: "istio-gateway"},
662-
Gateway: &types.NamespacedName{Namespace: "istio-system", Name: "istio-gateway"},
720+
Service: &types.NamespacedName{Namespace: "istio-system", Name: "istio-gateway"},
721+
Gateway: &types.NamespacedName{Namespace: "istio-system", Name: "istio-gateway"},
722+
HTTPListenerName: "http",
663723
},
664724
v1alpha1.IngressVisibilityClusterLocal: {
665-
Service: &types.NamespacedName{Namespace: "istio-system", Name: "knative-local-gateway"},
666-
Gateway: &types.NamespacedName{Namespace: "istio-system", Name: "knative-local-gateway"},
725+
Service: &types.NamespacedName{Namespace: "istio-system", Name: "knative-local-gateway"},
726+
Gateway: &types.NamespacedName{Namespace: "istio-system", Name: "knative-local-gateway"},
727+
HTTPListenerName: "http",
667728
},
668729
},
669730
},

pkg/reconciler/ingress/lister_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,10 @@ func withBasicSpec(i *v1alpha1.Ingress) {
313313
})
314314
}
315315

316+
func withHTTPOptionRedirected(i *v1alpha1.Ingress) {
317+
i.Spec.HTTPOption = v1alpha1.HTTPOptionRedirected
318+
}
319+
316320
func withInternalSpec(i *v1alpha1.Ingress) {
317321
i.Spec.Rules = append(i.Spec.Rules, v1alpha1.IngressRule{
318322
Hosts: []string{"foo.svc", "foo.svc.cluster.local"},

0 commit comments

Comments
 (0)