k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/measurement/common/wait_for_generic_k8s_object.go (about)

     1  /*
     2  Copyright 2023 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 common
    18  
    19  import (
    20  	"context"
    21  	"time"
    22  
    23  	"k8s.io/apimachinery/pkg/runtime/schema"
    24  	"k8s.io/klog/v2"
    25  	"k8s.io/perf-tests/clusterloader2/pkg/measurement"
    26  	measurementutil "k8s.io/perf-tests/clusterloader2/pkg/measurement/util"
    27  	"k8s.io/perf-tests/clusterloader2/pkg/util"
    28  )
    29  
    30  const (
    31  	defaultWaitForGenericK8sObjectsTimeout  = 30 * time.Minute
    32  	defaultWaitForGenericK8sObjectsInterval = 30 * time.Second
    33  	waitForGenericK8sObjectsMeasurementName = "WaitForGenericK8sObjects"
    34  )
    35  
    36  func init() {
    37  	if err := measurement.Register(waitForGenericK8sObjectsMeasurementName, createWaitForGenericK8sObjectsMeasurement); err != nil {
    38  		klog.Fatalf("Cannot register %s: %v", waitForGenericK8sObjectsMeasurementName, err)
    39  	}
    40  }
    41  
    42  func createWaitForGenericK8sObjectsMeasurement() measurement.Measurement {
    43  	return &waitForGenericK8sObjectsMeasurement{}
    44  }
    45  
    46  type waitForGenericK8sObjectsMeasurement struct{}
    47  
    48  // Execute waits until desired number of k8s objects reached given conditions.
    49  // Conditions can denote either success or failure. The measurement assumes the
    50  // k8s object has a status.conditions field, which contains a []metav1.Condition.
    51  // More here: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
    52  // Measurement will timeout if not enough objects have required conditions.
    53  func (w *waitForGenericK8sObjectsMeasurement) Execute(config *measurement.Config) ([]measurement.Summary, error) {
    54  	groupVersionResource, err := getGroupVersionResource(config.Params)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	namespaces, err := getNamespaces(config.ClusterFramework.GetAutomanagedNamespacePrefix(), config.Params)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	timeout, err := util.GetDurationOrDefault(config.Params, "timeout", defaultWaitForGenericK8sObjectsTimeout)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	refreshInterval, err := util.GetDurationOrDefault(config.Params, "refreshInterval", defaultWaitForGenericK8sObjectsInterval)
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  	successfulConditions, err := util.GetStringArray(config.Params, "successfulConditions")
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	failedConditions, err := util.GetStringArray(config.Params, "failedConditions")
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	minDesiredObjectCount, err := util.GetInt(config.Params, "minDesiredObjectCount")
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	maxFailedObjectCount, err := util.GetInt(config.Params, "maxFailedObjectCount")
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	dynamicClient := config.ClusterFramework.GetDynamicClients().GetClient()
    88  	ctx, cancel := context.WithTimeout(context.TODO(), timeout)
    89  	defer cancel()
    90  
    91  	options := &measurementutil.WaitForGenericK8sObjectsOptions{
    92  		GroupVersionResource:  groupVersionResource,
    93  		Namespaces:            namespaces,
    94  		SuccessfulConditions:  successfulConditions,
    95  		FailedConditions:      failedConditions,
    96  		MinDesiredObjectCount: minDesiredObjectCount,
    97  		MaxFailedObjectCount:  maxFailedObjectCount,
    98  		CallerName:            w.String(),
    99  		WaitInterval:          refreshInterval,
   100  	}
   101  	return nil, measurementutil.WaitForGenericK8sObjects(ctx, dynamicClient, options)
   102  }
   103  
   104  // Dispose cleans up after the measurement.
   105  func (*waitForGenericK8sObjectsMeasurement) Dispose() {}
   106  
   107  // String returns a string representation of the measurement.
   108  func (*waitForGenericK8sObjectsMeasurement) String() string {
   109  	return waitForGenericK8sObjectsMeasurementName
   110  }
   111  
   112  func getGroupVersionResource(params map[string]interface{}) (schema.GroupVersionResource, error) {
   113  	group, err := util.GetString(params, "objectGroup")
   114  	if err != nil {
   115  		return schema.GroupVersionResource{}, err
   116  	}
   117  	version, err := util.GetString(params, "objectVersion")
   118  	if err != nil {
   119  		return schema.GroupVersionResource{}, err
   120  	}
   121  	resource, err := util.GetString(params, "objectResource")
   122  	if err != nil {
   123  		return schema.GroupVersionResource{}, err
   124  	}
   125  
   126  	return schema.GroupVersionResource{
   127  		Group:    group,
   128  		Version:  version,
   129  		Resource: resource,
   130  	}, nil
   131  }
   132  
   133  func getNamespaces(namespacesPrefix string, params map[string]interface{}) (measurementutil.NamespacesRange, error) {
   134  	namespaceRange, err := util.GetMap(params, "namespaceRange")
   135  	if err != nil {
   136  		return measurementutil.NamespacesRange{}, err
   137  	}
   138  	min, err := util.GetInt(namespaceRange, "min")
   139  	if err != nil {
   140  		return measurementutil.NamespacesRange{}, err
   141  	}
   142  	max, err := util.GetInt(namespaceRange, "max")
   143  	if err != nil {
   144  		return measurementutil.NamespacesRange{}, err
   145  	}
   146  
   147  	return measurementutil.NamespacesRange{
   148  		Prefix: namespacesPrefix,
   149  		Min:    min,
   150  		Max:    max,
   151  	}, nil
   152  }