50
vendor/helm.sh/helm/v3/pkg/kube/client.go
vendored
50
vendor/helm.sh/helm/v3/pkg/kube/client.go
vendored
@@ -35,6 +35,7 @@ import (
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@@ -42,6 +43,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/cli-runtime/pkg/resource"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
cachetools "k8s.io/client-go/tools/cache"
|
||||
watchtools "k8s.io/client-go/tools/watch"
|
||||
@@ -59,6 +61,8 @@ type Client struct {
|
||||
Log func(string, ...interface{})
|
||||
// Namespace allows to bypass the kubeconfig file for the choice of the namespace
|
||||
Namespace string
|
||||
|
||||
kubeClient *kubernetes.Clientset
|
||||
}
|
||||
|
||||
var addToScheme sync.Once
|
||||
@@ -86,9 +90,19 @@ func New(getter genericclioptions.RESTClientGetter) *Client {
|
||||
|
||||
var nopLogger = func(_ string, _ ...interface{}) {}
|
||||
|
||||
// getKubeClient get or create a new KubernetesClientSet
|
||||
func (c *Client) getKubeClient() (*kubernetes.Clientset, error) {
|
||||
var err error
|
||||
if c.kubeClient == nil {
|
||||
c.kubeClient, err = c.Factory.KubernetesClientSet()
|
||||
}
|
||||
|
||||
return c.kubeClient, err
|
||||
}
|
||||
|
||||
// IsReachable tests connectivity to the cluster
|
||||
func (c *Client) IsReachable() error {
|
||||
client, err := c.Factory.KubernetesClientSet()
|
||||
client, err := c.getKubeClient()
|
||||
if err == genericclioptions.ErrEmptyConfig {
|
||||
// re-replace kubernetes ErrEmptyConfig error with a friendy error
|
||||
// moar workarounds for Kubernetes API breaking.
|
||||
@@ -114,7 +128,7 @@ func (c *Client) Create(resources ResourceList) (*Result, error) {
|
||||
|
||||
// Wait up to the given timeout for the specified resources to be ready
|
||||
func (c *Client) Wait(resources ResourceList, timeout time.Duration) error {
|
||||
cs, err := c.Factory.KubernetesClientSet()
|
||||
cs, err := c.getKubeClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -123,7 +137,21 @@ func (c *Client) Wait(resources ResourceList, timeout time.Duration) error {
|
||||
log: c.Log,
|
||||
timeout: timeout,
|
||||
}
|
||||
return w.waitForResources(resources)
|
||||
return w.waitForResources(resources, false)
|
||||
}
|
||||
|
||||
// WaitWithJobs wait up to the given timeout for the specified resources to be ready, including jobs.
|
||||
func (c *Client) WaitWithJobs(resources ResourceList, timeout time.Duration) error {
|
||||
cs, err := c.getKubeClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := waiter{
|
||||
c: cs,
|
||||
log: c.Log,
|
||||
timeout: timeout,
|
||||
}
|
||||
return w.waitForResources(resources, true)
|
||||
}
|
||||
|
||||
func (c *Client) namespace() string {
|
||||
@@ -160,7 +188,7 @@ func (c *Client) Build(reader io.Reader, validate bool) (ResourceList, error) {
|
||||
}
|
||||
|
||||
// Update takes the current list of objects and target list of objects and
|
||||
// creates resources that don't already exists, updates resources that have been
|
||||
// creates resources that don't already exist, updates resources that have been
|
||||
// modified in the target configuration, and deletes resources from the current
|
||||
// configuration that are not present in the target configuration. If an error
|
||||
// occurs, a Result will still be returned with the error, containing all
|
||||
@@ -177,7 +205,7 @@ func (c *Client) Update(original, target ResourceList, force bool) (*Result, err
|
||||
}
|
||||
|
||||
helper := resource.NewHelper(info.Client, info.Mapping)
|
||||
if _, err := helper.Get(info.Namespace, info.Name, info.Export); err != nil {
|
||||
if _, err := helper.Get(info.Namespace, info.Name); err != nil {
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return errors.Wrap(err, "could not get information about the resource")
|
||||
}
|
||||
@@ -373,7 +401,7 @@ func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.P
|
||||
|
||||
// Fetch the current object for the three way merge
|
||||
helper := resource.NewHelper(target.Client, target.Mapping)
|
||||
currentObj, err := helper.Get(target.Namespace, target.Name, target.Export)
|
||||
currentObj, err := helper.Get(target.Namespace, target.Name)
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
return nil, types.StrategicMergePatchType, errors.Wrapf(err, "unable to get data for current object %s/%s", target.Namespace, target.Name)
|
||||
}
|
||||
@@ -478,7 +506,7 @@ func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) err
|
||||
|
||||
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
_, err = watchtools.ListWatchUntil(ctx, lw, func(e watch.Event) (bool, error) {
|
||||
_, err = watchtools.UntilWithSync(ctx, lw, &unstructured.Unstructured{}, nil, func(e watch.Event) (bool, error) {
|
||||
// Make sure the incoming object is versioned as we use unstructured
|
||||
// objects when we build manifests
|
||||
obj := convertWithMapper(e.Object, info.Mapping)
|
||||
@@ -542,14 +570,14 @@ func (c *Client) waitForPodSuccess(obj runtime.Object, name string) (bool, error
|
||||
|
||||
switch o.Status.Phase {
|
||||
case v1.PodSucceeded:
|
||||
fmt.Printf("Pod %s succeeded\n", o.Name)
|
||||
c.Log("Pod %s succeeded", o.Name)
|
||||
return true, nil
|
||||
case v1.PodFailed:
|
||||
return true, errors.Errorf("pod %s failed", o.Name)
|
||||
case v1.PodPending:
|
||||
fmt.Printf("Pod %s pending\n", o.Name)
|
||||
c.Log("Pod %s pending", o.Name)
|
||||
case v1.PodRunning:
|
||||
fmt.Printf("Pod %s running\n", o.Name)
|
||||
c.Log("Pod %s running", o.Name)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
@@ -571,7 +599,7 @@ func scrubValidationError(err error) error {
|
||||
// WaitAndGetCompletedPodPhase waits up to a timeout until a pod enters a completed phase
|
||||
// and returns said phase (PodSucceeded or PodFailed qualify).
|
||||
func (c *Client) WaitAndGetCompletedPodPhase(name string, timeout time.Duration) (v1.PodPhase, error) {
|
||||
client, err := c.Factory.KubernetesClientSet()
|
||||
client, err := c.getKubeClient()
|
||||
if err != nil {
|
||||
return v1.PodUnknown, err
|
||||
}
|
||||
|
||||
2
vendor/helm.sh/helm/v3/pkg/kube/interface.go
vendored
2
vendor/helm.sh/helm/v3/pkg/kube/interface.go
vendored
@@ -32,6 +32,8 @@ type Interface interface {
|
||||
|
||||
Wait(resources ResourceList, timeout time.Duration) error
|
||||
|
||||
WaitWithJobs(resources ResourceList, timeout time.Duration) error
|
||||
|
||||
// Delete destroys one or more resources.
|
||||
Delete(resources ResourceList) (*Result, []error)
|
||||
|
||||
|
||||
29
vendor/helm.sh/helm/v3/pkg/kube/wait.go
vendored
29
vendor/helm.sh/helm/v3/pkg/kube/wait.go
vendored
@@ -47,9 +47,9 @@ type waiter struct {
|
||||
log func(string, ...interface{})
|
||||
}
|
||||
|
||||
// waitForResources polls to get the current status of all pods, PVCs, and Services
|
||||
// until all are ready or a timeout is reached
|
||||
func (w *waiter) waitForResources(created ResourceList) error {
|
||||
// waitForResources polls to get the current status of all pods, PVCs, Services and
|
||||
// Jobs(optional) until all are ready or a timeout is reached
|
||||
func (w *waiter) waitForResources(created ResourceList, waitForJobsEnabled bool) error {
|
||||
w.log("beginning wait for %d resources with timeout of %v", len(created), w.timeout)
|
||||
|
||||
return wait.Poll(2*time.Second, w.timeout, func() (bool, error) {
|
||||
@@ -67,6 +67,13 @@ func (w *waiter) waitForResources(created ResourceList) error {
|
||||
if err != nil || !w.isPodReady(pod) {
|
||||
return false, err
|
||||
}
|
||||
case *batchv1.Job:
|
||||
if waitForJobsEnabled {
|
||||
job, err := w.c.BatchV1().Jobs(v.Namespace).Get(context.Background(), v.Name, metav1.GetOptions{})
|
||||
if err != nil || !w.jobReady(job) {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
case *appsv1.Deployment, *appsv1beta1.Deployment, *appsv1beta2.Deployment, *extensionsv1beta1.Deployment:
|
||||
currentDeployment, err := w.c.AppsV1().Deployments(v.Namespace).Get(context.Background(), v.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
@@ -182,14 +189,26 @@ func (w *waiter) isPodReady(pod *corev1.Pod) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (w *waiter) jobReady(job *batchv1.Job) bool {
|
||||
if job.Status.Failed >= *job.Spec.BackoffLimit {
|
||||
w.log("Job is failed: %s/%s", job.GetNamespace(), job.GetName())
|
||||
return false
|
||||
}
|
||||
if job.Status.Succeeded < *job.Spec.Completions {
|
||||
w.log("Job is not completed: %s/%s", job.GetNamespace(), job.GetName())
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *waiter) serviceReady(s *corev1.Service) bool {
|
||||
// ExternalName Services are external to cluster so helm shouldn't be checking to see if they're 'ready' (i.e. have an IP Set)
|
||||
if s.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
return true
|
||||
}
|
||||
|
||||
// Make sure the service is not explicitly set to "None" before checking the IP
|
||||
if s.Spec.ClusterIP != corev1.ClusterIPNone && s.Spec.ClusterIP == "" {
|
||||
// Ensure that the service cluster IP is not empty
|
||||
if s.Spec.ClusterIP == "" {
|
||||
w.log("Service does not have cluster IP address: %s/%s", s.GetNamespace(), s.GetName())
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user