From: Patrick Nawracay Date: Mon, 5 Feb 2018 10:15:06 +0000 (+0100) Subject: mgr/dashboard_v2: Migrate RGW daemon REST resource X-Git-Tag: wip-pdonnell-testing-20180317.202121~127^2~91 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=3913d54dae2c2b4f59ef9a488c65735673a63c9a;p=ceph-ci.git mgr/dashboard_v2: Migrate RGW daemon REST resource Signed-off-by: Patrick Nawracay --- diff --git a/src/pybind/mgr/dashboard_v2/controllers/rgw.py b/src/pybind/mgr/dashboard_v2/controllers/rgw.py new file mode 100644 index 00000000000..3ee8fcb9085 --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/controllers/rgw.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +import json + +from ..tools import ApiController, RESTController, AuthRequired +from .. import logger + + +@ApiController('rgw') +@AuthRequired() +class Rgw(RESTController): + + def __init__(self): + self.daemon = RgwDaemon(self.mgr) + + +class RgwDaemon(RESTController): + + def __init__(self, mgr): + RgwDaemon.mgr = mgr + + def list(self): + daemons = [] + for server in self.mgr.list_servers(): + for service in server['services']: + if service['type'] == 'rgw': + metadata = self.mgr.get_metadata('rgw', service['id']) + status = self.mgr.get_daemon_status('rgw', service['id']) + if 'json' in status: + try: + status = json.loads(status['json']) + except ValueError: + logger.warning("%s had invalid status json", service['id']) + status = {} + else: + logger.warning('%s has no key "json" in status', service['id']) + + # extract per-daemon service data and health + daemon = { + 'id': service['id'], + 'version': metadata['ceph_version'], + 'server_hostname': server['hostname'] + } + + daemons.append(daemon) + + return sorted(daemons, key=lambda k: k['id']) + + def get(self, svc_id): + daemon = { + 'rgw_metadata': [], + 'rgw_id': svc_id, + 'rgw_status': [] + } + for server in self.mgr.list_servers(): + for service in server['services']: + if service['type'] == 'rgw' and service['id'] == svc_id: + metadata = self.mgr.get_metadata('rgw', service['id']) + status = self.mgr.get_daemon_status('rgw', service['id']) + if 'json' in status: + try: + status = json.loads(status['json']) + except ValueError: + logger.warning("%s had invalid status json", service['id']) + status = {} + else: + logger.warning('%s has no key "json" in status', service['id']) + + daemon['rgw_metadata'] = metadata + daemon['rgw_status'] = status + + break + return daemon diff --git a/src/pybind/mgr/dashboard_v2/module.py b/src/pybind/mgr/dashboard_v2/module.py index 2e4cb97389b..5643e1bb328 100644 --- a/src/pybind/mgr/dashboard_v2/module.py +++ b/src/pybind/mgr/dashboard_v2/module.py @@ -6,6 +6,10 @@ from __future__ import absolute_import import errno import os +try: + from urlparse import urljoin +except ImportError: + from urllib.parse import urljoin import cherrypy from mgr_module import MgrModule @@ -41,9 +45,14 @@ class Module(MgrModule): } ] + @property + def url_prefix(self): + return self._url_prefix + def __init__(self, *args, **kwargs): super(Module, self).__init__(*args, **kwargs) logger.logger = self._logger + self._url_prefix = '' def configure_cherrypy(self, in_unittest=False): server_addr = self.get_localized_config('server_addr', '::') @@ -56,6 +65,16 @@ class Module(MgrModule): self.log.info('server_addr: %s server_port: %s', server_addr, server_port) + def prepare_url_prefix(url_prefix): + """ + return '' if no prefix, or '/prefix' without slash in the end. + """ + url_prefix = urljoin('/', url_prefix) + return url_prefix.rstrip('/') + + self._url_prefix = prepare_url_prefix(self.get_config('url_prefix', + default='')) + # Initialize custom handlers. cherrypy.tools.authenticate = cherrypy.Tool('before_handler', Auth.check_auth) cherrypy.tools.session_expire_at_browser_close = SessionExpireAtBrowserCloseTool() diff --git a/src/pybind/mgr/dashboard_v2/tests/test_rgw.py b/src/pybind/mgr/dashboard_v2/tests/test_rgw.py new file mode 100644 index 00000000000..aac4798c74e --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/tests/test_rgw.py @@ -0,0 +1,65 @@ +from mock import Mock +import cherrypy +from ..controllers.rgw import RgwDaemon +from .helper import ControllerTestCase + +mocked_servers = [{ + 'ceph_version': 'ceph version 13.0.0-5083-g8d1965af24 ' + + '(8d1965af241a5a5487e1b2e3684c676c47392be9) ' + + 'mimic (dev)', + 'hostname': 'ceph-dev', + 'services': [{'id': 'a', 'type': 'mds'}, + {'id': 'b', 'type': 'mds'}, + {'id': 'c', 'type': 'mds'}, + {'id': 'a', 'type': 'mon'}, + {'id': 'b', 'type': 'mon'}, + {'id': 'c', 'type': 'mon'}, + {'id': '0', 'type': 'osd'}, + {'id': '1', 'type': 'osd'}, + {'id': '2', 'type': 'osd'}, + {'id': 'rgw', 'type': 'rgw'}]}] + +mocked_metadata = { + 'arch': 'x86_64', + 'ceph_version': 'ceph version 13.0.0-5083-g8d1965af24 ' + + '(8d1965af241a5a5487e1b2e3684c676c47392be9) mimic (dev)', + 'cpu': 'Intel(R) Core(TM)2 Quad CPU Q9550 @ 2.83GHz', + 'distro': 'opensuse', + 'distro_description': 'openSUSE Tumbleweed', + 'distro_version': '20180202', + 'frontend_config#0': 'civetweb port=8000', + 'frontend_type#0': 'civetweb', + 'hostname': 'ceph-dev', + 'kernel_description': '#135-Ubuntu SMP Fri Jan 19 11:48:36 UTC 2018', + 'kernel_version': '4.4.0-112-generic', + 'mem_swap_kb': '6287356', + 'mem_total_kb': '8173856', + 'num_handles': '1', + 'os': 'Linux', + 'pid': '979', + 'zone_id': '850fbec4-9238-481d-9044-c8048f4d582e', + 'zone_name': 'default', + 'zonegroup_id': '47e10f8e-5801-4d4d-802c-fc32a252c0ba', + 'zonegroup_name': 'default'} + + +class RgwControllerTest(ControllerTestCase): + + @classmethod + def setup_test(cls): + mgr_mock = Mock() + mgr_mock.list_servers.return_value = mocked_servers + mgr_mock.get_metadata.return_value = mocked_metadata + mgr_mock.get_daemon_status.return_value = {'current_sync': []} + mgr_mock.url_prefix = '' + + cherrypy.tree.mount(RgwDaemon(mgr_mock), "/api/test/rgw") + + def test_list(self): + self._get('/api/test/rgw') + self.assertStatus(200) + self.assertJsonBody([{ + 'id': 'rgw', + 'version': mocked_servers[0]['ceph_version'], + 'server_hostname': mocked_servers[0]['hostname'] + }])