]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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 | |
9f95a23c | 9 | from ..rest_client import RequestException |
11fdf7f2 TL |
10 | from ..security import Permission, Scope |
11 | from ..services.ceph_service import CephService | |
12 | from ..services.iscsi_cli import IscsiGatewaysConfig | |
9f95a23c TL |
13 | from ..services.iscsi_client import IscsiClient |
14 | from ..tools import partial_dict | |
15 | from .host import get_hosts | |
11fdf7f2 TL |
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 | ||
11fdf7f2 TL |
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: | |
9f95a23c | 84 | result = partial_dict( |
11fdf7f2 TL |
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 | ||
11fdf7f2 | 97 | if self._minimal: |
9f95a23c | 98 | df = dict(stats=partial_dict( |
11fdf7f2 | 99 | df['stats'], |
81eedcae | 100 | ['total_avail_bytes', 'total_bytes', |
11fdf7f2 TL |
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: | |
9f95a23c | 108 | fs_map = partial_dict(fs_map, ['filesystems', 'standbys']) |
9f95a23c | 109 | fs_map['filesystems'] = [partial_dict(item, ['mdsmap']) for |
11fdf7f2 TL |
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(): | |
9f95a23c | 115 | min_mdsmap_info[k] = partial_dict(v, ['state']) |
11fdf7f2 TL |
116 | return fs_map |
117 | ||
118 | def host_count(self): | |
9f95a23c | 119 | return len(get_hosts()) |
11fdf7f2 TL |
120 | |
121 | def iscsi_daemons(self): | |
9f95a23c TL |
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} | |
11fdf7f2 TL |
131 | |
132 | def mgr_map(self): | |
133 | mgr_map = mgr.get('mgr_map') | |
134 | if self._minimal: | |
9f95a23c | 135 | mgr_map = partial_dict(mgr_map, ['active_name', 'standbys']) |
11fdf7f2 TL |
136 | return mgr_map |
137 | ||
138 | def mon_status(self): | |
139 | mon_status = json.loads(mgr.get('mon_status')['json']) | |
140 | if self._minimal: | |
9f95a23c TL |
141 | mon_status = partial_dict(mon_status, ['monmap', 'quorum']) |
142 | mon_status['monmap'] = partial_dict( | |
11fdf7f2 TL |
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: | |
9f95a23c | 155 | osd_map = partial_dict(osd_map, ['osds']) |
11fdf7f2 | 156 | osd_map['osds'] = [ |
9f95a23c | 157 | partial_dict(item, ['in', 'up']) |
11fdf7f2 TL |
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): | |
81eedcae | 168 | return CephService.get_pg_info() |
11fdf7f2 TL |
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() |