... And `get_latest()`.
* OSD Controller: `.stats_history` now returns the
derivative.
Fixes https://tracker.ceph.com/issues/23389
Signed-off-by: Sebastian Wagner <sebastian.wagner@suse.com>
import cherrypy
-from ..services.ceph_service import CephService
-
from . import ApiController, AuthRequired, BaseController
from .. import mgr
+from ..services.ceph_service import CephService
from ..tools import ViewCache
return names
- def get_rate(self, daemon_type, daemon_name, stat):
- data = mgr.get_counter(daemon_type, daemon_name, stat)[stat]
-
- if data and len(data) > 1:
- return (data[-1][1] - data[-2][1]) / float(data[-1][0] - data[-2][0])
-
- return 0
-
# pylint: disable=too-many-locals,too-many-statements,too-many-branches
def fs_status(self, fs_id):
mds_versions = defaultdict(list)
if up:
gid = mdsmap['up']["mds_{0}".format(rank)]
info = mdsmap['info']['gid_{0}'.format(gid)]
- dns = self.get_latest("mds", info['name'], "mds.inodes")
- inos = self.get_latest("mds", info['name'], "mds_mem.ino")
+ dns = mgr.get_latest("mds", info['name'], "mds.inodes")
+ inos = mgr.get_latest("mds", info['name'], "mds_mem.ino")
if rank == 0:
- client_count = self.get_latest("mds", info['name'],
- "mds_sessions.session_count")
+ client_count = mgr.get_latest("mds", info['name'],
+ "mds_sessions.session_count")
elif client_count == 0:
# In case rank 0 was down, look at another rank's
# sessionmap to get an indication of clients.
- client_count = self.get_latest("mds", info['name'],
- "mds_sessions.session_count")
+ client_count = mgr.get_latest("mds", info['name'],
+ "mds_sessions.session_count")
laggy = "laggy_since" in info
if laggy:
state += "(laggy)"
- # if state == "active" and not laggy:
- # c_state = self.colorize(state, self.GREEN)
- # else:
- # c_state = self.colorize(state, self.YELLOW)
-
# Populate based on context of state, e.g. client
# ops for an active daemon, replay progress, reconnect
# progress
- activity = ""
-
if state == "active":
- activity = self.get_rate("mds",
- info['name'],
- "mds_server.handle_client_request")
+ activity = CephService.get_rate("mds",
+ info['name'],
+ "mds_server.handle_client_request")
+ else:
+ activity = 0.0
metadata = mgr.get_metadata('mds', info['name'])
mds_versions[metadata.get('ceph_version', 'unknown')].append(
"rank": rank,
"state": "failed",
"mds": "",
- "activity": "",
+ "activity": 0.0,
"dns": 0,
"inos": 0
}
if daemon_info['state'] != "up:standby-replay":
continue
- inos = self.get_latest("mds", daemon_info['name'], "mds_mem.ino")
- dns = self.get_latest("mds", daemon_info['name'], "mds.inodes")
+ inos = mgr.get_latest("mds", daemon_info['name'], "mds_mem.ino")
+ dns = mgr.get_latest("mds", daemon_info['name'], "mds.inodes")
- activity = self.get_rate(
+ activity = CephService.get_rate(
"mds", daemon_info['name'], "mds_log.replay")
rank_table.append(
'data': clients
}
- def get_latest(self, daemon_type, daemon_name, stat):
- data = mgr.get_counter(daemon_type, daemon_name, stat)[stat]
- if data:
- return data[-1][1]
- return 0
-
class CephFSClients(object):
def __init__(self, module_inst, fscid):
from . import ApiController, AuthRequired, RESTController
from .. import logger, mgr
+from ..services.ceph_service import CephService
@ApiController('osd')
@AuthRequired()
class Osd(RESTController):
- def get_counter(self, daemon_name, stat):
- return mgr.get_counter('osd', daemon_name, stat)[stat]
-
- def get_rate(self, daemon_name, stat):
- data = self.get_counter(daemon_name, stat)
- rate = 0
- if data and len(data) > 1:
- rate = (data[-1][1] - data[-2][1]) / float(data[-1][0] - data[-2][0])
- return rate
-
- def get_latest(self, daemon_name, stat):
- data = self.get_counter(daemon_name, stat)
- latest = 0
- if data and data[-1] and len(data[-1]) == 2:
- latest = data[-1][1]
- return latest
-
def list(self):
osds = self.get_osd_map()
# Extending by osd stats information
osd_spec = str(o['osd'])
for s in ['osd.op_w', 'osd.op_in_bytes', 'osd.op_r', 'osd.op_out_bytes']:
prop = s.split('.')[1]
- o['stats'][prop] = self.get_rate(osd_spec, s)
- o['stats_history'][prop] = self.get_counter(osd_spec, s)
+ o['stats'][prop] = CephService.get_rate('osd', osd_spec, s)
+ o['stats_history'][prop] = CephService.get_rates('osd', osd_spec, s)
# Gauge stats
for s in ['osd.numpg', 'osd.stat_bytes', 'osd.stat_bytes_used']:
- o['stats'][s.split('.')[1]] = self.get_latest(osd_spec, s)
+ o['stats'][s.split('.')[1]] = mgr.get_latest('osd', osd_spec, s)
return list(osds.values())
def get_osd_map(self):
from . import ApiController, AuthRequired, RESTController
from .. import mgr
+from ..services.ceph_service import CephService
class PerfCounter(RESTController):
service_type = None # type: str
- def _get_rate(self, daemon_type, daemon_name, stat):
- data = mgr.get_counter(daemon_type, daemon_name, stat)[stat]
- if data and len(data) > 1:
- return (data[-1][1] - data[-2][1]) / float(data[-1][0] - data[-2][0])
- return 0
-
- def _get_latest(self, daemon_type, daemon_name, stat):
- data = mgr.get_counter(daemon_type, daemon_name, stat)[stat]
- if data:
- return data[-1][1]
- return 0
-
def get(self, service_id):
schema_dict = mgr.get_perf_schema(self.service_type, str(service_id))
schema = schema_dict["{}.{}".format(self.service_type, service_id)]
counter['description'] = value['description']
# pylint: disable=W0212
if mgr._stattype_to_str(value['type']) == 'counter':
- counter['value'] = self._get_rate(
+ counter['value'] = CephService.get_rate(
self.service_type, service_id, key)
counter['unit'] = mgr._unit_to_str(value['units'])
else:
- counter['value'] = self._get_latest(
+ counter['value'] = mgr.get_latest(
self.service_type, service_id, key)
counter['unit'] = ''
counters.append(counter)
@ApiController('tcmuiscsi')
@AuthRequired()
class TcmuIscsi(RESTController):
- def _get_rate(self, daemon_type, daemon_name, stat):
- data = mgr.get_counter(daemon_type, daemon_name, stat)[stat]
-
- if data and len(data) > 1:
- last_value = data[0][1]
- last_time = data[0][0]
- rates = []
- for datum in data[1:]:
- rates.append([datum[0], ((datum[1] - last_value) /
- float(datum[0] - last_time))])
- last_value = datum[1]
- last_time = datum[0]
- return rates
- return [[0, 0]]
-
# pylint: disable=too-many-locals,too-many-nested-blocks
def list(self): # pylint: disable=unused-argument
daemons = {}
image['stats_history'] = {}
for s in ['rd', 'wr', 'rd_bytes', 'wr_bytes']:
perf_key = "{}{}".format(perf_key_prefix, s)
- image['stats'][s] = self._get_rate(
- 'tcmu-runner', service_id, perf_key)[-1][1]
- image['stats_history'][s] = self._get_rate(
+ image['stats'][s] = CephService.get_rate(
+ 'tcmu-runner', service_id, perf_key)
+ image['stats_history'][s] = CephService.get_rates(
'tcmu-runner', service_id, perf_key)
else:
daemon['non_optimized_paths'] += 1
import json
from mgr_module import CommandResult
+
+try:
+ from more_itertools import pairwise
+except ImportError:
+ def pairwise(iterable):
+ from itertools import tee
+ a, b = tee(iterable)
+ next(b, None)
+ return zip(a, b)
+
from .. import logger, mgr
def get_rate(series):
if len(series) >= 2:
- return (float(series[0][1]) - float(series[1][1])) / \
- (float(series[0][0]) - float(series[1][0]))
+ return differentiate(*series[0:1])
return 0
for stat_name, stat_series in stats.items():
return json.loads(outb)
except Exception: # pylint: disable=broad-except
return outb
+
+ @classmethod
+ def get_rates(cls, svc_type, svc_name, path):
+ """
+ :return: the derivative of mgr.get_counter()
+ :rtype: list[tuple[int, float]]"""
+ data = mgr.get_counter(svc_type, svc_name, path)[path]
+ if not data:
+ return [(0, 0)]
+ elif len(data) == 1:
+ return [(data[0][0], 0)]
+ return [(data2[0], differentiate(data1, data2)) for data1, data2 in pairwise(data)]
+
+ @classmethod
+ def get_rate(cls, svc_type, svc_name, path):
+ """returns most recent rate"""
+ data = mgr.get_counter(svc_type, svc_name, path)[path]
+
+ if data and len(data) > 1:
+ return differentiate(*data[-2:])
+ return 0.0
+
+
+def differentiate(data1, data2):
+ """
+ >>> times = [0, 2]
+ >>> values = [100, 101]
+ >>> differentiate(*zip(times, values))
+ 0.5
+ """
+ return (data2[1] - data1[1]) / float(data2[0] - data1[0])
LD_LIBRARY_PATH = {toxinidir}/../../../../build/lib
PATH = {toxinidir}/../../../../build/bin:$PATH
commands=
- {envbindir}/py.test --cov=. --cov-report= --junitxml=junit.{envname}.xml --doctest-modules controllers/rbd.py tests/
+ {envbindir}/py.test --cov=. --cov-report= --junitxml=junit.{envname}.xml --doctest-modules controllers/rbd.py services/ tests/
[testenv:cov-init]
setenv =
"""
return self._ceph_get_osdmap()
+ # TODO: improve C++->Python interface to return just
+ # the latest if that's all we want.
+ def get_latest(self, daemon_type, daemon_name, counter):
+ data = self.get_counter(daemon_type, daemon_name, counter)[counter]
+ if data:
+ return data[-1][1]
+ else:
+ return 0
+
def get_all_perf_counters(self, prio_limit=PRIO_USEFUL):
"""
Return the perf counters currently known to this ceph-mgr
result = defaultdict(dict)
- # TODO: improve C++->Python interface to return just
- # the latest if that's all we want.
- def get_latest(daemon_type, daemon_name, counter):
- data = self.get_counter(daemon_type, daemon_name, counter)[counter]
- if data:
- return data[-1][1]
- else:
- return 0
for server in self.list_servers():
for service in server['services']:
continue
counter_info = counter_schema
- counter_info['value'] = get_latest(service['type'], service['id'], counter_path)
+ counter_info['value'] = self.get_latest(service['type'], service['id'],
+ counter_path)
result[svc_full_name][counter_path] = counter_info
self.log.debug("returning {0} counter".format(len(result)))