k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/measurement/util/pvs.go (about) 1 /* 2 Copyright 2019 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 util 18 19 import ( 20 "fmt" 21 22 corev1 "k8s.io/api/core/v1" 23 "k8s.io/apimachinery/pkg/util/sets" 24 ) 25 26 // PVsStartupStatus represents phase of a PV group. 27 type PVsStartupStatus struct { 28 Pending int 29 Available int 30 Bound int 31 Released int 32 Failed int 33 Expected int 34 Created int 35 } 36 37 // String returns string representation for PVsStartupStatus. 38 func (s *PVsStartupStatus) String() string { 39 return fmt.Sprintf("PVs: %d out of %d created, %d bound, %d pending, %d available, %d failed", 40 s.Created, s.Expected, s.Bound, s.Pending, s.Available, s.Failed) 41 } 42 43 // ComputePVsStartupStatus computes PVsStartupStatus for a group of PVs. 44 func ComputePVsStartupStatus(PVs []*corev1.PersistentVolume, expected int) PVsStartupStatus { 45 startupStatus := PVsStartupStatus{ 46 Expected: expected, 47 } 48 for _, p := range PVs { 49 startupStatus.Created++ 50 if p.Status.Phase == corev1.VolumePending { 51 startupStatus.Pending++ 52 } else if p.Status.Phase == corev1.VolumeAvailable { 53 startupStatus.Available++ 54 } else if p.Status.Phase == corev1.VolumeBound { 55 startupStatus.Bound++ 56 } else if p.Status.Phase == corev1.VolumeReleased { 57 startupStatus.Released++ 58 } else if p.Status.Phase == corev1.VolumeFailed { 59 startupStatus.Failed++ 60 } 61 } 62 return startupStatus 63 } 64 65 type pvInfo struct { 66 oldPhase string 67 phase string 68 } 69 70 // PVDiff represents diff between old and new group of PVs. 71 type PVDiff map[string]*pvInfo 72 73 // Print formats and prints the given PVDiff. 74 func (p PVDiff) String(ignorePhases sets.String) string { 75 ret := "" 76 for name, info := range p { 77 if ignorePhases.Has(info.phase) { 78 continue 79 } 80 if info.phase == nonExist { 81 ret += fmt.Sprintf("PV %v was deleted, had phase %v\n", name, info.oldPhase) 82 continue 83 } 84 msg := fmt.Sprintf("PV %v ", name) 85 if info.oldPhase != info.phase { 86 if info.oldPhase == nonExist { 87 msg += fmt.Sprintf("in phase %v ", info.phase) 88 } else { 89 msg += fmt.Sprintf("went from phase: %v -> %v ", info.oldPhase, info.phase) 90 } 91 ret += msg + "\n" 92 } 93 } 94 return ret 95 } 96 97 // DeletedPVs returns a slice of PVs that were present at the beginning 98 // and then disappeared. 99 func (p PVDiff) DeletedPVs() []string { 100 var deletedPVs []string 101 for PVName, pvInfo := range p { 102 if pvInfo.phase == nonExist { 103 deletedPVs = append(deletedPVs, PVName) 104 } 105 } 106 return deletedPVs 107 } 108 109 // AddedPVs returns a slice of PVs that were added. 110 func (p PVDiff) AddedPVs() []string { 111 var addedPVs []string 112 for PVName, pvInfo := range p { 113 if pvInfo.oldPhase == nonExist { 114 addedPVs = append(addedPVs, PVName) 115 } 116 } 117 return addedPVs 118 } 119 120 // DiffPVs computes a PVDiff given 2 lists of PVs. 121 func DiffPVs(oldPVs []*corev1.PersistentVolume, curPVs []*corev1.PersistentVolume) PVDiff { 122 pvInfoMap := PVDiff{} 123 124 // New PVs will show up in the curPVs list but not in oldPVs. They have oldhostname/phase == nonexist. 125 for _, PV := range curPVs { 126 pvInfoMap[PV.Name] = &pvInfo{phase: string(PV.Status.Phase), oldPhase: nonExist} 127 } 128 129 // Deleted PVs will show up in the oldPVs list but not in curPVs. They have a hostname/phase == nonexist. 130 for _, PV := range oldPVs { 131 if info, ok := pvInfoMap[PV.Name]; ok { 132 info.oldPhase = string(PV.Status.Phase) 133 } else { 134 pvInfoMap[PV.Name] = &pvInfo{phase: nonExist, oldPhase: string(PV.Status.Phase)} 135 } 136 } 137 return pvInfoMap 138 }