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  }