2016-01-21 19:07:23 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2016 The Kubernetes Authors .
2016-01-21 19:07:23 +00:00
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"
2017-10-24 15:56:54 +00:00
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
2017-01-11 14:09:48 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
2017-10-24 15:56:54 +00:00
"k8s.io/client-go/kubernetes"
clientappsv1beta1 "k8s.io/client-go/kubernetes/typed/apps/v1beta1"
clientextensionsv1beta1 "k8s.io/client-go/kubernetes/typed/extensions/v1beta1"
2017-01-10 16:25:32 +00:00
"k8s.io/kubernetes/pkg/apis/apps"
2016-10-10 11:07:38 +00:00
"k8s.io/kubernetes/pkg/controller/deployment/util"
2016-01-21 19:07:23 +00:00
)
2016-10-10 11:07:38 +00:00
// StatusViewer provides an interface for resources that have rollout status.
2016-01-21 19:07:23 +00:00
type StatusViewer interface {
2016-10-10 11:07:38 +00:00
Status ( namespace , name string , revision int64 ) ( string , bool , error )
2016-01-21 19:07:23 +00:00
}
2017-08-30 07:25:42 +00:00
// StatusViewerFor returns a StatusViewer for the resource specified by kind.
2017-10-24 15:56:54 +00:00
func StatusViewerFor ( kind schema . GroupKind , c kubernetes . Interface ) ( StatusViewer , error ) {
2016-01-21 19:07:23 +00:00
switch kind {
2017-10-24 15:56:54 +00:00
case extensionsv1beta1 . SchemeGroupVersion . WithKind ( "Deployment" ) . GroupKind ( ) , apps . Kind ( "Deployment" ) :
2017-11-18 07:00:21 +00:00
return & DeploymentStatusViewer { c . ExtensionsV1beta1 ( ) } , nil
2017-10-24 15:56:54 +00:00
case extensionsv1beta1 . SchemeGroupVersion . WithKind ( "DaemonSet" ) . GroupKind ( ) , apps . Kind ( "DaemonSet" ) :
2017-11-18 07:00:21 +00:00
return & DaemonSetStatusViewer { c . ExtensionsV1beta1 ( ) } , nil
2017-06-04 22:31:23 +00:00
case apps . Kind ( "StatefulSet" ) :
2017-10-24 15:56:54 +00:00
return & StatefulSetStatusViewer { c . AppsV1beta1 ( ) } , nil
2016-01-21 19:07:23 +00:00
}
return nil , fmt . Errorf ( "no status viewer has been implemented for %v" , kind )
}
2017-08-30 07:25:42 +00:00
// DeploymentStatusViewer implements the StatusViewer interface.
2016-01-21 19:07:23 +00:00
type DeploymentStatusViewer struct {
2017-10-24 15:56:54 +00:00
c clientextensionsv1beta1 . DeploymentsGetter
2016-01-21 19:07:23 +00:00
}
2017-08-30 07:25:42 +00:00
// DaemonSetStatusViewer implements the StatusViewer interface.
2017-02-23 10:23:38 +00:00
type DaemonSetStatusViewer struct {
2017-10-24 15:56:54 +00:00
c clientextensionsv1beta1 . DaemonSetsGetter
2017-02-23 10:23:38 +00:00
}
2017-08-30 07:25:42 +00:00
// StatefulSetStatusViewer implements the StatusViewer interface.
2017-06-04 22:31:23 +00:00
type StatefulSetStatusViewer struct {
2017-10-24 15:56:54 +00:00
c clientappsv1beta1 . StatefulSetsGetter
2017-06-04 22:31:23 +00:00
}
2017-08-30 07:25:42 +00:00
// Status returns a message describing deployment status, and a bool value indicating if the status is considered done.
2016-10-10 11:07:38 +00:00
func ( s * DeploymentStatusViewer ) Status ( namespace , name string , revision int64 ) ( string , bool , error ) {
2016-12-07 13:26:33 +00:00
deployment , err := s . c . Deployments ( namespace ) . Get ( name , metav1 . GetOptions { } )
2016-01-21 19:07:23 +00:00
if err != nil {
return "" , false , err
}
2016-10-10 11:07:38 +00:00
if revision > 0 {
deploymentRev , err := util . Revision ( deployment )
if err != nil {
return "" , false , fmt . Errorf ( "cannot get the revision of deployment %q: %v" , deployment . Name , err )
}
if revision != deploymentRev {
return "" , false , fmt . Errorf ( "desired revision (%d) is different from the running revision (%d)" , revision , deploymentRev )
}
}
2016-01-21 19:07:23 +00:00
if deployment . Generation <= deployment . Status . ObservedGeneration {
2017-10-24 15:56:54 +00:00
cond := util . GetDeploymentCondition ( deployment . Status , extensionsv1beta1 . DeploymentProgressing )
2016-09-27 14:48:39 +00:00
if cond != nil && cond . Reason == util . TimedOutReason {
return "" , false , fmt . Errorf ( "deployment %q exceeded its progress deadline" , name )
}
2017-10-24 15:56:54 +00:00
if deployment . Spec . Replicas != nil && deployment . Status . UpdatedReplicas < * deployment . Spec . Replicas {
return fmt . Sprintf ( "Waiting for rollout to finish: %d out of %d new replicas have been updated...\n" , deployment . Status . UpdatedReplicas , * deployment . Spec . Replicas ) , false , nil
2016-01-21 19:07:23 +00:00
}
2016-08-26 07:21:43 +00:00
if deployment . Status . Replicas > deployment . Status . UpdatedReplicas {
return fmt . Sprintf ( "Waiting for rollout to finish: %d old replicas are pending termination...\n" , deployment . Status . Replicas - deployment . Status . UpdatedReplicas ) , false , nil
}
2017-04-19 12:29:39 +00:00
if deployment . Status . AvailableReplicas < deployment . Status . UpdatedReplicas {
return fmt . Sprintf ( "Waiting for rollout to finish: %d of %d updated replicas are available...\n" , deployment . Status . AvailableReplicas , deployment . Status . UpdatedReplicas ) , false , nil
2016-08-26 07:21:43 +00:00
}
2016-10-10 11:07:38 +00:00
return fmt . Sprintf ( "deployment %q successfully rolled out\n" , name ) , true , nil
2016-01-21 19:07:23 +00:00
}
return fmt . Sprintf ( "Waiting for deployment spec update to be observed...\n" ) , false , nil
}
2017-02-23 10:23:38 +00:00
2017-08-30 07:25:42 +00:00
// Status returns a message describing daemon set status, and a bool value indicating if the status is considered done.
2017-02-23 10:23:38 +00:00
func ( s * DaemonSetStatusViewer ) Status ( namespace , name string , revision int64 ) ( string , bool , error ) {
2017-02-23 23:21:56 +00:00
//ignoring revision as DaemonSets does not have history yet
2017-02-23 10:23:38 +00:00
daemon , err := s . c . DaemonSets ( namespace ) . Get ( name , metav1 . GetOptions { } )
if err != nil {
return "" , false , err
}
2017-10-24 15:56:54 +00:00
if daemon . Spec . UpdateStrategy . Type != extensionsv1beta1 . RollingUpdateDaemonSetStrategyType {
2017-03-07 12:58:18 +00:00
return "" , true , fmt . Errorf ( "Status is available only for RollingUpdate strategy type" )
}
2017-02-23 10:23:38 +00:00
if daemon . Generation <= daemon . Status . ObservedGeneration {
if daemon . Status . UpdatedNumberScheduled < daemon . Status . DesiredNumberScheduled {
2017-03-07 12:58:18 +00:00
return fmt . Sprintf ( "Waiting for rollout to finish: %d out of %d new pods have been updated...\n" , daemon . Status . UpdatedNumberScheduled , daemon . Status . DesiredNumberScheduled ) , false , nil
2017-02-23 10:23:38 +00:00
}
2017-04-19 12:33:34 +00:00
if daemon . Status . NumberAvailable < daemon . Status . DesiredNumberScheduled {
return fmt . Sprintf ( "Waiting for rollout to finish: %d of %d updated pods are available...\n" , daemon . Status . NumberAvailable , daemon . Status . DesiredNumberScheduled ) , false , nil
2017-02-23 10:23:38 +00:00
}
return fmt . Sprintf ( "daemon set %q successfully rolled out\n" , name ) , true , nil
}
return fmt . Sprintf ( "Waiting for daemon set spec update to be observed...\n" ) , false , nil
}
2017-06-04 22:31:23 +00:00
2017-08-30 07:25:42 +00:00
// Status returns a message describing statefulset status, and a bool value indicating if the status is considered done.
2017-06-04 22:31:23 +00:00
func ( s * StatefulSetStatusViewer ) Status ( namespace , name string , revision int64 ) ( string , bool , error ) {
sts , err := s . c . StatefulSets ( namespace ) . Get ( name , metav1 . GetOptions { } )
if err != nil {
return "" , false , err
}
if sts . Spec . UpdateStrategy . Type == apps . OnDeleteStatefulSetStrategyType {
return "" , true , fmt . Errorf ( "%s updateStrategy does not have a Status`" , apps . OnDeleteStatefulSetStrategyType )
}
if sts . Status . ObservedGeneration == nil || sts . Generation > * sts . Status . ObservedGeneration {
return "Waiting for statefulset spec update to be observed...\n" , false , nil
}
2017-10-24 15:56:54 +00:00
if sts . Spec . Replicas != nil && sts . Status . ReadyReplicas < * sts . Spec . Replicas {
return fmt . Sprintf ( "Waiting for %d pods to be ready...\n" , * sts . Spec . Replicas - sts . Status . ReadyReplicas ) , false , nil
2017-06-04 22:31:23 +00:00
}
2017-06-12 17:07:07 +00:00
if sts . Spec . UpdateStrategy . Type == apps . RollingUpdateStatefulSetStrategyType && sts . Spec . UpdateStrategy . RollingUpdate != nil {
2017-10-24 15:56:54 +00:00
if sts . Spec . Replicas != nil && sts . Spec . UpdateStrategy . RollingUpdate . Partition != nil {
if sts . Status . UpdatedReplicas < ( * sts . Spec . Replicas - * sts . Spec . UpdateStrategy . RollingUpdate . Partition ) {
return fmt . Sprintf ( "Waiting for partitioned roll out to finish: %d out of %d new pods have been updated...\n" ,
sts . Status . UpdatedReplicas , ( * sts . Spec . Replicas - * sts . Spec . UpdateStrategy . RollingUpdate . Partition ) ) , false , nil
}
2017-06-04 22:31:23 +00:00
}
return fmt . Sprintf ( "partitioned roll out complete: %d new pods have been updated...\n" ,
2017-06-12 17:07:07 +00:00
sts . Status . UpdatedReplicas ) , true , nil
2017-06-04 22:31:23 +00:00
}
if sts . Status . UpdateRevision != sts . Status . CurrentRevision {
return fmt . Sprintf ( "waiting for statefulset rolling update to complete %d pods at revision %s...\n" ,
sts . Status . UpdatedReplicas , sts . Status . UpdateRevision ) , false , nil
}
return fmt . Sprintf ( "statefulset rolling update complete %d pods at revision %s...\n" , sts . Status . CurrentReplicas , sts . Status . CurrentRevision ) , true , nil
}