mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/kube-vip/kube-vip.git
synced 2026-09-20 08:03:47 +08:00
services: add opt-in support for endpointless Cluster LB services
Signed-off-by: Yannick Wahner <thenabsku@gmail.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -65,6 +66,8 @@ func (p *Processor) AddOrModify(svcCtx *servicecontext.Context, event watch.Even
|
||||
log.Error("updating instance", "err", err)
|
||||
}
|
||||
|
||||
allowReconcileWithoutEndpoints := shouldAllowReconcileWithoutEndpoints(service)
|
||||
|
||||
// Find out if we have any local endpoints
|
||||
// if out endpoint is empty then populate it
|
||||
// if not, go through the endpoints and see if ours still exists
|
||||
@@ -115,8 +118,11 @@ func (p *Processor) AddOrModify(svcCtx *servicecontext.Context, event watch.Even
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// There are no local endpoints
|
||||
if svcCtx.Signalled.Load() {
|
||||
if allowReconcileWithoutEndpoints {
|
||||
// Explicit opt-in for controllers that create LoadBalancer services without endpoints
|
||||
svcCtx.SignalReadiness()
|
||||
} else if svcCtx.Signalled.Load() {
|
||||
// There are no local endpoints
|
||||
svcCtx.ResetReadiness()
|
||||
p.worker.clear(svcCtx, lastKnownGoodEndpoint, service)
|
||||
if p.config.EnableARP && !p.config.EnableServicesElection {
|
||||
@@ -272,6 +278,14 @@ func (p *Processor) startLeaderElection(svcCtx *servicecontext.Context, service
|
||||
}
|
||||
}
|
||||
|
||||
func shouldAllowReconcileWithoutEndpoints(service *v1.Service) bool {
|
||||
if service == nil || service.Spec.ExternalTrafficPolicy != v1.ServiceExternalTrafficPolicyTypeCluster {
|
||||
return false
|
||||
}
|
||||
|
||||
return strings.EqualFold(service.Annotations[kubevip.AllowReconcileWithoutEndpoints], "true")
|
||||
}
|
||||
|
||||
func hasV6(endpoints []string) bool {
|
||||
for _, e := range endpoints {
|
||||
ip := net.ParseIP(e)
|
||||
|
||||
63
pkg/endpoints/endpoints_test.go
Normal file
63
pkg/endpoints/endpoints_test.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kube-vip/kube-vip/pkg/kubevip"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestShouldAllowReconcileWithoutEndpoints(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
service *v1.Service
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "nil service",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "cluster policy with opt-in annotation",
|
||||
service: &v1.Service{
|
||||
Spec: v1.ServiceSpec{ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeCluster},
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{kubevip.AllowReconcileWithoutEndpoints: "true"}},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "cluster policy with case-insensitive opt-in",
|
||||
service: &v1.Service{
|
||||
Spec: v1.ServiceSpec{ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeCluster},
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{kubevip.AllowReconcileWithoutEndpoints: "TRUE"}},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "cluster policy without opt-in",
|
||||
service: &v1.Service{
|
||||
Spec: v1.ServiceSpec{ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeCluster},
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "local policy with opt-in",
|
||||
service: &v1.Service{
|
||||
Spec: v1.ServiceSpec{ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeLocal},
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{kubevip.AllowReconcileWithoutEndpoints: "true"}},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual := shouldAllowReconcileWithoutEndpoints(test.service)
|
||||
if actual != test.expected {
|
||||
t.Fatalf("expected %v, got %v", test.expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,9 @@ const (
|
||||
// Name of the service lease object
|
||||
ServiceLease = "kube-vip.io/leaseName"
|
||||
|
||||
// Allow service reconciliation even when no endpoints are present (Cluster policy only)
|
||||
AllowReconcileWithoutEndpoints = "kube-vip.io/allow-reconcile-without-endpoints"
|
||||
|
||||
// Enable DDNS for the service
|
||||
ServiceDDNS = "kube-vip.io/ddns"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user