mgr/dashboard/backend: Enable get/set of cluster-wide OSD settings

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>
This commit is contained in:
Patrick Nawracay 2018-05-15 09:47:19 +02:00
parent 3234db0649
commit d7de1fa067
3 changed files with 81 additions and 2 deletions

View 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

View 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)

View 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)