kube-router/pkg/utils/service.go
Aaron U'Ren 43c3c9de86
Handle headless services (#1047)
* doc(ecmp_vip.go): add info around extra withdraw

Rename getWithdraw to make it more explicit what its doing here. Also
add documentation as to why this is needed on Update and not
Create/Delete as well as why we only treat externalIPs.

* fix(ecmp_vip.go): remove superfluous AddPolicies

AddPolicies is already called downstream of nrc.OnEndpointsUpdate() so
there is no need to do it here as well, the only result is that this
expensive operation and idempotent operation is run twice.

* feat: better handling of headless services

Also introduces a consolidated Service utilities section for controller
functionality related to services that is shared.

* fix: add logging back to tryHandleServiceDelete
2021-03-24 08:31:39 +05:30

61 lines
1.6 KiB
Go

package utils
import (
"fmt"
"strings"
v1core "k8s.io/api/core/v1"
"k8s.io/client-go/tools/cache"
)
func ServiceForEndpoints(ci *cache.Indexer, ep *v1core.Endpoints) (interface{}, error) {
key, err := cache.MetaNamespaceKeyFunc(ep)
if err != nil {
return nil, err
}
item, exists, err := (*ci).GetByKey(key)
if err != nil {
return nil, err
}
if !exists {
return nil, fmt.Errorf("service resource doesn't exist for endpoints: %q", ep.Name)
}
return item, nil
}
// ServiceIsHeadless decides whether or not the this service is a headless service which is often useful to kube-router
// as there is no need to execute logic on most headless changes. Function takes a generic interface as its input
// parameter so that it can be used more easily in early processing if needed. If a non-service object is given,
// function will return false.
func ServiceIsHeadless(obj interface{}) bool {
if svc, _ := obj.(*v1core.Service); svc != nil {
if svc.Spec.Type == v1core.ServiceTypeClusterIP {
if ClusterIPIsNone(svc.Spec.ClusterIP) && containsOnlyNone(svc.Spec.ClusterIPs) {
return true
}
}
}
return false
}
// ClusterIPIsNone checks to see whether the ClusterIP contains "None" which would indicate that it is headless
func ClusterIPIsNone(clusterIP string) bool {
return strings.ToLower(clusterIP) == "none"
}
func ClusterIPIsNoneOrBlank(clusterIP string) bool {
return ClusterIPIsNone(clusterIP) || clusterIP == ""
}
func containsOnlyNone(clusterIPs []string) bool {
for _, clusterIP := range clusterIPs {
if !ClusterIPIsNone(clusterIP) {
return false
}
}
return true
}