]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: fix unncessary traceback when bucket not exist 70034/head
authorNizamudeen A <nia@redhat.com>
Wed, 8 Jul 2026 09:27:33 +0000 (14:57 +0530)
committerNizamudeen A <nia@redhat.com>
Thu, 9 Jul 2026 10:45:19 +0000 (16:15 +0530)
UI has an async validator which calls the GET bucket API to make sure
the bucket name doesn't exist, but the proxy
was not properly handling the http_status_codes which results in raising
a massive traceback in logs whenever you type things in the bucket name
field. So handling that gracefully by capturing the proper status codes
for both RequestException and DashboardException

BEFORE
```
File "/usr/share/ceph/mgr/dashboard/services/exception.py", line 47, in dashboard_exception_handler
return handler(*args, **kwargs)
File "/lib/python3.9/site-packages/cherrypy/_cpdispatch.py", line 54, in _call_
return self.callable(*self.args, **self.kwargs)
File "/usr/share/ceph/mgr/dashboard/controllers/_base_controller.py", line 263, in inner
ret = func(*args, **kwargs)
File "/usr/share/ceph/mgr/dashboard/controllers/_rest_controller.py", line 193, in wrapper
return func(*vpath, **params)
File "/usr/share/ceph/mgr/dashboard/controllers/rgw.py", line 357, in get
result = self.proxy(daemon_name, 'GET', 'bucket', {'bucket': bucket})
File "/usr/share/ceph/mgr/dashboard/controllers/rgw.py", line 213, in proxy
raise DashboardException(e, http_status_code=http_status_code, component='rgw')
dashboard.exceptions.DashboardException: RGW REST API failed request with status code 404
(b'{"Code":"NoSuchBucket","Message":"","RequestId":"tx00000f14e08c1af0d5615-006'
b'71f54a7-3bc6-default","HostId":"3bc6-default-default"}')
2024-10-28T09:08:55.990+0000 7f89e045b640  0 [dashboard INFO request] [::ffff:10.74.18.122:51853] [GET] [500] [0.007s] [admin] [200.0B] /api/rgw/bucket/bucket-das
```

AFTER
```
Jul 08 09:28:28 ceph-node-00 ceph-mgr[2243]: [dashboard ERROR dashboard.rest_client] RGW REST API failed GET req status: 404
Jul 08 09:28:28 ceph-node-00 ceph-mgr[2243]: [dashboard INFO dashboard.services.exception] Dashboard Exception: RGW REST API failed request with status code 404
                                             (b'{"Code":"NoSuchBucket","Message":"","RequestId":"tx00000c029a81e5d154844-006'
                                              b'a4e183c-14251-default","HostId":"14251-default-default"}')
Jul 08 09:28:28 ceph-node-00 ceph-mgr[2243]: [dashboard INFO dashboard.tools] [::ffff:192.168.100.1:60408] [GET] [404] [0.078s] [admin] [200.0B] /api/rgw/bucket/testsa
```

Fixes: https://tracker.ceph.com/issues/78038
Signed-off-by: Nizamudeen A <nia@redhat.com>
qa/tasks/mgr/dashboard/test_rgw.py
src/pybind/mgr/dashboard/controllers/rgw.py
src/pybind/mgr/dashboard/tests/test_rgw.py

index 3f385f79a27f29c45e6553d1a9a21e68ef52eea7..40a294a80db803333973e1063838d0ab25487bfc 100644 (file)
@@ -550,7 +550,7 @@ class RgwUserTest(RgwTestCase):
         self._delete('/api/rgw/user/teuth-test-user')
         self.assertStatus(204)
         self.get_rgw_user('teuth-test-user')
-        self.assertStatus(500)
+        self.assertStatus(404)
         resp = self.jsonBody()
         self.assertIn('detail', resp)
         self.assertIn('failed request with status code 404', resp['detail'])
@@ -593,7 +593,7 @@ class RgwUserTest(RgwTestCase):
         self._delete('/api/rgw/user/test01$teuth-test-user')
         self.assertStatus(204)
         self.get_rgw_user('test01$teuth-test-user')
-        self.assertStatus(500)
+        self.assertStatus(404)
         resp = self.jsonBody()
         self.assertIn('detail', resp)
         self.assertIn('failed request with status code 404', resp['detail'])
index a0ef6965771f394b3da2fe16436608fecba28890..c7f22103bd71fe538cdd173e542ca062fc0fbb85 100755 (executable)
@@ -394,7 +394,11 @@ class RgwRESTController(RESTController):
                 result = json_str_to_object(result)
             return result
         except (DashboardException, RequestException) as e:
-            http_status_code = e.status if isinstance(e, DashboardException) else 500
+            response = getattr(e, 'response', None)
+            if isinstance(e, RequestException) and response is not None:
+                http_status_code = getattr(response, 'status_code', 500)
+            else:
+                http_status_code = getattr(e, 'status_code', getattr(e, 'status', None)) or 500
             raise DashboardException(e, http_status_code=http_status_code, component='rgw')
 
 
index 609d5388fc4dab1bf68306c9610ba733dede50d8..a1e37e6110bc0515f6e0790a0de73b6ba4b0a734 100644 (file)
@@ -2,7 +2,7 @@
 from unittest.mock import Mock, call, patch
 
 from .. import mgr
-from ..controllers.rgw import Rgw, RgwDaemon, RgwTopic, RgwUser
+from ..controllers.rgw import Rgw, RgwBucket, RgwDaemon, RgwTopic, RgwUser
 from ..rest_client import RequestException
 from ..services.rgw_client import RgwClient, RgwMultisite
 from ..tests import ControllerTestCase, RgwStub
@@ -600,3 +600,51 @@ class TestRgwTopicController(ControllerTestCase):
         result = controller.delete(key='RGW22222222222222222:HttpTest')
         mock_delete_topic.assert_called_with(key='RGW22222222222222222:HttpTest')
         self.assertEqual(result, None)
+
+
+class RgwBucketControllerTestCase(ControllerTestCase):
+    @classmethod
+    def setup_server(cls):
+        cls.setup_controllers([RgwBucket], '/test')
+
+    @patch('dashboard.services.rgw_client.RgwClient.admin_instance')
+    def test_get_bucket_not_found(self, mock_admin_instance):
+        mock_instance = Mock()
+        mock_admin_instance.return_value = mock_instance
+
+        mock_response = Mock()
+        mock_response.status_code = 404
+        mock_exception = RequestException('RGW REST API failed request')
+        mock_exception.response = mock_response
+        mock_instance.proxy.side_effect = mock_exception
+
+        self._get('/test/api/rgw/bucket/i-do-not-exist')
+        self.assertStatus(404)
+
+    @patch('dashboard.services.rgw_client.RgwClient.admin_instance')
+    def test_get_bucket_not_found_with_fallback_attribute(self, mock_admin_instance):
+
+        mock_instance = Mock()
+        mock_admin_instance.return_value = mock_instance
+
+        # mock that lacks a .response but has a direct .status_code attribute.
+        mock_exception = RequestException('RGW REST API failed request')
+        mock_exception.status_code = 404
+
+        mock_instance.proxy.side_effect = mock_exception
+
+        self._get('/test/api/rgw/bucket/i-do-not-exist')
+        self.assertStatus(404)
+
+    @patch('dashboard.services.rgw_client.RgwClient.admin_instance')
+    def test_get_bucket_server_error(self, mock_admin_instance):
+        mock_instance = Mock()
+        mock_admin_instance.return_value = mock_instance
+
+        mock_exception = RequestException('Internal Server Error')
+        mock_exception.status_code = 500
+
+        mock_instance.proxy.side_effect = mock_exception
+
+        self._get('/test/api/rgw/bucket/i-do-not-exist')
+        self.assertStatus(500)