@@ -11,6 +11,7 @@ import (
1111 "github.com/stretchr/testify/assert"
1212 "github.com/stretchr/testify/require"
1313 appsv1 "k8s.io/api/apps/v1"
14+ coordinationv1 "k8s.io/api/coordination/v1"
1415 corev1 "k8s.io/api/core/v1"
1516 apimeta "k8s.io/apimachinery/pkg/api/meta"
1617 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -195,13 +196,14 @@ func TestClusterExtensionAfterOLMUpgrade(t *testing.T) {
195196
196197// waitForDeployment checks that the updated deployment with the given app.kubernetes.io/name label
197198// has reached the desired number of replicas and that the number pods matches that number
198- // i.e. no old pods remain. It will return a pointer to the first pod. This is only necessary
199+ // i.e. no old pods remain. It will return a pointer to the leader pod. This is only necessary
199200// to facilitate the mitigation put in place for https://github.com/operator-framework/operator-controller/issues/1626
200201func waitForDeployment (t * testing.T , ctx context.Context , controlPlaneLabel string ) * corev1.Pod {
201202 deploymentLabelSelector := labels.Set {"app.kubernetes.io/name" : controlPlaneLabel }.AsSelector ()
202203
203204 t .Log ("Checking that the deployment is updated" )
204205 var desiredNumReplicas int32
206+ var deploymentNamespace string
205207 require .EventuallyWithT (t , func (ct * assert.CollectT ) {
206208 var managerDeployments appsv1.DeploymentList
207209 require .NoError (ct , c .List (ctx , & managerDeployments , client.MatchingLabelsSelector {Selector : deploymentLabelSelector }))
@@ -215,15 +217,51 @@ func waitForDeployment(t *testing.T, ctx context.Context, controlPlaneLabel stri
215217 managerDeployment .Status .ReadyReplicas == * managerDeployment .Spec .Replicas ,
216218 )
217219 desiredNumReplicas = * managerDeployment .Spec .Replicas
220+ deploymentNamespace = managerDeployment .Namespace
218221 }, time .Minute , time .Second )
219222
220223 var managerPods corev1.PodList
221224 t .Logf ("Ensure the number of remaining pods equal the desired number of replicas (%d)" , desiredNumReplicas )
222225 require .EventuallyWithT (t , func (ct * assert.CollectT ) {
223226 require .NoError (ct , c .List (ctx , & managerPods , client.MatchingLabelsSelector {Selector : deploymentLabelSelector }))
224- require .Len (ct , managerPods .Items , 1 )
227+ require .Len (ct , managerPods .Items , int ( desiredNumReplicas ) )
225228 }, time .Minute , time .Second )
226- return & managerPods .Items [0 ]
229+
230+ // Find the leader pod by checking the lease
231+ t .Log ("Finding the leader pod" )
232+ // Map component labels to their leader election lease names
233+ leaseNames := map [string ]string {
234+ "catalogd" : "catalogd-operator-lock" ,
235+ "operator-controller" : "9c4404e7.operatorframework.io" ,
236+ }
237+
238+ leaseName , ok := leaseNames [controlPlaneLabel ]
239+ if ! ok {
240+ t .Fatalf ("Unknown control plane component: %s" , controlPlaneLabel )
241+ }
242+
243+ var leaderPod * corev1.Pod
244+ require .EventuallyWithT (t , func (ct * assert.CollectT ) {
245+ var lease coordinationv1.Lease
246+ require .NoError (ct , c .Get (ctx , types.NamespacedName {Name : leaseName , Namespace : deploymentNamespace }, & lease ))
247+ require .NotNil (ct , lease .Spec .HolderIdentity )
248+
249+ leaderIdentity := * lease .Spec .HolderIdentity
250+ // The lease holder identity format is: <pod-name>_<leader-election-id-suffix>
251+ // Extract just the pod name by splitting on '_'
252+ podName := strings .Split (leaderIdentity , "_" )[0 ]
253+
254+ // Find the pod with matching name
255+ for i := range managerPods .Items {
256+ if managerPods .Items [i ].Name == podName {
257+ leaderPod = & managerPods .Items [i ]
258+ break
259+ }
260+ }
261+ require .NotNil (ct , leaderPod , "leader pod not found with identity: %s (pod name: %s)" , leaderIdentity , podName )
262+ }, time .Minute , time .Second )
263+
264+ return leaderPod
227265}
228266
229267func watchPodLogsForSubstring (ctx context.Context , pod * corev1.Pod , substrings ... string ) (bool , error ) {
0 commit comments