create_resources.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. "k8s.io/api/core/v1"
  22. apierrors "k8s.io/apimachinery/pkg/api/errors"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. utilnet "k8s.io/apimachinery/pkg/util/net"
  25. "k8s.io/apimachinery/pkg/util/wait"
  26. clientset "k8s.io/client-go/kubernetes"
  27. )
  28. const (
  29. // Parameters for retrying with exponential backoff.
  30. retryBackoffInitialDuration = 100 * time.Millisecond
  31. retryBackoffFactor = 3
  32. retryBackoffJitter = 0
  33. retryBackoffSteps = 6
  34. )
  35. // Utility for retrying the given function with exponential backoff.
  36. func RetryWithExponentialBackOff(fn wait.ConditionFunc) error {
  37. backoff := wait.Backoff{
  38. Duration: retryBackoffInitialDuration,
  39. Factor: retryBackoffFactor,
  40. Jitter: retryBackoffJitter,
  41. Steps: retryBackoffSteps,
  42. }
  43. return wait.ExponentialBackoff(backoff, fn)
  44. }
  45. func IsRetryableAPIError(err error) bool {
  46. // These errors may indicate a transient error that we can retry in tests.
  47. if apierrors.IsInternalError(err) || apierrors.IsTimeout(err) || apierrors.IsServerTimeout(err) ||
  48. apierrors.IsTooManyRequests(err) || utilnet.IsProbableEOF(err) || utilnet.IsConnectionReset(err) {
  49. return true
  50. }
  51. // If the error sends the Retry-After header, we respect it as an explicit confirmation we should retry.
  52. if _, shouldRetry := apierrors.SuggestsClientDelay(err); shouldRetry {
  53. return true
  54. }
  55. return false
  56. }
  57. func CreatePodWithRetries(c clientset.Interface, namespace string, obj *v1.Pod) error {
  58. if obj == nil {
  59. return fmt.Errorf("Object provided to create is empty")
  60. }
  61. createFunc := func() (bool, error) {
  62. _, err := c.CoreV1().Pods(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  63. if err == nil || apierrors.IsAlreadyExists(err) {
  64. return true, nil
  65. }
  66. if IsRetryableAPIError(err) {
  67. return false, nil
  68. }
  69. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  70. }
  71. return RetryWithExponentialBackOff(createFunc)
  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 err == nil || apierrors.IsAlreadyExists(err) {
  80. return true, nil
  81. }
  82. if IsRetryableAPIError(err) {
  83. return false, nil
  84. }
  85. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  86. }
  87. return RetryWithExponentialBackOff(createFunc)
  88. }
  89. func CreateReplicaSetWithRetries(c clientset.Interface, namespace string, obj *apps.ReplicaSet) error {
  90. if obj == nil {
  91. return fmt.Errorf("Object provided to create is empty")
  92. }
  93. createFunc := func() (bool, error) {
  94. _, err := c.AppsV1().ReplicaSets(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  95. if err == nil || apierrors.IsAlreadyExists(err) {
  96. return true, nil
  97. }
  98. if IsRetryableAPIError(err) {
  99. return false, nil
  100. }
  101. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  102. }
  103. return RetryWithExponentialBackOff(createFunc)
  104. }
  105. func CreateDeploymentWithRetries(c clientset.Interface, namespace string, obj *apps.Deployment) error {
  106. if obj == nil {
  107. return fmt.Errorf("Object provided to create is empty")
  108. }
  109. createFunc := func() (bool, error) {
  110. _, err := c.AppsV1().Deployments(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  111. if err == nil || apierrors.IsAlreadyExists(err) {
  112. return true, nil
  113. }
  114. if IsRetryableAPIError(err) {
  115. return false, nil
  116. }
  117. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  118. }
  119. return RetryWithExponentialBackOff(createFunc)
  120. }
  121. func CreateDaemonSetWithRetries(c clientset.Interface, namespace string, obj *apps.DaemonSet) error {
  122. if obj == nil {
  123. return fmt.Errorf("Object provided to create is empty")
  124. }
  125. createFunc := func() (bool, error) {
  126. _, err := c.AppsV1().DaemonSets(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  127. if err == nil || apierrors.IsAlreadyExists(err) {
  128. return true, nil
  129. }
  130. if IsRetryableAPIError(err) {
  131. return false, nil
  132. }
  133. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  134. }
  135. return RetryWithExponentialBackOff(createFunc)
  136. }
  137. func CreateJobWithRetries(c clientset.Interface, namespace string, obj *batch.Job) error {
  138. if obj == nil {
  139. return fmt.Errorf("Object provided to create is empty")
  140. }
  141. createFunc := func() (bool, error) {
  142. _, err := c.BatchV1().Jobs(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  143. if err == nil || apierrors.IsAlreadyExists(err) {
  144. return true, nil
  145. }
  146. if IsRetryableAPIError(err) {
  147. return false, nil
  148. }
  149. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  150. }
  151. return RetryWithExponentialBackOff(createFunc)
  152. }
  153. func CreateSecretWithRetries(c clientset.Interface, namespace string, obj *v1.Secret) error {
  154. if obj == nil {
  155. return fmt.Errorf("Object provided to create is empty")
  156. }
  157. createFunc := func() (bool, error) {
  158. _, err := c.CoreV1().Secrets(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  159. if err == nil || apierrors.IsAlreadyExists(err) {
  160. return true, nil
  161. }
  162. if IsRetryableAPIError(err) {
  163. return false, nil
  164. }
  165. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  166. }
  167. return RetryWithExponentialBackOff(createFunc)
  168. }
  169. func CreateConfigMapWithRetries(c clientset.Interface, namespace string, obj *v1.ConfigMap) error {
  170. if obj == nil {
  171. return fmt.Errorf("Object provided to create is empty")
  172. }
  173. createFunc := func() (bool, error) {
  174. _, err := c.CoreV1().ConfigMaps(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  175. if err == nil || apierrors.IsAlreadyExists(err) {
  176. return true, nil
  177. }
  178. if IsRetryableAPIError(err) {
  179. return false, nil
  180. }
  181. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  182. }
  183. return RetryWithExponentialBackOff(createFunc)
  184. }
  185. func CreateServiceWithRetries(c clientset.Interface, namespace string, obj *v1.Service) error {
  186. if obj == nil {
  187. return fmt.Errorf("Object provided to create is empty")
  188. }
  189. createFunc := func() (bool, error) {
  190. _, err := c.CoreV1().Services(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  191. if err == nil || apierrors.IsAlreadyExists(err) {
  192. return true, nil
  193. }
  194. if IsRetryableAPIError(err) {
  195. return false, nil
  196. }
  197. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  198. }
  199. return RetryWithExponentialBackOff(createFunc)
  200. }
  201. func CreateResourceQuotaWithRetries(c clientset.Interface, namespace string, obj *v1.ResourceQuota) error {
  202. if obj == nil {
  203. return fmt.Errorf("Object provided to create is empty")
  204. }
  205. createFunc := func() (bool, error) {
  206. _, err := c.CoreV1().ResourceQuotas(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  207. if err == nil || apierrors.IsAlreadyExists(err) {
  208. return true, nil
  209. }
  210. if IsRetryableAPIError(err) {
  211. return false, nil
  212. }
  213. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  214. }
  215. return RetryWithExponentialBackOff(createFunc)
  216. }
  217. func CreatePersistentVolumeWithRetries(c clientset.Interface, obj *v1.PersistentVolume) error {
  218. if obj == nil {
  219. return fmt.Errorf("Object provided to create is empty")
  220. }
  221. createFunc := func() (bool, error) {
  222. _, err := c.CoreV1().PersistentVolumes().Create(context.TODO(), obj, metav1.CreateOptions{})
  223. if err == nil || apierrors.IsAlreadyExists(err) {
  224. return true, nil
  225. }
  226. if IsRetryableAPIError(err) {
  227. return false, nil
  228. }
  229. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  230. }
  231. return RetryWithExponentialBackOff(createFunc)
  232. }
  233. func CreatePersistentVolumeClaimWithRetries(c clientset.Interface, namespace string, obj *v1.PersistentVolumeClaim) error {
  234. if obj == nil {
  235. return fmt.Errorf("Object provided to create is empty")
  236. }
  237. createFunc := func() (bool, error) {
  238. _, err := c.CoreV1().PersistentVolumeClaims(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
  239. if err == nil || apierrors.IsAlreadyExists(err) {
  240. return true, nil
  241. }
  242. if IsRetryableAPIError(err) {
  243. return false, nil
  244. }
  245. return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
  246. }
  247. return RetryWithExponentialBackOff(createFunc)
  248. }