]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/services/ceph_service.py
1 # -*- coding: utf-8 -*-
2 from __future__
import absolute_import
8 from mgr_module
import CommandResult
11 from more_itertools
import pairwise
13 def pairwise(iterable
):
14 from itertools
import tee
19 from .. import logger
, mgr
22 from typing
import Dict
, Any
# pylint: disable=unused-import
24 pass # For typing only
27 class SendCommandError(rados
.Error
):
28 def __init__(self
, err
, prefix
, argdict
, errno
):
30 self
.argdict
= argdict
31 super(SendCommandError
, self
).__init
__(err
, errno
)
34 class CephService(object):
36 OSD_FLAG_NO_SCRUB
= 'noscrub'
37 OSD_FLAG_NO_DEEP_SCRUB
= 'nodeep-scrub'
39 PG_STATUS_SCRUBBING
= 'scrubbing'
40 PG_STATUS_DEEP_SCRUBBING
= 'deep'
42 SCRUB_STATUS_DISABLED
= 'Disabled'
43 SCRUB_STATUS_ACTIVE
= 'Active'
44 SCRUB_STATUS_INACTIVE
= 'Inactive'
47 def get_service_map(cls
, service_name
):
48 service_map
= {} # type: Dict[str, Dict[str, Any]]
49 for server
in mgr
.list_servers():
50 for service
in server
['services']:
51 if service
['type'] == service_name
:
52 if server
['hostname'] not in service_map
:
53 service_map
[server
['hostname']] = {
57 inst_id
= service
['id']
58 metadata
= mgr
.get_metadata(service_name
, inst_id
)
59 status
= mgr
.get_daemon_status(service_name
, inst_id
)
60 service_map
[server
['hostname']]['services'].append({
63 'hostname': server
['hostname'],
70 def get_service_list(cls
, service_name
):
71 service_map
= cls
.get_service_map(service_name
)
72 return [svc
for _
, svcs
in service_map
.items() for svc
in svcs
['services']]
75 def get_service(cls
, service_name
, service_id
):
76 for server
in mgr
.list_servers():
77 for service
in server
['services']:
78 if service
['type'] == service_name
:
79 inst_id
= service
['id']
80 if inst_id
== service_id
:
81 metadata
= mgr
.get_metadata(service_name
, inst_id
)
82 status
= mgr
.get_daemon_status(service_name
, inst_id
)
86 'hostname': server
['hostname'],
93 def get_pool_list(cls
, application
=None):
94 osd_map
= mgr
.get('osd_map')
96 return osd_map
['pools']
97 return [pool
for pool
in osd_map
['pools']
98 if application
in pool
.get('application_metadata', {})]
101 def get_pool_list_with_stats(cls
, application
=None):
102 # pylint: disable=too-many-locals
103 pools
= cls
.get_pool_list(application
)
107 pg_summary
= mgr
.get("pg_summary")
108 pool_stats
= mgr
.get_updated_pool_stats()
111 pool
['pg_status'] = pg_summary
['by_pool'][pool
['pool'].__str
__()]
112 stats
= pool_stats
[pool
['pool']]
115 def get_rate(series
):
117 return differentiate(*list(series
)[-2:])
120 for stat_name
, stat_series
in stats
.items():
122 'latest': stat_series
[0][1],
123 'rate': get_rate(stat_series
),
124 'rates': get_rates_from_data(stat_series
)
127 pools_w_stats
.append(pool
)
131 def get_pool_name_from_id(cls
, pool_id
):
132 pool_list
= cls
.get_pool_list()
133 for pool
in pool_list
:
134 if pool
['pool'] == pool_id
:
135 return pool
['pool_name']
139 def send_command(cls
, srv_type
, prefix
, srv_spec
='', **kwargs
):
142 :param srv_type: mon |
143 :param kwargs: will be added to argdict
144 :param srv_spec: typically empty. or something like "<fs_id>:0"
146 :raises PermissionError: See rados.make_ex
147 :raises ObjectNotFound: See rados.make_ex
148 :raises IOError: See rados.make_ex
149 :raises NoSpace: See rados.make_ex
150 :raises ObjectExists: See rados.make_ex
151 :raises ObjectBusy: See rados.make_ex
152 :raises NoData: See rados.make_ex
153 :raises InterruptedOrTimeoutError: See rados.make_ex
154 :raises TimedOut: See rados.make_ex
155 :raises ValueError: return code != 0
161 argdict
.update({k
: v
for k
, v
in kwargs
.items() if v
is not None})
162 result
= CommandResult("")
163 mgr
.send_command(result
, srv_type
, srv_spec
, json
.dumps(argdict
), "")
164 r
, outb
, outs
= result
.wait()
166 msg
= "send_command '{}' failed. (r={}, outs=\"{}\", kwargs={})".format(prefix
, r
, outs
,
169 raise SendCommandError(outs
, prefix
, argdict
, r
)
172 return json
.loads(outb
)
173 except Exception: # pylint: disable=broad-except
177 def get_rates(cls
, svc_type
, svc_name
, path
):
179 :return: the derivative of mgr.get_counter()
180 :rtype: list[tuple[int, float]]"""
181 data
= mgr
.get_counter(svc_type
, svc_name
, path
)[path
]
182 return get_rates_from_data(data
)
185 def get_rate(cls
, svc_type
, svc_name
, path
):
186 """returns most recent rate"""
187 data
= mgr
.get_counter(svc_type
, svc_name
, path
)[path
]
189 if data
and len(data
) > 1:
190 return differentiate(*data
[-2:])
194 def get_client_perf(cls
):
195 pools_stats
= mgr
.get('osd_pool_stats')['pool_stats']
199 'read_op_per_sec': 0,
200 'write_bytes_sec': 0,
201 'write_op_per_sec': 0,
203 recovery_stats
= {'recovering_bytes_per_sec': 0}
205 for pool_stats
in pools_stats
:
206 client_io
= pool_stats
['client_io_rate']
207 for stat
in list(io_stats
.keys()):
208 if stat
in client_io
:
209 io_stats
[stat
] += client_io
[stat
]
211 client_recovery
= pool_stats
['recovery_rate']
212 for stat
in list(recovery_stats
.keys()):
213 if stat
in client_recovery
:
214 recovery_stats
[stat
] += client_recovery
[stat
]
216 client_perf
= io_stats
.copy()
217 client_perf
.update(recovery_stats
)
222 def get_scrub_status(cls
):
223 enabled_flags
= mgr
.get('osd_map')['flags_set']
224 if cls
.OSD_FLAG_NO_SCRUB
in enabled_flags
or cls
.OSD_FLAG_NO_DEEP_SCRUB
in enabled_flags
:
225 return cls
.SCRUB_STATUS_DISABLED
227 grouped_pg_statuses
= mgr
.get('pg_summary')['all']
228 for grouped_pg_status
in grouped_pg_statuses
.keys():
229 if len(grouped_pg_status
.split(cls
.PG_STATUS_SCRUBBING
)) > 1 \
230 or len(grouped_pg_status
.split(cls
.PG_STATUS_DEEP_SCRUBBING
)) > 1:
231 return cls
.SCRUB_STATUS_ACTIVE
233 return cls
.SCRUB_STATUS_INACTIVE
236 def get_pg_info(cls
):
237 pg_summary
= mgr
.get('pg_summary')
238 object_stats
= {stat
: pg_summary
['pg_stats_sum']['stat_sum'][stat
] for stat
in [
239 'num_objects', 'num_object_copies', 'num_objects_degraded',
240 'num_objects_misplaced', 'num_objects_unfound']}
243 total_osds
= len(pg_summary
['by_osd'])
246 for _
, osd_pg_statuses
in pg_summary
['by_osd'].items():
247 for _
, pg_amount
in osd_pg_statuses
.items():
248 total_pgs
+= pg_amount
250 pgs_per_osd
= total_pgs
/ total_osds
253 'object_stats': object_stats
,
254 'statuses': pg_summary
['all'],
255 'pgs_per_osd': pgs_per_osd
,
259 def get_rates_from_data(data
):
261 >>> get_rates_from_data([])
263 >>> get_rates_from_data([[1, 42]])
265 >>> get_rates_from_data([[0, 100], [2, 101], [3, 100], [4, 100]])
266 [(2, 0.5), (3, 1.0), (4, 0.0)]
271 return [(data
[0][0], 0.0)]
272 return [(data2
[0], differentiate(data1
, data2
)) for data1
, data2
in pairwise(data
)]
275 def differentiate(data1
, data2
):
278 >>> values = [100, 101]
279 >>> differentiate(*zip(times, values))
282 >>> values = [100, 99]
283 >>> differentiate(*zip(times, values))
286 return abs((data2
[1] - data1
[1]) / float(data2
[0] - data1
[0]))