pkg/k8s/service_utils.go (70 lines of code) (raw):
package k8s
import (
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
// LookupServiceListenPort returns the numerical port for the service listen port if the target port name matches
// or the port number and the protocol matches the target port. If no matching port is found, it returns a 0 and an error.
func LookupServiceListenPort(svc *corev1.Service, port intstr.IntOrString, protocol corev1.Protocol) (int32, error) {
for _, svcPort := range svc.Spec.Ports {
if svcPort.TargetPort.Type == port.Type && svcPort.TargetPort.String() == port.String() && svcPort.Protocol == protocol {
return svcPort.Port, nil
}
}
return 0, errors.Errorf("unable to find port %s on service %s", port.String(), NamespacedName(svc))
}
// LookupListenPortFromPodSpec returns the numerical listener port from the service spec if the input port matches the target port
// in the pod spec
func LookupListenPortFromPodSpec(svc *corev1.Service, pod *corev1.Pod, port intstr.IntOrString, protocol corev1.Protocol) (int32, error) {
containerPort, containerPortName, err := LookupContainerPortAndName(pod, port, protocol)
if err != nil {
return 0, err
}
for _, svcPort := range svc.Spec.Ports {
if svcPort.Protocol != protocol {
continue
}
switch svcPort.TargetPort.Type {
case intstr.String:
if containerPortName == svcPort.TargetPort.StrVal {
return svcPort.Port, nil
}
case intstr.Int:
if containerPort == svcPort.TargetPort.IntVal {
return svcPort.Port, nil
}
}
}
return 0, errors.Errorf("unable to find listener port for port %s on service %s", port.String(), NamespacedName(svc))
}
// IsServiceHeadless returns true if the service is headless
func IsServiceHeadless(svc *corev1.Service) bool {
if svc.Spec.ClusterIP == "" || svc.Spec.ClusterIP == "None" {
return true
}
return false
}
// StripDownServiceTransformFunc is a transform function that strips down service to reduce memory usage.
// see details in [stripDownServiceObject].
func StripDownServiceTransformFunc(obj interface{}) (interface{}, error) {
if service, ok := obj.(*corev1.Service); ok {
return stripDownServiceObject(service), nil
}
return obj, nil
}
// stripDownServiceObject provides an stripDown version of service to reduce memory usage.
// NOTE: if the controller needs to refer to more service fields in the future
// these fields need to be added to the cache
func stripDownServiceObject(service *corev1.Service) *corev1.Service {
service.ObjectMeta = metav1.ObjectMeta{
Name: service.Name,
Namespace: service.Namespace,
UID: service.UID,
DeletionTimestamp: service.DeletionTimestamp,
ResourceVersion: service.ResourceVersion,
Finalizers: service.Finalizers,
}
service.Spec = corev1.ServiceSpec{
Selector: service.Spec.Selector,
ClusterIP: service.Spec.ClusterIP,
ClusterIPs: service.Spec.ClusterIPs,
Ports: service.Spec.Ports,
Type: service.Spec.Type,
}
service.Status = corev1.ServiceStatus{
LoadBalancer: service.Status.LoadBalancer,
}
return service
}