@@ -79,6 +79,37 @@ func (t *Translator) TranslateIngress(
7979 labels := label .GenLabel (obj )
8080
8181 // handle TLS configuration, convert to SSL objects
82+ if err := t .translateIngressTLSSection (tctx , obj , result , labels ); err != nil {
83+ return nil , err
84+ }
85+
86+ // process Ingress rules, convert to Service and Route objects
87+ for i , rule := range obj .Spec .Rules {
88+ if rule .HTTP == nil {
89+ continue
90+ }
91+
92+ hosts := []string {}
93+ if rule .Host != "" {
94+ hosts = append (hosts , rule .Host )
95+ }
96+
97+ for j , path := range rule .HTTP .Paths {
98+ if svc := t .buildServiceFromIngressPath (tctx , obj , & path , i , j , hosts , labels ); svc != nil {
99+ result .Services = append (result .Services , svc )
100+ }
101+ }
102+ }
103+
104+ return result , nil
105+ }
106+
107+ func (t * Translator ) translateIngressTLSSection (
108+ tctx * provider.TranslateContext ,
109+ obj * networkingv1.Ingress ,
110+ result * TranslateResult ,
111+ labels map [string ]string ,
112+ ) error {
82113 for tlsIndex , tls := range obj .Spec .TLS {
83114 if tls .SecretName == "" {
84115 continue
@@ -92,148 +123,150 @@ func (t *Translator) TranslateIngress(
92123 }
93124 ssl , err := t .translateIngressTLS (obj .Namespace , obj .Name , tlsIndex , & tls , secret , labels )
94125 if err != nil {
95- return nil , err
126+ return err
96127 }
97-
98128 result .SSL = append (result .SSL , ssl )
99129 }
130+ return nil
131+ }
100132
101- // process Ingress rules, convert to Service and Route objects
102- for i , rule := range obj .Spec .Rules {
103- // extract hostnames
104- var hosts []string
105- if rule .Host != "" {
106- hosts = append (hosts , rule .Host )
133+ func (t * Translator ) buildServiceFromIngressPath (
134+ tctx * provider.TranslateContext ,
135+ obj * networkingv1.Ingress ,
136+ path * networkingv1.HTTPIngressPath ,
137+ ruleIndex , pathIndex int ,
138+ hosts []string ,
139+ labels map [string ]string ,
140+ ) * adctypes.Service {
141+ if path .Backend .Service == nil {
142+ return nil
143+ }
144+
145+ service := adctypes .NewDefaultService ()
146+ service .Labels = labels
147+ service .Name = adctypes .ComposeServiceNameWithRule (obj .Namespace , obj .Name , fmt .Sprintf ("%d-%d" , ruleIndex , pathIndex ))
148+ service .ID = id .GenID (service .Name )
149+ service .Hosts = hosts
150+
151+ upstream := adctypes .NewDefaultUpstream ()
152+ protocol := t .resolveIngressUpstream (tctx , obj , path .Backend .Service , upstream )
153+ service .Upstream = upstream
154+
155+ route := buildRouteFromIngressPath (obj , path , ruleIndex , pathIndex , labels )
156+ if protocol == internaltypes .AppProtocolWS || protocol == internaltypes .AppProtocolWSS {
157+ route .EnableWebsocket = ptr .To (true )
158+ }
159+ service .Routes = []* adctypes.Route {route }
160+
161+ t .fillHTTPRoutePoliciesForIngress (tctx , service .Routes )
162+ return service
163+ }
164+
165+ func (t * Translator ) resolveIngressUpstream (
166+ tctx * provider.TranslateContext ,
167+ obj * networkingv1.Ingress ,
168+ backendService * networkingv1.IngressServiceBackend ,
169+ upstream * adctypes.Upstream ,
170+ ) string {
171+ backendRef := convertBackendRef (obj .Namespace , backendService .Name , internaltypes .KindService )
172+ t .AttachBackendTrafficPolicyToUpstream (backendRef , tctx .BackendTrafficPolicies , upstream )
173+ // determine service port/port name
174+ var protocol string
175+ var servicePort int32 = 0
176+ var servicePortName string
177+ if backendService .Port .Number != 0 {
178+ servicePort = backendService .Port .Number
179+ } else if backendService .Port .Name != "" {
180+ servicePortName = backendService .Port .Name
181+ }
182+
183+ getService := tctx .Services [types.NamespacedName {
184+ Namespace : obj .Namespace ,
185+ Name : backendService .Name ,
186+ }]
187+ if getService == nil {
188+ return protocol
189+ }
190+
191+ if getService .Spec .Type == corev1 .ServiceTypeExternalName {
192+ defaultServicePort := 80
193+ if servicePort > 0 {
194+ defaultServicePort = int (servicePort )
107195 }
108- // if there is no HTTP path, skip
109- if rule .HTTP == nil {
110- continue
196+ upstream .Nodes = adctypes.UpstreamNodes {
197+ {
198+ Host : getService .Spec .ExternalName ,
199+ Port : defaultServicePort ,
200+ Weight : 1 ,
201+ },
111202 }
203+ return protocol
204+ }
112205
113- // create a service for each path
114- for j , path := range rule .HTTP .Paths {
115- if path .Backend .Service == nil {
116- continue
117- }
118- var enableWebsocket * bool
119-
120- service := adctypes .NewDefaultService ()
121- service .Labels = labels
122- service .Name = adctypes .ComposeServiceNameWithRule (obj .Namespace , obj .Name , fmt .Sprintf ("%d-%d" , i , j ))
123- service .ID = id .GenID (service .Name )
124- service .Hosts = hosts
125-
126- // create an upstream
127- upstream := adctypes .NewDefaultUpstream ()
128-
129- // get the EndpointSlice of the backend service
130- backendService := path .Backend .Service
131- if backendService != nil {
132- backendRef := convertBackendRef (obj .Namespace , backendService .Name , internaltypes .KindService )
133- t .AttachBackendTrafficPolicyToUpstream (backendRef , tctx .BackendTrafficPolicies , upstream )
134- }
206+ // find matching service port object
207+ var getServicePort * corev1.ServicePort
208+ for _ , port := range getService .Spec .Ports {
209+ p := port
210+ if servicePort > 0 && p .Port == servicePort {
211+ getServicePort = & p
212+ break
213+ }
214+ if servicePortName != "" && p .Name == servicePortName {
215+ getServicePort = & p
216+ break
217+ }
218+ }
135219
136- // get the service port configuration
137- var servicePort int32 = 0
138- var servicePortName string
139- if backendService .Port .Number != 0 {
140- servicePort = backendService .Port .Number
141- } else if backendService .Port .Name != "" {
142- servicePortName = backendService .Port .Name
143- }
220+ if getServicePort != nil && getServicePort .AppProtocol != nil {
221+ protocol = * getServicePort .AppProtocol
222+ if upstream .Scheme == "" {
223+ upstream .Scheme = appProtocolToUpstreamScheme (* getServicePort .AppProtocol )
224+ }
225+ }
144226
145- getService := tctx .Services [types.NamespacedName {
146- Namespace : obj .Namespace ,
147- Name : backendService .Name ,
148- }]
149- if getService == nil {
150- continue
151- }
152- if getService .Spec .Type == corev1 .ServiceTypeExternalName {
153- defaultServicePort := 80
154- if servicePort > 0 {
155- defaultServicePort = int (servicePort )
156- }
157- upstream .Nodes = adctypes.UpstreamNodes {
158- {
159- Host : getService .Spec .ExternalName ,
160- Port : defaultServicePort ,
161- Weight : 1 ,
162- },
163- }
164- } else {
165- var getServicePort * corev1.ServicePort
166- for _ , port := range getService .Spec .Ports {
167- port := port
168- if servicePort > 0 && port .Port == servicePort {
169- getServicePort = & port
170- break
171- }
172- if servicePortName != "" && port .Name == servicePortName {
173- getServicePort = & port
174- break
175- }
176- }
177- if getServicePort != nil && getServicePort .AppProtocol != nil {
178- if upstream .Scheme == "" {
179- upstream .Scheme = appProtocolToUpstreamScheme (* getServicePort .AppProtocol )
180- }
181- if * getServicePort .AppProtocol == internaltypes .AppProtocolWS ||
182- * getServicePort .AppProtocol == internaltypes .AppProtocolWSS {
183- enableWebsocket = ptr .To (true )
184- }
185- }
186- endpointSlices := tctx .EndpointSlices [types.NamespacedName {
187- Namespace : obj .Namespace ,
188- Name : backendService .Name ,
189- }]
190- // convert the EndpointSlice to upstream nodes
191- if len (endpointSlices ) > 0 {
192- upstream .Nodes = t .translateEndpointSliceForIngress (1 , endpointSlices , getServicePort )
193- }
194- }
227+ endpointSlices := tctx .EndpointSlices [types.NamespacedName {
228+ Namespace : obj .Namespace ,
229+ Name : backendService .Name ,
230+ }]
231+ if len (endpointSlices ) > 0 {
232+ upstream .Nodes = t .translateEndpointSliceForIngress (1 , endpointSlices , getServicePort )
233+ }
195234
196- service .Upstream = upstream
197-
198- // create a route
199- route := adctypes .NewDefaultRoute ()
200- route .Name = adctypes .ComposeRouteName (obj .Namespace , obj .Name , fmt .Sprintf ("%d-%d" , i , j ))
201- route .ID = id .GenID (route .Name )
202- route .EnableWebsocket = enableWebsocket
203- route .Labels = labels
204-
205- uris := []string {path .Path }
206- if path .PathType != nil {
207- switch * path .PathType {
208- case networkingv1 .PathTypePrefix :
209- // As per the specification of Ingress path matching rule:
210- // if the last element of the path is a substring of the
211- // last element in request path, it is not a match, e.g. /foo/bar
212- // matches /foo/bar/baz, but does not match /foo/barbaz.
213- // While in APISIX, /foo/bar matches both /foo/bar/baz and
214- // /foo/barbaz.
215- // In order to be conformant with Ingress specification, here
216- // we create two paths here, the first is the path itself
217- // (exact match), the other is path + "/*" (prefix match).
218- prefix := path .Path
219- if strings .HasSuffix (prefix , "/" ) {
220- prefix += "*"
221- } else {
222- prefix += "/*"
223- }
224- uris = append (uris , prefix )
225- case networkingv1 .PathTypeImplementationSpecific :
226- uris = []string {"/*" }
227- }
228- }
229- route .Uris = uris
230- service .Routes = []* adctypes.Route {route }
231- t .fillHTTPRoutePoliciesForIngress (tctx , service .Routes )
232- result .Services = append (result .Services , service )
235+ return protocol
236+ }
237+
238+ func buildRouteFromIngressPath (
239+ obj * networkingv1.Ingress ,
240+ path * networkingv1.HTTPIngressPath ,
241+ ruleIndex , pathIndex int ,
242+ labels map [string ]string ,
243+ ) * adctypes.Route {
244+ route := adctypes .NewDefaultRoute ()
245+ route .Name = adctypes .ComposeRouteName (obj .Namespace , obj .Name , fmt .Sprintf ("%d-%d" , ruleIndex , pathIndex ))
246+ route .ID = id .GenID (route .Name )
247+ route .Labels = labels
248+
249+ uris := []string {path .Path }
250+ if path .PathType != nil {
251+ switch * path .PathType {
252+ case networkingv1 .PathTypePrefix :
253+ // As per the specification of Ingress path matching rule:
254+ // if the last element of the path is a substring of the
255+ // last element in request path, it is not a match, e.g. /foo/bar
256+ // matches /foo/bar/baz, but does not match /foo/barbaz.
257+ // While in APISIX, /foo/bar matches both /foo/bar/baz and
258+ // /foo/barbaz.
259+ // In order to be conformant with Ingress specification, here
260+ // we create two paths here, the first is the path itself
261+ // (exact match), the other is path + "/*" (prefix match).
262+ prefix := strings .TrimSuffix (path .Path , "/" ) + "/*"
263+ uris = append (uris , prefix )
264+ case networkingv1 .PathTypeImplementationSpecific :
265+ uris = []string {"/*" }
233266 }
234267 }
235-
236- return result , nil
268+ route . Uris = uris
269+ return route
237270}
238271
239272// translateEndpointSliceForIngress create upstream nodes from EndpointSlice
0 commit comments