From: Kiefer Chang Date: Tue, 15 Oct 2019 03:18:00 +0000 (+0800) Subject: mgr/dashboard: add create osd feature in the backend X-Git-Tag: v15.1.0~727^2~2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=e064244b4a43fa5fcee92c5dac9aea2e3ba3d6f7;p=ceph-ci.git mgr/dashboard: add create osd feature in the backend Fixes: https://tracker.ceph.com/issues/40335 Signed-off-by: Kiefer Chang --- diff --git a/src/pybind/mgr/dashboard/controllers/orchestrator.py b/src/pybind/mgr/dashboard/controllers/orchestrator.py index 06011a40370..3ddfb2bc118 100644 --- a/src/pybind/mgr/dashboard/controllers/orchestrator.py +++ b/src/pybind/mgr/dashboard/controllers/orchestrator.py @@ -2,10 +2,12 @@ from __future__ import absolute_import import cherrypy +from ceph.deployment.drive_group import DriveGroupSpec, DriveGroupValidationError from . import ApiController, Endpoint, ReadPermission from . import RESTController, Task from .. import mgr +from ..exceptions import DashboardException from ..security import Scope from ..services.orchestrator import OrchClient from ..tools import wraps @@ -94,3 +96,15 @@ class OrchestratorService(RESTController): def list(self, hostname=None): orch = OrchClient.instance() return [service.to_json() for service in orch.services.list(None, None, hostname)] + + +@ApiController('/orchestrator/osd', Scope.OSD) +class OrchestratorOsd(RESTController): + + @raise_if_no_orchestrator + def create(self, drive_group, all_hosts=None): + orch = OrchClient.instance() + try: + orch.osds.create(DriveGroupSpec.from_json(drive_group), all_hosts) + except (ValueError, TypeError, DriveGroupValidationError) as e: + raise DashboardException(e, component='osd') diff --git a/src/pybind/mgr/dashboard/requirements.txt b/src/pybind/mgr/dashboard/requirements.txt index eca83046077..0305187216d 100644 --- a/src/pybind/mgr/dashboard/requirements.txt +++ b/src/pybind/mgr/dashboard/requirements.txt @@ -8,4 +8,4 @@ python3-saml requests Routes six -../../../python-common +../../../python-common \ No newline at end of file diff --git a/src/pybind/mgr/dashboard/services/orchestrator.py b/src/pybind/mgr/dashboard/services/orchestrator.py index 22746e8abd6..dfadfeb04d3 100644 --- a/src/pybind/mgr/dashboard/services/orchestrator.py +++ b/src/pybind/mgr/dashboard/services/orchestrator.py @@ -86,6 +86,13 @@ class ServiceManager(ResourceManager): raise_if_exception(c) +class OsdManager(ResourceManager): + + @wait_api_result + def create(self, drive_group, all_hosts=None): + return self.api.create_osds(drive_group, all_hosts) + + class OrchClient(object): _instance = None @@ -102,6 +109,7 @@ class OrchClient(object): self.hosts = HostManger(self.api) self.inventory = InventoryManager(self.api) self.services = ServiceManager(self.api) + self.osds = OsdManager(self.api) def available(self): return self.status()['available'] diff --git a/src/pybind/mgr/dashboard/tests/test_orchestrator.py b/src/pybind/mgr/dashboard/tests/test_orchestrator.py index 9e44ea74fdc..7ed687e1eb0 100644 --- a/src/pybind/mgr/dashboard/tests/test_orchestrator.py +++ b/src/pybind/mgr/dashboard/tests/test_orchestrator.py @@ -8,16 +8,18 @@ from orchestrator import InventoryNode, ServiceDescription from . import ControllerTestCase from .. import mgr +from ..controllers.orchestrator import get_device_osd_map from ..controllers.orchestrator import Orchestrator from ..controllers.orchestrator import OrchestratorInventory +from ..controllers.orchestrator import OrchestratorOsd from ..controllers.orchestrator import OrchestratorService -from ..controllers.orchestrator import get_device_osd_map class OrchestratorControllerTest(ControllerTestCase): URL_STATUS = '/api/orchestrator/status' URL_INVENTORY = '/api/orchestrator/inventory' URL_SERVICE = '/api/orchestrator/service' + URL_OSD = '/api/orchestrator/osd' @classmethod def setup_server(cls): @@ -25,7 +27,11 @@ class OrchestratorControllerTest(ControllerTestCase): Orchestrator._cp_config['tools.authenticate.on'] = False OrchestratorInventory._cp_config['tools.authenticate.on'] = False OrchestratorService._cp_config['tools.authenticate.on'] = False - cls.setup_controllers([Orchestrator, OrchestratorInventory, OrchestratorService]) + OrchestratorOsd._cp_config['tools.authenticate.on'] = False + cls.setup_controllers([Orchestrator, + OrchestratorInventory, + OrchestratorService, + OrchestratorOsd]) @mock.patch('dashboard.controllers.orchestrator.OrchClient.instance') def test_status_get(self, instance): @@ -165,6 +171,28 @@ class OrchestratorControllerTest(ControllerTestCase): self._get(self.URL_SERVICE) self.assertStatus(503) + @mock.patch('dashboard.controllers.orchestrator.OrchClient.instance') + def test_osd_create(self, instance): + # with orchestrator service + fake_client = mock.Mock() + fake_client.available.return_value = False + instance.return_value = fake_client + self._post(self.URL_OSD, {}) + self.assertStatus(503) + + # without orchestrator service + fake_client.available.return_value = True + # incorrect drive group + self._post(self.URL_OSD, {'drive_group': {}}) + self.assertStatus(400) + + # correct drive group + dg = { + 'host_pattern': '*' + } + self._post(self.URL_OSD, {'drive_group': dg}) + self.assertStatus(201) + class TestOrchestrator(unittest.TestCase): def test_get_device_osd_map(self):