k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/measurement/util/wait_for_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 "strings" 22 "time" 23 24 clientset "k8s.io/client-go/kubernetes" 25 "k8s.io/klog/v2" 26 "k8s.io/perf-tests/clusterloader2/pkg/util" 27 ) 28 29 // WaitForPVOptions is an options used by WaitForPVs methods. 30 type WaitForPVOptions struct { 31 Selector *util.ObjectSelector 32 DesiredPVCount int 33 Provisioner string 34 CallerName string 35 WaitForPVsInterval time.Duration 36 } 37 38 func (options WaitForPVOptions) filter() string { 39 filter := options.Selector.String() 40 if options.Provisioner != "" { 41 filter += " && provisioner=" + options.Provisioner 42 } 43 return filter 44 } 45 46 // WaitForPVs waits till desired number of PVs is running. 47 // PVs are be specified by field and/or label selectors. 48 // If stopCh is closed before all PVs are running, the error will be returned. 49 func WaitForPVs(clientSet clientset.Interface, stopCh <-chan struct{}, options *WaitForPVOptions) error { 50 ps, err := NewPVStore(clientSet, options.Selector, options.Provisioner) 51 if err != nil { 52 return fmt.Errorf("PV store creation error: %v", err) 53 } 54 defer ps.Stop() 55 56 oldPVs := ps.List() 57 scaling := uninitialized 58 var pvStatus PVsStartupStatus 59 60 switch { 61 case len(oldPVs) == options.DesiredPVCount: 62 scaling = none 63 case len(oldPVs) < options.DesiredPVCount: 64 scaling = up 65 case len(oldPVs) > options.DesiredPVCount: 66 scaling = down 67 } 68 69 for { 70 select { 71 case <-stopCh: 72 example := "" 73 if len(oldPVs) > 0 { 74 example = fmt.Sprintf(", first one is %+v", oldPVs[0]) 75 } 76 return fmt.Errorf("timeout while waiting for %d PVs with selector '%s' - only %d found provisioned%s", 77 options.DesiredPVCount, options.filter(), pvStatus.Bound+pvStatus.Available, example) 78 case <-time.After(options.WaitForPVsInterval): 79 pvs := ps.List() 80 pvStatus = ComputePVsStartupStatus(pvs, options.DesiredPVCount) 81 82 diff := DiffPVs(oldPVs, pvs) 83 deletedPVs := diff.DeletedPVs() 84 if scaling != down && len(deletedPVs) > 0 { 85 klog.Errorf("%s: %s: %d PVs disappeared: %v", options.CallerName, options.Selector.String(), len(deletedPVs), strings.Join(deletedPVs, ", ")) 86 } 87 addedPVs := diff.AddedPVs() 88 if scaling != up && len(addedPVs) > 0 { 89 klog.Errorf("%s: %s: %d PVs appeared: %v", options.CallerName, options.filter(), len(addedPVs), strings.Join(addedPVs, ", ")) 90 } 91 klog.V(2).Infof("%s: %s: %s", options.CallerName, options.filter(), pvStatus.String()) 92 // We wait until there is a desired number of PVs provisioned and all other PVs are pending. 93 if len(pvs) == (pvStatus.Bound+pvStatus.Available+pvStatus.Pending) && pvStatus.Bound+pvStatus.Available == options.DesiredPVCount { 94 return nil 95 } 96 oldPVs = pvs 97 } 98 } 99 }