]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard/backend: Enable get/set of cluster-wide OSD settings
authorPatrick Nawracay <pnawracay@suse.com>
Tue, 15 May 2018 07:47:19 +0000 (09:47 +0200)
committerPatrick Nawracay <pnawracay@suse.com>
Fri, 15 Jun 2018 08:26:29 +0000 (10:26 +0200)
Add ability to list, set and unset cluster-wide OSD flags.

Flags can be listed and changed through the `/api/osd/flags` API
resource. By using a GET request, the list is retrieved. By using a PUT
request, the flags are updated (all at once). Flags not contained in the
data of the PUT are removed, additional once are added. Note that the
PUT requests require a JSON body with the data contained as value of the
'flags' key like so:

    {"flags": ["flag1", "flag2", ...]}

Fixes: http://tracker.ceph.com/issues/24056
Signed-off-by: Patrick Nawracay <pnawracay@suse.com>
qa/suites/rados/mgr/tasks/dashboard.yaml
qa/tasks/mgr/dashboard/test_osd.py
src/pybind/mgr/dashboard/controllers/osd.py

index 3550ff41badb065f6e94b74d676a7b5cd5292ac0..8a134aad22a8bdf00c10e0fa36338fa221c2a582 100644 (file)
@@ -18,6 +18,7 @@ tasks:
         - \(MDS_DAMAGE\)
         - \(MDS_ALL_DOWN\)
         - \(MDS_UP_LESS_THAN_MAX\)
+        - pauserd,pausewr flag\(s\) set
   - rgw: [client.0]
   - cephfs_test_runner:
       fail_on_skip: false
index c61a8020c739299bf857e174d68c4b3e5d92b3cd..f322544b36f6232134455b0dd52666b6b6a499d1 100644 (file)
@@ -2,6 +2,8 @@
 
 from __future__ import absolute_import
 
+import json
+
 from .helper import DashboardTestCase, authenticate, JObj, JAny, JList, JLeaf, JTuple
 
 
@@ -42,3 +44,42 @@ class OsdTest(DashboardTestCase):
 
         self._post('/api/osd/0/scrub?deep=True')
         self.assertStatus(200)
+
+
+class OsdFlagsTest(DashboardTestCase):
+    def __init__(self, *args, **kwargs):
+        super(OsdFlagsTest, self).__init__(*args, **kwargs)
+        self._initial_flags = sorted(  # These flags cannot be unset
+            ['sortbitwise', 'recovery_deletes', 'purged_snapdirs'])
+
+    @classmethod
+    def _get_cluster_osd_flags(cls):
+        return sorted(
+            json.loads(cls._ceph_cmd(['osd', 'dump',
+                                      '--format=json']))['flags_set'])
+
+    @classmethod
+    def _put_flags(cls, flags):
+        cls._put('/api/osd/flags', data={'flags': flags})
+        return sorted(cls._resp.json())
+
+    @authenticate
+    def test_list_osd_flags(self):
+        flags = self._get('/api/osd/flags')
+        self.assertStatus(200)
+        self.assertEqual(len(flags), 3)
+        self.assertEqual(sorted(flags), self._initial_flags)
+
+    @authenticate
+    def test_add_osd_flag(self):
+        flags = self._put_flags([
+            'sortbitwise', 'recovery_deletes', 'purged_snapdirs', 'noout',
+            'pause'
+        ])
+        self.assertEqual(flags, sorted([
+            'sortbitwise', 'recovery_deletes', 'purged_snapdirs', 'noout',
+            'pause'
+        ]))
+
+        # Restore flags
+        self._put_flags(self._initial_flags)
index 3259649b8e4841fe0a2ab08e0d72a7bc139bc0a5..77b275a0ccc423f0bc97d8fe8dc883c82fd0723d 100644 (file)
@@ -2,8 +2,7 @@
 from __future__ import absolute_import
 
 from . import ApiController, AuthRequired, RESTController
-from .. import mgr
-
+from .. import mgr, logger
 from ..services.ceph_service import CephService
 from ..services.exception import handle_send_command_error
 from ..tools import str_to_bool
@@ -63,3 +62,41 @@ class Osd(RESTController):
     def scrub(self, svc_id, deep=False):
         api_scrub = "osd deep-scrub" if str_to_bool(deep) else "osd scrub"
         CephService.send_command("mon", api_scrub, who=svc_id)
+
+
+@ApiController('/osd/flags')
+class OsdFlagsController(RESTController):
+    @staticmethod
+    def _osd_flags():
+        enabled_flags = mgr.get('osd_map')['flags_set']
+        if 'pauserd' in enabled_flags and 'pausewr' in enabled_flags:
+            # 'pause' is set by calling `ceph osd set pause` and unset by
+            # calling `set osd unset pause`, but `ceph osd dump | jq '.flags'`
+            # will contain 'pauserd,pausewr' if pause is set.
+            # Let's pretend to the API that 'pause' is in fact a proper flag.
+            enabled_flags = list(
+                set(enabled_flags) - {'pauserd', 'pausewr'} | {'pause'})
+        return sorted(enabled_flags)
+
+    def list(self):
+        return self._osd_flags()
+
+    def bulk_set(self, flags):
+        """
+        The `recovery_deletes` and `sortbitwise` flags cannot be unset.
+        `purged_snapshots` cannot even be set. It is therefore required to at
+        least include those three flags for a successful operation.
+        """
+        assert isinstance(flags, list)
+
+        enabled_flags = set(self._osd_flags())
+        data = set(flags)
+        added = data - enabled_flags
+        removed = enabled_flags - data
+        for flag in added:
+            CephService.send_command('mon', 'osd set', '', key=flag)
+        for flag in removed:
+            CephService.send_command('mon', 'osd unset', '', key=flag)
+        logger.info('Changed OSD flags: added=%s removed=%s', added, removed)
+
+        return sorted(enabled_flags - removed | added)