Skip to content

Commit d5fe3e0

Browse files
committed
feat: support stream_route for ApisixRoute (#2551)
1 parent ec01721 commit d5fe3e0

File tree

20 files changed

+1093
-344
lines changed

20 files changed

+1093
-344
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

0 commit comments

Comments
 (0)