From 2e785fb76c0ad304eb107370dbc65ef1679202fe Mon Sep 17 00:00:00 2001 From: Chai Bot Date: Fri, 31 Jul 2026 13:51:32 +0000 Subject: [PATCH 1/2] OCPBUGS-98468: Fix project name collision in test framework Add retry-on-AlreadyExists logic to setupProject() and setupNamespace() in the test framework. When Ginkgo parallel workers start at the same nanosecond, the PRNG produces identical names causing AlreadyExists errors. On collision, generate a new name and retry up to 3 attempts. Co-Authored-By: Claude Opus 4.6 --- test/extended/util/client.go | 56 +++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/test/extended/util/client.go b/test/extended/util/client.go index c6928d7d6018..84650f7102c6 100644 --- a/test/extended/util/client.go +++ b/test/extended/util/client.go @@ -367,10 +367,23 @@ func (c *CLI) setupProject() string { c.SetNamespace(newNamespace).ChangeUser(fmt.Sprintf("%s-user", newNamespace)) framework.Logf("The user is now %q", c.Username()) - framework.Logf("Creating project %q", newNamespace) - _, err := c.ProjectClient().ProjectV1().ProjectRequests().Create(context.Background(), &projectv1.ProjectRequest{ - ObjectMeta: metav1.ObjectMeta{Name: newNamespace}, - }, metav1.CreateOptions{}) + const maxRetries = 3 + var err error + for attempt := 0; attempt < maxRetries; attempt++ { + framework.Logf("Creating project %q", newNamespace) + _, err = c.ProjectClient().ProjectV1().ProjectRequests().Create(context.Background(), &projectv1.ProjectRequest{ + ObjectMeta: metav1.ObjectMeta{Name: newNamespace}, + }, metav1.CreateOptions{}) + if err == nil { + break + } + if !apierrors.IsAlreadyExists(err) { + break + } + framework.Logf("Project name %q already exists (attempt %d/%d), generating a new name", newNamespace, attempt+1, maxRetries) + newNamespace = names.SimpleNameGenerator.GenerateName(fmt.Sprintf("e2e-test-%s-", c.kubeFramework.BaseName)) + c.SetNamespace(newNamespace).ChangeUser(fmt.Sprintf("%s-user", newNamespace)) + } o.Expect(err).NotTo(o.HaveOccurred()) c.kubeFramework.AddNamespacesToDelete(&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: newNamespace}}) @@ -487,18 +500,33 @@ func (c *CLI) setupNamespace() string { serviceAccountName := "default" c.SetNamespace(newNamespace) - nsObject := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: newNamespace, - Annotations: map[string]string{ - annotations.OpenShiftDescription: username, - annotations.OpenShiftDisplayName: newNamespace, - "openshift.io/requester": username, + const maxRetries = 3 + var err error + var nsObject *corev1.Namespace + for attempt := 0; attempt < maxRetries; attempt++ { + nsObject = &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: newNamespace, + Annotations: map[string]string{ + annotations.OpenShiftDescription: username, + annotations.OpenShiftDisplayName: newNamespace, + "openshift.io/requester": username, + }, }, - }, + } + framework.Logf("Creating namespace %q", newNamespace) + _, err = c.AdminKubeClient().CoreV1().Namespaces().Create(context.Background(), nsObject, metav1.CreateOptions{}) + if err == nil { + break + } + if !apierrors.IsAlreadyExists(err) { + break + } + framework.Logf("Namespace name %q already exists (attempt %d/%d), generating a new name", newNamespace, attempt+1, maxRetries) + newNamespace = names.SimpleNameGenerator.GenerateName(fmt.Sprintf("e2e-test-%s-", c.kubeFramework.BaseName)) + username = fmt.Sprintf("%s-user", newNamespace) + c.SetNamespace(newNamespace) } - framework.Logf("Creating namespace %q", newNamespace) - _, err := c.AdminKubeClient().CoreV1().Namespaces().Create(context.Background(), nsObject, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) c.kubeFramework.AddNamespacesToDelete(nsObject) From e41e44e5c2f9ffd0a4a5a8d0e5bf5b5f889d0803 Mon Sep 17 00:00:00 2001 From: Chai Bot Date: Fri, 31 Jul 2026 15:13:31 +0000 Subject: [PATCH 2/2] fixup: use <= for maxRetries to allow initial attempt + 3 retries Co-Authored-By: Claude Opus 4.6 --- test/extended/util/client.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/test/extended/util/client.go b/test/extended/util/client.go index 84650f7102c6..7f83499c8be9 100644 --- a/test/extended/util/client.go +++ b/test/extended/util/client.go @@ -369,7 +369,7 @@ func (c *CLI) setupProject() string { const maxRetries = 3 var err error - for attempt := 0; attempt < maxRetries; attempt++ { + for attempt := 0; attempt <= maxRetries; attempt++ { framework.Logf("Creating project %q", newNamespace) _, err = c.ProjectClient().ProjectV1().ProjectRequests().Create(context.Background(), &projectv1.ProjectRequest{ ObjectMeta: metav1.ObjectMeta{Name: newNamespace}, @@ -380,9 +380,11 @@ func (c *CLI) setupProject() string { if !apierrors.IsAlreadyExists(err) { break } - framework.Logf("Project name %q already exists (attempt %d/%d), generating a new name", newNamespace, attempt+1, maxRetries) - newNamespace = names.SimpleNameGenerator.GenerateName(fmt.Sprintf("e2e-test-%s-", c.kubeFramework.BaseName)) - c.SetNamespace(newNamespace).ChangeUser(fmt.Sprintf("%s-user", newNamespace)) + if attempt < maxRetries { + framework.Logf("Project name %q already exists (attempt %d/%d), generating a new name", newNamespace, attempt+1, maxRetries) + newNamespace = names.SimpleNameGenerator.GenerateName(fmt.Sprintf("e2e-test-%s-", c.kubeFramework.BaseName)) + c.SetNamespace(newNamespace).ChangeUser(fmt.Sprintf("%s-user", newNamespace)) + } } o.Expect(err).NotTo(o.HaveOccurred()) @@ -503,7 +505,7 @@ func (c *CLI) setupNamespace() string { const maxRetries = 3 var err error var nsObject *corev1.Namespace - for attempt := 0; attempt < maxRetries; attempt++ { + for attempt := 0; attempt <= maxRetries; attempt++ { nsObject = &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: newNamespace, @@ -522,10 +524,12 @@ func (c *CLI) setupNamespace() string { if !apierrors.IsAlreadyExists(err) { break } - framework.Logf("Namespace name %q already exists (attempt %d/%d), generating a new name", newNamespace, attempt+1, maxRetries) - newNamespace = names.SimpleNameGenerator.GenerateName(fmt.Sprintf("e2e-test-%s-", c.kubeFramework.BaseName)) - username = fmt.Sprintf("%s-user", newNamespace) - c.SetNamespace(newNamespace) + if attempt < maxRetries { + framework.Logf("Namespace name %q already exists (attempt %d/%d), generating a new name", newNamespace, attempt+1, maxRetries) + newNamespace = names.SimpleNameGenerator.GenerateName(fmt.Sprintf("e2e-test-%s-", c.kubeFramework.BaseName)) + username = fmt.Sprintf("%s-user", newNamespace) + c.SetNamespace(newNamespace) + } } o.Expect(err).NotTo(o.HaveOccurred()) c.kubeFramework.AddNamespacesToDelete(nsObject)