]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: introduce dashboard setting to resolve rgw hostname 62596/head
authorNizamudeen A <nia@redhat.com>
Tue, 1 Apr 2025 07:18:23 +0000 (12:48 +0530)
committerNizamudeen A <nia@redhat.com>
Wed, 2 Apr 2025 08:04:52 +0000 (13:34 +0530)
drops using the `rgw_dns_name` to resolve the rgw hosts in dashboard and
introduces a command `ceph dashboard set-rgw-hostname <daemon>
<hostname>` to set custom dns names for each gateways. Once set
dashboard will pick up that address for the selected gateway.

And a config can be unset by

`ceph dashboard unset-rgw-hostname <daemon>`

Fixes: https://tracker.ceph.com/issues/70744
Signed-off-by: Nizamudeen A <nia@redhat.com>
doc/mgr/dashboard.rst
src/pybind/mgr/dashboard/module.py
src/pybind/mgr/dashboard/services/rgw_client.py
src/pybind/mgr/dashboard/services/service.py
src/pybind/mgr/dashboard/settings.py
src/pybind/mgr/dashboard/tests/test_rgw_client.py

index 32824fab4b52686e086310f39e4ce2b4a90ee4d3..76e815cdb466e9b9b87d3b0ba51f8e456947e067 100644 (file)
@@ -429,6 +429,19 @@ the host name:
 
    ceph dashboard set-rgw-api-ssl-verify False
 
+To set a custom hostname or address for an RGW gateway, set the value of ``RGW_HOSTNAME_PER_DAEMON``
+accordingly:
+
+.. promt:: bash $
+
+   ceph dashboard set-rgw-hostname <gateway_name> <hostname>
+
+The setting can be unset using:
+
+.. promt:: bash $
+
+   ceph dashboard unset-rgw-hostname <gateway_name>
+
 If the Object Gateway takes too long to process requests and the dashboard runs
 into timeouts, you can set the timeout value to your needs:
 
index 846401f76fc7113448ebcddddcdae814aac39142..295403f6fe3389bc881f4211b017bc99ffc1193d 100644 (file)
@@ -429,6 +429,24 @@ class Module(MgrModule, CherryPyConfig):
 
         return 0, 'RGW credentials configured', ''
 
+    @CLIWriteCommand("dashboard set-rgw-hostname")
+    def set_rgw_hostname(self, daemon_name: str, hostname: str):
+        try:
+            rgw_service_manager = RgwServiceManager()
+            rgw_service_manager.set_rgw_hostname(daemon_name, hostname)
+            return 0, f'RGW hostname for daemon {daemon_name} configured', ''
+        except Exception as error:
+            return -errno.EINVAL, '', str(error)
+
+    @CLIWriteCommand("dashboard unset-rgw-hostname")
+    def unset_rgw_hostname(self, daemon_name: str):
+        try:
+            rgw_service_manager = RgwServiceManager()
+            rgw_service_manager.unset_rgw_hostname(daemon_name)
+            return 0, f'RGW hostname for daemon {daemon_name} resetted', ''
+        except Exception as error:
+            return -errno.EINVAL, '', str(error)
+
     @CLIWriteCommand("dashboard set-login-banner")
     def set_login_banner(self, inbuf: str):
         '''
index ce33e37a18ff452de1660e6f0886958bf105ff05..fb633726805f7ea3d413b36ee9cd82c7cccc1a29 100755 (executable)
@@ -22,7 +22,7 @@ try:
 except ModuleNotFoundError:
     logging.error("Module 'xmltodict' is not installed.")
 
-from mgr_util import build_url, name_to_config_section
+from mgr_util import build_url
 
 from .. import mgr
 from ..awsauth import S3Auth
@@ -100,9 +100,12 @@ def _determine_rgw_addr(daemon_info: Dict[str, Any]) -> RgwDaemon:
     Parse RGW daemon info to determine the configured host (IP address) and port.
     """
     daemon = RgwDaemon()
-    rgw_dns_name = CephService.send_command('mon', 'config get',
-                                            who=name_to_config_section('rgw.' + daemon_info['metadata']['id']),  # noqa E501 #pylint: disable=line-too-long
-                                            key='rgw_dns_name').rstrip()
+    rgw_dns_name = ''
+    if (
+        Settings.RGW_HOSTNAME_PER_DAEMON
+        and daemon_info['metadata']['id'] in Settings.RGW_HOSTNAME_PER_DAEMON
+    ):
+        rgw_dns_name = Settings.RGW_HOSTNAME_PER_DAEMON[daemon_info['metadata']['id']]
 
     daemon.port, daemon.ssl = _parse_frontend_config(daemon_info['metadata']['frontend_config#0'])
 
@@ -279,7 +282,9 @@ class RgwClient(RestClient):
         return (Settings.RGW_API_ACCESS_KEY,
                 Settings.RGW_API_SECRET_KEY,
                 Settings.RGW_API_ADMIN_RESOURCE,
-                Settings.RGW_API_SSL_VERIFY)
+                Settings.RGW_API_SSL_VERIFY,
+                Settings.RGW_HOSTNAME_PER_DAEMON
+                )
 
     @staticmethod
     def instance(userid: Optional[str] = None,
index 679e2919b7df2cb38e71cf5fdc887c512f00f2b5..057b6f03ef7c62ef45db7acefec77e721afba786 100644 (file)
@@ -204,3 +204,20 @@ class RgwServiceManager:
         except (AssertionError, SubprocessError) as error:
             logger.exception(error)
             raise NoCredentialsException
+
+    def set_rgw_hostname(self, daemon_name: str, hostname: str):
+        if not Settings.RGW_HOSTNAME_PER_DAEMON:
+            Settings.RGW_HOSTNAME_PER_DAEMON = {daemon_name: hostname}
+            return
+
+        rgw_hostname_setting = Settings.RGW_HOSTNAME_PER_DAEMON
+        rgw_hostname_setting[daemon_name] = hostname
+        Settings.RGW_HOSTNAME_PER_DAEMON = rgw_hostname_setting
+
+    def unset_rgw_hostname(self, daemon_name: str):
+        if not Settings.RGW_HOSTNAME_PER_DAEMON:
+            return
+
+        rgw_hostname_setting = Settings.RGW_HOSTNAME_PER_DAEMON
+        rgw_hostname_setting.pop(daemon_name, None)
+        Settings.RGW_HOSTNAME_PER_DAEMON = rgw_hostname_setting
index e98383070e29c4878ea5f29d49188ad5a214f348..9cb1e3de289a8b425f87e8177820e1838e46b891 100644 (file)
@@ -67,6 +67,7 @@ class Options(object):
     RGW_API_SECRET_KEY = Setting('', [dict, str])
     RGW_API_ADMIN_RESOURCE = Setting('admin', [str])
     RGW_API_SSL_VERIFY = Setting(True, [bool])
+    RGW_HOSTNAME_PER_DAEMON = Setting('', [dict, str])
 
     # Ceph Issue Tracker API Access Key
     ISSUE_TRACKER_API_KEY = Setting('', [str])
index f2d34ca5458c13c9251e4dc8e0ae0432932c0e85..898803dd29a66300579de7551d3051f088057beb 100644 (file)
@@ -6,7 +6,8 @@ from unittest.mock import Mock, patch
 
 from .. import mgr
 from ..exceptions import DashboardException
-from ..services.rgw_client import NoRgwDaemonsException, RgwClient, _parse_frontend_config
+from ..services.rgw_client import NoRgwDaemonsException, RgwClient, \
+    _determine_rgw_addr, _parse_frontend_config
 from ..services.service import NoCredentialsException
 from ..settings import Settings
 from ..tests import CLICommandTestMixin, RgwStub
@@ -273,6 +274,57 @@ class RgwClientTest(TestCase, CLICommandTestMixin):
                 retention_period_years=years
             ))
 
+    def test_set_rgw_hostname(self):
+        result = self.exec_cmd(
+            'set-rgw-hostname',
+            daemon_name='test_daemon',
+            hostname='example.hostname.com'
+        )
+        self.assertEqual(
+            result,
+            'RGW hostname for daemon test_daemon configured'
+        )
+        self.assertEqual(
+            Settings.RGW_HOSTNAME_PER_DAEMON,
+            {'test_daemon': 'example.hostname.com'}
+        )
+
+    @patch("dashboard.services.rgw_client.RgwDaemon")
+    def test_hostname_when_rgw_hostname_config_is_set(self, mock_daemons):
+        mock_instance = Mock()
+        mock_daemons.return_value = mock_instance
+
+        self.test_set_rgw_hostname()
+
+        daemon_info = {
+            'metadata': {
+                'id': 'test_daemon',
+                'hostname': 'my-hostname.com',
+                'frontend_config#0': 'beast port=8000'
+            },
+            'addr': '192.0.2.1'
+        }
+
+        result = _determine_rgw_addr(daemon_info)
+        self.assertEqual(result.host, "example.hostname.com")
+
+    @patch("dashboard.services.rgw_client.RgwDaemon")
+    def test_hostname_when_rgw_hostname_config_is_not_set(self, mock_daemons):
+        mock_instance = Mock()
+        mock_daemons.return_value = mock_instance
+
+        daemon_info = {
+            'metadata': {
+                'id': 'test_daemon',
+                'hostname': 'my.hostname.com',
+                'frontend_config#0': 'beast port=8000'
+            },
+            'addr': '192.168.178.3:49774/1534999298'
+        }
+
+        result = _determine_rgw_addr(daemon_info)
+        self.assertEqual(result.host, "192.168.178.3")
+
 
 class RgwClientHelperTest(TestCase):
     def test_parse_frontend_config_1(self):