Skip to content

Commit 337e676

Browse files
authored
Check if Kubernetes resources exist before creating them in XPK setup (#1195)
* Check if Kubernetes resources exist before creating them in XPK setup In GKE clusters with restricted permissions, users might have read access to Roles/ServiceAccounts/RoleBindings but not create access. XPK was previously using try-create-catch-409 logic, which causes 403 Forbidden errors if the user lacks create permission, even if the resource already exists. This change implements a 'check before create' pattern for ServiceAccount, Role, and RoleBinding creation in cluster.py. It checks if the resource exists first (using GET), and only attempts to create it (POST) if it doesn't exist. This allows administrators to pre-create these resources and lets developers run XPK without needing elevated creation permissions. * Format cluster.py with pyink
1 parent 0f92c2b commit 337e676

1 file changed

Lines changed: 45 additions & 9 deletions

File tree

src/xpk/core/cluster.py

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -447,16 +447,31 @@ def create_xpk_k8s_service_account() -> None:
447447
metadata=k8s_client.V1ObjectMeta(name=XPK_SA)
448448
)
449449

450+
try:
451+
k8s_core_client.read_namespaced_service_account(XPK_SA, DEFAULT_NAMESPACE)
452+
xpk_print(
453+
f'Service account: {XPK_SA} already exists. Skipping its creation.'
454+
)
455+
return
456+
except ApiException as e:
457+
if e.status != 404:
458+
xpk_print(f'Error reading ServiceAccount {XPK_SA}: {e}')
459+
xpk_exit(1)
460+
450461
xpk_print(f'Creating a new service account: {XPK_SA}')
451462
try:
452463
k8s_core_client.create_namespaced_service_account(
453464
DEFAULT_NAMESPACE, sa, pretty=True
454465
)
455-
xpk_print(f'Created a new service account: {sa} successfully')
456-
except ApiException:
457-
xpk_print(
458-
f'Service account: {XPK_SA} already exists. Skipping its creation'
459-
)
466+
xpk_print(f'Created a new service account: {XPK_SA} successfully')
467+
except ApiException as e:
468+
if e.status == 409:
469+
xpk_print(
470+
f'Service account: {XPK_SA} already exists. Skipping its creation.'
471+
)
472+
else:
473+
xpk_print(f'Error creating ServiceAccount {XPK_SA}: {e}')
474+
xpk_exit(1)
460475

461476

462477
def create_pod_reader_role() -> str:
@@ -466,6 +481,15 @@ def create_pod_reader_role() -> str:
466481
k8s_rbac_client = k8s_client.RbacAuthorizationV1Api()
467482
role_name = 'pod-reader'
468483

484+
try:
485+
k8s_rbac_client.read_namespaced_role(role_name, DEFAULT_NAMESPACE)
486+
xpk_print(f'Role: {role_name} already exists. Skipping its creation.')
487+
return role_name
488+
except ApiException as e:
489+
if e.status != 404:
490+
xpk_print(f'Error reading Role {role_name}: {e}')
491+
xpk_exit(1)
492+
469493
role = k8s_client.V1Role(
470494
metadata=k8s_client.V1ObjectMeta(
471495
name=role_name, namespace=DEFAULT_NAMESPACE
@@ -510,6 +534,20 @@ def create_role_binding(sa: str, role_name: str) -> None:
510534
k8s_rbac_client = k8s_client.RbacAuthorizationV1Api()
511535
role_binding_name = f'{sa}-{role_name}-binding'
512536

537+
try:
538+
k8s_rbac_client.read_namespaced_role_binding(
539+
role_binding_name, DEFAULT_NAMESPACE
540+
)
541+
xpk_print(
542+
f'RoleBinding: {role_binding_name} already exists. Skipping its'
543+
' creation.'
544+
)
545+
return
546+
except ApiException as e:
547+
if e.status != 404:
548+
xpk_print(f'Error reading RoleBinding {role_binding_name}: {e}')
549+
xpk_exit(1)
550+
513551
role_binding = k8s_client.V1RoleBinding(
514552
metadata=k8s_client.V1ObjectMeta(
515553
name=role_binding_name, namespace=DEFAULT_NAMESPACE
@@ -526,16 +564,14 @@ def create_role_binding(sa: str, role_name: str) -> None:
526564

527565
xpk_print(
528566
f'Attempting to create RoleBinding: {role_binding_name} for Service'
529-
f' Account: {XPK_SA} to Role: {role_name} in namespace:'
567+
f' Account: {sa} to Role: {role_name} in namespace:'
530568
f' {DEFAULT_NAMESPACE}'
531569
)
532570
try:
533571
k8s_rbac_client.create_namespaced_role_binding(
534572
DEFAULT_NAMESPACE, role_binding, pretty=True
535573
)
536-
xpk_print(
537-
f'Successfully created RoleBinding: {role_binding_name} for {XPK_SA}'
538-
)
574+
xpk_print(f'Successfully created RoleBinding: {role_binding_name} for {sa}')
539575
except ApiException as e:
540576
if e.status == 409: # Conflict, meaning it already exists
541577
xpk_print(

0 commit comments

Comments
 (0)