@@ -357,3 +357,93 @@ def getMasPublicClusterIssuer(dynClient: DynamicClient, instanceId: str) -> str
357357 except UnauthorizedError as e :
358358 logger .error (f"Error: Unable to retrieve MAS instance due to failed authorization: { e } " )
359359 return None
360+
361+
362+ def getPermissionMode (dynClient : DynamicClient , instanceId : str ) -> str | None :
363+ """
364+ Detect the current RBAC permission mode for a MAS instance.
365+
366+ This function determines whether MAS is installed with cluster-level permissions,
367+ namespace-scoped permissions (essential + non-essential), or minimal essential-only
368+ permissions by checking for the existence of RBAC resources in the cluster.
369+
370+ RBAC Resource Distribution:
371+ - Cluster mode: ClusterRoles + Essential Roles
372+ - Namespaced mode: Essential Roles + Non-essential Roles
373+ - Minimal mode: Essential Roles ONLY
374+
375+ Detection Logic:
376+ 1. Check for ClusterRoles → cluster mode
377+ 2. Check for non-essential openshift-marketplace Role → namespaced mode
378+ 3. No ClusterRole and no openshift-marketplace Role → minimal mode
379+
380+ Args:
381+ dynClient (DynamicClient): OpenShift dynamic client for cluster API interactions.
382+ instanceId (str): The MAS instance identifier.
383+
384+ Returns:
385+ str: Permission mode - "cluster", "namespaced", or "minimal"
386+ Returns None if unable to determine (e.g., no RBAC resources found)
387+ """
388+ try :
389+ # Step 1: Check for ClusterRoles (indicates cluster mode)
390+ clusterRoleAPI = dynClient .resources .get (api_version = "rbac.authorization.k8s.io/v1" , kind = "ClusterRole" )
391+
392+ # Look for MAS ClusterRoles with the instance ID pattern
393+ clusterRoleName = f"mas:{ instanceId } :core:coreapi"
394+ try :
395+ clusterRoleAPI .get (name = clusterRoleName )
396+ logger .info (f"Found ClusterRole '{ clusterRoleName } ' - permission mode is 'cluster'" )
397+ return "cluster"
398+ except NotFoundError :
399+ logger .debug (f"ClusterRole '{ clusterRoleName } ' not found, checking for non-essential Roles" )
400+
401+ # Step 2: Check for non-essential openshift-marketplace Role (only exists in namespaced mode)
402+ roleAPI = dynClient .resources .get (api_version = "rbac.authorization.k8s.io/v1" , kind = "Role" )
403+
404+ # This role only exists in namespaced mode (applied via role-non-essential-core-coreapi-openshift-marketplace.yaml)
405+ marketplaceRoleName = f"mas:{ instanceId } :core:coreapi:openshift-marketplace"
406+ marketplaceNamespace = "openshift-marketplace"
407+
408+ try :
409+ roleAPI .get (name = marketplaceRoleName , namespace = marketplaceNamespace )
410+ logger .info (f"Found non-essential Role '{ marketplaceRoleName } ' in namespace '{ marketplaceNamespace } ' - permission mode is 'namespaced'" )
411+ return "namespaced"
412+ except NotFoundError :
413+ logger .debug ("Non-essential openshift-marketplace Role not found, checking for essential roles" )
414+
415+ # Step 3: Verify minimal mode by checking for essential roles in mas-{instanceId}-core namespace
416+ # Essential roles have pattern: mas:{instanceId}:core:suite:{app}:essential
417+ coreNamespace = f"mas-{ instanceId } -core"
418+
419+ # Try to find at least one essential role to confirm minimal mode
420+ # Check common apps that might be installed
421+ essentialRolePatterns = [
422+ f"mas:{ instanceId } :core:suite:manage:essential" ,
423+ f"mas:{ instanceId } :core:suite:iot:essential" ,
424+ f"mas:{ instanceId } :core:suite:monitor:essential" ,
425+ f"mas:{ instanceId } :core:suite:predict:essential" ,
426+ f"mas:{ instanceId } :core:suite:arcgis:essential" ,
427+ f"mas:{ instanceId } :core:suite:facilities:essential" ,
428+ f"mas:{ instanceId } :core:suite:optimizer:essential" ,
429+ f"mas:{ instanceId } :core:suite:visualinspection:essential"
430+ ]
431+
432+ for essentialRoleName in essentialRolePatterns :
433+ try :
434+ roleAPI .get (name = essentialRoleName , namespace = coreNamespace )
435+ logger .info (f"Found essential Role '{ essentialRoleName } ' in namespace '{ coreNamespace } ' with no non-essential roles - permission mode is 'minimal'" )
436+ return "minimal"
437+ except NotFoundError :
438+ continue
439+
440+ # If we couldn't find any RBAC resources, return None
441+ logger .warning (f"Unable to determine permission mode for instance '{ instanceId } ' " )
442+ return None
443+
444+ except ResourceNotFoundError :
445+ logger .warning ("Required API resources not found in the cluster" )
446+ return None
447+ except UnauthorizedError as e :
448+ logger .error (f"Error: Unable to check permissions due to failed authorization: { e } " )
449+ return None
0 commit comments