This is an automated email from the ASF dual-hosted git repository. ronething pushed a commit to branch feat/enable-websocket in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git
commit f40213537bf040584fee56f1b63129ae1d9beb4a Author: Ashing Zheng <[email protected]> AuthorDate: Sun Oct 26 16:00:25 2025 +0800 feat: support websocket annotations for ingress Signed-off-by: Ashing Zheng <[email protected]> --- internal/adc/translator/annotations.go | 7 +++-- .../translator/annotations/websocket/websocket.go | 30 ++++++++++++++++++++++ internal/adc/translator/annotations_test.go | 9 +++++++ internal/adc/translator/ingress.go | 5 +++- internal/webhook/v1/ingress_webhook.go | 1 - internal/webhook/v1/ingress_webhook_test.go | 23 ----------------- test/e2e/ingress/annotations.go | 30 ++++++++++++++++++++++ test/e2e/webhook/ingress.go | 2 -- 8 files changed, 78 insertions(+), 29 deletions(-) diff --git a/internal/adc/translator/annotations.go b/internal/adc/translator/annotations.go index 28319b65..ca4f27c6 100644 --- a/internal/adc/translator/annotations.go +++ b/internal/adc/translator/annotations.go @@ -23,16 +23,19 @@ import ( "github.com/apache/apisix-ingress-controller/internal/adc/translator/annotations" "github.com/apache/apisix-ingress-controller/internal/adc/translator/annotations/upstream" + "github.com/apache/apisix-ingress-controller/internal/adc/translator/annotations/websocket" ) // Structure extracted by Ingress Resource type IngressConfig struct { - Upstream upstream.Upstream + Upstream upstream.Upstream + EnableWebsocket bool } // parsers registered for ingress annotations var ingressAnnotationParsers = map[string]annotations.IngressAnnotationsParser{ - "upstream": upstream.NewParser(), + "upstream": upstream.NewParser(), + "EnableWebsocket": websocket.NewParser(), } func (t *Translator) TranslateIngressAnnotations(anno map[string]string) *IngressConfig { diff --git a/internal/adc/translator/annotations/websocket/websocket.go b/internal/adc/translator/annotations/websocket/websocket.go new file mode 100644 index 00000000..61474b91 --- /dev/null +++ b/internal/adc/translator/annotations/websocket/websocket.go @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package websocket + +import ( + "github.com/apache/apisix-ingress-controller/internal/adc/translator/annotations" +) + +type WebSocket struct{} + +func NewParser() annotations.IngressAnnotationsParser { + return &WebSocket{} +} + +func (w *WebSocket) Parse(e annotations.Extractor) (any, error) { + return e.GetBoolAnnotation(annotations.AnnotationsEnableWebSocket), nil +} diff --git a/internal/adc/translator/annotations_test.go b/internal/adc/translator/annotations_test.go index 8216be3f..32084eb3 100644 --- a/internal/adc/translator/annotations_test.go +++ b/internal/adc/translator/annotations_test.go @@ -160,6 +160,15 @@ func TestTranslateIngressAnnotations(t *testing.T) { }, }, }, + { + name: "enable websocket", + anno: map[string]string{ + annotations.AnnotationsEnableWebSocket: "true", + }, + expected: &IngressConfig{ + EnableWebsocket: true, + }, + }, } for _, tt := range tests { diff --git a/internal/adc/translator/ingress.go b/internal/adc/translator/ingress.go index da3c5d0e..22d6430e 100644 --- a/internal/adc/translator/ingress.go +++ b/internal/adc/translator/ingress.go @@ -162,7 +162,10 @@ func (t *Translator) buildServiceFromIngressPath( service.Upstream = upstream route := buildRouteFromIngressPath(obj, path, index, labels) - if protocol == internaltypes.AppProtocolWS || protocol == internaltypes.AppProtocolWSS { + // Check if websocket is enabled via annotation first, then fall back to appProtocol detection + if config != nil && config.EnableWebsocket { + route.EnableWebsocket = ptr.To(true) + } else if protocol == internaltypes.AppProtocolWS || protocol == internaltypes.AppProtocolWSS { route.EnableWebsocket = ptr.To(true) } service.Routes = []*adctypes.Route{route} diff --git a/internal/webhook/v1/ingress_webhook.go b/internal/webhook/v1/ingress_webhook.go index 4941a821..db65f219 100644 --- a/internal/webhook/v1/ingress_webhook.go +++ b/internal/webhook/v1/ingress_webhook.go @@ -40,7 +40,6 @@ var ingresslog = logf.Log.WithName("ingress-resource") // ref: https://apisix.apache.org/docs/ingress-controller/upgrade-guide/#limited-support-for-ingress-annotations var unsupportedAnnotations = []string{ "k8s.apisix.apache.org/use-regex", - "k8s.apisix.apache.org/enable-websocket", "k8s.apisix.apache.org/plugin-config-name", "k8s.apisix.apache.org/enable-cors", "k8s.apisix.apache.org/cors-allow-origin", diff --git a/internal/webhook/v1/ingress_webhook_test.go b/internal/webhook/v1/ingress_webhook_test.go index 89f3fa6d..65c1afb7 100644 --- a/internal/webhook/v1/ingress_webhook_test.go +++ b/internal/webhook/v1/ingress_webhook_test.go @@ -64,29 +64,6 @@ func buildIngressValidator(t *testing.T, objects ...runtime.Object) *IngressCust return NewIngressCustomValidator(builder.Build()) } -func TestIngressCustomValidator_ValidateCreate_UnsupportedAnnotations(t *testing.T) { - validator := buildIngressValidator(t) - obj := &networkingv1.Ingress{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-ingress", - Namespace: "default", - Annotations: map[string]string{ - "k8s.apisix.apache.org/use-regex": "true", - "k8s.apisix.apache.org/enable-websocket": "true", - }, - }, - } - - warnings, err := validator.ValidateCreate(context.TODO(), obj) - assert.NoError(t, err) - assert.Len(t, warnings, 2) - - // Check that warnings contain the expected unsupported annotations - warningsStr := strings.Join(warnings, " ") - assert.Contains(t, warningsStr, "k8s.apisix.apache.org/use-regex") - assert.Contains(t, warningsStr, "k8s.apisix.apache.org/enable-websocket") -} - func TestIngressCustomValidator_ValidateCreate_SupportedAnnotations(t *testing.T) { validator := buildIngressValidator(t) obj := &networkingv1.Ingress{ diff --git a/test/e2e/ingress/annotations.go b/test/e2e/ingress/annotations.go index 3043d5b1..8cf3f07f 100644 --- a/test/e2e/ingress/annotations.go +++ b/test/e2e/ingress/annotations.go @@ -102,6 +102,28 @@ spec: port: number: 443 ` + + ingressWebSocket = ` +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: websocket + annotations: + k8s.apisix.apache.org/enable-websocket: "true" +spec: + ingressClassName: %s + rules: + - host: nginx.example + http: + paths: + - path: /ws + pathType: Exact + backend: + service: + name: nginx + port: + number: 80 +` ) BeforeEach(func() { s.DeployNginx(framework.NginxOptions{ @@ -167,5 +189,13 @@ spec: Expect(upstreams[0].Timeout.Send).To(Equal(3), "checking Upstream send timeout") Expect(upstreams[0].Timeout.Connect).To(Equal(4), "checking Upstream connect timeout") }) + It("websocket", func() { + Expect(s.CreateResourceFromString(fmt.Sprintf(ingressWebSocket, s.Namespace()))).ShouldNot(HaveOccurred(), "creating Ingress") + + routes, err := s.DefaultDataplaneResource().Route().List(context.Background()) + Expect(err).NotTo(HaveOccurred(), "listing Route") + Expect(routes).To(HaveLen(1), "checking Route length") + Expect(routes[0].EnableWebsocket).To(Equal(ptr.To(true)), "checking Route EnableWebsocket") + }) }) }) diff --git a/test/e2e/webhook/ingress.go b/test/e2e/webhook/ingress.go index 37608fb2..8836d90b 100644 --- a/test/e2e/webhook/ingress.go +++ b/test/e2e/webhook/ingress.go @@ -58,7 +58,6 @@ metadata: namespace: %s annotations: k8s.apisix.apache.org/use-regex: "true" - k8s.apisix.apache.org/enable-websocket: "true" spec: ingressClassName: %s rules: @@ -76,7 +75,6 @@ spec: output, err := s.CreateResourceFromStringAndGetOutput(ingressYAML) Expect(err).ShouldNot(HaveOccurred()) - Expect(output).To(ContainSubstring(`Warning: Annotation 'k8s.apisix.apache.org/enable-websocket' is not supported`)) Expect(output).To(ContainSubstring(`Warning: Annotation 'k8s.apisix.apache.org/use-regex' is not supported`)) s.RequestAssert(&scaffold.RequestAssert{
