From: Naman Munet Date: Mon, 6 Jul 2026 17:15:22 +0000 (+0530) Subject: mgr/dashboard: Stale RGW user/account metadata cache in mgr after delete and recreate X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=6bf1347dbc2734ccbc6dcc386470b9f9656d842e;p=ceph.git mgr/dashboard: Stale RGW user/account metadata cache in mgr after delete and recreate fixes: https://tracker.ceph.com/issues/77544 Signed-off-by: Naman Munet --- diff --git a/src/pybind/mgr/dashboard/controllers/rgw.py b/src/pybind/mgr/dashboard/controllers/rgw.py index a0ef6965771..61b26c2e734 100755 --- a/src/pybind/mgr/dashboard/controllers/rgw.py +++ b/src/pybind/mgr/dashboard/controllers/rgw.py @@ -1099,8 +1099,15 @@ class RgwUser(RgwRESTController): raise DashboardException(msg='Unable to delete "{}" - this user ' 'account is required for managing the ' 'Object Gateway'.format(uid)) - # Finally redirect request to the RGW proxy. - return self.proxy(daemon_name, 'DELETE', 'user', {'uid': uid}, json_response=False) + daemon_name_to_use = daemon_name if daemon_name else instance.daemon.name + user_instance = RgwClient.get_cached_user_instance(daemon_name_to_use, uid) + result = self.proxy(daemon_name, 'DELETE', 'user', {'uid': uid}, json_response=False) + # Only invalidate cache after successful deletion to prevent negative cache hits + # when the user is recreated with the same UID. This fixes the issue where + # Dashboard fails to authenticate after deleting and recreating a user. + if user_instance: + RgwClient.drop_instance(user_instance) + return result except (DashboardException, RequestException) as e: # pragma: no cover raise DashboardException(e, component='rgw') diff --git a/src/pybind/mgr/dashboard/services/rgw_client.py b/src/pybind/mgr/dashboard/services/rgw_client.py index a36eded72dd..f060efd4fc3 100755 --- a/src/pybind/mgr/dashboard/services/rgw_client.py +++ b/src/pybind/mgr/dashboard/services/rgw_client.py @@ -370,6 +370,20 @@ class RgwClient(RestClient): def admin_instance(daemon_name: Optional[str] = None) -> 'RgwClient': return RgwClient.instance(daemon_name=daemon_name) + @staticmethod + def get_cached_user_instance(daemon_name: str, userid: str) -> Optional['RgwClient']: + """ + Get a cached user instance if it exists. + + :param daemon_name: The daemon name + :param userid: The user ID + :return: The cached RgwClient instance or None if not found + """ + if daemon_name in RgwClient._user_instances and \ + userid in RgwClient._user_instances[daemon_name]: + return RgwClient._user_instances[daemon_name][userid] + return None + @staticmethod def drop_instance(instance: Optional['RgwClient'] = None): """