]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/controllers/health.py
import 15.2.9
[ceph.git] / ceph / src / pybind / mgr / dashboard / controllers / health.py
1 # -*- coding: utf-8 -*-
2 from __future__ import absolute_import
3
4 import json
5
6 from . import ApiController, Endpoint, BaseController
7
8 from .. import mgr
9 from ..rest_client import RequestException
10 from ..security import Permission, Scope
11 from ..services.ceph_service import CephService
12 from ..services.iscsi_cli import IscsiGatewaysConfig
13 from ..services.iscsi_client import IscsiClient
14 from ..tools import partial_dict
15 from .host import get_hosts
16
17
18 class HealthData(object):
19 """
20 A class to be used in combination with BaseController to allow either
21 "full" or "minimal" sets of health data to be collected.
22
23 To function properly, it needs BaseCollector._has_permissions to be passed
24 in as ``auth_callback``.
25 """
26
27 def __init__(self, auth_callback, minimal=True):
28 self._has_permissions = auth_callback
29 self._minimal = minimal
30
31 def all_health(self):
32 result = {
33 "health": self.basic_health(),
34 }
35
36 if self._has_permissions(Permission.READ, Scope.MONITOR):
37 result['mon_status'] = self.mon_status()
38
39 if self._has_permissions(Permission.READ, Scope.CEPHFS):
40 result['fs_map'] = self.fs_map()
41
42 if self._has_permissions(Permission.READ, Scope.OSD):
43 result['osd_map'] = self.osd_map()
44 result['scrub_status'] = self.scrub_status()
45 result['pg_info'] = self.pg_info()
46
47 if self._has_permissions(Permission.READ, Scope.MANAGER):
48 result['mgr_map'] = self.mgr_map()
49
50 if self._has_permissions(Permission.READ, Scope.POOL):
51 result['pools'] = self.pools()
52 result['df'] = self.df()
53 result['client_perf'] = self.client_perf()
54
55 if self._has_permissions(Permission.READ, Scope.HOSTS):
56 result['hosts'] = self.host_count()
57
58 if self._has_permissions(Permission.READ, Scope.RGW):
59 result['rgw'] = self.rgw_count()
60
61 if self._has_permissions(Permission.READ, Scope.ISCSI):
62 result['iscsi_daemons'] = self.iscsi_daemons()
63
64 return result
65
66 def basic_health(self):
67 health_data = mgr.get("health")
68 health = json.loads(health_data['json'])
69
70 # Transform the `checks` dict into a list for the convenience
71 # of rendering from javascript.
72 checks = []
73 for k, v in health['checks'].items():
74 v['type'] = k
75 checks.append(v)
76
77 checks = sorted(checks, key=lambda c: c['severity'])
78 health['checks'] = checks
79 return health
80
81 def client_perf(self):
82 result = CephService.get_client_perf()
83 if self._minimal:
84 result = partial_dict(
85 result,
86 ['read_bytes_sec', 'read_op_per_sec',
87 'recovering_bytes_per_sec', 'write_bytes_sec',
88 'write_op_per_sec']
89 )
90 return result
91
92 def df(self):
93 df = mgr.get('df')
94
95 del df['stats_by_class']
96
97 if self._minimal:
98 df = dict(stats=partial_dict(
99 df['stats'],
100 ['total_avail_bytes', 'total_bytes',
101 'total_used_raw_bytes']
102 ))
103 return df
104
105 def fs_map(self):
106 fs_map = mgr.get('fs_map')
107 if self._minimal:
108 fs_map = partial_dict(fs_map, ['filesystems', 'standbys'])
109 fs_map['filesystems'] = [partial_dict(item, ['mdsmap']) for
110 item in fs_map['filesystems']]
111 for fs in fs_map['filesystems']:
112 mdsmap_info = fs['mdsmap']['info']
113 min_mdsmap_info = dict()
114 for k, v in mdsmap_info.items():
115 min_mdsmap_info[k] = partial_dict(v, ['state'])
116 return fs_map
117
118 def host_count(self):
119 return len(get_hosts())
120
121 def iscsi_daemons(self):
122 up_counter = 0
123 down_counter = 0
124 for gateway_name in IscsiGatewaysConfig.get_gateways_config()['gateways']:
125 try:
126 IscsiClient.instance(gateway_name=gateway_name).ping()
127 up_counter += 1
128 except RequestException:
129 down_counter += 1
130 return {'up': up_counter, 'down': down_counter}
131
132 def mgr_map(self):
133 mgr_map = mgr.get('mgr_map')
134 if self._minimal:
135 mgr_map = partial_dict(mgr_map, ['active_name', 'standbys'])
136 return mgr_map
137
138 def mon_status(self):
139 mon_status = json.loads(mgr.get('mon_status')['json'])
140 if self._minimal:
141 mon_status = partial_dict(mon_status, ['monmap', 'quorum'])
142 mon_status['monmap'] = partial_dict(
143 mon_status['monmap'], ['mons']
144 )
145 mon_status['monmap']['mons'] = [{}] * \
146 len(mon_status['monmap']['mons'])
147 return mon_status
148
149 def osd_map(self):
150 osd_map = mgr.get('osd_map')
151 assert osd_map is not None
152 # Not needed, skip the effort of transmitting this to UI
153 del osd_map['pg_temp']
154 if self._minimal:
155 osd_map = partial_dict(osd_map, ['osds'])
156 osd_map['osds'] = [
157 partial_dict(item, ['in', 'up'])
158 for item in osd_map['osds']
159 ]
160 else:
161 osd_map['tree'] = mgr.get('osd_map_tree')
162 osd_map['crush'] = mgr.get('osd_map_crush')
163 osd_map['crush_map_text'] = mgr.get('osd_map_crush_map_text')
164 osd_map['osd_metadata'] = mgr.get('osd_metadata')
165 return osd_map
166
167 def pg_info(self):
168 return CephService.get_pg_info()
169
170 def pools(self):
171 pools = CephService.get_pool_list_with_stats()
172 if self._minimal:
173 pools = [{}] * len(pools)
174 return pools
175
176 def rgw_count(self):
177 return len(CephService.get_service_list('rgw'))
178
179 def scrub_status(self):
180 return CephService.get_scrub_status()
181
182
183 @ApiController('/health')
184 class Health(BaseController):
185 def __init__(self):
186 super(Health, self).__init__()
187 self.health_full = HealthData(self._has_permissions, minimal=False)
188 self.health_minimal = HealthData(self._has_permissions, minimal=True)
189
190 @Endpoint()
191 def full(self):
192 return self.health_full.all_health()
193
194 @Endpoint()
195 def minimal(self):
196 return self.health_minimal.all_health()