diff --git a/endpointslices/endpointslices.go b/endpointslices/endpointslices.go index 274d35d6..82d28792 100644 --- a/endpointslices/endpointslices.go +++ b/endpointslices/endpointslices.go @@ -3,6 +3,7 @@ package endpointslices import ( "context" "fmt" + "strings" log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" @@ -200,6 +201,30 @@ func getContainerName(portNum int, pods []corev1.Pod) (string, error) { return res, nil } +func extractPodName(pod *corev1.Pod) (string, error) { + if len(pod.OwnerReferences) == 0 { + return pod.Name, nil + } + + ownerRefName := pod.OwnerReferences[0].Name + switch pod.OwnerReferences[0].Kind { + case "Node": + res, found := strings.CutSuffix(pod.Name, fmt.Sprintf("-%s", pod.Spec.NodeName)) + if !found { + return "", fmt.Errorf("pod name %s is not ending with node name %s", pod.Name, pod.Spec.NodeName) + } + return res, nil + case "ReplicaSet": + return ownerRefName[:strings.LastIndex(ownerRefName, "-")], nil + case "DaemonSet": + return ownerRefName, nil + case "StatefulSet": + return ownerRefName, nil + } + + return "", fmt.Errorf("failed to extract pod name for %s", pod.Name) +} + func (epSliceinfo *EndpointSlicesInfo) toComDetails(nodes []corev1.Node) ([]types.ComDetails, error) { if len(epSliceinfo.EndpointSlice.OwnerReferences) == 0 { return nil, fmt.Errorf("empty OwnerReferences in EndpointSlice %s/%s. skipping", epSliceinfo.EndpointSlice.Namespace, epSliceinfo.EndpointSlice.Name) @@ -209,7 +234,10 @@ func (epSliceinfo *EndpointSlicesInfo) toComDetails(nodes []corev1.Node) ([]type // Get the Namespace and Pod's name from the service. namespace := epSliceinfo.Service.Namespace - name := epSliceinfo.EndpointSlice.OwnerReferences[0].Name + name, err := extractPodName(&epSliceinfo.Pods[0]) + if err != nil { + return nil, fmt.Errorf("failed to get pod name for endpointslice %s: %w", epSliceinfo.EndpointSlice.Name, err) + } // Get the node roles of this endpointslice. (master or worker or both). roles := getEndpointSliceNodeRoles(epSliceinfo, nodes) diff --git a/endpointslices/endpointslices_test.go b/endpointslices/endpointslices_test.go new file mode 100644 index 00000000..f8b44774 --- /dev/null +++ b/endpointslices/endpointslices_test.go @@ -0,0 +1,84 @@ +package endpointslices + +import ( + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type TestCase struct { + desc string + podName string + nodeName string + ownerRefs []metav1.OwnerReference + expected string +} + +func TestExtractPodName(t *testing.T) { + tests := []TestCase{ + { + desc: "with-no-owner-reference", + podName: "kube-rbac-proxy", + expected: "kube-rbac-proxy", + }, + { + desc: "with-owner-reference-kind-node", + nodeName: "worker-node", + podName: "kube-rbac-proxy-worker-node", + ownerRefs: []metav1.OwnerReference{ + { + Kind: "Node", + }, + }, + expected: "kube-rbac-proxy", + }, + { + desc: "with-owner-reference-kind-replicaset", + ownerRefs: []metav1.OwnerReference{ + { + Kind: "ReplicaSet", + Name: "kube-rbac-proxy-7b7df454c7", + }, + }, + expected: "kube-rbac-proxy", + }, + { + desc: "with-owner-reference-kind-daemonset", + ownerRefs: []metav1.OwnerReference{ + { + Kind: "DaemonSet", + Name: "kube-rbac-proxy", + }, + }, + expected: "kube-rbac-proxy", + }, + { + desc: "with-owner-reference-kind-statefulset", + ownerRefs: []metav1.OwnerReference{ + { + Kind: "StatefulSet", + Name: "kube-rbac-proxy", + }, + }, + expected: "kube-rbac-proxy", + }, + } + for _, test := range tests { + p := defineTestPod(&test) + res, err := extractPodName(p) + if err != nil { + t.Fatalf("test %s failed. got error: %s", test.desc, err) + } + if res != test.expected { + t.Fatalf("test %s failed. expected %v got %v", test.desc, test.expected, res) + } + } +} + +func defineTestPod(t *TestCase) *corev1.Pod { + return &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{Name: t.podName, OwnerReferences: t.ownerRefs}, + Spec: corev1.PodSpec{NodeName: t.nodeName}, + } +}