diff --git a/pkg/provider/kubernetes/ingress-nginx/fixtures/ingresses/ingress-with-endpoint-conditions.yml b/pkg/provider/kubernetes/ingress-nginx/fixtures/ingresses/ingress-with-endpoint-conditions.yml new file mode 100644 index 000000000..4def723e7 --- /dev/null +++ b/pkg/provider/kubernetes/ingress-nginx/fixtures/ingresses/ingress-with-endpoint-conditions.yml @@ -0,0 +1,69 @@ +--- +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: ingress-with-endpoint-conditions + namespace: default + annotations: + kubernetes.io/ingress.class: nginx + +spec: + rules: + - host: whoami.localhost + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: whoami + port: + number: 80 + +--- +kind: Service +apiVersion: v1 +metadata: + name: whoami + namespace: default + +spec: + clusterIP: 10.10.10.1 + ports: + - name: web + protocol: TCP + port: 80 + targetPort: web + +--- +kind: EndpointSlice +apiVersion: discovery.k8s.io/v1 +metadata: + name: whoami-abc + namespace: default + labels: + kubernetes.io/service-name: whoami + +addressType: IPv4 +ports: + - name: web + port: 80 +endpoints: + - addresses: + - 10.10.0.1 + conditions: + ready: true + serving: true + terminating: false + - addresses: + - 10.10.0.2 + conditions: + ready: false + serving: true + terminating: true + - addresses: + - 10.10.0.3 + conditions: + ready: false + serving: false + terminating: true diff --git a/pkg/provider/kubernetes/ingress-nginx/kubernetes_test.go b/pkg/provider/kubernetes/ingress-nginx/kubernetes_test.go index a594a8406..ed7acf395 100644 --- a/pkg/provider/kubernetes/ingress-nginx/kubernetes_test.go +++ b/pkg/provider/kubernetes/ingress-nginx/kubernetes_test.go @@ -15687,6 +15687,102 @@ func TestLoadIngresses(t *testing.T) { TLS: &dynamic.TLSConfiguration{}, }, }, + { + desc: "Ingress with endpoint conditions", + paths: []string{ + "ingressclasses.yml", + "ingresses/ingress-with-endpoint-conditions.yml", + }, + expected: &dynamic.Configuration{ + TCP: &dynamic.TCPConfiguration{ + Routers: map[string]*dynamic.TCPRouter{}, + Services: map[string]*dynamic.TCPService{}, + }, + HTTP: &dynamic.HTTPConfiguration{ + Routers: map[string]*dynamic.Router{ + "default-ingress-with-endpoint-conditions-rule-0-path-0": { + EntryPoints: []string{"http"}, + Rule: `Host("whoami.localhost") && PathPrefix("/")`, + RuleSyntax: "default", + Service: "default-ingress-with-endpoint-conditions-whoami-80", + Middlewares: []string{"default-ingress-with-endpoint-conditions-rule-0-path-0-retry"}, + Observability: &dynamic.RouterObservabilityConfig{ + Metadata: &dynamic.ObservabilityMetadata{ + Ingress: &dynamic.KubernetesIngressMetadata{ + Namespace: "default", + IngressName: "ingress-with-endpoint-conditions", + ServiceName: "whoami", + ServicePort: "80", + }, + }, + }, + }, + "default-ingress-with-endpoint-conditions-rule-0-path-0-tls": { + EntryPoints: []string{"https"}, + Rule: `Host("whoami.localhost") && PathPrefix("/")`, + RuleSyntax: "default", + Service: "default-ingress-with-endpoint-conditions-whoami-80", + Middlewares: []string{"default-ingress-with-endpoint-conditions-rule-0-path-0-tls-retry"}, + TLS: &dynamic.RouterTLSConfig{}, + Observability: &dynamic.RouterObservabilityConfig{ + Metadata: &dynamic.ObservabilityMetadata{ + Ingress: &dynamic.KubernetesIngressMetadata{ + Namespace: "default", + IngressName: "ingress-with-endpoint-conditions", + ServiceName: "whoami", + ServicePort: "80", + }, + }, + }, + }, + }, + Middlewares: map[string]*dynamic.Middleware{ + "default-ingress-with-endpoint-conditions-rule-0-path-0-retry": { + Retry: &dynamic.Retry{Attempts: 3}, + }, + "default-ingress-with-endpoint-conditions-rule-0-path-0-tls-retry": { + Retry: &dynamic.Retry{Attempts: 3}, + }, + }, + Services: map[string]*dynamic.Service{ + "default-ingress-with-endpoint-conditions-whoami-80": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + Servers: []dynamic.Server{ + {URL: "http://10.10.0.1:80"}, + {URL: "http://10.10.0.2:80", Fenced: true}, + }, + Strategy: dynamic.BalancerStrategyWRR, + PassHostHeader: ptr.To(true), + ServersTransport: "default-ingress-with-endpoint-conditions", + ResponseForwarding: &dynamic.ResponseForwarding{ + FlushInterval: dynamic.DefaultFlushInterval, + }, + }, + }, + "unavailable-service": { + LoadBalancer: &dynamic.ServersLoadBalancer{ + Strategy: dynamic.BalancerStrategyWRR, + PassHostHeader: ptr.To(true), + ResponseForwarding: &dynamic.ResponseForwarding{ + FlushInterval: dynamic.DefaultFlushInterval, + }, + }, + }, + }, + ServersTransports: map[string]*dynamic.ServersTransport{ + "default-ingress-with-endpoint-conditions": { + ForwardingTimeouts: &dynamic.ForwardingTimeouts{ + DialTimeout: ptypes.Duration(60 * time.Second), + ReadTimeout: ptypes.Duration(60 * time.Second), + WriteTimeout: ptypes.Duration(60 * time.Second), + IdleConnTimeout: ptypes.Duration(60 * time.Second), + }, + }, + }, + }, + TLS: &dynamic.TLSConfiguration{}, + }, + }, { desc: "Auth TLS secret missing — ingress is skipped entirely", paths: []string{ diff --git a/pkg/provider/kubernetes/ingress-nginx/translator.go b/pkg/provider/kubernetes/ingress-nginx/translator.go index c70a4e718..80b66e927 100644 --- a/pkg/provider/kubernetes/ingress-nginx/translator.go +++ b/pkg/provider/kubernetes/ingress-nginx/translator.go @@ -294,7 +294,8 @@ func buildService(backend *backend, serversTransportName string) *dynamic.Servic svc := &dynamic.Service{LoadBalancer: lb} for _, ep := range backend.Endpoints { svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, dynamic.Server{ - URL: fmt.Sprintf("http://%s", ep.Address), + URL: fmt.Sprintf("http://%s", ep.Address), + Fenced: ep.Fenced, }) } @@ -320,7 +321,8 @@ func buildServiceWithLocConfig(backend *backend, serversTransportName string, lo svc := &dynamic.Service{LoadBalancer: lb} for _, ep := range backend.Endpoints { svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, dynamic.Server{ - URL: fmt.Sprintf("%s://%s", scheme, ep.Address), + URL: fmt.Sprintf("%s://%s", scheme, ep.Address), + Fenced: ep.Fenced, }) }