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 }