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  }