@@ -19,13 +19,14 @@ package deployment
19
19
import (
20
20
"context"
21
21
"fmt"
22
+ "sort"
22
23
23
24
appsv1 "k8s.io/api/apps/v1"
24
25
v1 "k8s.io/api/core/v1"
26
+ apiequality "k8s.io/apimachinery/pkg/api/equality"
25
27
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26
28
"k8s.io/apimachinery/pkg/util/uuid"
27
29
clientset "k8s.io/client-go/kubernetes"
28
- deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
29
30
"k8s.io/kubernetes/test/e2e/framework"
30
31
testutils "k8s.io/kubernetes/test/utils"
31
32
imageutils "k8s.io/kubernetes/test/utils/image"
@@ -86,22 +87,90 @@ func CreateDeployment(client clientset.Interface, replicas int32, podLabels map[
86
87
87
88
// GetPodsForDeployment gets pods for the given deployment
88
89
func GetPodsForDeployment (client clientset.Interface , deployment * appsv1.Deployment ) (* v1.PodList , error ) {
89
- replicaSet , err := deploymentutil . GetNewReplicaSet (deployment , client . AppsV1 () )
90
+ replicaSetSelector , err := metav1 . LabelSelectorAsSelector (deployment . Spec . Selector )
90
91
if err != nil {
91
- return nil , fmt . Errorf ( "Failed to get new replica set for deployment %q: %v" , deployment . Name , err )
92
+ return nil , err
92
93
}
94
+
95
+ replicaSetListOptions := metav1.ListOptions {LabelSelector : replicaSetSelector .String ()}
96
+ allReplicaSets , err := client .AppsV1 ().ReplicaSets (deployment .Namespace ).List (context .TODO (), replicaSetListOptions )
97
+ if err != nil {
98
+ return nil , err
99
+ }
100
+
101
+ ownedReplicaSets := make ([]* appsv1.ReplicaSet , 0 , len (allReplicaSets .Items ))
102
+ for _ , rs := range allReplicaSets .Items {
103
+ if ! metav1 .IsControlledBy (& rs , deployment ) {
104
+ continue
105
+ }
106
+
107
+ ownedReplicaSets = append (ownedReplicaSets , & rs )
108
+ }
109
+
110
+ // We ignore pod-template-hash because:
111
+ // 1. The hash result would be different upon podTemplateSpec API changes
112
+ // (e.g. the addition of a new field will cause the hash code to change)
113
+ // 2. The deployment template won't have hash labels
114
+ podTemplatesEqualsIgnoringHash := func (template1 , template2 * v1.PodTemplateSpec ) bool {
115
+ t1Copy := template1 .DeepCopy ()
116
+ t2Copy := template2 .DeepCopy ()
117
+ // Remove hash labels from template.Labels before comparing
118
+ delete (t1Copy .Labels , appsv1 .DefaultDeploymentUniqueLabelKey )
119
+ delete (t2Copy .Labels , appsv1 .DefaultDeploymentUniqueLabelKey )
120
+ return apiequality .Semantic .DeepEqual (t1Copy , t2Copy )
121
+ }
122
+
123
+ var replicaSet * appsv1.ReplicaSet
124
+ // In rare cases, such as after cluster upgrades, Deployment may end up with
125
+ // having more than one new ReplicaSets that have the same template as its template,
126
+ // see https://github.com/kubernetes/kubernetes/issues/40415
127
+ // We deterministically choose the oldest new ReplicaSet.
128
+ sort .Sort (replicaSetsByCreationTimestamp (ownedReplicaSets ))
129
+ for _ , rs := range ownedReplicaSets {
130
+ if ! podTemplatesEqualsIgnoringHash (& rs .Spec .Template , & deployment .Spec .Template ) {
131
+ continue
132
+ }
133
+
134
+ replicaSet = rs
135
+ break
136
+ }
137
+
93
138
if replicaSet == nil {
94
139
return nil , fmt .Errorf ("expected a new replica set for deployment %q, found none" , deployment .Name )
95
140
}
96
- podListFunc := func (namespace string , options metav1.ListOptions ) (* v1.PodList , error ) {
97
- return client .CoreV1 ().Pods (namespace ).List (context .TODO (), options )
141
+
142
+ podSelector , err := metav1 .LabelSelectorAsSelector (deployment .Spec .Selector )
143
+ if err != nil {
144
+ return nil , err
98
145
}
99
- rsList := [] * appsv1. ReplicaSet { replicaSet }
100
- podList , err := deploymentutil . ListPods ( deployment , rsList , podListFunc )
146
+ podListOptions := metav1. ListOptions { LabelSelector : podSelector . String () }
147
+ allPods , err := client . CoreV1 (). Pods ( deployment . Namespace ). List ( context . TODO (), podListOptions )
101
148
if err != nil {
102
- return nil , fmt .Errorf ("Failed to list Pods of Deployment %q: %v" , deployment .Name , err )
149
+ return nil , err
150
+ }
151
+
152
+ replicaSetUID := replicaSet .UID
153
+ ownedPods := & v1.PodList {Items : make ([]v1.Pod , 0 , len (allPods .Items ))}
154
+ for _ , pod := range allPods .Items {
155
+ controllerRef := metav1 .GetControllerOf (& pod )
156
+ if controllerRef != nil && controllerRef .UID == replicaSetUID {
157
+ ownedPods .Items = append (ownedPods .Items , pod )
158
+ }
159
+ }
160
+
161
+ return ownedPods , nil
162
+ }
163
+
164
+ // replicaSetsByCreationTimestamp sorts a list of ReplicaSet by creation timestamp, using their names as a tie breaker.
165
+ type replicaSetsByCreationTimestamp []* appsv1.ReplicaSet
166
+
167
+ func (o replicaSetsByCreationTimestamp ) Len () int { return len (o ) }
168
+ func (o replicaSetsByCreationTimestamp ) Swap (i , j int ) { o [i ], o [j ] = o [j ], o [i ] }
169
+ func (o replicaSetsByCreationTimestamp ) Less (i , j int ) bool {
170
+ if o [i ].CreationTimestamp .Equal (& o [j ].CreationTimestamp ) {
171
+ return o [i ].Name < o [j ].Name
103
172
}
104
- return podList , nil
173
+ return o [ i ]. CreationTimestamp . Before ( & o [ j ]. CreationTimestamp )
105
174
}
106
175
107
176
// testDeployment creates a deployment definition based on the namespace. The deployment references the PVC's
0 commit comments