]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: add create osd feature in the backend
authorKiefer Chang <kiefer.chang@suse.com>
Tue, 15 Oct 2019 03:18:00 +0000 (11:18 +0800)
committerKiefer Chang <kiefer.chang@suse.com>
Tue, 26 Nov 2019 04:29:45 +0000 (12:29 +0800)
Fixes: https://tracker.ceph.com/issues/40335
Signed-off-by: Kiefer Chang <kiefer.chang@suse.com>
src/pybind/mgr/dashboard/controllers/orchestrator.py
src/pybind/mgr/dashboard/requirements.txt
src/pybind/mgr/dashboard/services/orchestrator.py
src/pybind/mgr/dashboard/tests/test_orchestrator.py

index 06011a4037023bd5b09c63aabfde56f3e4d95ed7..3ddfb2bc118858cfd2baf9142d6970f54c1d4635 100644 (file)
@@ -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')
index eca83046077e6756d101546ccc63f4d2d0ac15a2..0305187216d784e19bd7aebd43eb79e97cb44172 100644 (file)
@@ -8,4 +8,4 @@ python3-saml
 requests
 Routes
 six
-../../../python-common
+../../../python-common
\ No newline at end of file
index 22746e8abd612efa13156aba038d473f511636fe..dfadfeb04d3b4c1909d98e329e4fb25e2269fb66 100644 (file)
@@ -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']
index 9e44ea74fdce6a099e55e220f088fba42971c8bf..7ed687e1eb074247f2539ad70e338a3f8caaeeb5 100644 (file)
@@ -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):