github.com/y-taka-23/helm@v2.8.0+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 *extensions.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 *extensions.DaemonSet: 107 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 108 if err != nil { 109 return false, err 110 } 111 pods = append(pods, list...) 112 case *appsv1.StatefulSet: 113 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 114 if err != nil { 115 return false, err 116 } 117 pods = append(pods, list...) 118 case *appsv1beta1.StatefulSet: 119 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 120 if err != nil { 121 return false, err 122 } 123 pods = append(pods, list...) 124 case *appsv1beta2.StatefulSet: 125 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 126 if err != nil { 127 return false, err 128 } 129 pods = append(pods, list...) 130 case *extensions.ReplicaSet: 131 list, err := getPods(kcs, value.Namespace, value.Spec.Selector.MatchLabels) 132 if err != nil { 133 return false, err 134 } 135 pods = append(pods, list...) 136 case *v1.PersistentVolumeClaim: 137 claim, err := kcs.CoreV1().PersistentVolumeClaims(value.Namespace).Get(value.Name, metav1.GetOptions{}) 138 if err != nil { 139 return false, err 140 } 141 pvc = append(pvc, *claim) 142 case *v1.Service: 143 svc, err := kcs.CoreV1().Services(value.Namespace).Get(value.Name, metav1.GetOptions{}) 144 if err != nil { 145 return false, err 146 } 147 services = append(services, *svc) 148 } 149 } 150 isReady := c.podsReady(pods) && c.servicesReady(services) && c.volumesReady(pvc) && c.deploymentsReady(deployments) 151 return isReady, nil 152 }) 153 } 154 155 func (c *Client) podsReady(pods []v1.Pod) bool { 156 for _, pod := range pods { 157 if !podutil.IsPodReady(&pod) { 158 c.Log("Pod is not ready: %s/%s", pod.GetNamespace(), pod.GetName()) 159 return false 160 } 161 } 162 return true 163 } 164 165 func (c *Client) servicesReady(svc []v1.Service) bool { 166 for _, s := range svc { 167 // ExternalName Services are external to cluster so helm shouldn't be checking to see if they're 'ready' (i.e. have an IP Set) 168 if s.Spec.Type == v1.ServiceTypeExternalName { 169 continue 170 } 171 172 // Make sure the service is not explicitly set to "None" before checking the IP 173 if s.Spec.ClusterIP != v1.ClusterIPNone && !helper.IsServiceIPSet(&s) { 174 c.Log("Service is not ready: %s/%s", s.GetNamespace(), s.GetName()) 175 return false 176 } 177 // This checks if the service has a LoadBalancer and that balancer has an Ingress defined 178 if s.Spec.Type == v1.ServiceTypeLoadBalancer && s.Status.LoadBalancer.Ingress == nil { 179 c.Log("Service is not ready: %s/%s", s.GetNamespace(), s.GetName()) 180 return false 181 } 182 } 183 return true 184 } 185 186 func (c *Client) volumesReady(vols []v1.PersistentVolumeClaim) bool { 187 for _, v := range vols { 188 if v.Status.Phase != v1.ClaimBound { 189 c.Log("PersistentVolumeClaim is not ready: %s/%s", v.GetNamespace(), v.GetName()) 190 return false 191 } 192 } 193 return true 194 } 195 196 func (c *Client) deploymentsReady(deployments []deployment) bool { 197 for _, v := range deployments { 198 if !(v.replicaSets.Status.ReadyReplicas >= *v.deployment.Spec.Replicas-deploymentutil.MaxUnavailable(*v.deployment)) { 199 c.Log("Deployment is not ready: %s/%s", v.deployment.GetNamespace(), v.deployment.GetName()) 200 return false 201 } 202 } 203 return true 204 } 205 206 func getPods(client kubernetes.Interface, namespace string, selector map[string]string) ([]v1.Pod, error) { 207 list, err := client.CoreV1().Pods(namespace).List(metav1.ListOptions{ 208 FieldSelector: fields.Everything().String(), 209 LabelSelector: labels.Set(selector).AsSelector().String(), 210 }) 211 return list.Items, err 212 }