k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/measurement/util/object_store.go (about) 1 /* 2 Copyright 2018 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 /* 18 This file is copy of https://github.com/kubernetes/kubernetes/blob/master/test/utils/pod_store.go 19 with slight changes regarding labelSelector and flagSelector applied. 20 */ 21 22 package util 23 24 import ( 25 "context" 26 "fmt" 27 "reflect" 28 "time" 29 30 v1 "k8s.io/api/core/v1" 31 "k8s.io/apimachinery/pkg/api/meta" 32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 33 "k8s.io/apimachinery/pkg/runtime" 34 "k8s.io/apimachinery/pkg/util/wait" 35 "k8s.io/apimachinery/pkg/watch" 36 clientset "k8s.io/client-go/kubernetes" 37 "k8s.io/client-go/tools/cache" 38 "k8s.io/perf-tests/clusterloader2/pkg/util" 39 ) 40 41 // ObjectStore is a convenient wrapper around cache.Store. 42 type ObjectStore struct { 43 cache.Store 44 stopCh chan struct{} 45 Reflector *cache.Reflector 46 } 47 48 // newObjectStore creates ObjectStore based on given object selector. 49 func newObjectStore(obj runtime.Object, lw *cache.ListWatch, selector *util.ObjectSelector) (*ObjectStore, error) { 50 store := cache.NewStore(cache.MetaNamespaceKeyFunc) 51 stopCh := make(chan struct{}) 52 name := fmt.Sprintf("%sStore: %s", reflect.TypeOf(obj).String(), selector.String()) 53 reflector := cache.NewNamedReflector(name, lw, obj, store, 0) 54 go reflector.Run(stopCh) 55 if err := wait.PollImmediate(50*time.Millisecond, 2*time.Minute, func() (bool, error) { 56 if len(reflector.LastSyncResourceVersion()) != 0 { 57 return true, nil 58 } 59 return false, nil 60 }); err != nil { 61 close(stopCh) 62 return nil, fmt.Errorf("couldn't initialize %s: %v", name, err) 63 } 64 return &ObjectStore{ 65 Store: store, 66 stopCh: stopCh, 67 Reflector: reflector, 68 }, nil 69 } 70 71 // Stop stops ObjectStore watch. 72 func (s *ObjectStore) Stop() { 73 close(s.stopCh) 74 } 75 76 // PodStore is a convenient wrapper around cache.Store. 77 type PodStore struct { 78 *ObjectStore 79 selector *util.ObjectSelector 80 } 81 82 // NewPodStore creates PodStore based on given object selector. 83 func NewPodStore(c clientset.Interface, selector *util.ObjectSelector) (*PodStore, error) { 84 lw := &cache.ListWatch{ 85 ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 86 options.LabelSelector = selector.LabelSelector 87 options.FieldSelector = selector.FieldSelector 88 return c.CoreV1().Pods(selector.Namespace).List(context.TODO(), options) 89 }, 90 WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 91 options.LabelSelector = selector.LabelSelector 92 options.FieldSelector = selector.FieldSelector 93 return c.CoreV1().Pods(selector.Namespace).Watch(context.TODO(), options) 94 }, 95 } 96 objectStore, err := newObjectStore(&v1.Pod{}, lw, selector) 97 if err != nil { 98 return nil, err 99 } 100 return &PodStore{ObjectStore: objectStore, selector: selector}, nil 101 } 102 103 // List returns list of pods (that satisfy conditions provided to NewPodStore). 104 func (s *PodStore) List() ([]*v1.Pod, error) { 105 objects := s.Store.List() 106 pods := make([]*v1.Pod, 0, len(objects)) 107 for _, o := range objects { 108 pods = append(pods, o.(*v1.Pod)) 109 } 110 return pods, nil 111 } 112 113 // String returns human readable identifier of pods kept in the store. 114 func (s *PodStore) String() string { 115 return s.selector.String() 116 } 117 118 type controlledPodsIndexer interface { 119 PodsControlledBy(obj interface{}) ([]*v1.Pod, error) 120 } 121 122 // OwnerReferenceBasedPodStore returns pods with ownerReference set to the owner 123 // (with exception for Deployment, see ControlledPodsIndexer implementation) and matching given labelSelector. 124 type OwnerReferenceBasedPodStore struct { 125 controlledPodsIndexer controlledPodsIndexer 126 owner interface{} 127 cachedString string 128 } 129 130 func NewOwnerReferenceBasedPodStore(controlledPodsIndexer controlledPodsIndexer, owner interface{}) (*OwnerReferenceBasedPodStore, error) { 131 metaAccessor, err := meta.Accessor(owner) 132 if err != nil { 133 return nil, fmt.Errorf("object has no meta: %w", err) 134 } 135 136 return &OwnerReferenceBasedPodStore{ 137 controlledPodsIndexer: controlledPodsIndexer, 138 owner: owner, 139 cachedString: fmt.Sprintf("namespace(%s), controlledBy(%s)", metaAccessor.GetNamespace(), metaAccessor.GetName()), 140 }, nil 141 } 142 143 // List returns controlled pods. 144 func (s *OwnerReferenceBasedPodStore) List() ([]*v1.Pod, error) { 145 // Technically to be 100% correct we should check here label selectors here as this is how API of pod controllers is defined. 146 // In practice, comparing ownerReference only should be eventually consistent with label selectors, so it should be enough. 147 return s.controlledPodsIndexer.PodsControlledBy(s.owner) 148 } 149 150 // String returns human readable identifier of pods kept in the store. 151 func (s *OwnerReferenceBasedPodStore) String() string { 152 return s.cachedString 153 } 154 155 // PVCStore is a convenient wrapper around cache.Store. 156 type PVCStore struct { 157 *ObjectStore 158 } 159 160 // NewPVCStore creates PVCStore based on a given object selector. 161 func NewPVCStore(c clientset.Interface, selector *util.ObjectSelector) (*PVCStore, error) { 162 lw := &cache.ListWatch{ 163 ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 164 options.LabelSelector = selector.LabelSelector 165 options.FieldSelector = selector.FieldSelector 166 return c.CoreV1().PersistentVolumeClaims(selector.Namespace).List(context.TODO(), options) 167 }, 168 WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 169 options.LabelSelector = selector.LabelSelector 170 options.FieldSelector = selector.FieldSelector 171 return c.CoreV1().PersistentVolumeClaims(selector.Namespace).Watch(context.TODO(), options) 172 }, 173 } 174 objectStore, err := newObjectStore(&v1.PersistentVolumeClaim{}, lw, selector) 175 if err != nil { 176 return nil, err 177 } 178 return &PVCStore{ObjectStore: objectStore}, nil 179 } 180 181 // List returns list of pvcs (that satisfy conditions provided to NewPVCStore). 182 func (s *PVCStore) List() []*v1.PersistentVolumeClaim { 183 objects := s.Store.List() 184 pvcs := make([]*v1.PersistentVolumeClaim, 0, len(objects)) 185 for _, o := range objects { 186 pvcs = append(pvcs, o.(*v1.PersistentVolumeClaim)) 187 } 188 return pvcs 189 } 190 191 // PVStore is a convenient wrapper around cache.Store. 192 type PVStore struct { 193 *ObjectStore 194 provisioner string 195 } 196 197 // NewPVStore creates PVStore based on a given object selector. 198 func NewPVStore(c clientset.Interface, selector *util.ObjectSelector, provisioner string) (*PVStore, error) { 199 lw := &cache.ListWatch{ 200 ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 201 options.LabelSelector = selector.LabelSelector 202 options.FieldSelector = selector.FieldSelector 203 return c.CoreV1().PersistentVolumes().List(context.TODO(), options) 204 }, 205 WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 206 options.LabelSelector = selector.LabelSelector 207 options.FieldSelector = selector.FieldSelector 208 return c.CoreV1().PersistentVolumes().Watch(context.TODO(), options) 209 }, 210 } 211 objectStore, err := newObjectStore(&v1.PersistentVolume{}, lw, selector) 212 if err != nil { 213 return nil, err 214 } 215 return &PVStore{ObjectStore: objectStore, provisioner: provisioner}, nil 216 } 217 218 // List returns list of pvs (that satisfy conditions provided to NewPVStore). 219 func (s *PVStore) List() []*v1.PersistentVolume { 220 objects := s.Store.List() 221 pvs := make([]*v1.PersistentVolume, 0, len(objects)) 222 for _, o := range objects { 223 pv := o.(*v1.PersistentVolume) 224 if s.provisioner == "" || 225 pv.Annotations["pv.kubernetes.io/provisioned-by"] == s.provisioner { 226 pvs = append(pvs, pv) 227 } 228 } 229 return pvs 230 } 231 232 // NodeStore is a convenient wrapper around cache.Store. 233 type NodeStore struct { 234 *ObjectStore 235 } 236 237 // NewNodeStore creates NodeStore based on a given object selector. 238 func NewNodeStore(c clientset.Interface, selector *util.ObjectSelector) (*NodeStore, error) { 239 lw := &cache.ListWatch{ 240 ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 241 options.LabelSelector = selector.LabelSelector 242 options.FieldSelector = selector.FieldSelector 243 return c.CoreV1().Nodes().List(context.TODO(), options) 244 }, 245 WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 246 options.LabelSelector = selector.LabelSelector 247 options.FieldSelector = selector.FieldSelector 248 return c.CoreV1().Nodes().Watch(context.TODO(), options) 249 }, 250 } 251 objectStore, err := newObjectStore(&v1.Node{}, lw, selector) 252 if err != nil { 253 return nil, err 254 } 255 return &NodeStore{ObjectStore: objectStore}, nil 256 } 257 258 // List returns list of nodes that satisfy conditions provided to NewNodeStore. 259 func (s *NodeStore) List() []*v1.Node { 260 objects := s.Store.List() 261 nodes := make([]*v1.Node, 0, len(objects)) 262 for _, o := range objects { 263 nodes = append(nodes, o.(*v1.Node)) 264 } 265 return nodes 266 }