create_resources.go 7.3 KB

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