github.com/Beeketing/helm@v2.12.1+incompatible/pkg/kube/wait.go (about) 1 /* 2 Copyright The Helm Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package kube // import "k8s.io/helm/pkg/kube" 18 19 import ( 20 "time" 21 22 appsv1 "k8s.io/api/apps/v1" 23 appsv1beta1 "k8s.io/api/apps/v1beta1" 24 appsv1beta2 "k8s.io/api/apps/v1beta2" 25 "k8s.io/api/core/v1" 26 extensions "k8s.io/api/extensions/v1beta1" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/fields" 29 "k8s.io/apimachinery/pkg/labels" 30 "k8s.io/apimachinery/pkg/util/wait" 31 "k8s.io/client-go/kubernetes" 32 podutil "k8s.io/kubernetes/pkg/api/v1/pod" 33 "k8s.io/kubernetes/pkg/apis/core/v1/helper" 34 deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" 35 ) 36 37 // deployment holds associated replicaSets for a deployment 38 type deployment struct { 39 replicaSets *appsv1.ReplicaSet 40 deployment *appsv1.Deployment 41 } 42 43 // waitForResources polls to get the current status of all pods, PVCs, and Services 44 // until all are ready or a timeout is reached 45 func (c *Client) waitForResources(timeout time.Duration, created Result) error { 46 c.Log("beginning wait for %d resources with timeout of %v", len(created), timeout) 47 48 kcs, err := c.KubernetesClientSet() 49 if err != nil { 50 return err 51 } 52 return wait.Poll(2*time.Second, timeout, func() (bool, error) { 53 pods := []v1.Pod{} 54 services := []v1.Service{} 55 pvc := []v1.PersistentVolumeClaim{} 56 deployments := []deployment{} 57 for _, v := range created { 58 switch value := asVersioned(v).(type) { 59 case *v1.ReplicationController: 60 list, err := getPods(kcs, value.Namespace, value.Spec.Selector) 61 if err != nil { 62 return false, err 63 } 64 pods = append(pods, list...) 65 case *v1.Pod: 66 pod, err := kcs.CoreV1().Pods(value.Namespace).Get(value.Name, metav1.GetOptions{}) 67 if err != nil { 68 return false, err 69 } 70 pods = append(pods, *pod) 71 case *appsv1.Deployment: 72 currentDeployment, err := kcs.AppsV1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) 73 if err != nil { 74 return false, err 75 } 76 // Find RS associated with deployment 77 newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.AppsV1()) 78 if err != nil || newReplicaSet == nil { 79 return false, err 80 } 81 newDeployment := deployment{ 82 newReplicaSet, 83 currentDeployment, 84 } 85 deployments = append(deployments, newDeployment) 86 case *appsv1beta1.Deployment: 87 currentDeployment, err := kcs.AppsV1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) 88 if err != nil { 89 return false, err 90 } 91 // Find RS associated with deployment 92 newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.AppsV1()) 93 if err != nil || newReplicaSet == nil { 94 return false, err 95 } 96 newDeployment := deployment{ 97 newReplicaSet, 98 currentDeployment, 99 } 100 deployments = append(deployments, newDeployment) 101 case *appsv1beta2.Deployment: 102 currentDeployment, err := kcs.AppsV1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) 103 if err != nil { 104 return false, err 105 } 106 // Find RS associated with deployment 107 newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.AppsV1()) 108 if err != nil || newReplicaSet == nil { 109 return false, err 110 } 111 newDeployment := deployment{ 112 newReplicaSet, 113 currentDeployment, 114 } 115 deployments = append(deployments, newDeployment) 116 case *extensions.Deployment: 117 currentDeployment, err := kcs.AppsV1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) 118 if err != nil { 119 return false, err 120 } 121 // Find RS associated with deployment 122 newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.AppsV1()) 123 if err != nil || newReplicaSet == nil { 124 return false, err 125 } 126 newDeployment := deployment{ 127 newReplicaSet, 128 currentDeployment, 129 } 130 deployments = append(deployments, newDeployment) 131 case *extensions.DaemonSet: 132 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 133 if err != nil { 134 return false, err 135 } 136 pods = append(pods, list...) 137 case *appsv1.DaemonSet: 138 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 139 if err != nil { 140 return false, err 141 } 142 pods = append(pods, list...) 143 case *appsv1beta2.DaemonSet: 144 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 145 if err != nil { 146 return false, err 147 } 148 pods = append(pods, list...) 149 case *appsv1.StatefulSet: 150 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 151 if err != nil { 152 return false, err 153 } 154 pods = append(pods, list...) 155 case *appsv1beta1.StatefulSet: 156 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 157 if err != nil { 158 return false, err 159 } 160 pods = append(pods, list...) 161 case *appsv1beta2.StatefulSet: 162 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 163 if err != nil { 164 return false, err 165 } 166 pods = append(pods, list...) 167 case *extensions.ReplicaSet: 168 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 169 if err != nil { 170 return false, err 171 } 172 pods = append(pods, list...) 173 case *appsv1beta2.ReplicaSet: 174 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 175 if err != nil { 176 return false, err 177 } 178 pods = append(pods, list...) 179 case *appsv1.ReplicaSet: 180 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 181 if err != nil { 182 return false, err 183 } 184 pods = append(pods, list...) 185 case *v1.PersistentVolumeClaim: 186 claim, err := kcs.CoreV1().PersistentVolumeClaims(value.Namespace).Get(value.Name, metav1.GetOptions{}) 187 if err != nil { 188 return false, err 189 } 190 pvc = append(pvc, *claim) 191 case *v1.Service: 192 svc, err := kcs.CoreV1().Services(value.Namespace).Get(value.Name, metav1.GetOptions{}) 193 if err != nil { 194 return false, err 195 } 196 services = append(services, *svc) 197 } 198 } 199 isReady := c.podsReady(pods) && c.servicesReady(services) && c.volumesReady(pvc) && c.deploymentsReady(deployments) 200 return isReady, nil 201 }) 202 } 203 204 func (c *Client) podsReady(pods []v1.Pod) bool { 205 for _, pod := range pods { 206 if !podutil.IsPodReady(&pod) { 207 c.Log("Pod is not ready: %s/%s", pod.GetNamespace(), pod.GetName()) 208 return false 209 } 210 } 211 return true 212 } 213 214 func (c *Client) servicesReady(svc []v1.Service) bool { 215 for _, s := range svc { 216 // ExternalName Services are external to cluster so helm shouldn't be checking to see if they're 'ready' (i.e. have an IP Set) 217 if s.Spec.Type == v1.ServiceTypeExternalName { 218 continue 219 } 220 221 // Make sure the service is not explicitly set to "None" before checking the IP 222 if s.Spec.ClusterIP != v1.ClusterIPNone && !helper.IsServiceIPSet(&s) { 223 c.Log("Service is not ready: %s/%s", s.GetNamespace(), s.GetName()) 224 return false 225 } 226 // This checks if the service has a LoadBalancer and that balancer has an Ingress defined 227 if s.Spec.Type == v1.ServiceTypeLoadBalancer && s.Status.LoadBalancer.Ingress == nil { 228 c.Log("Service is not ready: %s/%s", s.GetNamespace(), s.GetName()) 229 return false 230 } 231 } 232 return true 233 } 234 235 func (c *Client) volumesReady(vols []v1.PersistentVolumeClaim) bool { 236 for _, v := range vols { 237 if v.Status.Phase != v1.ClaimBound { 238 c.Log("PersistentVolumeClaim is not ready: %s/%s", v.GetNamespace(), v.GetName()) 239 return false 240 } 241 } 242 return true 243 } 244 245 func (c *Client) deploymentsReady(deployments []deployment) bool { 246 for _, v := range deployments { 247 if !(v.replicaSets.Status.ReadyReplicas >= *v.deployment.Spec.Replicas-deploymentutil.MaxUnavailable(*v.deployment)) { 248 c.Log("Deployment is not ready: %s/%s", v.deployment.GetNamespace(), v.deployment.GetName()) 249 return false 250 } 251 } 252 return true 253 } 254 255 func getPods(client kubernetes.Interface, namespace string, selector map[string]string) ([]v1.Pod, error) { 256 list, err := client.CoreV1().Pods(namespace).List(metav1.ListOptions{ 257 FieldSelector: fields.Everything().String(), 258 LabelSelector: labels.Set(selector).AsSelector().String(), 259 }) 260 return list.Items, err 261 }