Skip to content

Commit

Permalink
fix(parser) support same-name services across NSes (#4375)
Browse files Browse the repository at this point in the history
Correctly build upstreams for multiple backends where multiple services
in the backends share the same name in different namespaces. Previously
services were indexed by name alone in the rule builder, resulting in
one clobbering the other(s).
  • Loading branch information
rainest authored Jul 28, 2023
1 parent 988d47c commit 7a32afb
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ Adding a new version? You'll need three changes:

### Fixed

- Correctly support multi-Service backends that have multiple Services sharing
the same name in different namespaces.
[#4375](https://github.com/Kong/kubernetes-ingress-controller/pull/4375)
- Properly construct targets for IPv6-only clusters.
[#4391](https://github.com/Kong/kubernetes-ingress-controller/pull/4391)
- Attach kubernetes events to `KongConsumer`s when the parser fails to
Expand Down
2 changes: 1 addition & 1 deletion internal/dataplane/parser/ingressrules.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func (ir *ingressRules) populateServices(log logrus.FieldLogger, s store.Storer,
for _, k8sService := range k8sServices {
// at this point we know the Kubernetes service itself is valid and can be
// used for traffic, so cache it amongst the kong Services k8s services.
service.K8sServices[k8sService.Name] = k8sService
service.K8sServices[fmt.Sprintf("%s/%s", k8sService.Namespace, k8sService.Name)] = k8sService

// extract client certificates intended for use by the service
secretName := annotations.ExtractClientCertificate(k8sService.Annotations)
Expand Down
10 changes: 9 additions & 1 deletion internal/dataplane/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,15 @@ func (p *Parser) getUpstreams(serviceMap map[string]kongstate.Service) []kongsta
var targets []kongstate.Target
for _, backend := range service.Backends {
// gather the Kubernetes service for the backend
k8sService, ok := service.K8sServices[backend.Name]
backendNamespace := backend.Namespace
if backendNamespace == "" {
// if the backend namespace isn't specified, it's in the same namespace as the referee route (which is,
// somewhat confusingly, the _service_ namespace in serviceMap services, as historically there was no option
// to reference services outside the route namespace, and we could always stuff the route namespace into the
// placeholder service.
backendNamespace = service.Namespace
}
k8sService, ok := service.K8sServices[fmt.Sprintf("%s/%s", backendNamespace, backend.Name)]
if !ok {
p.registerTranslationFailure(
fmt.Sprintf("can't add target for backend %s: no kubernetes service found", backend.Name),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
_format_version: "3.0"
services:
- connect_timeout: 60000
host: httproute.default.test.0
name: httproute.default.test.0
protocol: http
read_timeout: 60000
retries: 5
routes:
- https_redirect_status_code: 426
name: httproute.default.test.0.0
path_handling: v0
paths:
- ~/test$
- /test/
preserve_host: true
protocols:
- http
- https
strip_path: true
tags:
- k8s-name:test
- k8s-namespace:default
- k8s-kind:HTTPRoute
- k8s-group:gateway.networking.k8s.io
- k8s-version:v1beta1
tags:
- k8s-name:test
- k8s-namespace:default
- k8s-kind:HTTPRoute
- k8s-group:gateway.networking.k8s.io
- k8s-version:v1beta1
write_timeout: 60000
upstreams:
- algorithm: round-robin
name: httproute.default.test.0
tags:
- k8s-name:test
- k8s-namespace:default
- k8s-kind:HTTPRoute
- k8s-group:gateway.networking.k8s.io
- k8s-version:v1beta1
targets:
- target: 10.244.0.5:9443
weight: 50
- target: 10.244.0.4:9443
weight: 50
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: testing
namespace: other
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: default
to:
- group: ""
kind: Service
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: test
namespace: default
annotations:
konghq.com/strip-path: "true"
spec:
parentRefs:
- name: kong
rules:
- matches:
- path:
type: PathPrefix
value: /test
backendRefs:
- name: one
kind: Service
port: 80
weight: 50
group: ""
- name: two
namespace: other
kind: Service
port: 80
weight: 50
group: ""
---
apiVersion: v1
kind: Service
metadata:
labels:
app: example
name: one
namespace: default
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: example
type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
labels:
app: example
name: two
namespace: other
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: example
type: ClusterIP
---
apiVersion: discovery.k8s.io/v1
addressType: IPv4
kind: EndpointSlice
metadata:
namespace: default
labels:
kubernetes.io/service-name: one
name: one-n5g6g
endpoints:
- addresses:
- 10.244.0.5
conditions:
ready: true
serving: true
terminating: false
ports:
- name: ""
port: 9443
protocol: TCP
---
apiVersion: discovery.k8s.io/v1
addressType: IPv4
kind: EndpointSlice
metadata:
namespace: other
labels:
kubernetes.io/service-name: two
name: two-n5g6g
endpoints:
- addresses:
- 10.244.0.4
conditions:
ready: true
serving: true
terminating: false
ports:
- name: ""
port: 9443
protocol: TCP

0 comments on commit 7a32afb

Please sign in to comment.