@@ -261,14 +261,39 @@ func portForwardAPIServer(ctx context.Context, t *testing.T) (uint16, func()) {
261261// a member pod, authenticating with the server keypair (issued with
262262// clientAuth EKU for exactly this kind of loopback use). Member pods carry
263263// operator-generated names, so the pod is found via the cluster label.
264+ //
265+ // The pod must be picked by READINESS, not list order: the dump runs while
266+ // the cluster may still be scaling up (Available latches on quorum, not on
267+ // the full replica count), and a freshly-created member pod whose etcd
268+ // container has not started yet fails the exec with "container not found".
269+ // etcdctl get is linearizable, so any ready member returns the same keys.
264270func etcdKeys (ctx context.Context , t * testing.T ) string {
265271 t .Helper ()
266272 pods := & corev1.PodList {}
267273 if err := kube .List (ctx , pods , client .InNamespace (e2eNamespace ),
268274 client.MatchingLabels {"etcd-operator.cozystack.io/cluster" : clusterName }); err != nil || len (pods .Items ) == 0 {
269275 t .Fatalf ("list etcd member pods: %v (found %d)" , err , len (pods .Items ))
270276 }
271- stdout , stderr , err := podExec (ctx , e2eNamespace , pods .Items [0 ].Name , "etcd" , []string {
277+ podName := ""
278+ for i := range pods .Items {
279+ p := & pods .Items [i ]
280+ if p .Status .Phase != corev1 .PodRunning {
281+ continue
282+ }
283+ for _ , cs := range p .Status .ContainerStatuses {
284+ if cs .Name == "etcd" && cs .Ready {
285+ podName = p .Name
286+ break
287+ }
288+ }
289+ if podName != "" {
290+ break
291+ }
292+ }
293+ if podName == "" {
294+ t .Fatalf ("no Running etcd member pod with a ready etcd container (of %d pods)" , len (pods .Items ))
295+ }
296+ stdout , stderr , err := podExec (ctx , e2eNamespace , podName , "etcd" , []string {
272297 "etcdctl" ,
273298 "--endpoints=https://localhost:2379" ,
274299 "--cert=/etc/etcd/tls/client/tls.crt" ,
0 commit comments