mirror of
https://github.com/ceph/ceph
synced 2025-04-11 04:02:04 +00:00
Adds two tabs named 'Devices' on the host and OSD page. The host respectively OSD needs to be selected before the tab will be shown next to the other tabs below the table where the host or OSD has been selected. It will display the graphical representation of `ceph device ls`, filtered by the selected host or OSD. Fixes: https://tracker.ceph.com/issues/39352 Signed-off-by: Patrick Seidensal <pseidensal@suse.com>
167 lines
5.7 KiB
Python
167 lines
5.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from __future__ import absolute_import
|
|
|
|
import json
|
|
|
|
from .helper import DashboardTestCase, JObj, JAny, JList, JLeaf, JTuple
|
|
|
|
|
|
class OsdTest(DashboardTestCase):
|
|
|
|
AUTH_ROLES = ['cluster-manager']
|
|
|
|
def tearDown(self):
|
|
self._post('/api/osd/0/mark_in')
|
|
|
|
@DashboardTestCase.RunAs('test', 'test', ['block-manager'])
|
|
def test_access_permissions(self):
|
|
self._get('/api/osd')
|
|
self.assertStatus(403)
|
|
self._get('/api/osd/0')
|
|
self.assertStatus(403)
|
|
|
|
def assert_in_and_not_none(self, data, properties):
|
|
self.assertSchema(data, JObj({p: JAny(none=False) for p in properties}, allow_unknown=True))
|
|
|
|
def test_list(self):
|
|
data = self._get('/api/osd')
|
|
self.assertStatus(200)
|
|
|
|
self.assertGreaterEqual(len(data), 1)
|
|
data = data[0]
|
|
self.assert_in_and_not_none(data, ['host', 'tree', 'state', 'stats', 'stats_history'])
|
|
self.assert_in_and_not_none(data['host'], ['name'])
|
|
self.assert_in_and_not_none(data['tree'], ['id'])
|
|
self.assert_in_and_not_none(data['stats'], ['numpg', 'stat_bytes_used', 'stat_bytes',
|
|
'op_r', 'op_w'])
|
|
self.assert_in_and_not_none(data['stats_history'], ['op_out_bytes', 'op_in_bytes'])
|
|
self.assertSchema(data['stats_history']['op_out_bytes'],
|
|
JList(JTuple([JLeaf(float), JLeaf(float)])))
|
|
|
|
def test_details(self):
|
|
data = self._get('/api/osd/0')
|
|
self.assertStatus(200)
|
|
self.assert_in_and_not_none(data, ['osd_metadata', 'histogram'])
|
|
self.assert_in_and_not_none(data['histogram'], ['osd'])
|
|
self.assert_in_and_not_none(data['histogram']['osd'], ['op_w_latency_in_bytes_histogram',
|
|
'op_r_latency_out_bytes_histogram'])
|
|
|
|
def test_scrub(self):
|
|
self._post('/api/osd/0/scrub?deep=False')
|
|
self.assertStatus(200)
|
|
|
|
self._post('/api/osd/0/scrub?deep=True')
|
|
self.assertStatus(200)
|
|
|
|
def test_mark_out_and_in(self):
|
|
self._post('/api/osd/0/mark_out')
|
|
self.assertStatus(200)
|
|
|
|
self._post('/api/osd/0/mark_in')
|
|
self.assertStatus(200)
|
|
|
|
def test_mark_down(self):
|
|
self._post('/api/osd/0/mark_down')
|
|
self.assertStatus(200)
|
|
|
|
def test_reweight(self):
|
|
self._post('/api/osd/0/reweight', {'weight': 0.4})
|
|
self.assertStatus(200)
|
|
|
|
def get_reweight_value():
|
|
self._get('/api/osd/0')
|
|
response = self.jsonBody()
|
|
if 'osd_map' in response and 'weight' in response['osd_map']:
|
|
return round(response['osd_map']['weight'], 1)
|
|
self.wait_until_equal(get_reweight_value, 0.4, 10)
|
|
self.assertStatus(200)
|
|
|
|
# Undo
|
|
self._post('/api/osd/0/reweight', {'weight': 1})
|
|
|
|
def test_create_lost_destroy_remove(self):
|
|
# Create
|
|
self._post('/api/osd', {
|
|
'uuid': 'f860ca2e-757d-48ce-b74a-87052cad563f',
|
|
'svc_id': 5
|
|
})
|
|
self.assertStatus(201)
|
|
# Lost
|
|
self._post('/api/osd/5/mark_lost')
|
|
self.assertStatus(200)
|
|
# Destroy
|
|
self._post('/api/osd/5/destroy')
|
|
self.assertStatus(200)
|
|
# Purge
|
|
self._post('/api/osd/5/purge')
|
|
self.assertStatus(200)
|
|
|
|
def test_safe_to_destroy(self):
|
|
osd_dump = json.loads(self._ceph_cmd(['osd', 'dump', '-f', 'json']))
|
|
unused_osd_id = max(map(lambda e: e['osd'], osd_dump['osds'])) + 10
|
|
self._get('/api/osd/{}/safe_to_destroy'.format(unused_osd_id))
|
|
self.assertStatus(200)
|
|
self.assertJsonBody({
|
|
'is_safe_to_destroy': True,
|
|
'active': [],
|
|
'missing_stats': [],
|
|
'safe_to_destroy': [unused_osd_id],
|
|
'stored_pgs': [],
|
|
})
|
|
|
|
def get_destroy_status():
|
|
self._get('/api/osd/0/safe_to_destroy')
|
|
if 'is_safe_to_destroy' in self.jsonBody():
|
|
return self.jsonBody()['is_safe_to_destroy']
|
|
return None
|
|
self.wait_until_equal(get_destroy_status, False, 10)
|
|
self.assertStatus(200)
|
|
|
|
def test_osd_devices(self):
|
|
data = self._get('/api/osd/0/devices')
|
|
self.assertStatus(200)
|
|
self.assertSchema(data, JList(JObj({
|
|
'daemons': JList(str),
|
|
'devid': str,
|
|
'location': JList(JObj({'host': str, 'dev': str}))
|
|
})))
|
|
|
|
|
|
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',
|
|
'pglog_hardlimit'])
|
|
|
|
@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())
|
|
|
|
def test_list_osd_flags(self):
|
|
flags = self._get('/api/osd/flags')
|
|
self.assertStatus(200)
|
|
self.assertEqual(len(flags), 4)
|
|
self.assertEqual(sorted(flags), self._initial_flags)
|
|
|
|
def test_add_osd_flag(self):
|
|
flags = self._put_flags([
|
|
'sortbitwise', 'recovery_deletes', 'purged_snapdirs', 'noout',
|
|
'pause', 'pglog_hardlimit'
|
|
])
|
|
self.assertEqual(flags, sorted([
|
|
'sortbitwise', 'recovery_deletes', 'purged_snapdirs', 'noout',
|
|
'pause', 'pglog_hardlimit'
|
|
]))
|
|
|
|
# Restore flags
|
|
self._put_flags(self._initial_flags)
|