github.com/caicloud/helm@v2.5.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 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 "k8s.io/apimachinery/pkg/fields" 24 "k8s.io/apimachinery/pkg/labels" 25 "k8s.io/apimachinery/pkg/runtime" 26 "k8s.io/apimachinery/pkg/util/wait" 27 "k8s.io/kubernetes/pkg/api/v1" 28 apps "k8s.io/kubernetes/pkg/apis/apps/v1beta1" 29 extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" 30 "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" 31 core "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1" 32 extensionsclient "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/extensions/v1beta1" 33 internalclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" 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 cs, err := c.ClientSet() 49 if err != nil { 50 return err 51 } 52 client := versionedClientsetForDeployment(cs) 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(client, 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 := client.Core().Pods(value.Namespace).Get(value.Name, metav1.GetOptions{}) 72 if err != nil { 73 return false, err 74 } 75 pods = append(pods, *pod) 76 case (*extensions.Deployment): 77 currentDeployment, err := client.Extensions().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, client) 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.DaemonSet): 92 list, err := getPods(client, value.Namespace, value.Spec.Selector.MatchLabels) 93 if err != nil { 94 return false, err 95 } 96 pods = append(pods, list...) 97 case (*apps.StatefulSet): 98 list, err := getPods(client, value.Namespace, value.Spec.Selector.MatchLabels) 99 if err != nil { 100 return false, err 101 } 102 pods = append(pods, list...) 103 case (*extensions.ReplicaSet): 104 list, err := getPods(client, value.Namespace, value.Spec.Selector.MatchLabels) 105 if err != nil { 106 return false, err 107 } 108 pods = append(pods, list...) 109 case (*v1.PersistentVolumeClaim): 110 claim, err := client.Core().PersistentVolumeClaims(value.Namespace).Get(value.Name, metav1.GetOptions{}) 111 if err != nil { 112 return false, err 113 } 114 pvc = append(pvc, *claim) 115 case (*v1.Service): 116 svc, err := client.Core().Services(value.Namespace).Get(value.Name, metav1.GetOptions{}) 117 if err != nil { 118 return false, err 119 } 120 services = append(services, *svc) 121 } 122 } 123 isReady := podsReady(pods) && servicesReady(services) && volumesReady(pvc) && deploymentsReady(deployments) 124 c.Log("resources ready: %v", isReady) 125 return isReady, nil 126 }) 127 } 128 129 func podsReady(pods []v1.Pod) bool { 130 for _, pod := range pods { 131 if !v1.IsPodReady(&pod) { 132 return false 133 } 134 } 135 return true 136 } 137 138 func servicesReady(svc []v1.Service) bool { 139 for _, s := range svc { 140 // ExternalName Services are external to cluster so helm shouldn't be checking to see if they're 'ready' (i.e. have an IP Set) 141 if s.Spec.Type == v1.ServiceTypeExternalName { 142 continue 143 } 144 145 // Make sure the service is not explicitly set to "None" before checking the IP 146 if s.Spec.ClusterIP != v1.ClusterIPNone && !v1.IsServiceIPSet(&s) { 147 return false 148 } 149 // This checks if the service has a LoadBalancer and that balancer has an Ingress defined 150 if s.Spec.Type == v1.ServiceTypeLoadBalancer && s.Status.LoadBalancer.Ingress == nil { 151 return false 152 } 153 } 154 return true 155 } 156 157 func volumesReady(vols []v1.PersistentVolumeClaim) bool { 158 for _, v := range vols { 159 if v.Status.Phase != v1.ClaimBound { 160 return false 161 } 162 } 163 return true 164 } 165 166 func deploymentsReady(deployments []deployment) bool { 167 for _, v := range deployments { 168 if !(v.replicaSets.Status.ReadyReplicas >= *v.deployment.Spec.Replicas-deploymentutil.MaxUnavailable(*v.deployment)) { 169 return false 170 } 171 } 172 return true 173 } 174 175 func getPods(client clientset.Interface, namespace string, selector map[string]string) ([]v1.Pod, error) { 176 list, err := client.Core().Pods(namespace).List(metav1.ListOptions{ 177 FieldSelector: fields.Everything().String(), 178 LabelSelector: labels.Set(selector).AsSelector().String(), 179 }) 180 return list.Items, err 181 } 182 183 func versionedClientsetForDeployment(internalClient internalclientset.Interface) clientset.Interface { 184 if internalClient == nil { 185 return &clientset.Clientset{} 186 } 187 return &clientset.Clientset{ 188 CoreV1Client: core.New(internalClient.Core().RESTClient()), 189 ExtensionsV1beta1Client: extensionsclient.New(internalClient.Extensions().RESTClient()), 190 } 191 }