k8s.io/kubernetes@v1.29.3/test/utils/create_resources.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  // TODO: Refactor common part of functions in this file for generic object kinds.
    18  
    19  package utils
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"time"
    25  
    26  	apps "k8s.io/api/apps/v1"
    27  	batch "k8s.io/api/batch/v1"
    28  	storage "k8s.io/api/storage/v1"
    29  
    30  	v1 "k8s.io/api/core/v1"
    31  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    32  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    33  	"k8s.io/apimachinery/pkg/util/wait"
    34  	clientset "k8s.io/client-go/kubernetes"
    35  )
    36  
    37  const (
    38  	// Parameters for retrying with exponential backoff.
    39  	retryBackoffInitialDuration = 100 * time.Millisecond
    40  	retryBackoffFactor          = 3
    41  	retryBackoffJitter          = 0
    42  	retryBackoffSteps           = 6
    43  )
    44  
    45  // Utility for retrying the given function with exponential backoff.
    46  func RetryWithExponentialBackOff(fn wait.ConditionFunc) error {
    47  	backoff := wait.Backoff{
    48  		Duration: retryBackoffInitialDuration,
    49  		Factor:   retryBackoffFactor,
    50  		Jitter:   retryBackoffJitter,
    51  		Steps:    retryBackoffSteps,
    52  	}
    53  	return wait.ExponentialBackoff(backoff, fn)
    54  }
    55  
    56  func CreatePodWithRetries(c clientset.Interface, namespace string, obj *v1.Pod) error {
    57  	if obj == nil {
    58  		return fmt.Errorf("object provided to create is empty")
    59  	}
    60  	createFunc := func() (bool, error) {
    61  		_, err := c.CoreV1().Pods(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
    62  		if isGenerateNameConflict(obj.ObjectMeta, err) {
    63  			return false, nil
    64  		}
    65  		if err == nil || apierrors.IsAlreadyExists(err) {
    66  			return true, nil
    67  		}
    68  		return false, fmt.Errorf("failed to create object with non-retriable error: %v ", err)
    69  	}
    70  	return RetryWithExponentialBackOff(createFunc)
    71  }
    72  
    73  func CreateRCWithRetries(c clientset.Interface, namespace string, obj *v1.ReplicationController) error {
    74  	if obj == nil {
    75  		return fmt.Errorf("object provided to create is empty")
    76  	}
    77  	createFunc := func() (bool, error) {
    78  		_, err := c.CoreV1().ReplicationControllers(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
    79  		if isGenerateNameConflict(obj.ObjectMeta, err) {
    80  			return false, nil
    81  		}
    82  		if err == nil || apierrors.IsAlreadyExists(err) {
    83  			return true, nil
    84  		}
    85  		return false, fmt.Errorf("failed to create object with non-retriable error: %v", err)
    86  	}
    87  	return RetryWithExponentialBackOff(createFunc)
    88  }
    89  
    90  func CreateReplicaSetWithRetries(c clientset.Interface, namespace string, obj *apps.ReplicaSet) error {
    91  	if obj == nil {
    92  		return fmt.Errorf("object provided to create is empty")
    93  	}
    94  	createFunc := func() (bool, error) {
    95  		_, err := c.AppsV1().ReplicaSets(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
    96  		if isGenerateNameConflict(obj.ObjectMeta, err) {
    97  			return false, nil
    98  		}
    99  		if err == nil || apierrors.IsAlreadyExists(err) {
   100  			return true, nil
   101  		}
   102  		return false, fmt.Errorf("failed to create object with non-retriable error: %v", err)
   103  	}
   104  	return RetryWithExponentialBackOff(createFunc)
   105  }
   106  
   107  func CreateDeploymentWithRetries(c clientset.Interface, namespace string, obj *apps.Deployment) error {
   108  	if obj == nil {
   109  		return fmt.Errorf("object provided to create is empty")
   110  	}
   111  	createFunc := func() (bool, error) {
   112  		_, err := c.AppsV1().Deployments(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
   113  		if isGenerateNameConflict(obj.ObjectMeta, err) {
   114  			return false, nil
   115  		}
   116  		if err == nil || apierrors.IsAlreadyExists(err) {
   117  			return true, nil
   118  		}
   119  		return false, fmt.Errorf("failed to create object with non-retriable error: %v", err)
   120  	}
   121  	return RetryWithExponentialBackOff(createFunc)
   122  }
   123  
   124  func CreateDaemonSetWithRetries(c clientset.Interface, namespace string, obj *apps.DaemonSet) error {
   125  	if obj == nil {
   126  		return fmt.Errorf("object provided to create is empty")
   127  	}
   128  	createFunc := func() (bool, error) {
   129  		_, err := c.AppsV1().DaemonSets(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
   130  		if isGenerateNameConflict(obj.ObjectMeta, err) {
   131  			return false, nil
   132  		}
   133  		if err == nil || apierrors.IsAlreadyExists(err) {
   134  			return true, nil
   135  		}
   136  		return false, fmt.Errorf("failed to create object with non-retriable error: %v", err)
   137  	}
   138  	return RetryWithExponentialBackOff(createFunc)
   139  }
   140  
   141  func CreateJobWithRetries(c clientset.Interface, namespace string, obj *batch.Job) error {
   142  	if obj == nil {
   143  		return fmt.Errorf("object provided to create is empty")
   144  	}
   145  	createFunc := func() (bool, error) {
   146  		_, err := c.BatchV1().Jobs(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
   147  		if isGenerateNameConflict(obj.ObjectMeta, err) {
   148  			return false, nil
   149  		}
   150  		if err == nil || apierrors.IsAlreadyExists(err) {
   151  			return true, nil
   152  		}
   153  		return false, fmt.Errorf("failed to create object with non-retriable error: %v", err)
   154  	}
   155  	return RetryWithExponentialBackOff(createFunc)
   156  }
   157  
   158  func CreateSecretWithRetries(c clientset.Interface, namespace string, obj *v1.Secret) error {
   159  	if obj == nil {
   160  		return fmt.Errorf("object provided to create is empty")
   161  	}
   162  	createFunc := func() (bool, error) {
   163  		_, err := c.CoreV1().Secrets(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
   164  		if isGenerateNameConflict(obj.ObjectMeta, err) {
   165  			return false, nil
   166  		}
   167  		if err == nil || apierrors.IsAlreadyExists(err) {
   168  			return true, nil
   169  		}
   170  		return false, fmt.Errorf("failed to create object with non-retriable error: %v", err)
   171  	}
   172  	return RetryWithExponentialBackOff(createFunc)
   173  }
   174  
   175  func CreateConfigMapWithRetries(c clientset.Interface, namespace string, obj *v1.ConfigMap) error {
   176  	if obj == nil {
   177  		return fmt.Errorf("object provided to create is empty")
   178  	}
   179  	createFunc := func() (bool, error) {
   180  		_, err := c.CoreV1().ConfigMaps(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
   181  		if isGenerateNameConflict(obj.ObjectMeta, err) {
   182  			return false, nil
   183  		}
   184  		if err == nil || apierrors.IsAlreadyExists(err) {
   185  			return true, nil
   186  		}
   187  		return false, fmt.Errorf("failed to create object with non-retriable error: %v", err)
   188  	}
   189  	return RetryWithExponentialBackOff(createFunc)
   190  }
   191  
   192  func CreateServiceWithRetries(c clientset.Interface, namespace string, obj *v1.Service) error {
   193  	if obj == nil {
   194  		return fmt.Errorf("object provided to create is empty")
   195  	}
   196  	createFunc := func() (bool, error) {
   197  		_, err := c.CoreV1().Services(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
   198  		if isGenerateNameConflict(obj.ObjectMeta, err) {
   199  			return false, nil
   200  		}
   201  		if err == nil || apierrors.IsAlreadyExists(err) {
   202  			return true, nil
   203  		}
   204  		return false, fmt.Errorf("failed to create object with non-retriable error: %v", err)
   205  	}
   206  	return RetryWithExponentialBackOff(createFunc)
   207  }
   208  
   209  func CreateStorageClassWithRetries(c clientset.Interface, obj *storage.StorageClass) error {
   210  	if obj == nil {
   211  		return fmt.Errorf("object provided to create is empty")
   212  	}
   213  	createFunc := func() (bool, error) {
   214  		_, err := c.StorageV1().StorageClasses().Create(context.TODO(), obj, metav1.CreateOptions{})
   215  		if isGenerateNameConflict(obj.ObjectMeta, err) {
   216  			return false, nil
   217  		}
   218  		if err == nil || apierrors.IsAlreadyExists(err) {
   219  			return true, nil
   220  		}
   221  		return false, fmt.Errorf("failed to create object with non-retriable error: %v", err)
   222  	}
   223  	return RetryWithExponentialBackOff(createFunc)
   224  }
   225  
   226  func CreateResourceQuotaWithRetries(c clientset.Interface, namespace string, obj *v1.ResourceQuota) error {
   227  	if obj == nil {
   228  		return fmt.Errorf("object provided to create is empty")
   229  	}
   230  	createFunc := func() (bool, error) {
   231  		_, err := c.CoreV1().ResourceQuotas(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
   232  		if isGenerateNameConflict(obj.ObjectMeta, err) {
   233  			return false, nil
   234  		}
   235  		if err == nil || apierrors.IsAlreadyExists(err) {
   236  			return true, nil
   237  		}
   238  		return false, fmt.Errorf("failed to create object with non-retriable error: %v", err)
   239  	}
   240  	return RetryWithExponentialBackOff(createFunc)
   241  }
   242  
   243  func CreatePersistentVolumeWithRetries(c clientset.Interface, obj *v1.PersistentVolume) error {
   244  	if obj == nil {
   245  		return fmt.Errorf("object provided to create is empty")
   246  	}
   247  	createFunc := func() (bool, error) {
   248  		_, err := c.CoreV1().PersistentVolumes().Create(context.TODO(), obj, metav1.CreateOptions{})
   249  		if isGenerateNameConflict(obj.ObjectMeta, err) {
   250  			return false, nil
   251  		}
   252  		if err == nil || apierrors.IsAlreadyExists(err) {
   253  			return true, nil
   254  		}
   255  		return false, fmt.Errorf("failed to create object with non-retriable error: %v", err)
   256  	}
   257  	return RetryWithExponentialBackOff(createFunc)
   258  }
   259  
   260  func CreatePersistentVolumeClaimWithRetries(c clientset.Interface, namespace string, obj *v1.PersistentVolumeClaim) error {
   261  	if obj == nil {
   262  		return fmt.Errorf("object provided to create is empty")
   263  	}
   264  	createFunc := func() (bool, error) {
   265  		_, err := c.CoreV1().PersistentVolumeClaims(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
   266  		if isGenerateNameConflict(obj.ObjectMeta, err) {
   267  			return false, nil
   268  		}
   269  		if err == nil || apierrors.IsAlreadyExists(err) {
   270  			return true, nil
   271  		}
   272  		return false, fmt.Errorf("failed to create object with non-retriable error: %v", err)
   273  	}
   274  	return RetryWithExponentialBackOff(createFunc)
   275  }
   276  
   277  // isGenerateNameConflict returns whether the error is generateName conflict or not.
   278  func isGenerateNameConflict(meta metav1.ObjectMeta, err error) bool {
   279  	if apierrors.IsAlreadyExists(err) && meta.Name == "" {
   280  		return true
   281  	}
   282  	return false
   283  }