ceph/qa/tasks/mgr/dashboard/test_health.py
Kefu Chai b0bdbc3414 qa/tasks/mgr: partial revert of 'import with full path'
this change partially reverts #34139

using relative import helps with readability and ease the pain to write
down the full parent module name

in #34139, all relative imports were replaced with full path, because we
were using following code to verify if the code is python3 compatible:

```
  mod_spec = importlib.util.spec_from_file_location(mod_name, path)
  mod = importlib.util.module_from_spec(mod_spec)
  mod_spec.loader.exec_module(mod)
```

but this does not work with submodule which can import using relative
import without specifying the name of the package and its parent module.

Signed-off-by: Kefu Chai <kchai@redhat.com>
2020-03-26 14:37:06 +08:00

318 lines
11 KiB
Python

# -*- coding: utf-8 -*-
from __future__ import absolute_import
from .helper import DashboardTestCase, JAny, JLeaf, JList, JObj
class HealthTest(DashboardTestCase):
CEPHFS = True
__pg_info_schema = JObj({
'object_stats': JObj({
'num_objects': int,
'num_object_copies': int,
'num_objects_degraded': int,
'num_objects_misplaced': int,
'num_objects_unfound': int
}),
'pgs_per_osd': float,
'statuses': JObj({}, allow_unknown=True, unknown_schema=int)
})
__mdsmap_schema = JObj({
'session_autoclose': int,
'balancer': str,
'up': JObj({}, allow_unknown=True),
'last_failure_osd_epoch': int,
'in': JList(int),
'last_failure': int,
'max_file_size': int,
'explicitly_allowed_features': int,
'damaged': JList(int),
'tableserver': int,
'failed': JList(int),
'metadata_pool': int,
'epoch': int,
'stopped': JList(int),
'max_mds': int,
'compat': JObj({
'compat': JObj({}, allow_unknown=True),
'ro_compat': JObj({}, allow_unknown=True),
'incompat': JObj({}, allow_unknown=True)
}),
'min_compat_client': str,
'data_pools': JList(int),
'info': JObj({}, allow_unknown=True),
'fs_name': str,
'created': str,
'standby_count_wanted': int,
'enabled': bool,
'modified': str,
'session_timeout': int,
'flags': int,
'ever_allowed_features': int,
'root': int
})
def test_minimal_health(self):
data = self._get('/api/health/minimal')
self.assertStatus(200)
schema = JObj({
'client_perf': JObj({
'read_bytes_sec': int,
'read_op_per_sec': int,
'recovering_bytes_per_sec': int,
'write_bytes_sec': int,
'write_op_per_sec': int
}),
'df': JObj({
'stats': JObj({
'total_avail_bytes': int,
'total_bytes': int,
'total_used_raw_bytes': int,
})
}),
'fs_map': JObj({
'filesystems': JList(
JObj({
'mdsmap': self.__mdsmap_schema
}),
),
'standbys': JList(JObj({}, allow_unknown=True)),
}),
'health': JObj({
'checks': JList(JObj({}, allow_unknown=True)),
'mutes': JList(JObj({}, allow_unknown=True)),
'status': str,
}),
'hosts': int,
'iscsi_daemons': JObj({
'up': int,
'down': int
}),
'mgr_map': JObj({
'active_name': str,
'standbys': JList(JLeaf(dict))
}),
'mon_status': JObj({
'monmap': JObj({
'mons': JList(JLeaf(dict)),
}),
'quorum': JList(int)
}),
'osd_map': JObj({
'osds': JList(
JObj({
'in': int,
'up': int,
})),
}),
'pg_info': self.__pg_info_schema,
'pools': JList(JLeaf(dict)),
'rgw': int,
'scrub_status': str
})
self.assertSchema(data, schema)
def test_full_health(self):
data = self._get('/api/health/full')
self.assertStatus(200)
module_info_schema = JObj({
'can_run': bool,
'error_string': str,
'name': str,
'module_options': JObj(
{},
allow_unknown=True,
unknown_schema=JObj({
'name': str,
'type': str,
'level': str,
'flags': int,
'default_value': str,
'min': str,
'max': str,
'enum_allowed': JList(str),
'see_also': JList(str),
'desc': str,
'long_desc': str,
'tags': JList(str),
})),
})
schema = JObj({
'client_perf': JObj({
'read_bytes_sec': int,
'read_op_per_sec': int,
'recovering_bytes_per_sec': int,
'write_bytes_sec': int,
'write_op_per_sec': int
}),
'df': JObj({
'pools': JList(JObj({
'stats': JObj({
'stored': int,
'stored_data': int,
'stored_omap': int,
'objects': int,
'kb_used': int,
'bytes_used': int,
'data_bytes_used': int,
'omap_bytes_used': int,
'percent_used': float,
'max_avail': int,
'quota_objects': int,
'quota_bytes': int,
'dirty': int,
'rd': int,
'rd_bytes': int,
'wr': int,
'wr_bytes': int,
'compress_bytes_used': int,
'compress_under_bytes': int,
'stored_raw': int
}),
'name': str,
'id': int
})),
'stats': JObj({
'total_avail_bytes': int,
'total_bytes': int,
'total_used_bytes': int,
'total_used_raw_bytes': int,
'total_used_raw_ratio': float,
'num_osds': int,
'num_per_pool_osds': int,
'num_per_pool_omap_osds': int
})
}),
'fs_map': JObj({
'compat': JObj({
'compat': JObj({}, allow_unknown=True, unknown_schema=str),
'incompat': JObj(
{}, allow_unknown=True, unknown_schema=str),
'ro_compat': JObj(
{}, allow_unknown=True, unknown_schema=str)
}),
'default_fscid': int,
'epoch': int,
'feature_flags': JObj(
{}, allow_unknown=True, unknown_schema=bool),
'filesystems': JList(
JObj({
'id': int,
'mdsmap': self.__mdsmap_schema
}),
),
'standbys': JList(JObj({}, allow_unknown=True)),
}),
'health': JObj({
'checks': JList(JObj({}, allow_unknown=True)),
'mutes': JList(JObj({}, allow_unknown=True)),
'status': str,
}),
'hosts': int,
'iscsi_daemons': JObj({
'up': int,
'down': int
}),
'mgr_map': JObj({
'active_addr': str,
'active_addrs': JObj({
'addrvec': JList(JObj({
'addr': str,
'nonce': int,
'type': str
}))
}),
'active_change': str, # timestamp
'active_mgr_features': int,
'active_gid': int,
'active_name': str,
'always_on_modules': JObj({}, allow_unknown=True),
'available': bool,
'available_modules': JList(module_info_schema),
'epoch': int,
'modules': JList(str),
'services': JObj(
{'dashboard': str}, # This module should always be present
allow_unknown=True, unknown_schema=str
),
'standbys': JList(JObj({
'available_modules': JList(module_info_schema),
'gid': int,
'name': str,
'mgr_features': int
}, allow_unknown=True))
}, allow_unknown=True),
'mon_status': JObj({
'election_epoch': int,
'extra_probe_peers': JList(JAny(none=True)),
'feature_map': JObj(
{}, allow_unknown=True, unknown_schema=JList(JObj({
'features': str,
'num': int,
'release': str
}))
),
'features': JObj({
'quorum_con': str,
'quorum_mon': JList(str),
'required_con': str,
'required_mon': JList(str)
}),
'monmap': JObj({
# TODO: expand on monmap schema
'mons': JList(JLeaf(dict)),
}, allow_unknown=True),
'name': str,
'outside_quorum': JList(int),
'quorum': JList(int),
'quorum_age': int,
'rank': int,
'state': str,
# TODO: What type should be expected here?
'sync_provider': JList(JAny(none=True))
}),
'osd_map': JObj({
# TODO: define schema for crush map and osd_metadata, among
# others
'osds': JList(
JObj({
'in': int,
'up': int,
}, allow_unknown=True)),
}, allow_unknown=True),
'pg_info': self.__pg_info_schema,
'pools': JList(JLeaf(dict)),
'rgw': int,
'scrub_status': str
})
self.assertSchema(data, schema)
cluster_pools = self.ceph_cluster.mon_manager.list_pools()
self.assertEqual(len(cluster_pools), len(data['pools']))
for pool in data['pools']:
self.assertIn(pool['pool_name'], cluster_pools)
@DashboardTestCase.RunAs('test', 'test', ['pool-manager'])
def test_health_permissions(self):
data = self._get('/api/health/full')
self.assertStatus(200)
schema = JObj({
'client_perf': JObj({}, allow_unknown=True),
'df': JObj({}, allow_unknown=True),
'health': JObj({
'checks': JList(JObj({}, allow_unknown=True)),
'mutes': JList(JObj({}, allow_unknown=True)),
'status': str
}),
'pools': JList(JLeaf(dict)),
})
self.assertSchema(data, schema)
cluster_pools = self.ceph_cluster.mon_manager.list_pools()
self.assertEqual(len(cluster_pools), len(data['pools']))
for pool in data['pools']:
self.assertIn(pool['pool_name'], cluster_pools)