1
16
17
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
39 retryBackoffInitialDuration = 100 * time.Millisecond
40 retryBackoffFactor = 3
41 retryBackoffJitter = 0
42 retryBackoffSteps = 6
43 )
44
45
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
278 func isGenerateNameConflict(meta metav1.ObjectMeta, err error) bool {
279 if apierrors.IsAlreadyExists(err) && meta.Name == "" {
280 return true
281 }
282 return false
283 }
284
View as plain text