From: Sebastian Wagner Date: Wed, 14 Mar 2018 14:51:10 +0000 (+0100) Subject: mgr/dashboard: Add ErasureCodeProfile controller X-Git-Tag: v13.1.0~328^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=7b6a45cc8c28c8a2eda486218a47f97d39861346;p=ceph.git mgr/dashboard: Add ErasureCodeProfile controller Signed-off-by: Sebastian Wagner --- diff --git a/qa/tasks/mgr/dashboard/test_erasure_code_profile.py b/qa/tasks/mgr/dashboard/test_erasure_code_profile.py new file mode 100644 index 00000000000..9cd0e78a238 --- /dev/null +++ b/qa/tasks/mgr/dashboard/test_erasure_code_profile.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +from __future__ import absolute_import + +import unittest + +from .helper import DashboardTestCase, authenticate + + +class ECPTest(DashboardTestCase): + + + @classmethod + def tearDownClass(cls): + super(ECPTest, cls).tearDownClass() + cls._ceph_cmd(['osd', 'erasure-code-profile', 'rm', 'ecp32']) + cls._ceph_cmd(['osd', 'erasure-code-profile', 'rm', 'lrc']) + + @authenticate + def test_list(self): + data = self._get('/api/erasure_code_profile') + self.assertStatus(200) + + default = [p for p in data if p['name'] == 'default'] + if default: + default_ecp = { + 'k': 2, + 'technique': "reed_sol_van", + 'm': 1, + 'name': "default", + 'plugin': "jerasure" + } + if 'crush-failure-domain' in default[0]: + default_ecp['crush-failure-domain'] = default[0]['crush-failure-domain'] + self.assertEqual(default[0], default_ecp) + get_data = self._get('/api/erasure_code_profile/default') + self.assertEqual(get_data, default[0]) + + + @authenticate + def test_create(self): + data = {'name': 'ecp32', 'k': 3, 'm': 2} + self._post('/api/erasure_code_profile', data) + self.assertStatus(201) + + 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" + }) + + self.assertStatus(200) + + self._delete('/api/erasure_code_profile/ecp32') + self.assertStatus(204) + + @authenticate + def test_create_plugin(self): + data = {'name': 'lrc', 'k': '2', 'm': '2', 'l': '2', 'plugin': 'lrc'} + self._post('/api/erasure_code_profile', data) + self.assertJsonBody(None) + self.assertStatus(201) + + 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" + }) + + self.assertStatus(200) + + self._delete('/api/erasure_code_profile/lrc') + self.assertStatus(204) + diff --git a/src/pybind/mgr/dashboard/controllers/erasure_code_profile.py b/src/pybind/mgr/dashboard/controllers/erasure_code_profile.py new file mode 100644 index 00000000000..a6602ebea00 --- /dev/null +++ b/src/pybind/mgr/dashboard/controllers/erasure_code_profile.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +from cherrypy import NotFound + +from . import ApiController, AuthRequired, RESTController +from ..services.ceph_service import CephService +from .. import mgr + + +def _serialize_ecp(name, ecp): + ecp['name'] = name + ecp['k'] = int(ecp['k']) + ecp['m'] = int(ecp['m']) + return ecp + + +@ApiController('erasure_code_profile') +@AuthRequired() +class ErasureCodeProfile(RESTController): + """ + create() supports additional key-value arguments that are passed to the + ECP plugin. + """ + + def list(self): + ret = [] + for name, ecp in mgr.get('osd_map').get('erasure_code_profiles', {}).items(): + ret.append(_serialize_ecp(name, ecp)) + return ret + + def get(self, name): + try: + ecp = mgr.get('osd_map')['erasure_code_profiles'][name] + return _serialize_ecp(name, ecp) + except KeyError: + raise NotFound('No such erasure code profile') + + # pylint: disable=too-many-arguments + @RESTController.args_from_json + 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 + + 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)