Skip to content

Commit 37dbfb5

Browse files
committed
feat(run-tests): Handle existing namespaces and permission errors more gracefully
This _does_ change behavior. In the past run-tests would fail if we can't create the namespace but now we'll proceed because it might already exist and we just can't check easily.
1 parent e62e8ac commit 37dbfb5

File tree

1 file changed

+52
-16
lines changed

1 file changed

+52
-16
lines changed

template/scripts/run-tests

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -353,22 +353,7 @@ def run_tests(test: str, parallel: int, namespace: str, skip_delete: bool) -> No
353353
if namespace:
354354
kuttl_cmd.extend(["--namespace", namespace])
355355
# kuttl doesn't create the namespace so we need to do it ourselves
356-
create_ns_cmd = ["kubectl", "create", "namespace", namespace]
357-
try:
358-
logging.debug(f"Running : {create_ns_cmd}")
359-
subprocess.run(
360-
create_ns_cmd,
361-
check=True,
362-
capture_output=True,
363-
)
364-
except subprocess.CalledProcessError as e:
365-
stderr = e.stderr.decode("utf-8")
366-
# If the namespace already exists, this will fail and we ignore the
367-
# error. If it fails for any other reason, we raise an exception.
368-
if "already exists" not in stderr:
369-
logging.error(stderr)
370-
logging.error("namespace creation failed")
371-
raise TestRunnerException()
356+
ensure_namespace_exists(namespace)
372357

373358
logging.debug(f"Running : {kuttl_cmd}")
374359

@@ -381,6 +366,57 @@ def run_tests(test: str, parallel: int, namespace: str, skip_delete: bool) -> No
381366
logging.error("kuttl failed")
382367
raise TestRunnerException()
383368

369+
def ensure_namespace_exists(namespace: str) -> None:
370+
"""
371+
Ensure the specified namespace exists, creating it if necessary.
372+
373+
This function handles various permission scenarios:
374+
- If the namespace already exists, it does nothing
375+
- If it doesn't exist and we have permission, it creates it
376+
- If we don't have permission to create/check namespaces, it logs a warning
377+
and assumes the namespace exists or will be created externally (useful for OpenShift)
378+
379+
Examples of (permission) errors we handle:
380+
- Error from server (Forbidden): namespaces is forbidden: User "developer" cannot create resource "namespaces" in API group "" at the cluster scope
381+
- Error from server (Forbidden): namespaces "foobar123" is forbidden: User "developer" cannot get resource "namespaces" in API group "" in the namespace "foobar123"
382+
- Error from server (AlreadyExists): namespaces "kuttl-test-finer-caiman" already exists
383+
"""
384+
# First check if the namespace already exists
385+
check_ns_cmd = ["kubectl", "get", "namespace", namespace]
386+
try:
387+
logging.debug(f"Checking if namespace exists: {check_ns_cmd}")
388+
subprocess.run(
389+
check_ns_cmd,
390+
check=True,
391+
capture_output=True,
392+
)
393+
logging.debug(f"Namespace '{namespace}' already exists")
394+
except subprocess.CalledProcessError:
395+
# Namespace doesn't exist, try to create it
396+
create_ns_cmd = ["kubectl", "create", "namespace", namespace]
397+
try:
398+
logging.debug(f"Creating namespace: {create_ns_cmd}")
399+
subprocess.run(
400+
create_ns_cmd,
401+
check=True,
402+
capture_output=True,
403+
)
404+
logging.debug(f"Successfully created namespace '{namespace}'")
405+
except subprocess.CalledProcessError as e:
406+
stderr = e.stderr.decode("utf-8")
407+
if "already exists" in stderr:
408+
logging.debug(
409+
f"Namespace '{namespace}' already exists (race condition)"
410+
)
411+
elif "forbidden" in stderr.lower():
412+
logging.warning(
413+
f"No permission to create namespace '{namespace}', assuming it exists or will be created externally"
414+
)
415+
else:
416+
logging.error(stderr)
417+
logging.error("namespace creation failed")
418+
raise TestRunnerException()
419+
384420

385421
def main(argv) -> int:
386422
ret = 0

0 commit comments

Comments
 (0)