1
16
17 package kube
18
19 import (
20 "context"
21 "fmt"
22 "net/http"
23 "time"
24
25 "github.com/pkg/errors"
26 appsv1 "k8s.io/api/apps/v1"
27 appsv1beta1 "k8s.io/api/apps/v1beta1"
28 appsv1beta2 "k8s.io/api/apps/v1beta2"
29 batchv1 "k8s.io/api/batch/v1"
30 corev1 "k8s.io/api/core/v1"
31 extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
32 apierrors "k8s.io/apimachinery/pkg/api/errors"
33 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34 "k8s.io/apimachinery/pkg/labels"
35 "k8s.io/apimachinery/pkg/runtime"
36 "k8s.io/cli-runtime/pkg/resource"
37
38 "k8s.io/apimachinery/pkg/util/wait"
39 )
40
41 type waiter struct {
42 c ReadyChecker
43 timeout time.Duration
44 log func(string, ...interface{})
45 }
46
47
48
49 func (w *waiter) waitForResources(created ResourceList) error {
50 w.log("beginning wait for %d resources with timeout of %v", len(created), w.timeout)
51
52 ctx, cancel := context.WithTimeout(context.Background(), w.timeout)
53 defer cancel()
54
55 numberOfErrors := make([]int, len(created))
56 for i := range numberOfErrors {
57 numberOfErrors[i] = 0
58 }
59
60 return wait.PollUntilContextCancel(ctx, 2*time.Second, true, func(ctx context.Context) (bool, error) {
61 waitRetries := 30
62 for i, v := range created {
63 ready, err := w.c.IsReady(ctx, v)
64
65 if waitRetries > 0 && w.isRetryableError(err, v) {
66 numberOfErrors[i]++
67 if numberOfErrors[i] > waitRetries {
68 w.log("Max number of retries reached")
69 return false, err
70 }
71 w.log("Retrying as current number of retries %d less than max number of retries %d", numberOfErrors[i]-1, waitRetries)
72 return false, nil
73 }
74 numberOfErrors[i] = 0
75 if !ready {
76 return false, err
77 }
78 }
79 return true, nil
80 })
81 }
82
83 func (w *waiter) isRetryableError(err error, resource *resource.Info) bool {
84 if err == nil {
85 return false
86 }
87 w.log("Error received when checking status of resource %s. Error: '%s', Resource details: '%s'", resource.Name, err, resource)
88 if ev, ok := err.(*apierrors.StatusError); ok {
89 statusCode := ev.Status().Code
90 retryable := w.isRetryableHTTPStatusCode(statusCode)
91 w.log("Status code received: %d. Retryable error? %t", statusCode, retryable)
92 return retryable
93 }
94 w.log("Retryable error? %t", true)
95 return true
96 }
97
98 func (w *waiter) isRetryableHTTPStatusCode(httpStatusCode int32) bool {
99 return httpStatusCode == 0 || httpStatusCode == http.StatusTooManyRequests || (httpStatusCode >= 500 && httpStatusCode != http.StatusNotImplemented)
100 }
101
102
103 func (w *waiter) waitForDeletedResources(deleted ResourceList) error {
104 w.log("beginning wait for %d resources to be deleted with timeout of %v", len(deleted), w.timeout)
105
106 ctx, cancel := context.WithTimeout(context.Background(), w.timeout)
107 defer cancel()
108
109 return wait.PollUntilContextCancel(ctx, 2*time.Second, true, func(_ context.Context) (bool, error) {
110 for _, v := range deleted {
111 err := v.Get()
112 if err == nil || !apierrors.IsNotFound(err) {
113 return false, err
114 }
115 }
116 return true, nil
117 })
118 }
119
120
121
122
123 func SelectorsForObject(object runtime.Object) (selector labels.Selector, err error) {
124 switch t := object.(type) {
125 case *extensionsv1beta1.ReplicaSet:
126 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
127 case *appsv1.ReplicaSet:
128 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
129 case *appsv1beta2.ReplicaSet:
130 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
131 case *corev1.ReplicationController:
132 selector = labels.SelectorFromSet(t.Spec.Selector)
133 case *appsv1.StatefulSet:
134 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
135 case *appsv1beta1.StatefulSet:
136 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
137 case *appsv1beta2.StatefulSet:
138 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
139 case *extensionsv1beta1.DaemonSet:
140 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
141 case *appsv1.DaemonSet:
142 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
143 case *appsv1beta2.DaemonSet:
144 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
145 case *extensionsv1beta1.Deployment:
146 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
147 case *appsv1.Deployment:
148 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
149 case *appsv1beta1.Deployment:
150 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
151 case *appsv1beta2.Deployment:
152 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
153 case *batchv1.Job:
154 selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
155 case *corev1.Service:
156 if t.Spec.Selector == nil || len(t.Spec.Selector) == 0 {
157 return nil, fmt.Errorf("invalid service '%s': Service is defined without a selector", t.Name)
158 }
159 selector = labels.SelectorFromSet(t.Spec.Selector)
160
161 default:
162 return nil, fmt.Errorf("selector for %T not implemented", object)
163 }
164
165 return selector, errors.Wrap(err, "invalid label selector")
166 }
167
View as plain text