Skip to content

Commit f554569

Browse files
authored
feat: support websocket annotations for ingress (#2621)
Signed-off-by: Ashing Zheng <[email protected]>
1 parent 6b70857 commit f554569

File tree

8 files changed

+81
-32
lines changed

8 files changed

+81
-32
lines changed

internal/adc/translator/annotations.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,20 @@ import (
2525
"github.com/apache/apisix-ingress-controller/internal/adc/translator/annotations"
2626
"github.com/apache/apisix-ingress-controller/internal/adc/translator/annotations/plugins"
2727
"github.com/apache/apisix-ingress-controller/internal/adc/translator/annotations/upstream"
28+
"github.com/apache/apisix-ingress-controller/internal/adc/translator/annotations/websocket"
2829
)
2930

3031
// Structure extracted by Ingress Resource
3132
type IngressConfig struct {
32-
Upstream upstream.Upstream
33-
Plugins adctypes.Plugins
33+
Upstream upstream.Upstream
34+
Plugins adctypes.Plugins
35+
EnableWebsocket bool
3436
}
3537

3638
var ingressAnnotationParsers = map[string]annotations.IngressAnnotationsParser{
37-
"upstream": upstream.NewParser(),
38-
"plugins": plugins.NewParser(),
39+
"upstream": upstream.NewParser(),
40+
"plugins": plugins.NewParser(),
41+
"EnableWebsocket": websocket.NewParser(),
3942
}
4043

4144
func (t *Translator) TranslateIngressAnnotations(anno map[string]string) *IngressConfig {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one or more
2+
// contributor license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright ownership.
4+
// The ASF licenses this file to You under the Apache License, Version 2.0
5+
// (the "License"); you may not use this file except in compliance with
6+
// the License. You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
package websocket
17+
18+
import (
19+
"github.com/apache/apisix-ingress-controller/internal/adc/translator/annotations"
20+
)
21+
22+
type WebSocket struct{}
23+
24+
func NewParser() annotations.IngressAnnotationsParser {
25+
return &WebSocket{}
26+
}
27+
28+
func (w *WebSocket) Parse(e annotations.Extractor) (any, error) {
29+
return e.GetBoolAnnotation(annotations.AnnotationsEnableWebSocket), nil
30+
}

internal/adc/translator/annotations_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,15 @@ func TestTranslateIngressAnnotations(t *testing.T) {
207207
},
208208
},
209209
},
210+
{
211+
name: "enable websocket",
212+
anno: map[string]string{
213+
annotations.AnnotationsEnableWebSocket: "true",
214+
},
215+
expected: &IngressConfig{
216+
EnableWebsocket: true,
217+
},
218+
},
210219
}
211220

212221
for _, tt := range tests {

internal/adc/translator/ingress.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,10 @@ func (t *Translator) buildServiceFromIngressPath(
162162
service.Upstream = upstream
163163

164164
route := buildRouteFromIngressPath(obj, path, config, index, labels)
165-
if protocol == internaltypes.AppProtocolWS || protocol == internaltypes.AppProtocolWSS {
165+
// Check if websocket is enabled via annotation first, then fall back to appProtocol detection
166+
if config != nil && config.EnableWebsocket {
167+
route.EnableWebsocket = ptr.To(true)
168+
} else if protocol == internaltypes.AppProtocolWS || protocol == internaltypes.AppProtocolWSS {
166169
route.EnableWebsocket = ptr.To(true)
167170
}
168171
service.Routes = []*adctypes.Route{route}

internal/webhook/v1/ingress_webhook.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ var ingresslog = logf.Log.WithName("ingress-resource")
4040
// ref: https://apisix.apache.org/docs/ingress-controller/upgrade-guide/#limited-support-for-ingress-annotations
4141
var unsupportedAnnotations = []string{
4242
"k8s.apisix.apache.org/use-regex",
43-
"k8s.apisix.apache.org/enable-websocket",
4443
"k8s.apisix.apache.org/plugin-config-name",
4544
"k8s.apisix.apache.org/enable-csrf",
4645
"k8s.apisix.apache.org/csrf-key",

internal/webhook/v1/ingress_webhook_test.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ package v1
1717

1818
import (
1919
"context"
20-
"strings"
2120
"testing"
2221

2322
"github.com/stretchr/testify/assert"
@@ -64,29 +63,6 @@ func buildIngressValidator(t *testing.T, objects ...runtime.Object) *IngressCust
6463
return NewIngressCustomValidator(builder.Build())
6564
}
6665

67-
func TestIngressCustomValidator_ValidateCreate_UnsupportedAnnotations(t *testing.T) {
68-
validator := buildIngressValidator(t)
69-
obj := &networkingv1.Ingress{
70-
ObjectMeta: metav1.ObjectMeta{
71-
Name: "test-ingress",
72-
Namespace: "default",
73-
Annotations: map[string]string{
74-
"k8s.apisix.apache.org/use-regex": "true",
75-
"k8s.apisix.apache.org/enable-websocket": "true",
76-
},
77-
},
78-
}
79-
80-
warnings, err := validator.ValidateCreate(context.TODO(), obj)
81-
assert.NoError(t, err)
82-
assert.Len(t, warnings, 2)
83-
84-
// Check that warnings contain the expected unsupported annotations
85-
warningsStr := strings.Join(warnings, " ")
86-
assert.Contains(t, warningsStr, "k8s.apisix.apache.org/use-regex")
87-
assert.Contains(t, warningsStr, "k8s.apisix.apache.org/enable-websocket")
88-
}
89-
9066
func TestIngressCustomValidator_ValidateCreate_SupportedAnnotations(t *testing.T) {
9167
validator := buildIngressValidator(t)
9268
obj := &networkingv1.Ingress{

test/e2e/ingress/annotations.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,28 @@ spec:
128128
port:
129129
number: 80
130130
`
131+
132+
ingressWebSocket = `
133+
apiVersion: networking.k8s.io/v1
134+
kind: Ingress
135+
metadata:
136+
name: websocket
137+
annotations:
138+
k8s.apisix.apache.org/enable-websocket: "true"
139+
spec:
140+
ingressClassName: %s
141+
rules:
142+
- host: nginx.example
143+
http:
144+
paths:
145+
- path: /ws
146+
pathType: Exact
147+
backend:
148+
service:
149+
name: nginx
150+
port:
151+
number: 80
152+
`
131153
)
132154
BeforeEach(func() {
133155
s.DeployNginx(framework.NginxOptions{
@@ -240,6 +262,15 @@ spec:
240262
Expect(corsConfig["allow_methods"]).To(Equal("GET,POST"), "checking cors allow methods")
241263
Expect(corsConfig["allow_headers"]).To(Equal("Origin,Authorization"), "checking cors allow headers")
242264
})
265+
266+
It("websocket", func() {
267+
Expect(s.CreateResourceFromString(fmt.Sprintf(ingressWebSocket, s.Namespace()))).ShouldNot(HaveOccurred(), "creating Ingress")
268+
269+
routes, err := s.DefaultDataplaneResource().Route().List(context.Background())
270+
Expect(err).NotTo(HaveOccurred(), "listing Route")
271+
Expect(routes).To(HaveLen(1), "checking Route length")
272+
Expect(routes[0].EnableWebsocket).To(Equal(ptr.To(true)), "checking Route EnableWebsocket")
273+
})
243274
})
244275

245276
Context("Plugins", func() {

test/e2e/webhook/ingress.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ metadata:
5858
namespace: %s
5959
annotations:
6060
k8s.apisix.apache.org/use-regex: "true"
61-
k8s.apisix.apache.org/enable-websocket: "true"
6261
spec:
6362
ingressClassName: %s
6463
rules:
@@ -76,7 +75,6 @@ spec:
7675

7776
output, err := s.CreateResourceFromStringAndGetOutput(ingressYAML)
7877
Expect(err).ShouldNot(HaveOccurred())
79-
Expect(output).To(ContainSubstring(`Warning: Annotation 'k8s.apisix.apache.org/enable-websocket' is not supported`))
8078
Expect(output).To(ContainSubstring(`Warning: Annotation 'k8s.apisix.apache.org/use-regex' is not supported`))
8179

8280
s.RequestAssert(&scaffold.RequestAssert{

0 commit comments

Comments
 (0)