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
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')
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
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']
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):
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):
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):