]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/controllers/health.py
1 # -*- coding: utf-8 -*-
2 from __future__
import absolute_import
7 from ..rest_client
import RequestException
8 from ..security
import Permission
, Scope
9 from ..services
.ceph_service
import CephService
10 from ..services
.iscsi_cli
import IscsiGatewaysConfig
11 from ..services
.iscsi_client
import IscsiClient
12 from ..tools
import partial_dict
13 from . import APIDoc
, APIRouter
, BaseController
, Endpoint
, EndpointDoc
14 from .host
import get_hosts
16 HEALTH_MINIMAL_SCHEMA
= ({
18 'read_bytes_sec': (int, ''),
19 'read_op_per_sec': (int, ''),
20 'recovering_bytes_per_sec': (int, ''),
21 'write_bytes_sec': (int, ''),
22 'write_op_per_sec': (int, ''),
26 'total_avail_bytes': (int, ''),
27 'total_bytes': (int, ''),
28 'total_used_raw_bytes': (int, ''),
34 'session_autoclose': (int, ''),
35 'balancer': (str, ''),
37 'last_failure_osd_epoch': (int, ''),
39 'last_failure': (int, ''),
40 'max_file_size': (int, ''),
41 'explicitly_allowed_features': (int, ''),
42 'damaged': ([int], ''),
43 'tableserver': (int, ''),
44 'failed': ([int], ''),
45 'metadata_pool': (int, ''),
47 'stopped': ([int], ''),
51 'ro_compat': (str, ''),
52 'incompat': (str, ''),
54 'required_client_features': (str, ''),
55 'data_pools': ([int], ''),
59 'standby_count_wanted': (int, ''),
60 'enabled': (bool, ''),
61 'modified': (str, ''),
62 'session_timeout': (int, ''),
64 'ever_allowed_features': (int, ''),
67 'standbys': (str, ''),
81 'active_name': (str, ''),
98 'num_objects': (int, ''),
99 'num_object_copies': (int, ''),
100 'num_objects_degraded': (int, ''),
101 'num_objects_misplaced': (int, ''),
102 'num_objects_unfound': (int, ''),
104 'pgs_per_osd': (int, ''),
105 'statuses': (str, '')
109 'scrub_status': (str, '')
113 class HealthData(object):
115 A class to be used in combination with BaseController to allow either
116 "full" or "minimal" sets of health data to be collected.
118 To function properly, it needs BaseCollector._has_permissions to be passed
119 in as ``auth_callback``.
122 def __init__(self
, auth_callback
, minimal
=True):
123 self
._has
_permissions
= auth_callback
124 self
._minimal
= minimal
126 def all_health(self
):
128 "health": self
.basic_health(),
131 if self
._has
_permissions
(Permission
.READ
, Scope
.MONITOR
):
132 result
['mon_status'] = self
.mon_status()
134 if self
._has
_permissions
(Permission
.READ
, Scope
.CEPHFS
):
135 result
['fs_map'] = self
.fs_map()
137 if self
._has
_permissions
(Permission
.READ
, Scope
.OSD
):
138 result
['osd_map'] = self
.osd_map()
139 result
['scrub_status'] = self
.scrub_status()
140 result
['pg_info'] = self
.pg_info()
142 if self
._has
_permissions
(Permission
.READ
, Scope
.MANAGER
):
143 result
['mgr_map'] = self
.mgr_map()
145 if self
._has
_permissions
(Permission
.READ
, Scope
.POOL
):
146 result
['pools'] = self
.pools()
147 result
['df'] = self
.df()
148 result
['client_perf'] = self
.client_perf()
150 if self
._has
_permissions
(Permission
.READ
, Scope
.HOSTS
):
151 result
['hosts'] = self
.host_count()
153 if self
._has
_permissions
(Permission
.READ
, Scope
.RGW
):
154 result
['rgw'] = self
.rgw_count()
156 if self
._has
_permissions
(Permission
.READ
, Scope
.ISCSI
):
157 result
['iscsi_daemons'] = self
.iscsi_daemons()
161 def basic_health(self
):
162 health_data
= mgr
.get("health")
163 health
= json
.loads(health_data
['json'])
165 # Transform the `checks` dict into a list for the convenience
166 # of rendering from javascript.
168 for k
, v
in health
['checks'].items():
172 checks
= sorted(checks
, key
=lambda c
: c
['severity'])
173 health
['checks'] = checks
176 def client_perf(self
):
177 result
= CephService
.get_client_perf()
179 result
= partial_dict(
181 ['read_bytes_sec', 'read_op_per_sec',
182 'recovering_bytes_per_sec', 'write_bytes_sec',
190 del df
['stats_by_class']
193 df
= dict(stats
=partial_dict(
195 ['total_avail_bytes', 'total_bytes',
196 'total_used_raw_bytes']
201 fs_map
= mgr
.get('fs_map')
203 fs_map
= partial_dict(fs_map
, ['filesystems', 'standbys'])
204 fs_map
['filesystems'] = [partial_dict(item
, ['mdsmap']) for
205 item
in fs_map
['filesystems']]
206 for fs
in fs_map
['filesystems']:
207 mdsmap_info
= fs
['mdsmap']['info']
208 min_mdsmap_info
= dict()
209 for k
, v
in mdsmap_info
.items():
210 min_mdsmap_info
[k
] = partial_dict(v
, ['state'])
213 def host_count(self
):
214 return len(get_hosts())
216 def iscsi_daemons(self
):
219 for gateway_name
in IscsiGatewaysConfig
.get_gateways_config()['gateways']:
221 IscsiClient
.instance(gateway_name
=gateway_name
).ping()
223 except RequestException
:
225 return {'up': up_counter
, 'down': down_counter
}
228 mgr_map
= mgr
.get('mgr_map')
230 mgr_map
= partial_dict(mgr_map
, ['active_name', 'standbys'])
233 def mon_status(self
):
234 mon_status
= json
.loads(mgr
.get('mon_status')['json'])
236 mon_status
= partial_dict(mon_status
, ['monmap', 'quorum'])
237 mon_status
['monmap'] = partial_dict(
238 mon_status
['monmap'], ['mons']
240 mon_status
['monmap']['mons'] = [{}] * \
241 len(mon_status
['monmap']['mons'])
245 osd_map
= mgr
.get('osd_map')
246 assert osd_map
is not None
247 # Not needed, skip the effort of transmitting this to UI
248 del osd_map
['pg_temp']
250 osd_map
= partial_dict(osd_map
, ['osds'])
252 partial_dict(item
, ['in', 'up'])
253 for item
in osd_map
['osds']
256 osd_map
['tree'] = mgr
.get('osd_map_tree')
257 osd_map
['crush'] = mgr
.get('osd_map_crush')
258 osd_map
['crush_map_text'] = mgr
.get('osd_map_crush_map_text')
259 osd_map
['osd_metadata'] = mgr
.get('osd_metadata')
263 return CephService
.get_pg_info()
266 pools
= CephService
.get_pool_list_with_stats()
268 pools
= [{}] * len(pools
)
272 return len(CephService
.get_service_list('rgw'))
274 def scrub_status(self
):
275 return CephService
.get_scrub_status()
278 @APIRouter('/health')
279 @APIDoc("Display Detailed Cluster health Status", "Health")
280 class Health(BaseController
):
283 self
.health_full
= HealthData(self
._has
_permissions
, minimal
=False)
284 self
.health_minimal
= HealthData(self
._has
_permissions
, minimal
=True)
288 return self
.health_full
.all_health()
291 @EndpointDoc("Get Cluster's minimal health report",
292 responses
={200: HEALTH_MINIMAL_SCHEMA
})
294 return self
.health_minimal
.all_health()