Skip to content

Commit a2f6e64

Browse files
committed
feat: add translator
Signed-off-by: ashing <[email protected]>
1 parent 3f18a63 commit a2f6e64

File tree

2 files changed

+187
-1
lines changed

2 files changed

+187
-1
lines changed

internal/provider/adc/adc.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ func (d *adcClient) Delete(ctx context.Context, obj client.Object) error {
9696
labels = label.GenLabel(obj)
9797
case *gatewayv1.Gateway:
9898
// delete all resources
99+
case *networkingv1.Ingress:
100+
resourceTypes = append(resourceTypes, "service", "ssl")
101+
labels = label.GenLabel(obj)
99102
}
100103

101104
return d.sync(Task{
Lines changed: 184 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,193 @@
11
package translator
22

33
import (
4+
"fmt"
5+
6+
adctypes "github.com/api7/api7-ingress-controller/api/adc"
7+
"github.com/api7/api7-ingress-controller/internal/controller/label"
8+
"github.com/api7/api7-ingress-controller/internal/id"
49
"github.com/api7/api7-ingress-controller/internal/provider"
10+
"github.com/api7/gopkg/pkg/log"
11+
"go.uber.org/zap"
12+
corev1 "k8s.io/api/core/v1"
13+
discoveryv1 "k8s.io/api/discovery/v1"
514
networkingv1 "k8s.io/api/networking/v1"
15+
"k8s.io/apimachinery/pkg/types"
616
)
717

18+
func (t *Translator) translateIngressTLS(ingressTLS *networkingv1.IngressTLS, secret *corev1.Secret, labels map[string]string) (*adctypes.SSL, error) {
19+
// extract the key pair from the secret
20+
cert, key, err := extractKeyPair(secret, true)
21+
if err != nil {
22+
return nil, err
23+
}
24+
25+
hosts := ingressTLS.Hosts
26+
certHosts, err := extractHost(cert)
27+
if err != nil {
28+
return nil, err
29+
}
30+
hosts = append(hosts, certHosts...)
31+
if len(hosts) == 0 {
32+
return nil, fmt.Errorf("no hosts found in ingress TLS")
33+
}
34+
35+
ssl := &adctypes.SSL{
36+
Metadata: adctypes.Metadata{
37+
Labels: labels,
38+
},
39+
Certificates: []adctypes.Certificate{
40+
{
41+
Certificate: string(cert),
42+
Key: string(key),
43+
},
44+
},
45+
Snis: hosts,
46+
}
47+
ssl.ID = id.GenID(string(cert))
48+
49+
return ssl, nil
50+
}
51+
852
func (t *Translator) TranslateIngress(tctx *provider.TranslateContext, obj *networkingv1.Ingress) (*TranslateResult, error) {
9-
return nil, nil
53+
result := &TranslateResult{}
54+
55+
labels := label.GenLabel(obj)
56+
57+
// handle TLS configuration, convert to SSL objects
58+
for _, tls := range obj.Spec.TLS {
59+
if tls.SecretName == "" {
60+
continue
61+
}
62+
secret := tctx.Secrets[types.NamespacedName{
63+
Namespace: obj.Namespace,
64+
Name: tls.SecretName,
65+
}]
66+
if secret == nil {
67+
continue
68+
}
69+
if secret.Data == nil {
70+
log.Warnw("secret data is nil", zap.String("secret", secret.Namespace+"/"+secret.Name))
71+
continue
72+
}
73+
ssl, err := t.translateIngressTLS(&tls, secret, labels)
74+
if err != nil {
75+
return nil, err
76+
}
77+
78+
result.SSL = append(result.SSL, ssl)
79+
}
80+
81+
// process Ingress rules, convert to Service and Route objects
82+
for i, rule := range obj.Spec.Rules {
83+
// extract hostnames
84+
var hosts []string
85+
if rule.Host != "" {
86+
hosts = append(hosts, rule.Host)
87+
}
88+
// if there is no HTTP path, skip
89+
if rule.HTTP == nil {
90+
continue
91+
}
92+
93+
// create a service for each path
94+
for j, path := range rule.HTTP.Paths {
95+
if path.Backend.Service == nil {
96+
continue
97+
}
98+
99+
service := adctypes.NewDefaultService()
100+
service.Labels = labels
101+
service.Name = adctypes.ComposeServiceNameWithRule(obj.Namespace, obj.Name, fmt.Sprintf("%d-%d", i, j))
102+
service.ID = id.GenID(service.Name)
103+
service.Hosts = hosts
104+
105+
// create an upstream
106+
upstream := adctypes.NewDefaultUpstream()
107+
108+
// get the EndpointSlice of the backend service
109+
backendService := path.Backend.Service
110+
endpointSlices := tctx.EndpointSlices[types.NamespacedName{
111+
Namespace: obj.Namespace,
112+
Name: backendService.Name,
113+
}]
114+
115+
// get the service port configuration
116+
var servicePort int32 = 0
117+
var servicePortName string
118+
if backendService.Port.Number != 0 {
119+
servicePort = backendService.Port.Number
120+
} else if backendService.Port.Name != "" {
121+
servicePortName = backendService.Port.Name
122+
}
123+
124+
// convert the EndpointSlice to upstream nodes
125+
if len(endpointSlices) > 0 {
126+
upstream.Nodes = t.translateEndpointSliceForIngress(1, endpointSlices, servicePort, servicePortName)
127+
}
128+
129+
// if there is no upstream node, create a placeholder node
130+
if len(upstream.Nodes) == 0 {
131+
upstream.Nodes = adctypes.UpstreamNodes{
132+
{
133+
Host: "0.0.0.0",
134+
Port: int(servicePort),
135+
Weight: 1,
136+
},
137+
}
138+
}
139+
140+
service.Upstream = upstream
141+
142+
// create a route
143+
route := adctypes.NewDefaultRoute()
144+
route.Name = adctypes.ComposeRouteName(obj.Namespace, obj.Name, fmt.Sprintf("%d-%d", i, j))
145+
route.ID = id.GenID(route.Name)
146+
route.Labels = labels
147+
148+
// set the path matching rule
149+
switch *path.PathType {
150+
case networkingv1.PathTypeExact:
151+
route.Uris = []string{path.Path}
152+
case networkingv1.PathTypePrefix:
153+
route.Uris = []string{path.Path + "*"}
154+
case networkingv1.PathTypeImplementationSpecific:
155+
route.Uris = []string{path.Path + "*"}
156+
}
157+
158+
service.Routes = []*adctypes.Route{route}
159+
result.Services = append(result.Services, service)
160+
}
161+
}
162+
163+
return result, nil
164+
}
165+
166+
// translateEndpointSliceForIngress create upstream nodes from EndpointSlice
167+
func (t *Translator) translateEndpointSliceForIngress(weight int, endpointSlices []discoveryv1.EndpointSlice, portNumber int32, portName string) adctypes.UpstreamNodes {
168+
var nodes adctypes.UpstreamNodes
169+
if len(endpointSlices) == 0 {
170+
return nodes
171+
}
172+
173+
for _, endpointSlice := range endpointSlices {
174+
for _, port := range endpointSlice.Ports {
175+
// if the port number or port name is specified, only use the matching port
176+
if (portNumber != 0 && *port.Port != portNumber) || (portName != "" && *port.Name != portName) {
177+
continue
178+
}
179+
for _, endpoint := range endpointSlice.Endpoints {
180+
for _, addr := range endpoint.Addresses {
181+
node := adctypes.UpstreamNode{
182+
Host: addr,
183+
Port: int(*port.Port),
184+
Weight: weight,
185+
}
186+
nodes = append(nodes, node)
187+
}
188+
}
189+
}
190+
}
191+
192+
return nodes
10193
}

0 commit comments

Comments
 (0)