From 495ff0a2cf1713312deba3b61da6d213019fc920 Mon Sep 17 00:00:00 2001 From: Volker Theile Date: Wed, 2 Dec 2020 17:14:45 +0100 Subject: [PATCH] mgr/dashboard: Drop invalid RGW client instances, improve logging * Log RGW settings for easier problem tracking. * Drop RGW client instances that do not exist anymore. This happens when a RGW service is removed via the orchestrator. The Dashboard tries to access the RGW client using the previous settings which leads to an error which might be confusing. Without dropping the error message 'RGW REST API failed request ...' is displayed instead of the correct one 'No RGW found'. Dropping the RGW client instance will produce correct error messages the next time the backend tries to establish a new connection. Fixes: https://tracker.ceph.com/issues/48586 Signed-off-by: Volker Theile --- src/pybind/mgr/dashboard/controllers/rgw.py | 14 ++++++++++- .../mgr/dashboard/services/rgw_client.py | 24 ++++++++++++++----- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/pybind/mgr/dashboard/controllers/rgw.py b/src/pybind/mgr/dashboard/controllers/rgw.py index 984c8622d9bd1..59ed06aa24ba5 100644 --- a/src/pybind/mgr/dashboard/controllers/rgw.py +++ b/src/pybind/mgr/dashboard/controllers/rgw.py @@ -51,7 +51,19 @@ class Rgw(BaseController): try: instance = RgwClient.admin_instance() # Check if the service is online. - if not instance.is_service_online(): # pragma: no cover - no complexity there + try: + is_online = instance.is_service_online() + except RequestException as e: + # Drop this instance because the RGW client seems not to + # exist anymore (maybe removed via orchestrator). Removing + # the instance from the cache will result in the correct + # error message next time when the backend tries to + # establish a new connection (-> 'No RGW found' instead + # of 'RGW REST API failed request ...'). + # Note, this only applies to auto-detected RGW clients. + RgwClient.drop_instance(instance.userid) + raise e + if not is_online: msg = 'Failed to connect to the Object Gateway\'s Admin Ops API.' raise RequestException(msg) # Ensure the API user ID is known by the RGW. diff --git a/src/pybind/mgr/dashboard/services/rgw_client.py b/src/pybind/mgr/dashboard/services/rgw_client.py index 2355bbbc1ffe8..54b26a7a3a1a3 100644 --- a/src/pybind/mgr/dashboard/services/rgw_client.py +++ b/src/pybind/mgr/dashboard/services/rgw_client.py @@ -15,7 +15,7 @@ from ..settings import Options, Settings from ..tools import build_url, dict_contains_path, dict_get, json_str_to_object try: - from typing import Any, Dict, List, Optional + from typing import Any, Dict, List, Optional, Tuple except ImportError: pass # For typing only @@ -88,19 +88,21 @@ def _get_daemon_info() -> Dict[str, Any]: return daemon -def _determine_rgw_addr(): +def _determine_rgw_addr() -> Tuple[str, int, bool]: """ Parse RGW daemon info to determine the configured host (IP address) and port. """ daemon = _get_daemon_info() - addr = _parse_addr(daemon['addr']) port, ssl = _parse_frontend_config(daemon['metadata']['frontend_config#0']) + logger.info('Auto-detected RGW configuration: addr=%s, port=%d, ssl=%s', + addr, port, str(ssl)) + return addr, port, ssl -def _parse_addr(value): +def _parse_addr(value) -> str: """ Get the IP address the RGW is running on. @@ -154,7 +156,7 @@ def _parse_addr(value): raise LookupError('Failed to determine RGW address') -def _parse_frontend_config(config): +def _parse_frontend_config(config) -> Tuple[int, bool]: """ Get the port the RGW is running on. Due the complexity of the syntax not all variations are supported. @@ -270,7 +272,7 @@ class RgwClient(RestClient): # Discard all cached instances if any rgw setting has changed if RgwClient._rgw_settings_snapshot != RgwClient._rgw_settings(): RgwClient._rgw_settings_snapshot = RgwClient._rgw_settings() - RgwClient._user_instances.clear() + RgwClient.drop_instance() if not RgwClient._user_instances: RgwClient._load_settings() @@ -297,6 +299,16 @@ class RgwClient(RestClient): def admin_instance(): return RgwClient.instance(RgwClient._SYSTEM_USERID) + @staticmethod + def drop_instance(userid: Optional[str] = None): + """ + Drop a cached instance by name or all. + """ + if userid: + RgwClient._user_instances.pop(userid, None) + else: + RgwClient._user_instances.clear() + def _reset_login(self): if self.userid != RgwClient._SYSTEM_USERID: logger.info("Fetching new keys for user: %s", self.userid) -- 2.39.5