k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/measurement/common/network/worker_pod_info.go (about) 1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package network 18 19 import ( 20 "container/heap" 21 "fmt" 22 23 "k8s.io/klog/v2" 24 ) 25 26 // workerNodeInfo represents node in heap 27 type workerNodeInfo struct { 28 nodeName string 29 numberOfPods int 30 } 31 32 type nodeHeap []*workerNodeInfo 33 34 func (nh nodeHeap) Len() int { return len(nh) } 35 func (nh nodeHeap) Less(i, j int) bool { 36 return nh[i].numberOfPods > nh[j].numberOfPods 37 } 38 39 func (nh nodeHeap) Swap(i, j int) { 40 nh[i], nh[j] = nh[j], nh[i] 41 } 42 43 func (nh *nodeHeap) Push(x interface{}) { 44 *nh = append(*nh, x.(*workerNodeInfo)) 45 } 46 47 func (nh *nodeHeap) Pop() interface{} { 48 old := *nh 49 n := len(old) 50 x := old[n-1] 51 *nh = old[0 : n-1] 52 return x 53 } 54 55 // workerPodData represents details of pods running on worker node 56 type workerPodData struct { 57 podName string 58 workerNode string 59 podIP string 60 } 61 62 type podList []workerPodData 63 64 func (l *podList) Pop() (*workerPodData, error) { 65 if len(*l) == 0 { 66 return nil, fmt.Errorf("empty pod list") 67 } 68 lastElement := (*l)[len(*l)-1] 69 *l = (*l)[:len(*l)-1] 70 return &lastElement, nil 71 } 72 73 // podPair represents source-destination worker pod pair. 74 type podPair struct { 75 index int 76 sourcePodName string 77 sourcePodIP string 78 destinationPodName string 79 destinationPodIP string 80 } 81 82 func newPodPair(index int, sourcePod, destinationPod *workerPodData) podPair { 83 return podPair{ 84 index: index, 85 sourcePodName: sourcePod.podName, 86 sourcePodIP: sourcePod.podIP, 87 destinationPodName: destinationPod.podName, 88 destinationPodIP: destinationPod.podIP, 89 } 90 } 91 92 type workerPodInfo struct { 93 workerPodMap map[string]podList 94 } 95 96 func (wp *workerPodInfo) formUniquePodPair() []podPair { 97 nh := make(nodeHeap, 0, len(wp.workerPodMap)) 98 podPairList := make([]podPair, 0) 99 for key, value := range wp.workerPodMap { 100 nh = append(nh, &workerNodeInfo{nodeName: key, numberOfPods: len(value)}) 101 } 102 heap.Init(&nh) 103 for i := 0; nh.Len() > 1; i++ { 104 firstNode := heap.Pop(&nh).(*workerNodeInfo) 105 secondNode := heap.Pop(&nh).(*workerNodeInfo) 106 if firstNode.numberOfPods > 1 { 107 heap.Push(&nh, &workerNodeInfo{nodeName: firstNode.nodeName, numberOfPods: firstNode.numberOfPods - 1}) 108 } 109 if secondNode.numberOfPods > 1 { 110 heap.Push(&nh, &workerNodeInfo{nodeName: secondNode.nodeName, numberOfPods: secondNode.numberOfPods - 1}) 111 } 112 113 sourcePod, err1 := wp.pop(firstNode.nodeName) 114 destinationPod, err2 := wp.pop(secondNode.nodeName) 115 if err1 != nil || err2 != nil { 116 klog.Errorf("error in popping pods. err1: %v, err2: %v", err1, err2) 117 continue 118 } 119 podPairList = append(podPairList, newPodPair(i, sourcePod, destinationPod)) 120 } 121 return podPairList 122 } 123 124 func (wp *workerPodInfo) pop(nodeName string) (*workerPodData, error) { 125 podList, ok := wp.workerPodMap[nodeName] 126 if !ok { 127 return nil, fmt.Errorf("worker node %s is removed", nodeName) 128 } 129 pod, err := podList.Pop() 130 if err != nil { 131 delete(wp.workerPodMap, nodeName) 132 return nil, err 133 } 134 wp.workerPodMap[nodeName] = podList 135 return pod, nil 136 }