]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Adds ECP info endpoint
authorStephan Müller <smueller@suse.com>
Mon, 17 Sep 2018 07:54:11 +0000 (09:54 +0200)
committerStephan Müller <smueller@suse.com>
Fri, 9 Nov 2018 08:40:39 +0000 (09:40 +0100)
The new info endpoint will provide the frontend with the necessary
information it needs to create new profiles.

Fixes: https://tracker.ceph.com/issues/25156
Signed-off-by: Stephan Müller <smueller@suse.com>
qa/tasks/mgr/dashboard/test_erasure_code_profile.py
src/pybind/mgr/dashboard/controllers/erasure_code_profile.py

index cf5012f8dde4c590cd9ab48ad7971d9ed46fd6e9..2a9bd2e5a0a5e45909f6ff01d51ce805ffa427e4 100644 (file)
@@ -2,9 +2,9 @@
 
 from __future__ import absolute_import
 
-import unittest
+import six
 
-from .helper import DashboardTestCase
+from .helper import DashboardTestCase, JObj, JList
 
 
 class ECPTest(DashboardTestCase):
@@ -13,12 +13,12 @@ class ECPTest(DashboardTestCase):
 
     @DashboardTestCase.RunAs('test', 'test', ['block-manager'])
     def test_read_access_permissions(self):
-        self._get("/api/erasure_code_profile")
+        self._get('/api/erasure_code_profile')
         self.assertStatus(403)
 
     @DashboardTestCase.RunAs('test', 'test', ['read-only'])
     def test_write_access_permissions(self):
-        self._get("/api/erasure_code_profile")
+        self._get('/api/erasure_code_profile')
         self.assertStatus(200)
         data = {'name': 'ecp32', 'k': 3, 'm': 2}
         self._post('/api/erasure_code_profile', data)
@@ -40,10 +40,10 @@ class ECPTest(DashboardTestCase):
         if default:
             default_ecp = {
                 'k': 2,
-                'technique': "reed_sol_van",
+                'technique': 'reed_sol_van',
                 'm': 1,
-                'name': "default",
-                'plugin': "jerasure"
+                'name': 'default',
+                'plugin': 'jerasure'
             }
             if 'crush-failure-domain' in default[0]:
                 default_ecp['crush-failure-domain'] = default[0]['crush-failure-domain']
@@ -59,16 +59,16 @@ class ECPTest(DashboardTestCase):
 
         self._get('/api/erasure_code_profile/ecp32')
         self.assertJsonBody({
-            "crush-device-class": "",
-            "crush-failure-domain": "osd",
-            "crush-root": "default",
-            "jerasure-per-chunk-alignment": "false",
-            "k": 3,
-            "m": 2,
-            "name": "ecp32",
-            "plugin": "jerasure",
-            "technique": "reed_sol_van",
-            "w": "8"
+            'crush-device-class': '',
+            'crush-failure-domain': 'osd',
+            'crush-root': 'default',
+            'jerasure-per-chunk-alignment': 'false',
+            'k': 3,
+            'm': 2,
+            'name': 'ecp32',
+            'plugin': 'jerasure',
+            'technique': 'reed_sol_van',
+            'w': '8'
         })
 
         self.assertStatus(200)
@@ -84,14 +84,14 @@ class ECPTest(DashboardTestCase):
 
         self._get('/api/erasure_code_profile/lrc')
         self.assertJsonBody({
-            "crush-device-class": "",
-            "crush-failure-domain": "host",
-            "crush-root": "default",
-            "k": 2,
-            "l": "2",
-            "m": 2,
-            "name": "lrc",
-            "plugin": "lrc"
+            'crush-device-class': '',
+            'crush-failure-domain': 'host',
+            'crush-root': 'default',
+            'k': 2,
+            'l': '2',
+            'm': 2,
+            'name': 'lrc',
+            'plugin': 'lrc'
         })
 
         self.assertStatus(200)
@@ -99,3 +99,13 @@ class ECPTest(DashboardTestCase):
         self._delete('/api/erasure_code_profile/lrc')
         self.assertStatus(204)
 
+    def test_ecp_info(self):
+        self._get('/api/erasure_code_profile/_info')
+        self.assertSchemaBody(JObj({
+            'names': JList(six.string_types),
+            'failure_domains': JList(six.string_types),
+            'plugins': JList(six.string_types),
+            'devices': JList(six.string_types),
+            'directory': six.string_types,
+        }))
+
index 688fbf783547ff1d3b6250ed44c4746b37bd0631..742604beb6307a121aa4fe61c8f782704e428488 100644 (file)
@@ -3,25 +3,30 @@ from __future__ import absolute_import
 
 from cherrypy import NotFound
 
-from . import ApiController, RESTController
+from . import ApiController, RESTController, Endpoint, ReadPermission
 from ..security import Scope
 from ..services.ceph_service import CephService
 from .. import mgr
 
 
 def _serialize_ecp(name, ecp):
+    def serialize_numbers(key):
+        value = ecp.get(key)
+        if value is not None:
+            ecp[key] = int(value)
+
     ecp['name'] = name
-    ecp['k'] = int(ecp['k'])
-    ecp['m'] = int(ecp['m'])
+    serialize_numbers('k')
+    serialize_numbers('m')
     return ecp
 
 
 @ApiController('/erasure_code_profile', Scope.POOL)
 class ErasureCodeProfile(RESTController):
-    """
+    '''
     create() supports additional key-value arguments that are passed to the
     ECP plugin.
-    """
+    '''
 
     def list(self):
         ret = []
@@ -36,17 +41,26 @@ class ErasureCodeProfile(RESTController):
         except KeyError:
             raise NotFound('No such erasure code profile')
 
-    def create(self, name, k, m, plugin=None, ruleset_failure_domain=None, **kwargs):
-        kwargs['k'] = k
-        kwargs['m'] = m
-        if plugin:
-            kwargs['plugin'] = plugin
-        if ruleset_failure_domain:
-            kwargs['ruleset_failure_domain'] = ruleset_failure_domain
-
+    def create(self, name, **kwargs):
         profile = ['{}={}'.format(key, value) for key, value in kwargs.items()]
         CephService.send_command('mon', 'osd erasure-code-profile set', name=name,
                                  profile=profile)
 
     def delete(self, name):
         CephService.send_command('mon', 'osd erasure-code-profile rm', name=name)
+
+    @Endpoint()
+    @ReadPermission
+    def _info(self):
+        '''Used for profile creation and editing'''
+        config = mgr.get('config')
+        osd_map_crush = mgr.get('osd_map_crush')
+        return {
+            # Because 'shec' is experimental it's not included
+            'plugins': config['osd_erasure_code_plugins'].split() + ['shec'],
+            'directory': config['erasure_code_dir'],
+            'devices': list(set([device['class'] for device in osd_map_crush['devices']])),
+            'failure_domains': [domain['name'] for domain in osd_map_crush['types']],
+            'names': [name for name, _ in
+                      mgr.get('osd_map').get('erasure_code_profiles', {}).items()]
+        }