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{

Reply via email to