github.com/flant/helm@v2.8.1+incompatible/pkg/kube/wait.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors All rights reserved. 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/runtime" 31 "k8s.io/apimachinery/pkg/util/wait" 32 "k8s.io/client-go/kubernetes" 33 podutil "k8s.io/kubernetes/pkg/api/v1/pod" 34 "k8s.io/kubernetes/pkg/apis/core/v1/helper" 35 deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" 36 ) 37 38 // deployment holds associated replicaSets for a deployment 39 type deployment struct { 40 replicaSets *extensions.ReplicaSet 41 deployment *extensions.Deployment 42 } 43 44 // waitForResources polls to get the current status of all pods, PVCs, and Services 45 // until all are ready or a timeout is reached 46 func (c *Client) waitForResources(timeout time.Duration, created Result) error { 47 c.Log("beginning wait for %d resources with timeout of %v", len(created), timeout) 48 49 kcs, err := c.KubernetesClientSet() 50 if err != nil { 51 return err 52 } 53 return wait.Poll(2*time.Second, timeout, func() (bool, error) { 54 pods := []v1.Pod{} 55 services := []v1.Service{} 56 pvc := []v1.PersistentVolumeClaim{} 57 deployments := []deployment{} 58 for _, v := range created { 59 obj, err := c.AsVersionedObject(v.Object) 60 if err != nil && !runtime.IsNotRegisteredError(err) { 61 return false, err 62 } 63 switch value := obj.(type) { 64 case *v1.ReplicationController: 65 list, err := getPods(kcs, value.Namespace, value.Spec.Selector) 66 if err != nil { 67 return false, err 68 } 69 pods = append(pods, list...) 70 case *v1.Pod: 71 pod, err := kcs.CoreV1().Pods(value.Namespace).Get(value.Name, metav1.GetOptions{}) 72 if err != nil { 73 return false, err 74 } 75 pods = append(pods, *pod) 76 case *appsv1.Deployment: 77 currentDeployment, err := kcs.ExtensionsV1beta1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) 78 if err != nil { 79 return false, err 80 } 81 // Find RS associated with deployment 82 newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.ExtensionsV1beta1()) 83 if err != nil || newReplicaSet == nil { 84 return false, err 85 } 86 newDeployment := deployment{ 87 newReplicaSet, 88 currentDeployment, 89 } 90 deployments = append(deployments, newDeployment) 91 case *appsv1beta1.Deployment: 92 currentDeployment, err := kcs.ExtensionsV1beta1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) 93 if err != nil { 94 return false, err 95 } 96 // Find RS associated with deployment 97 newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.ExtensionsV1beta1()) 98 if err != nil || newReplicaSet == nil { 99 return false, err 100 } 101 newDeployment := deployment{ 102 newReplicaSet, 103 currentDeployment, 104 } 105 deployments = append(deployments, newDeployment) 106 case *appsv1beta2.Deployment: 107 currentDeployment, err := kcs.ExtensionsV1beta1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) 108 if err != nil { 109 return false, err 110 } 111 // Find RS associated with deployment 112 newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.ExtensionsV1beta1()) 113 if err != nil || newReplicaSet == nil { 114 return false, err 115 } 116 newDeployment := deployment{ 117 newReplicaSet, 118 currentDeployment, 119 } 120 deployments = append(deployments, newDeployment) 121 case *extensions.Deployment: 122 currentDeployment, err := kcs.ExtensionsV1beta1().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) 123 if err != nil { 124 return false, err 125 } 126 // Find RS associated with deployment 127 newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.ExtensionsV1beta1()) 128 if err != nil || newReplicaSet == nil { 129 return false, err 130 } 131 newDeployment := deployment{ 132 newReplicaSet, 133 currentDeployment, 134 } 135 deployments = append(deployments, newDeployment) 136 case *extensions.DaemonSet: 137 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 138 if err != nil { 139 return false, err 140 } 141 pods = append(pods, list...) 142 case *appsv1.DaemonSet: 143 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 144 if err != nil { 145 return false, err 146 } 147 pods = append(pods, list...) 148 case *appsv1beta2.DaemonSet: 149 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 150 if err != nil { 151 return false, err 152 } 153 pods = append(pods, list...) 154 case *appsv1.StatefulSet: 155 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 156 if err != nil { 157 return false, err 158 } 159 pods = append(pods, list...) 160 case *appsv1beta1.StatefulSet: 161 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 162 if err != nil { 163 return false, err 164 } 165 pods = append(pods, list...) 166 case *appsv1beta2.StatefulSet: 167 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 168 if err != nil { 169 return false, err 170 } 171 pods = append(pods, list...) 172 case *extensions.ReplicaSet: 173 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 174 if err != nil { 175 return false, err 176 } 177 pods = append(pods, list...) 178 case *appsv1beta2.ReplicaSet: 179 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 180 if err != nil { 181 return false, err 182 } 183 pods = append(pods, list...) 184 case *appsv1.ReplicaSet: 185 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 186 if err != nil { 187 return false, err 188 } 189 pods = append(pods, list...) 190 case *v1.PersistentVolumeClaim: 191 claim, err := kcs.CoreV1().PersistentVolumeClaims(value.Namespace).Get(value.Name, metav1.GetOptions{}) 192 if err != nil { 193 return false, err 194 } 195 pvc = append(pvc, *claim) 196 case *v1.Service: 197 svc, err := kcs.CoreV1().Services(value.Namespace).Get(value.Name, metav1.GetOptions{}) 198 if err != nil { 199 return false, err 200 } 201 services = append(services, *svc) 202 } 203 } 204 isReady := c.podsReady(pods) && c.servicesReady(services) && c.volumesReady(pvc) && c.deploymentsReady(deployments) 205 return isReady, nil 206 }) 207 } 208 209 func (c *Client) podsReady(pods []v1.Pod) bool { 210 for _, pod := range pods { 211 if !podutil.IsPodReady(&pod) { 212 c.Log("Pod is not ready: %s/%s", pod.GetNamespace(), pod.GetName()) 213 return false 214 } 215 } 216 return true 217 } 218 219 func (c *Client) servicesReady(svc []v1.Service) bool { 220 for _, s := range svc { 221 // ExternalName Services are external to cluster so helm shouldn't be checking to see if they're 'ready' (i.e. have an IP Set) 222 if s.Spec.Type == v1.ServiceTypeExternalName { 223 continue 224 } 225 226 // Make sure the service is not explicitly set to "None" before checking the IP 227 if s.Spec.ClusterIP != v1.ClusterIPNone && !helper.IsServiceIPSet(&s) { 228 c.Log("Service is not ready: %s/%s", s.GetNamespace(), s.GetName()) 229 return false 230 } 231 // This checks if the service has a LoadBalancer and that balancer has an Ingress defined 232 if s.Spec.Type == v1.ServiceTypeLoadBalancer && s.Status.LoadBalancer.Ingress == nil { 233 c.Log("Service is not ready: %s/%s", s.GetNamespace(), s.GetName()) 234 return false 235 } 236 } 237 return true 238 } 239 240 func (c *Client) volumesReady(vols []v1.PersistentVolumeClaim) bool { 241 for _, v := range vols { 242 if v.Status.Phase != v1.ClaimBound { 243 c.Log("PersistentVolumeClaim is not ready: %s/%s", v.GetNamespace(), v.GetName()) 244 return false 245 } 246 } 247 return true 248 } 249 250 func (c *Client) deploymentsReady(deployments []deployment) bool { 251 for _, v := range deployments { 252 if !(v.replicaSets.Status.ReadyReplicas >= *v.deployment.Spec.Replicas-deploymentutil.MaxUnavailable(*v.deployment)) { 253 c.Log("Deployment is not ready: %s/%s", v.deployment.GetNamespace(), v.deployment.GetName()) 254 return false 255 } 256 } 257 return true 258 } 259 260 func getPods(client kubernetes.Interface, namespace string, selector map[string]string) ([]v1.Pod, error) { 261 list, err := client.CoreV1().Pods(namespace).List(metav1.ListOptions{ 262 FieldSelector: fields.Everything().String(), 263 LabelSelector: labels.Set(selector).AsSelector().String(), 264 }) 265 return list.Items, err 266 }