| /* |
| Copyright 2014 The Kubernetes Authors. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package kubectl |
| |
| import ( |
| "fmt" |
| |
| corev1 "k8s.io/api/core/v1" |
| "k8s.io/apimachinery/pkg/api/errors" |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| "k8s.io/apimachinery/pkg/runtime/schema" |
| "k8s.io/apimachinery/pkg/util/wait" |
| "k8s.io/apimachinery/pkg/watch" |
| corev1client "k8s.io/client-go/kubernetes/typed/core/v1" |
| ) |
| |
| // ControllerHasDesiredReplicas returns a condition that will be true if and only if |
| // the desired replica count for a controller's ReplicaSelector equals the Replicas count. |
| func ControllerHasDesiredReplicas(rcClient corev1client.ReplicationControllersGetter, controller *corev1.ReplicationController) wait.ConditionFunc { |
| |
| // If we're given a controller where the status lags the spec, it either means that the controller is stale, |
| // or that the rc manager hasn't noticed the update yet. Polling status.Replicas is not safe in the latter case. |
| desiredGeneration := controller.Generation |
| |
| return func() (bool, error) { |
| ctrl, err := rcClient.ReplicationControllers(controller.Namespace).Get(controller.Name, metav1.GetOptions{}) |
| if err != nil { |
| return false, err |
| } |
| // There's a chance a concurrent update modifies the Spec.Replicas causing this check to pass, |
| // or, after this check has passed, a modification causes the rc manager to create more pods. |
| // This will not be an issue once we've implemented graceful delete for rcs, but till then |
| // concurrent stop operations on the same rc might have unintended side effects. |
| return ctrl.Status.ObservedGeneration >= desiredGeneration && ctrl.Status.Replicas == valOrZero(ctrl.Spec.Replicas), nil |
| } |
| } |
| |
| // ErrPodCompleted is returned by PodRunning or PodContainerRunning to indicate that |
| // the pod has already reached completed state. |
| var ErrPodCompleted = fmt.Errorf("pod ran to completion") |
| |
| // PodCompleted returns true if the pod has run to completion, false if the pod has not yet |
| // reached running state, or an error in any other case. |
| func PodCompleted(event watch.Event) (bool, error) { |
| switch event.Type { |
| case watch.Deleted: |
| return false, errors.NewNotFound(schema.GroupResource{Resource: "pods"}, "") |
| } |
| switch t := event.Object.(type) { |
| case *corev1.Pod: |
| switch t.Status.Phase { |
| case corev1.PodFailed, corev1.PodSucceeded: |
| return true, nil |
| } |
| } |
| return false, nil |
| } |
| |
| // PodRunningAndReady returns true if the pod is running and ready, false if the pod has not |
| // yet reached those states, returns ErrPodCompleted if the pod has run to completion, or |
| // an error in any other case. |
| func PodRunningAndReady(event watch.Event) (bool, error) { |
| switch event.Type { |
| case watch.Deleted: |
| return false, errors.NewNotFound(schema.GroupResource{Resource: "pods"}, "") |
| } |
| switch t := event.Object.(type) { |
| case *corev1.Pod: |
| switch t.Status.Phase { |
| case corev1.PodFailed, corev1.PodSucceeded: |
| return false, ErrPodCompleted |
| case corev1.PodRunning: |
| conditions := t.Status.Conditions |
| if conditions == nil { |
| return false, nil |
| } |
| for i := range conditions { |
| if conditions[i].Type == corev1.PodReady && |
| conditions[i].Status == corev1.ConditionTrue { |
| return true, nil |
| } |
| } |
| } |
| } |
| return false, nil |
| } |