Skip to content

Commit 356cc38

Browse files
AlinsRanbackport-bot[bot]
authored andcommitted
feat(gateway-api): support TLSRoute (#2594)
(cherry picked from commit 1afb9acea8f55270055e7274e18647731d6150f1)
1 parent 6b98bdb commit 356cc38

File tree

18 files changed

+1093
-1
lines changed

18 files changed

+1093
-1
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ GATEAY_API_VERSION ?= v1.3.0
6262
SUPPORTED_EXTENDED_FEATURES = "HTTPRouteDestinationPortMatching,HTTPRouteMethodMatching,HTTPRoutePortRedirect,HTTPRouteRequestMirror,HTTPRouteSchemeRedirect,GatewayAddressEmpty,HTTPRouteResponseHeaderModification,GatewayPort8080"
6363
CONFORMANCE_TEST_REPORT_OUTPUT ?= $(DIR)/apisix-ingress-controller-conformance-report.yaml
6464
## https://github.com/kubernetes-sigs/gateway-api/blob/v1.3.0/conformance/utils/suite/profiles.go
65-
CONFORMANCE_PROFILES ?= GATEWAY-HTTP,GATEWAY-GRPC
65+
CONFORMANCE_PROFILES ?= GATEWAY-HTTP,GATEWAY-GRPC,GATEWAY-TLS
6666

6767
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
6868
ifeq (,$(shell go env GOBIN))

api/v2/shared_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ const (
101101
SchemeTCP = "tcp"
102102
// SchemeUDP represents the UDP protocol.
103103
SchemeUDP = "udp"
104+
// SchemeTLS represents the TLS protocol.
105+
SchemeTLS = "tls"
104106
)
105107

106108
const (

config/rbac/role.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ rules:
9393
- grpcroutes/status
9494
- httproutes/status
9595
- referencegrants/status
96+
<<<<<<< HEAD
97+
=======
98+
- tcproutes/status
99+
- tlsroutes/status
100+
- udproutes/status
101+
>>>>>>> 1afb9ace (feat(gateway-api): support TLSRoute (#2594))
96102
verbs:
97103
- get
98104
- update
@@ -103,6 +109,12 @@ rules:
103109
- grpcroutes
104110
- httproutes
105111
- referencegrants
112+
<<<<<<< HEAD
113+
=======
114+
- tcproutes
115+
- tlsroutes
116+
- udproutes
117+
>>>>>>> 1afb9ace (feat(gateway-api): support TLSRoute (#2594))
106118
verbs:
107119
- get
108120
- list

docs/en/latest/concepts/gateway-api.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,15 @@ By supporting Gateway API, the APISIX Ingress controller can realize richer func
5050
| HTTPRoute | Supported | Partially supported | Not supported | v1 |
5151
| GRPCRoute | Supported | Supported | Not supported | v1 |
5252
| ReferenceGrant | Supported | Not supported | Not supported | v1beta1 |
53+
<<<<<<< HEAD
5354
| TLSRoute | Not supported | Not supported | Not supported | v1alpha2 |
5455
| TCPRoute | Not supported | Not supported | Not supported | v1alpha2 |
5556
| UDPRoute | Not supported | Not supported | Not supported | v1alpha2 |
57+
=======
58+
| TLSRoute | Supported | Supported | Not supported | v1alpha2 |
59+
| TCPRoute | Supported | Supported | Not supported | v1alpha2 |
60+
| UDPRoute | Supported | Supported | Not supported | v1alpha2 |
61+
>>>>>>> 1afb9ace (feat(gateway-api): support TLSRoute (#2594))
5662
| BackendTLSPolicy | Not supported | Not supported | Not supported | v1alpha3 |
5763

5864
## Examples
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package translator
19+
20+
import (
21+
"fmt"
22+
23+
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
24+
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
25+
26+
adctypes "github.com/apache/apisix-ingress-controller/api/adc"
27+
apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
28+
"github.com/apache/apisix-ingress-controller/internal/controller/label"
29+
"github.com/apache/apisix-ingress-controller/internal/id"
30+
"github.com/apache/apisix-ingress-controller/internal/provider"
31+
"github.com/apache/apisix-ingress-controller/internal/types"
32+
)
33+
34+
func (t *Translator) TranslateTLSRoute(tctx *provider.TranslateContext, tlsRoute *gatewayv1alpha2.TLSRoute) (*TranslateResult, error) {
35+
result := &TranslateResult{}
36+
rules := tlsRoute.Spec.Rules
37+
labels := label.GenLabel(tlsRoute)
38+
hosts := make([]string, 0, len(tlsRoute.Spec.Hostnames))
39+
for _, hostname := range tlsRoute.Spec.Hostnames {
40+
hosts = append(hosts, string(hostname))
41+
}
42+
for ruleIndex, rule := range rules {
43+
service := adctypes.NewDefaultService()
44+
service.Labels = labels
45+
service.Name = adctypes.ComposeServiceNameWithStream(tlsRoute.Namespace, tlsRoute.Name, fmt.Sprintf("%d", ruleIndex), "TLS")
46+
service.ID = id.GenID(service.Name)
47+
var (
48+
upstreams = make([]*adctypes.Upstream, 0)
49+
weightedUpstreams = make([]adctypes.TrafficSplitConfigRuleWeightedUpstream, 0)
50+
)
51+
for _, backend := range rule.BackendRefs {
52+
if backend.Namespace == nil {
53+
namespace := gatewayv1.Namespace(tlsRoute.Namespace)
54+
backend.Namespace = &namespace
55+
}
56+
upstream := newDefaultUpstreamWithoutScheme()
57+
upNodes, err := t.translateBackendRef(tctx, backend, DefaultEndpointFilter)
58+
if err != nil {
59+
continue
60+
}
61+
if len(upNodes) == 0 {
62+
continue
63+
}
64+
// TODO: Confirm BackendTrafficPolicy attachment with e2e test case.
65+
t.AttachBackendTrafficPolicyToUpstream(backend, tctx.BackendTrafficPolicies, upstream)
66+
upstream.Nodes = upNodes
67+
var (
68+
kind string
69+
port int32
70+
)
71+
if backend.Kind == nil {
72+
kind = types.KindService
73+
} else {
74+
kind = string(*backend.Kind)
75+
}
76+
if backend.Port != nil {
77+
port = int32(*backend.Port)
78+
}
79+
namespace := string(*backend.Namespace)
80+
name := string(backend.Name)
81+
upstreamName := adctypes.ComposeUpstreamNameForBackendRef(kind, namespace, name, port)
82+
upstream.Name = upstreamName
83+
upstream.ID = id.GenID(upstreamName)
84+
upstreams = append(upstreams, upstream)
85+
}
86+
87+
// Handle multiple backends with traffic-split plugin
88+
if len(upstreams) == 0 {
89+
// Create a default upstream if no valid backends
90+
upstream := adctypes.NewDefaultUpstream()
91+
service.Upstream = upstream
92+
} else if len(upstreams) == 1 {
93+
// Single backend - use directly as service upstream
94+
service.Upstream = upstreams[0]
95+
// remove the id and name of the service.upstream, adc schema does not need id and name for it
96+
service.Upstream.ID = ""
97+
service.Upstream.Name = ""
98+
} else {
99+
// Multiple backends - use traffic-split plugin
100+
service.Upstream = upstreams[0]
101+
// remove the id and name of the service.upstream, adc schema does not need id and name for it
102+
service.Upstream.ID = ""
103+
service.Upstream.Name = ""
104+
105+
upstreams = upstreams[1:]
106+
107+
if len(upstreams) > 0 {
108+
service.Upstreams = upstreams
109+
}
110+
111+
// Set weight in traffic-split for the default upstream
112+
weight := apiv2.DefaultWeight
113+
if rule.BackendRefs[0].Weight != nil {
114+
weight = int(*rule.BackendRefs[0].Weight)
115+
}
116+
weightedUpstreams = append(weightedUpstreams, adctypes.TrafficSplitConfigRuleWeightedUpstream{
117+
Weight: weight,
118+
})
119+
120+
// Set other upstreams in traffic-split using upstream_id
121+
for i, upstream := range upstreams {
122+
weight := apiv2.DefaultWeight
123+
// get weight from the backend refs starting from the second backend
124+
if i+1 < len(rule.BackendRefs) && rule.BackendRefs[i+1].Weight != nil {
125+
weight = int(*rule.BackendRefs[i+1].Weight)
126+
}
127+
weightedUpstreams = append(weightedUpstreams, adctypes.TrafficSplitConfigRuleWeightedUpstream{
128+
UpstreamID: upstream.ID,
129+
Weight: weight,
130+
})
131+
}
132+
133+
if len(weightedUpstreams) > 0 {
134+
if service.Plugins == nil {
135+
service.Plugins = make(map[string]any)
136+
}
137+
service.Plugins["traffic-split"] = &adctypes.TrafficSplitConfig{
138+
Rules: []adctypes.TrafficSplitConfigRule{
139+
{
140+
WeightedUpstreams: weightedUpstreams,
141+
},
142+
},
143+
}
144+
}
145+
}
146+
147+
for _, host := range hosts {
148+
streamRoute := adctypes.NewDefaultStreamRoute()
149+
streamRouteName := adctypes.ComposeStreamRouteName(tlsRoute.Namespace, tlsRoute.Name, fmt.Sprintf("%d", ruleIndex), "TLS")
150+
streamRoute.Name = streamRouteName
151+
streamRoute.ID = id.GenID(streamRouteName)
152+
streamRoute.SNI = host
153+
streamRoute.Labels = labels
154+
service.StreamRoutes = append(service.StreamRoutes, streamRoute)
155+
}
156+
result.Services = append(result.Services, service)
157+
}
158+
return result, nil
159+
}

internal/controller/indexer/indexer.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,19 @@ func SetupIndexer(mgr ctrl.Manager) error {
8989

9090
// Core Kubernetes and APISIX indexers - always setup these
9191
for _, setup := range []func(ctrl.Manager) error{
92+
<<<<<<< HEAD
93+
=======
94+
setupGatewayIndexer,
95+
setupHTTPRouteIndexer,
96+
setupTCPRouteIndexer,
97+
setupUDPRouteIndexer,
98+
setupGRPCRouteIndexer,
99+
setupTLSRouteIndexer,
100+
setupIngressIndexer,
101+
setupConsumerIndexer,
102+
setupBackendTrafficPolicyIndexer,
103+
setupIngressClassIndexer,
104+
>>>>>>> 1afb9ace (feat(gateway-api): support TLSRoute (#2594))
92105
setupGatewayProxyIndexer,
93106
setupApisixRouteIndexer,
94107
setupApisixPluginConfigIndexer,
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package indexer
19+
20+
import (
21+
"context"
22+
23+
internaltypes "github.com/apache/apisix-ingress-controller/internal/types"
24+
ctrl "sigs.k8s.io/controller-runtime"
25+
"sigs.k8s.io/controller-runtime/pkg/client"
26+
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
27+
)
28+
29+
func setupTLSRouteIndexer(mgr ctrl.Manager) error {
30+
if err := mgr.GetFieldIndexer().IndexField(
31+
context.Background(),
32+
&gatewayv1alpha2.TLSRoute{},
33+
ParentRefs,
34+
TLSRouteParentRefsIndexFunc,
35+
); err != nil {
36+
return err
37+
}
38+
39+
if err := mgr.GetFieldIndexer().IndexField(
40+
context.Background(),
41+
&gatewayv1alpha2.TLSRoute{},
42+
ServiceIndexRef,
43+
TLSPRouteServiceIndexFunc,
44+
); err != nil {
45+
return err
46+
}
47+
return nil
48+
}
49+
50+
func TLSRouteParentRefsIndexFunc(rawObj client.Object) []string {
51+
tr := rawObj.(*gatewayv1alpha2.TLSRoute)
52+
keys := make([]string, 0, len(tr.Spec.ParentRefs))
53+
for _, ref := range tr.Spec.ParentRefs {
54+
ns := tr.GetNamespace()
55+
if ref.Namespace != nil {
56+
ns = string(*ref.Namespace)
57+
}
58+
keys = append(keys, GenIndexKey(ns, string(ref.Name)))
59+
}
60+
return keys
61+
}
62+
63+
func TLSPRouteServiceIndexFunc(rawObj client.Object) []string {
64+
tr := rawObj.(*gatewayv1alpha2.TLSRoute)
65+
keys := make([]string, 0, len(tr.Spec.Rules))
66+
for _, rule := range tr.Spec.Rules {
67+
for _, backend := range rule.BackendRefs {
68+
namespace := tr.GetNamespace()
69+
if backend.Kind != nil && *backend.Kind != internaltypes.KindService {
70+
continue
71+
}
72+
if backend.Namespace != nil {
73+
namespace = string(*backend.Namespace)
74+
}
75+
keys = append(keys, GenIndexKey(namespace, string(backend.Name)))
76+
}
77+
}
78+
return keys
79+
}

0 commit comments

Comments
 (0)