2015-09-18 20:35:56 +00:00
/ *
Copyright 2015 The Kubernetes Authors All rights reserved .
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 deployment
import (
"fmt"
2016-01-20 23:48:52 +00:00
"strconv"
2015-11-11 23:22:57 +00:00
"time"
2015-09-18 20:35:56 +00:00
"k8s.io/kubernetes/pkg/api"
2015-10-09 22:04:41 +00:00
"k8s.io/kubernetes/pkg/apis/extensions"
2016-02-05 21:58:03 +00:00
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
2015-09-18 20:35:56 +00:00
"k8s.io/kubernetes/pkg/labels"
2016-01-12 23:37:51 +00:00
labelsutil "k8s.io/kubernetes/pkg/util/labels"
podutil "k8s.io/kubernetes/pkg/util/pod"
2015-09-18 20:35:56 +00:00
)
2016-01-13 01:52:18 +00:00
const (
2016-01-20 00:40:18 +00:00
// The revision annotation of a deployment's replica sets which records its rollout sequence
2016-01-13 01:52:18 +00:00
RevisionAnnotation = "deployment.kubernetes.io/revision"
2016-01-19 22:50:03 +00:00
// Here are the possible rollback event reasons
RollbackRevisionNotFound = "DeploymentRollbackRevisionNotFound"
RollbackTemplateUnchanged = "DeploymentRollbackTemplateUnchanged"
RollbackDone = "DeploymentRollback"
2016-01-13 01:52:18 +00:00
)
2016-01-20 00:40:18 +00:00
// GetOldReplicaSets returns the old replica sets targeted by the given Deployment; get PodList and ReplicaSetList from client interface.
// Note that the first set of old replica sets doesn't include the ones with no pods, and the second set of old replica sets include all old replica sets.
func GetOldReplicaSets ( deployment extensions . Deployment , c clientset . Interface ) ( [ ] * extensions . ReplicaSet , [ ] * extensions . ReplicaSet , error ) {
return GetOldReplicaSetsFromLists ( deployment , c ,
2015-12-04 00:00:13 +00:00
func ( namespace string , options api . ListOptions ) ( * api . PodList , error ) {
2016-02-03 21:21:05 +00:00
return c . Core ( ) . Pods ( namespace ) . List ( options )
2015-11-18 23:12:11 +00:00
} ,
2016-01-20 00:40:18 +00:00
func ( namespace string , options api . ListOptions ) ( [ ] extensions . ReplicaSet , error ) {
rsList , err := c . Extensions ( ) . ReplicaSets ( namespace ) . List ( options )
return rsList . Items , err
2015-11-18 23:12:11 +00:00
} )
}
2016-01-20 00:40:18 +00:00
// GetOldReplicaSetsFromLists returns two sets of old replica sets targeted by the given Deployment; get PodList and ReplicaSetList with input functions.
// Note that the first set of old replica sets doesn't include the ones with no pods, and the second set of old replica sets include all old replica sets.
func GetOldReplicaSetsFromLists ( deployment extensions . Deployment , c clientset . Interface , getPodList func ( string , api . ListOptions ) ( * api . PodList , error ) , getRcList func ( string , api . ListOptions ) ( [ ] extensions . ReplicaSet , error ) ) ( [ ] * extensions . ReplicaSet , [ ] * extensions . ReplicaSet , error ) {
2015-09-18 20:35:56 +00:00
namespace := deployment . ObjectMeta . Namespace
2016-01-20 00:40:18 +00:00
selector , err := extensions . LabelSelectorAsSelector ( deployment . Spec . Selector )
if err != nil {
return nil , fmt . Errorf ( "failed to convert LabelSelector to Selector: %v" , err )
}
2015-09-18 20:35:56 +00:00
// 1. Find all pods whose labels match deployment.Spec.Selector
2015-12-10 09:39:03 +00:00
options := api . ListOptions { LabelSelector : selector }
2015-11-18 23:12:11 +00:00
podList , err := getPodList ( namespace , options )
2015-09-18 20:35:56 +00:00
if err != nil {
2016-01-13 01:52:18 +00:00
return nil , nil , fmt . Errorf ( "error listing pods: %v" , err )
2015-09-18 20:35:56 +00:00
}
2016-01-20 00:40:18 +00:00
// 2. Find the corresponding replica sets for pods in podList.
// TODO: Right now we list all replica sets and then filter. We should add an API for this.
oldRSs := map [ string ] extensions . ReplicaSet { }
allOldRSs := map [ string ] extensions . ReplicaSet { }
rsList , err := getRcList ( namespace , options )
2015-09-18 20:35:56 +00:00
if err != nil {
2016-01-20 00:40:18 +00:00
return nil , nil , fmt . Errorf ( "error listing replica sets: %v" , err )
2015-09-18 20:35:56 +00:00
}
2016-01-20 00:40:18 +00:00
newRSTemplate := GetNewReplicaSetTemplate ( deployment )
2015-09-18 20:35:56 +00:00
for _ , pod := range podList . Items {
podLabelsSelector := labels . Set ( pod . ObjectMeta . Labels )
2016-01-20 00:40:18 +00:00
for _ , rs := range rsList {
rsLabelsSelector := labels . SelectorFromSet ( rs . Spec . Selector )
// Filter out replica set that has the same pod template spec as the deployment - that is the new replica set.
if api . Semantic . DeepEqual ( rs . Spec . Template , & newRSTemplate ) {
2016-01-13 01:52:18 +00:00
continue
}
2016-01-20 00:40:18 +00:00
allOldRSs [ rs . ObjectMeta . Name ] = rs
if rsLabelsSelector . Matches ( podLabelsSelector ) {
oldRSs [ rs . ObjectMeta . Name ] = rs
2015-09-18 20:35:56 +00:00
}
}
}
2016-01-20 00:40:18 +00:00
requiredRSs := [ ] * extensions . ReplicaSet { }
for key := range oldRSs {
value := oldRSs [ key ]
requiredRSs = append ( requiredRSs , & value )
2015-09-18 20:35:56 +00:00
}
2016-01-20 00:40:18 +00:00
allRSs := [ ] * extensions . ReplicaSet { }
for key := range allOldRSs {
value := allOldRSs [ key ]
allRSs = append ( allRSs , & value )
2016-01-13 01:52:18 +00:00
}
2016-01-20 00:40:18 +00:00
return requiredRSs , allRSs , nil
2015-09-18 20:35:56 +00:00
}
2016-01-20 00:40:18 +00:00
// GetNewReplicaSet returns a replica set that matches the intent of the given deployment; get ReplicaSetList from client interface.
// Returns nil if the new replica set doesnt exist yet.
func GetNewReplicaSet ( deployment extensions . Deployment , c clientset . Interface ) ( * extensions . ReplicaSet , error ) {
return GetNewReplicaSetFromList ( deployment , c ,
func ( namespace string , options api . ListOptions ) ( [ ] extensions . ReplicaSet , error ) {
rsList , err := c . Extensions ( ) . ReplicaSets ( namespace ) . List ( options )
return rsList . Items , err
2015-11-18 23:12:11 +00:00
} )
}
2016-01-20 00:40:18 +00:00
// GetNewReplicaSetFromList returns a replica set that matches the intent of the given deployment; get ReplicaSetList with the input function.
// Returns nil if the new replica set doesnt exist yet.
func GetNewReplicaSetFromList ( deployment extensions . Deployment , c clientset . Interface , getRcList func ( string , api . ListOptions ) ( [ ] extensions . ReplicaSet , error ) ) ( * extensions . ReplicaSet , error ) {
2015-09-18 20:35:56 +00:00
namespace := deployment . ObjectMeta . Namespace
2016-01-20 00:40:18 +00:00
rsList , err := getRcList ( namespace , api . ListOptions { LabelSelector : labels . SelectorFromSet ( deployment . Spec . Selector ) } )
2015-09-18 20:35:56 +00:00
if err != nil {
2016-01-20 00:40:18 +00:00
return nil , fmt . Errorf ( "error listing ReplicaSets: %v" , err )
2015-09-18 20:35:56 +00:00
}
2016-01-20 00:40:18 +00:00
newRSTemplate := GetNewReplicaSetTemplate ( deployment )
2015-09-18 20:35:56 +00:00
2016-01-20 00:40:18 +00:00
for i := range rsList {
if api . Semantic . DeepEqual ( rsList [ i ] . Spec . Template , & newRSTemplate ) {
// This is the new ReplicaSet.
return & rsList [ i ] , nil
2015-09-18 20:35:56 +00:00
}
}
2016-01-20 00:40:18 +00:00
// new ReplicaSet does not exist.
2015-09-18 20:35:56 +00:00
return nil , nil
}
2016-01-20 00:40:18 +00:00
// Returns the desired PodTemplateSpec for the new ReplicaSet corresponding to the given ReplicaSet.
func GetNewReplicaSetTemplate ( deployment extensions . Deployment ) api . PodTemplateSpec {
// newRS will have the same template as in deployment spec, plus a unique label in some cases.
newRSTemplate := api . PodTemplateSpec {
2015-09-18 20:35:56 +00:00
ObjectMeta : deployment . Spec . Template . ObjectMeta ,
Spec : deployment . Spec . Template . Spec ,
}
2016-01-20 00:40:18 +00:00
newRSTemplate . ObjectMeta . Labels = labelsutil . CloneAndAddLabel (
2015-10-07 22:28:39 +00:00
deployment . Spec . Template . ObjectMeta . Labels ,
2016-02-05 22:45:05 +00:00
extensions . DefaultDeploymentUniqueLabelKey ,
2016-01-20 00:40:18 +00:00
podutil . GetPodTemplateSpecHash ( newRSTemplate ) )
return newRSTemplate
2015-09-18 20:35:56 +00:00
}
2016-01-20 00:40:18 +00:00
// SetFromReplicaSetTemplate sets the desired PodTemplateSpec from a replica set template to the given deployment.
func SetFromReplicaSetTemplate ( deployment * extensions . Deployment , template api . PodTemplateSpec ) * extensions . Deployment {
2016-01-15 02:04:05 +00:00
deployment . Spec . Template . ObjectMeta = template . ObjectMeta
deployment . Spec . Template . Spec = template . Spec
deployment . Spec . Template . ObjectMeta . Labels = labelsutil . CloneAndRemoveLabel (
deployment . Spec . Template . ObjectMeta . Labels ,
2016-02-05 22:45:05 +00:00
extensions . DefaultDeploymentUniqueLabelKey )
2016-01-15 02:04:05 +00:00
return deployment
}
2016-01-20 00:40:18 +00:00
// Returns the sum of Replicas of the given replica sets.
func GetReplicaCountForReplicaSets ( replicationControllers [ ] * extensions . ReplicaSet ) int {
2015-09-29 23:55:06 +00:00
totalReplicaCount := 0
2016-01-20 00:40:18 +00:00
for _ , rs := range replicaSets {
totalReplicaCount += rs . Spec . Replicas
2015-09-29 23:55:06 +00:00
}
return totalReplicaCount
}
2016-01-20 00:40:18 +00:00
// Returns the number of available pods corresponding to the given replica sets.
func GetAvailablePodsForReplicaSets ( c clientset . Interface , rss [ ] * extensions . ReplicaSet , minReadySeconds int ) ( int , error ) {
allPods , err := getPodsForReplicaSets ( c , rss )
2015-09-29 23:55:06 +00:00
if err != nil {
return 0 , err
}
2015-11-11 23:22:57 +00:00
return getReadyPodsCount ( allPods , minReadySeconds ) , nil
}
func getReadyPodsCount ( pods [ ] api . Pod , minReadySeconds int ) int {
2015-09-29 23:55:06 +00:00
readyPodCount := 0
2015-11-11 23:22:57 +00:00
for _ , pod := range pods {
2015-09-29 23:55:06 +00:00
if api . IsPodReady ( & pod ) {
2015-11-11 23:22:57 +00:00
// Check if we've passed minReadySeconds since LastTransitionTime
// If so, this pod is ready
for _ , c := range pod . Status . Conditions {
// we only care about pod ready conditions
if c . Type == api . PodReady {
// 2 cases that this ready condition is valid (passed minReadySeconds, i.e. the pod is ready):
// 1. minReadySeconds <= 0
// 2. LastTransitionTime (is set) + minReadySeconds (>0) < current time
minReadySecondsDuration := time . Duration ( minReadySeconds ) * time . Second
if minReadySeconds <= 0 || ! c . LastTransitionTime . IsZero ( ) && c . LastTransitionTime . Add ( minReadySecondsDuration ) . Before ( time . Now ( ) ) {
readyPodCount ++
break
}
}
}
2015-09-29 23:55:06 +00:00
}
}
2015-11-11 23:22:57 +00:00
return readyPodCount
2015-09-29 23:55:06 +00:00
}
2016-01-20 00:40:18 +00:00
func getPodsForReplicaSets ( c clientset . Interface , replicationControllers [ ] * extensions . ReplicaSet ) ( [ ] api . Pod , error ) {
2015-09-29 23:55:06 +00:00
allPods := [ ] api . Pod { }
2016-01-20 00:40:18 +00:00
for _ , rs := range replicaSets {
selector , err := extensions . LabelSelectorAsSelector ( rs . Spec . Selector )
if err != nil {
return nil , fmt . Errorf ( "failed to convert LabelSelector to Selector: %v" , err )
}
2015-12-10 09:39:03 +00:00
options := api . ListOptions { LabelSelector : selector }
2016-01-20 00:40:18 +00:00
podList , err := c . Core ( ) . Pods ( rs . ObjectMeta . Namespace ) . List ( options )
2015-09-29 23:55:06 +00:00
if err != nil {
return allPods , fmt . Errorf ( "error listing pods: %v" , err )
}
allPods = append ( allPods , podList . Items ... )
}
return allPods , nil
}
2016-01-20 23:48:52 +00:00
2016-01-20 00:40:18 +00:00
// Revision returns the revision number of the input replica set
func Revision ( rs * extensions . ReplicaSet ) ( int64 , error ) {
v , ok := rs . Annotations [ RevisionAnnotation ]
2016-01-20 23:48:52 +00:00
if ! ok {
return 0 , nil
}
return strconv . ParseInt ( v , 10 , 64 )
}