create_resources.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. Copyright 2018 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. // TODO: Refactor common part of functions in this file for generic object kinds.
  14. package utils
  15. import (
  16. "context"
  17. "fmt"
  18. "time"
  19. apps "k8s.io/api/apps/v1"
  20. batch "k8s.io/api/batch/v1"
  21. storage "k8s.io/api/storage/v1"
  22. "k8s.io/api/core/v1"
  23. apierrors "k8s.io/apimachinery/pkg/api/errors"
  24. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  25. utilnet "k8s.io/apimachinery/pkg/util/net"
  26. "k8s.io/apimachinery/pkg/util/wait"
  27. clientset "k8s.io/client-go/kubernetes"
  28. )
  29. const (
  30. // Parameters for retrying with exponential backoff.
  31. retryBackoffInitialDuration = 100 * time.Millisecond
  32. retryBackoffFactor = 3
  33. retryBackoffJitter = 0
  34. retryBackoffSteps = 6
  35. )
  36. // Utility for retrying the given function with exponential backoff.
  37. func RetryWithExponentialBackOff(fn wait.ConditionFunc) error {
  38. backoff := wait.Backoff{
  39. Duration: retryBackoffInitialDuration,
  40. Factor: retryBackoffFactor,
  41. Jitter: retryBackoffJitter,
  42. Steps: retryBackoffSteps,
  43. }
  44. return wait.ExponentialBackoff(backoff, fn)
  45. }
  46. func IsRetryableAPIError(err error) bool {
  47. // These errors may indicate a transient error that we can retry in tests.
  48. if apierrors.IsInternalError(err) || apierrors.IsTimeout(err) || apierrors.IsServerTimeout(err) ||
  49. apierrors.IsTooManyRequests(err) || utilnet.IsProbableEOF(err) || utilnet.IsConnectionReset(err) {
  50. return true
  51. }
  52. // If the error sends the Retry-After header, we respect it as an explicit confirmation we should retry.
  53. if _, shouldRetry := apierrors.SuggestsClientDelay(err); shouldRetry {
  54. return true
  55. }
  56. return false
  57. }
  58. func CreatePodWithRetries(c clientset.Interface, namespace string, obj *v1.Pod) error {
  59. if obj == nil {
  60. return fmt.Errorf("Object provided to create is empty")
  61. }
  62. createFunc := func() (bool, error) {
  63. _, err := c.CoreV1().Pods(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  64. if err == nil || apierrors.IsAlreadyExists(err) {
  65. return true, nil
  66. }
  67. if IsRetryableAPIError(err) {
  68. return false, nil
  69. }
  70. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  71. }
  72. return RetryWithExponentialBackOff(createFunc)
  73. }
  74. func CreateRCWithRetries(c clientset.Interface, namespace string, obj *v1.ReplicationController) error {
  75. if obj == nil {
  76. return fmt.Errorf("Object provided to create is empty")
  77. }
  78. createFunc := func() (bool, error) {
  79. _, err := c.CoreV1().ReplicationControllers(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  80. if err == nil || apierrors.IsAlreadyExists(err) {
  81. return true, nil
  82. }
  83. if IsRetryableAPIError(err) {
  84. return false, nil
  85. }
  86. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  87. }
  88. return RetryWithExponentialBackOff(createFunc)
  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 err == nil || apierrors.IsAlreadyExists(err) {
  97. return true, nil
  98. }
  99. if IsRetryableAPIError(err) {
  100. return false, nil
  101. }
  102. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  103. }
  104. return RetryWithExponentialBackOff(createFunc)
  105. }
  106. func CreateDeploymentWithRetries(c clientset.Interface, namespace string, obj *apps.Deployment) error {
  107. if obj == nil {
  108. return fmt.Errorf("Object provided to create is empty")
  109. }
  110. createFunc := func() (bool, error) {
  111. _, err := c.AppsV1().Deployments(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  112. if err == nil || apierrors.IsAlreadyExists(err) {
  113. return true, nil
  114. }
  115. if IsRetryableAPIError(err) {
  116. return false, nil
  117. }
  118. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  119. }
  120. return RetryWithExponentialBackOff(createFunc)
  121. }
  122. func CreateDaemonSetWithRetries(c clientset.Interface, namespace string, obj *apps.DaemonSet) error {
  123. if obj == nil {
  124. return fmt.Errorf("Object provided to create is empty")
  125. }
  126. createFunc := func() (bool, error) {
  127. _, err := c.AppsV1().DaemonSets(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  128. if err == nil || apierrors.IsAlreadyExists(err) {
  129. return true, nil
  130. }
  131. if IsRetryableAPIError(err) {
  132. return false, nil
  133. }
  134. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  135. }
  136. return RetryWithExponentialBackOff(createFunc)
  137. }
  138. func CreateJobWithRetries(c clientset.Interface, namespace string, obj *batch.Job) error {
  139. if obj == nil {
  140. return fmt.Errorf("Object provided to create is empty")
  141. }
  142. createFunc := func() (bool, error) {
  143. _, err := c.BatchV1().Jobs(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  144. if err == nil || apierrors.IsAlreadyExists(err) {
  145. return true, nil
  146. }
  147. if IsRetryableAPIError(err) {
  148. return false, nil
  149. }
  150. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  151. }
  152. return RetryWithExponentialBackOff(createFunc)
  153. }
  154. func CreateSecretWithRetries(c clientset.Interface, namespace string, obj *v1.Secret) error {
  155. if obj == nil {
  156. return fmt.Errorf("Object provided to create is empty")
  157. }
  158. createFunc := func() (bool, error) {
  159. _, err := c.CoreV1().Secrets(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  160. if err == nil || apierrors.IsAlreadyExists(err) {
  161. return true, nil
  162. }
  163. if IsRetryableAPIError(err) {
  164. return false, nil
  165. }
  166. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  167. }
  168. return RetryWithExponentialBackOff(createFunc)
  169. }
  170. func CreateConfigMapWithRetries(c clientset.Interface, namespace string, obj *v1.ConfigMap) error {
  171. if obj == nil {
  172. return fmt.Errorf("Object provided to create is empty")
  173. }
  174. createFunc := func() (bool, error) {
  175. _, err := c.CoreV1().ConfigMaps(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  176. if err == nil || apierrors.IsAlreadyExists(err) {
  177. return true, nil
  178. }
  179. if IsRetryableAPIError(err) {
  180. return false, nil
  181. }
  182. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  183. }
  184. return RetryWithExponentialBackOff(createFunc)
  185. }
  186. func CreateServiceWithRetries(c clientset.Interface, namespace string, obj *v1.Service) error {
  187. if obj == nil {
  188. return fmt.Errorf("Object provided to create is empty")
  189. }
  190. createFunc := func() (bool, error) {
  191. _, err := c.CoreV1().Services(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  192. if err == nil || apierrors.IsAlreadyExists(err) {
  193. return true, nil
  194. }
  195. if IsRetryableAPIError(err) {
  196. return false, nil
  197. }
  198. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  199. }
  200. return RetryWithExponentialBackOff(createFunc)
  201. }
  202. func CreateStorageClassWithRetries(c clientset.Interface, obj *storage.StorageClass) error {
  203. if obj == nil {
  204. return fmt.Errorf("Object provided to create is empty")
  205. }
  206. createFunc := func() (bool, error) {
  207. _, err := c.StorageV1().StorageClasses().Create(context.TODO(), obj, metav1.CreateOptions{})
  208. if err == nil || apierrors.IsAlreadyExists(err) {
  209. return true, nil
  210. }
  211. if IsRetryableAPIError(err) {
  212. return false, nil
  213. }
  214. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  215. }
  216. return RetryWithExponentialBackOff(createFunc)
  217. }
  218. func CreateResourceQuotaWithRetries(c clientset.Interface, namespace string, obj *v1.ResourceQuota) error {
  219. if obj == nil {
  220. return fmt.Errorf("Object provided to create is empty")
  221. }
  222. createFunc := func() (bool, error) {
  223. _, err := c.CoreV1().ResourceQuotas(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  224. if err == nil || apierrors.IsAlreadyExists(err) {
  225. return true, nil
  226. }
  227. if IsRetryableAPIError(err) {
  228. return false, nil
  229. }
  230. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  231. }
  232. return RetryWithExponentialBackOff(createFunc)
  233. }
  234. func CreatePersistentVolumeWithRetries(c clientset.Interface, obj *v1.PersistentVolume) error {
  235. if obj == nil {
  236. return fmt.Errorf("Object provided to create is empty")
  237. }
  238. createFunc := func() (bool, error) {
  239. _, err := c.CoreV1().PersistentVolumes().Create(context.TODO(), obj, metav1.CreateOptions{})
  240. if err == nil || apierrors.IsAlreadyExists(err) {
  241. return true, nil
  242. }
  243. if IsRetryableAPIError(err) {
  244. return false, nil
  245. }
  246. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  247. }
  248. return RetryWithExponentialBackOff(createFunc)
  249. }
  250. func CreatePersistentVolumeClaimWithRetries(c clientset.Interface, namespace string, obj *v1.PersistentVolumeClaim) error {
  251. if obj == nil {
  252. return fmt.Errorf("Object provided to create is empty")
  253. }
  254. createFunc := func() (bool, error) {
  255. _, err := c.CoreV1().PersistentVolumeClaims(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  256. if err == nil || apierrors.IsAlreadyExists(err) {
  257. return true, nil
  258. }
  259. if IsRetryableAPIError(err) {
  260. return false, nil
  261. }
  262. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  263. }
  264. return RetryWithExponentialBackOff(createFunc)
  265. }