github.com/darkowlzz/helm@v2.5.1-0.20171213183701-6707fe0468d4+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 appsv1beta1 "k8s.io/api/apps/v1beta1" 23 appsv1beta2 "k8s.io/api/apps/v1beta2" 24 "k8s.io/api/core/v1" 25 extensions "k8s.io/api/extensions/v1beta1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/fields" 28 "k8s.io/apimachinery/pkg/labels" 29 "k8s.io/apimachinery/pkg/runtime" 30 "k8s.io/apimachinery/pkg/util/wait" 31 "k8s.io/client-go/kubernetes" 32 "k8s.io/kubernetes/pkg/api/v1/helper" 33 podutil "k8s.io/kubernetes/pkg/api/v1/pod" 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 *extensions.ReplicaSet 40 deployment *extensions.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 obj, err := c.AsVersionedObject(v.Object) 59 if err != nil && !runtime.IsNotRegisteredError(err) { 60 return false, err 61 } 62 switch value := obj.(type) { 63 case *v1.ReplicationController: 64 list, err := getPods(kcs, value.Namespace, value.Spec.Selector) 65 if err != nil { 66 return false, err 67 } 68 pods = append(pods, list...) 69 case *v1.Pod: 70 pod, err := kcs.Core().Pods(value.Namespace).Get(value.Name, metav1.GetOptions{}) 71 if err != nil { 72 return false, err 73 } 74 pods = append(pods, *pod) 75 case *extensions.Deployment: 76 currentDeployment, err := kcs.Extensions().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) 77 if err != nil { 78 return false, err 79 } 80 // Find RS associated with deployment 81 newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.ExtensionsV1beta1()) 82 if err != nil || newReplicaSet == nil { 83 return false, err 84 } 85 newDeployment := deployment{ 86 newReplicaSet, 87 currentDeployment, 88 } 89 deployments = append(deployments, newDeployment) 90 case *extensions.DaemonSet: 91 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 92 if err != nil { 93 return false, err 94 } 95 pods = append(pods, list...) 96 case *appsv1beta1.StatefulSet: 97 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 98 if err != nil { 99 return false, err 100 } 101 pods = append(pods, list...) 102 case *appsv1beta2.StatefulSet: 103 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 104 if err != nil { 105 return false, err 106 } 107 pods = append(pods, list...) 108 case *extensions.ReplicaSet: 109 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 110 if err != nil { 111 return false, err 112 } 113 pods = append(pods, list...) 114 case *v1.PersistentVolumeClaim: 115 claim, err := kcs.Core().PersistentVolumeClaims(value.Namespace).Get(value.Name, metav1.GetOptions{}) 116 if err != nil { 117 return false, err 118 } 119 pvc = append(pvc, *claim) 120 case *v1.Service: 121 svc, err := kcs.Core().Services(value.Namespace).Get(value.Name, metav1.GetOptions{}) 122 if err != nil { 123 return false, err 124 } 125 services = append(services, *svc) 126 } 127 } 128 isReady := c.podsReady(pods) && c.servicesReady(services) && c.volumesReady(pvc) && c.deploymentsReady(deployments) 129 return isReady, nil 130 }) 131 } 132 133 func (c *Client) podsReady(pods []v1.Pod) bool { 134 for _, pod := range pods { 135 if !podutil.IsPodReady(&pod) { 136 c.Log("Pod is not ready: %s/%s", pod.GetNamespace(), pod.GetName()) 137 return false 138 } 139 } 140 return true 141 } 142 143 func (c *Client) servicesReady(svc []v1.Service) bool { 144 for _, s := range svc { 145 // ExternalName Services are external to cluster so helm shouldn't be checking to see if they're 'ready' (i.e. have an IP Set) 146 if s.Spec.Type == v1.ServiceTypeExternalName { 147 continue 148 } 149 150 // Make sure the service is not explicitly set to "None" before checking the IP 151 if s.Spec.ClusterIP != v1.ClusterIPNone && !helper.IsServiceIPSet(&s) { 152 c.Log("Service is not ready: %s/%s", s.GetNamespace(), s.GetName()) 153 return false 154 } 155 // This checks if the service has a LoadBalancer and that balancer has an Ingress defined 156 if s.Spec.Type == v1.ServiceTypeLoadBalancer && s.Status.LoadBalancer.Ingress == nil { 157 c.Log("Service is not ready: %s/%s", s.GetNamespace(), s.GetName()) 158 return false 159 } 160 } 161 return true 162 } 163 164 func (c *Client) volumesReady(vols []v1.PersistentVolumeClaim) bool { 165 for _, v := range vols { 166 if v.Status.Phase != v1.ClaimBound { 167 c.Log("PersistentVolumeClaim is not ready: %s/%s", v.GetNamespace(), v.GetName()) 168 return false 169 } 170 } 171 return true 172 } 173 174 func (c *Client) deploymentsReady(deployments []deployment) bool { 175 for _, v := range deployments { 176 if !(v.replicaSets.Status.ReadyReplicas >= *v.deployment.Spec.Replicas-deploymentutil.MaxUnavailable(*v.deployment)) { 177 c.Log("Deployment is not ready: %s/%s", v.deployment.GetNamespace(), v.deployment.GetName()) 178 return false 179 } 180 } 181 return true 182 } 183 184 func getPods(client kubernetes.Interface, namespace string, selector map[string]string) ([]v1.Pod, error) { 185 list, err := client.Core().Pods(namespace).List(metav1.ListOptions{ 186 FieldSelector: fields.Everything().String(), 187 LabelSelector: labels.Set(selector).AsSelector().String(), 188 }) 189 return list.Items, err 190 }