Skip to content

Commit 2505c06

Browse files
authored
(backport)feat: support stream_route for ApisixRoute (#2551) (#257)
1 parent 5c876a9 commit 2505c06

File tree

24 files changed

+1074
-275
lines changed

24 files changed

+1074
-275
lines changed

api/adc/types.go

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,13 @@ type Timeout struct {
194194

195195
// +k8s:deepcopy-gen=true
196196
type StreamRoute struct {
197-
Description string `json:"description,omitempty"`
198-
ID string `json:"id,omitempty"`
199-
Labels map[string]string `json:"labels,omitempty"`
200-
Name string `json:"name"`
201-
Plugins Plugins `json:"plugins,omitempty"`
202-
RemoteAddr string `json:"remote_addr,omitempty"`
203-
ServerAddr string `json:"server_addr,omitempty"`
204-
ServerPort *int64 `json:"server_port,omitempty"`
205-
Sni string `json:"sni,omitempty"`
197+
Metadata `json:",inline" yaml:",inline"`
198+
199+
Plugins Plugins `json:"plugins,omitempty"`
200+
RemoteAddr string `json:"remote_addr,omitempty"`
201+
ServerAddr string `json:"server_addr,omitempty"`
202+
ServerPort int32 `json:"server_port,omitempty"`
203+
SNI string `json:"sni,omitempty"`
206204
}
207205

208206
// +k8s:deepcopy-gen=true
@@ -536,6 +534,24 @@ func ComposeRouteName(namespace, name string, rule string) string {
536534
return buf.String()
537535
}
538536

537+
// ComposeStreamRouteName uses namespace, name and rule name to compose
538+
// the stream_route name.
539+
func ComposeStreamRouteName(namespace, name string, rule string) string {
540+
// FIXME Use sync.Pool to reuse this buffer if the upstream
541+
// name composing code path is hot.
542+
p := make([]byte, 0, len(namespace)+len(name)+len(rule)+6)
543+
buf := bytes.NewBuffer(p)
544+
545+
buf.WriteString(namespace)
546+
buf.WriteByte('_')
547+
buf.WriteString(name)
548+
buf.WriteByte('_')
549+
buf.WriteString(rule)
550+
buf.WriteString("_tcp")
551+
552+
return buf.String()
553+
}
554+
539555
func ComposeServiceNameWithRule(namespace, name string, rule string) string {
540556
// FIXME Use sync.Pool to reuse this buffer if the upstream
541557
// name composing code path is hot.
@@ -553,6 +569,24 @@ func ComposeServiceNameWithRule(namespace, name string, rule string) string {
553569
return buf.String()
554570
}
555571

572+
func ComposeServiceNameWithStream(namespace, name string, rule string) string {
573+
// FIXME Use sync.Pool to reuse this buffer if the upstream
574+
// name composing code path is hot.
575+
var p []byte
576+
plen := len(namespace) + len(name) + 6
577+
578+
p = make([]byte, 0, plen)
579+
buf := bytes.NewBuffer(p)
580+
buf.WriteString(namespace)
581+
buf.WriteByte('_')
582+
buf.WriteString(name)
583+
buf.WriteByte('_')
584+
buf.WriteString(rule)
585+
buf.WriteString("_stream")
586+
587+
return buf.String()
588+
}
589+
556590
func ComposeConsumerName(namespace, name string) string {
557591
// FIXME Use sync.Pool to reuse this buffer if the upstream
558592
// name composing code path is hot.
@@ -603,6 +637,18 @@ func NewDefaultRoute() *Route {
603637
}
604638
}
605639

640+
// NewDefaultStreamRoute returns an empty StreamRoute with default values.
641+
func NewDefaultStreamRoute() *StreamRoute {
642+
return &StreamRoute{
643+
Metadata: Metadata{
644+
Desc: "Created by apisix-ingress-controller, DO NOT modify it manually",
645+
Labels: map[string]string{
646+
"managed-by": "apisix-ingress-controller",
647+
},
648+
},
649+
}
650+
}
651+
606652
const (
607653
PluginProxyRewrite string = "proxy-rewrite"
608654
PluginRedirect string = "redirect"

api/adc/zz_generated.deepcopy.go

Lines changed: 1 addition & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v2/apisixroute_types.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ type ApisixRouteSpec struct {
3939
HTTP []ApisixRouteHTTP `json:"http,omitempty" yaml:"http,omitempty"`
4040
// Stream defines a list of stream route rules.
4141
// Each rule specifies conditions to match TCP/UDP traffic and how to forward them.
42-
// Stream is currently not supported.
4342
Stream []ApisixRouteStream `json:"stream,omitempty" yaml:"stream,omitempty"`
4443
}
4544

@@ -111,7 +110,9 @@ type ApisixRouteHTTP struct {
111110
type ApisixRouteStream struct {
112111
// Name is a unique identifier for the route. This field must not be empty.
113112
Name string `json:"name" yaml:"name"`
114-
// Protocol specifies the L4 protocol to match. Can be `tcp` or `udp`.
113+
// Protocol specifies the L4 protocol to match. Can be `TCP` or `UDP`.
114+
//
115+
// +kubebuilder:validation:Enum=TCP;UDP
115116
Protocol string `json:"protocol" yaml:"protocol"`
116117
// Match defines the criteria used to match incoming TCP or UDP connections.
117118
Match ApisixRouteStreamMatch `json:"match" yaml:"match"`
@@ -226,6 +227,9 @@ type ApisixRouteAuthentication struct {
226227
type ApisixRouteStreamMatch struct {
227228
// IngressPort is the port on which the APISIX Ingress proxy server listens.
228229
// This must be a statically configured port, as APISIX does not support dynamic port binding.
230+
//
231+
// +kubebuilder:validation:Minimum=0
232+
// +kubebuilder:validation:Maximum=65535
229233
IngressPort int32 `json:"ingressPort" yaml:"ingressPort"`
230234
// Host is the destination host address used to match the incoming TCP/UDP traffic.
231235
Host string `json:"host,omitempty" yaml:"host,omitempty"`
@@ -241,9 +245,12 @@ type ApisixRouteStreamBackend struct {
241245
// This can be either the port name or port number.
242246
ServicePort intstr.IntOrString `json:"servicePort" yaml:"servicePort"`
243247
// ResolveGranularity determines how the backend service is resolved.
244-
// Valid values are `endpoints` and `service`. When set to `endpoints`,
248+
// Valid values are `endpoint` and `service`. When set to `endpoint`,
245249
// individual pod IPs will be used; otherwise, the Service's ClusterIP or ExternalIP is used.
246-
// The default is `endpoints`.
250+
// The default is `endpoint`.
251+
//
252+
// +kubebuilder:default=endpoint
253+
// +kubebuilder:validation:Enum=endpoint;service
247254
ResolveGranularity string `json:"resolveGranularity,omitempty" yaml:"resolveGranularity,omitempty"`
248255
// Subset specifies a named subset of the target Service.
249256
// The subset must be pre-defined in the corresponding ApisixUpstream resource.

api/v2/shared_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ const (
4545
DefaultWeight = 100
4646
)
4747

48+
const (
49+
ResolveGranularityService = "service"
50+
ResolveGranularityEndpoint = "endpoint"
51+
)
52+
4853
const (
4954
// OpEqual means the equal ("==") operator in nginxVars.
5055
OpEqual = "Equal"

config/crd/bases/apisix.apache.org_apisixroutes.yaml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,6 @@ spec:
356356
description: |-
357357
Stream defines a list of stream route rules.
358358
Each rule specifies conditions to match TCP/UDP traffic and how to forward them.
359-
Stream is currently not supported.
360359
items:
361360
description: ApisixRouteStream defines the configuration for a Layer
362361
4 (TCP/UDP) route. Currently not supported.
@@ -366,11 +365,15 @@ spec:
366365
traffic should be forwarded.
367366
properties:
368367
resolveGranularity:
368+
default: endpoint
369369
description: |-
370370
ResolveGranularity determines how the backend service is resolved.
371-
Valid values are `endpoints` and `service`. When set to `endpoints`,
371+
Valid values are `endpoint` and `service`. When set to `endpoint`,
372372
individual pod IPs will be used; otherwise, the Service's ClusterIP or ExternalIP is used.
373-
The default is `endpoints`.
373+
The default is `endpoint`.
374+
enum:
375+
- endpoint
376+
- service
374377
type: string
375378
serviceName:
376379
description: |-
@@ -408,6 +411,8 @@ spec:
408411
IngressPort is the port on which the APISIX Ingress proxy server listens.
409412
This must be a statically configured port, as APISIX does not support dynamic port binding.
410413
format: int32
414+
maximum: 65535
415+
minimum: 0
411416
type: integer
412417
required:
413418
- ingressPort
@@ -443,7 +448,10 @@ spec:
443448
type: array
444449
protocol:
445450
description: Protocol specifies the L4 protocol to match. Can
446-
be `tcp` or `udp`.
451+
be `TCP` or `UDP`.
452+
enum:
453+
- TCP
454+
- UDP
447455
type: string
448456
required:
449457
- backend

docs/en/latest/reference/api-reference.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,7 +1178,7 @@ It defines routing rules for both HTTP and stream traffic.
11781178
| --- | --- |
11791179
| `ingressClassName` _string_ | IngressClassName is the name of the IngressClass this route belongs to. It allows multiple controllers to watch and reconcile different routes. |
11801180
| `http` _[ApisixRouteHTTP](#apisixroutehttp) array_ | HTTP defines a list of HTTP route rules. Each rule specifies conditions to match HTTP requests and how to forward them. |
1181-
| `stream` _[ApisixRouteStream](#apisixroutestream) array_ | Stream defines a list of stream route rules. Each rule specifies conditions to match TCP/UDP traffic and how to forward them. Stream is currently not supported. |
1181+
| `stream` _[ApisixRouteStream](#apisixroutestream) array_ | Stream defines a list of stream route rules. Each rule specifies conditions to match TCP/UDP traffic and how to forward them. |
11821182

11831183

11841184
_Appears in:_
@@ -1194,7 +1194,7 @@ ApisixRouteStream defines the configuration for a Layer 4 (TCP/UDP) route. Curre
11941194
| Field | Description |
11951195
| --- | --- |
11961196
| `name` _string_ | Name is a unique identifier for the route. This field must not be empty. |
1197-
| `protocol` _string_ | Protocol specifies the L4 protocol to match. Can be `tcp` or `udp`. |
1197+
| `protocol` _string_ | Protocol specifies the L4 protocol to match. Can be `TCP` or `UDP`. |
11981198
| `match` _[ApisixRouteStreamMatch](#apisixroutestreammatch)_ | Match defines the criteria used to match incoming TCP or UDP connections. |
11991199
| `backend` _[ApisixRouteStreamBackend](#apisixroutestreambackend)_ | Backend specifies the destination service to which traffic should be forwarded. |
12001200
| `plugins` _[ApisixRoutePlugin](#apisixrouteplugin) array_ | Plugins defines a list of plugins to apply to this route. |
@@ -1214,7 +1214,7 @@ ApisixRouteStreamBackend represents the backend service for a TCP or UDP stream
12141214
| --- | --- |
12151215
| `serviceName` _string_ | ServiceName is the name of the Kubernetes Service. Cross-namespace references are not supported—ensure the ApisixRoute and the Service are in the same namespace. |
12161216
| `servicePort` _[IntOrString](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#intorstring-intstr-util)_ | ServicePort is the port of the Kubernetes Service. This can be either the port name or port number. |
1217-
| `resolveGranularity` _string_ | ResolveGranularity determines how the backend service is resolved. Valid values are `endpoints` and `service`. When set to `endpoints`, individual pod IPs will be used; otherwise, the Service's ClusterIP or ExternalIP is used. The default is `endpoints`. |
1217+
| `resolveGranularity` _string_ | ResolveGranularity determines how the backend service is resolved. Valid values are `endpoint` and `service`. When set to `endpoint`, individual pod IPs will be used; otherwise, the Service's ClusterIP or ExternalIP is used. The default is `endpoint`. |
12181218
| `subset` _string_ | Subset specifies a named subset of the target Service. The subset must be pre-defined in the corresponding ApisixUpstream resource. |
12191219

12201220

go.mod

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ toolchain go1.24.7
77
require (
88
github.com/Masterminds/sprig/v3 v3.2.3
99
github.com/api7/gopkg v0.2.1-0.20230601092738-0f3730f9b57a
10+
github.com/eclipse/paho.mqtt.golang v1.5.0
1011
github.com/gavv/httpexpect/v2 v2.16.0
1112
github.com/go-logr/logr v1.4.2
1213
github.com/go-logr/zapr v1.3.0
1314
github.com/google/go-cmp v0.7.0
1415
github.com/google/uuid v1.6.0
15-
github.com/gorilla/websocket v1.5.1
16-
github.com/gruntwork-io/terratest v0.47.0
16+
github.com/gorilla/websocket v1.5.3
17+
github.com/gruntwork-io/terratest v0.50.0
1718
github.com/hashicorp/go-memdb v1.3.4
1819
github.com/incubator4/go-resty-expr v0.1.1
1920
github.com/onsi/ginkgo/v2 v2.22.0
@@ -40,9 +41,10 @@ require (
4041

4142
require (
4243
cel.dev/expr v0.19.1 // indirect
44+
filippo.io/edwards25519 v1.1.0 // indirect
4345
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
4446
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
45-
github.com/BurntSushi/toml v1.3.2 // indirect
47+
github.com/BurntSushi/toml v1.4.0 // indirect
4648
github.com/MakeNowJust/heredoc v1.0.0 // indirect
4749
github.com/Masterminds/goutils v1.1.1 // indirect
4850
github.com/Masterminds/semver/v3 v3.2.1 // indirect
@@ -53,7 +55,42 @@ require (
5355
github.com/andybalholm/brotli v1.0.4 // indirect
5456
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
5557
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
56-
github.com/aws/aws-sdk-go v1.44.245 // indirect
58+
github.com/aws/aws-sdk-go-v2 v1.32.5 // indirect
59+
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect
60+
github.com/aws/aws-sdk-go-v2/config v1.28.5 // indirect
61+
github.com/aws/aws-sdk-go-v2/credentials v1.17.46 // indirect
62+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 // indirect
63+
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.41 // indirect
64+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect
65+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // indirect
66+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
67+
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.24 // indirect
68+
github.com/aws/aws-sdk-go-v2/service/acm v1.30.6 // indirect
69+
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.51.0 // indirect
70+
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.44.0 // indirect
71+
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.37.1 // indirect
72+
github.com/aws/aws-sdk-go-v2/service/ec2 v1.193.0 // indirect
73+
github.com/aws/aws-sdk-go-v2/service/ecr v1.36.6 // indirect
74+
github.com/aws/aws-sdk-go-v2/service/ecs v1.52.0 // indirect
75+
github.com/aws/aws-sdk-go-v2/service/iam v1.38.1 // indirect
76+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
77+
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.5 // indirect
78+
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.5 // indirect
79+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 // indirect
80+
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.5 // indirect
81+
github.com/aws/aws-sdk-go-v2/service/kms v1.37.6 // indirect
82+
github.com/aws/aws-sdk-go-v2/service/lambda v1.69.0 // indirect
83+
github.com/aws/aws-sdk-go-v2/service/rds v1.91.0 // indirect
84+
github.com/aws/aws-sdk-go-v2/service/route53 v1.46.2 // indirect
85+
github.com/aws/aws-sdk-go-v2/service/s3 v1.69.0 // indirect
86+
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.6 // indirect
87+
github.com/aws/aws-sdk-go-v2/service/sns v1.33.6 // indirect
88+
github.com/aws/aws-sdk-go-v2/service/sqs v1.37.1 // indirect
89+
github.com/aws/aws-sdk-go-v2/service/ssm v1.56.0 // indirect
90+
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 // indirect
91+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect
92+
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect
93+
github.com/aws/smithy-go v1.22.1 // indirect
5794
github.com/beorn7/perks v1.0.1 // indirect
5895
github.com/blang/semver/v4 v4.0.0 // indirect
5996
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
@@ -66,7 +103,7 @@ require (
66103
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
67104
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
68105
github.com/distribution/reference v0.5.0 // indirect
69-
github.com/docker/cli v25.0.1+incompatible // indirect
106+
github.com/docker/cli v27.1.1+incompatible // indirect
70107
github.com/docker/distribution v2.8.3+incompatible // indirect
71108
github.com/docker/docker v26.1.4+incompatible // indirect
72109
github.com/docker/docker-credential-helpers v0.7.0 // indirect
@@ -87,7 +124,7 @@ require (
87124
github.com/go-openapi/jsonpointer v0.21.0 // indirect
88125
github.com/go-openapi/jsonreference v0.21.0 // indirect
89126
github.com/go-openapi/swag v0.23.0 // indirect
90-
github.com/go-sql-driver/mysql v1.7.1 // indirect
127+
github.com/go-sql-driver/mysql v1.8.1 // indirect
91128
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
92129
github.com/gobwas/glob v0.2.3 // indirect
93130
github.com/gogo/protobuf v1.3.2 // indirect
@@ -114,6 +151,10 @@ require (
114151
github.com/imdario/mergo v0.3.16 // indirect
115152
github.com/imkira/go-interpol v1.1.0 // indirect
116153
github.com/inconshreveable/mousetrap v1.1.0 // indirect
154+
github.com/jackc/pgpassfile v1.0.0 // indirect
155+
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
156+
github.com/jackc/pgx/v5 v5.7.1 // indirect
157+
github.com/jackc/puddle/v2 v2.2.2 // indirect
117158
github.com/jmespath/go-jmespath v0.4.0 // indirect
118159
github.com/jmoiron/sqlx v1.3.5 // indirect
119160
github.com/josharian/intern v1.0.0 // indirect
@@ -146,7 +187,7 @@ require (
146187
github.com/opencontainers/image-spec v1.1.0 // indirect
147188
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
148189
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
149-
github.com/pquerna/otp v1.2.0 // indirect
190+
github.com/pquerna/otp v1.4.0 // indirect
150191
github.com/prometheus/client_model v0.6.1 // indirect
151192
github.com/prometheus/common v0.55.0 // indirect
152193
github.com/prometheus/procfs v0.15.1 // indirect
@@ -160,7 +201,7 @@ require (
160201
github.com/spf13/cast v1.6.0 // indirect
161202
github.com/spf13/pflag v1.0.6 // indirect
162203
github.com/stoewer/go-strcase v1.3.0 // indirect
163-
github.com/urfave/cli v1.22.14 // indirect
204+
github.com/urfave/cli v1.22.16 // indirect
164205
github.com/valyala/bytebufferpool v1.0.0 // indirect
165206
github.com/valyala/fasthttp v1.34.0 // indirect
166207
github.com/x448/float16 v0.8.4 // indirect
@@ -172,7 +213,7 @@ require (
172213
github.com/yudai/gojsondiff v1.0.0 // indirect
173214
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
174215
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
175-
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
216+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
176217
go.opentelemetry.io/otel v1.34.0 // indirect
177218
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
178219
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect

0 commit comments

Comments
 (0)