blob: c19c350d65e72b8c984dbb42830d0e2f2529f461 [file] [log] [blame]
koder aka kdanilov962ee5f2016-12-19 02:40:08 +02001import array
2import logging
3from typing import List, Dict, Tuple
koder aka kdanilov39e449e2016-12-17 15:15:26 +02004
koder aka kdanilova732a602017-02-01 20:29:56 +02005import numpy
6
koder aka kdanilov962ee5f2016-12-19 02:40:08 +02007from . import utils
koder aka kdanilov70227062016-11-26 23:23:21 +02008from .test_run_class import TestRun
koder aka kdanilova732a602017-02-01 20:29:56 +02009from .result_classes import DataSource
koder aka kdanilov39e449e2016-12-17 15:15:26 +020010from .stage import Stage, StepOrder
koder aka kdanilova732a602017-02-01 20:29:56 +020011from .hlstorage import ResultStorage
koder aka kdanilov70227062016-11-26 23:23:21 +020012
kdanylov aka koder150b2192017-04-01 16:53:01 +030013from cephlib import sensors_rpc_plugin
14
15
koder aka kdanilov70227062016-11-26 23:23:21 +020016plugin_fname = sensors_rpc_plugin.__file__.rsplit(".", 1)[0] + ".py"
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020017SENSORS_PLUGIN_CODE = open(plugin_fname, "rb").read() # type: bytes
koder aka kdanilov70227062016-11-26 23:23:21 +020018
19
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020020logger = logging.getLogger("wally")
koder aka kdanilov70227062016-11-26 23:23:21 +020021
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020022
koder aka kdanilova732a602017-02-01 20:29:56 +020023sensor_units = {
24 "system-cpu.idle_time": "ms",
25 "system-cpu.nice_processes": "",
26 "system-cpu.procs_blocked": "",
27 "system-cpu.procs_queue_x10": "",
28 "system-cpu.system_processes": "",
29 "system-cpu.user_processes": "",
30 "net-io.recv_bytes": "B",
31 "net-io.recv_packets": "",
32 "net-io.send_bytes": "B",
33 "net-io.send_packets": "",
34 "block-io.io_queue": "",
35 "block-io.io_time": "ms",
36 "block-io.reads_completed": "",
37 "block-io.rtime": "ms",
38 "block-io.sectors_read": "B",
39 "block-io.sectors_written": "B",
40 "block-io.writes_completed": "",
kdanylov aka koder150b2192017-04-01 16:53:01 +030041 "block-io.wtime": "ms",
42 "block-io.weighted_io_time": "ms"
koder aka kdanilova732a602017-02-01 20:29:56 +020043}
44
45
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020046# TODO(koder): in case if node has more than one role sensor settings might be incorrect
koder aka kdanilov39e449e2016-12-17 15:15:26 +020047class StartSensorsStage(Stage):
48 priority = StepOrder.START_SENSORS
49 config_block = 'sensors'
koder aka kdanilov70227062016-11-26 23:23:21 +020050
koder aka kdanilov39e449e2016-12-17 15:15:26 +020051 def run(self, ctx: TestRun) -> None:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020052 if array.array('L').itemsize != 8:
53 message = "Python array.array('L') items should be 8 bytes in size, not {}." + \
54 " Can't provide sensors on this platform. Disable sensors in config and retry"
55 logger.critical(message.format(array.array('L').itemsize))
56 raise utils.StopTestError()
koder aka kdanilov39e449e2016-12-17 15:15:26 +020057
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020058 # TODO: need carefully fix this
59 # sensors config is:
60 # role:
61 # sensor: [str]
62 # or
63 # role:
64 # sensor:
65 # allowed: [str]
66 # dissallowed: [str]
67 # params: Any
koder aka kdanilov39e449e2016-12-17 15:15:26 +020068 per_role_config = {} # type: Dict[str, Dict[str, str]]
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020069
70 for name, val in ctx.config.sensors.roles_mapping.raw().items():
koder aka kdanilov39e449e2016-12-17 15:15:26 +020071 if isinstance(val, str):
72 val = {vl.strip(): ".*" for vl in val.split(",")}
73 elif isinstance(val, list):
74 val = {vl: ".*" for vl in val}
75 per_role_config[name] = val
76
77 if 'all' in per_role_config:
78 all_vl = per_role_config.pop('all')
79 all_roles = set(per_role_config)
80
81 for node in ctx.nodes:
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020082 all_roles.update(node.info.roles) # type: ignore
koder aka kdanilov39e449e2016-12-17 15:15:26 +020083
84 for name, vals in list(per_role_config.items()):
85 new_vals = all_vl.copy()
86 new_vals.update(vals)
87 per_role_config[name] = new_vals
koder aka kdanilov70227062016-11-26 23:23:21 +020088
89 for node in ctx.nodes:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020090 node_cfg = {} # type: Dict[str, Dict[str, str]]
koder aka kdanilov39e449e2016-12-17 15:15:26 +020091 for role in node.info.roles:
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020092 node_cfg.update(per_role_config.get(role, {})) # type: ignore
koder aka kdanilov70227062016-11-26 23:23:21 +020093
koder aka kdanilov108ac362017-01-19 20:17:16 +020094 nid = node.node_id
koder aka kdanilov39e449e2016-12-17 15:15:26 +020095 if node_cfg:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020096 # ceph requires additional settings
97 if 'ceph' in node_cfg:
98 node_cfg['ceph'].update(node.info.params['ceph'])
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020099 node_cfg['ceph']['osds'] = [osd.id for osd in node.info.params['ceph-osds']] # type: ignore
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200100
kdanylov aka koder0e0cfcb2017-03-27 22:19:09 +0300101 logger.debug("Setting up sensors RPC plugin for node %s", nid)
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200102 node.upload_plugin("sensors", SENSORS_PLUGIN_CODE)
103 ctx.sensors_run_on.add(nid)
104 logger.debug("Start monitoring node %s", nid)
105 node.conn.sensors.start(node_cfg)
106 else:
107 logger.debug("Skip monitoring node %s, as no sensors selected", nid)
108
109
110def collect_sensors_data(ctx: TestRun, stop: bool = False):
koder aka kdanilova732a602017-02-01 20:29:56 +0200111 rstorage = ResultStorage(ctx.storage)
kdanylov aka koder150b2192017-04-01 16:53:01 +0300112 raw_skipped = False
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200113 for node in ctx.nodes:
koder aka kdanilov108ac362017-01-19 20:17:16 +0200114 node_id = node.node_id
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200115 if node_id in ctx.sensors_run_on:
116
117 if stop:
118 func = node.conn.sensors.stop
119 else:
120 func = node.conn.sensors.get_updates
121
koder aka kdanilova732a602017-02-01 20:29:56 +0200122 # TODO: units should came along with data
kdanylov aka koder150b2192017-04-01 16:53:01 +0300123 # TODO: process raw sensors data
124
125 for path, value, is_parsed in sensors_rpc_plugin.unpack_rpc_updates(func()):
126 if not is_parsed:
127 if not raw_skipped:
128 logger.warning("Raw sensors data at path %r and, maybe, others are skipped", path)
129 raw_skipped = True
130 continue
koder aka kdanilova732a602017-02-01 20:29:56 +0200131 if path == 'collected_at':
132 ds = DataSource(node_id=node_id, metric='collected_at')
133 units = 'us'
134 else:
135 sensor, dev, metric = path.split(".")
136 ds = DataSource(node_id=node_id, metric=metric, dev=dev, sensor=sensor)
137 units = sensor_units["{}.{}".format(sensor, metric)]
138 rstorage.append_sensor(numpy.array(value), ds, units)
koder aka kdanilov70227062016-11-26 23:23:21 +0200139
140
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200141class CollectSensorsStage(Stage):
142 priority = StepOrder.COLLECT_SENSORS
143 config_block = 'sensors'
koder aka kdanilov70227062016-11-26 23:23:21 +0200144
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200145 def run(self, ctx: TestRun) -> None:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200146 collect_sensors_data(ctx, True)
koder aka kdanilov70227062016-11-26 23:23:21 +0200147
148
149# def delta(func, only_upd=True):
150# prev = {}
151# while True:
152# for dev_name, vals in func():
153# if dev_name not in prev:
154# prev[dev_name] = {}
155# for name, (val, _) in vals.items():
156# prev[dev_name][name] = val
157# else:
158# dev_prev = prev[dev_name]
159# res = {}
160# for stat_name, (val, accum_val) in vals.items():
161# if accum_val:
162# if stat_name in dev_prev:
163# delta = int(val) - int(dev_prev[stat_name])
164# if not only_upd or 0 != delta:
165# res[stat_name] = str(delta)
166# dev_prev[stat_name] = val
167# elif not only_upd or '0' != val:
168# res[stat_name] = val
169#
170# if only_upd and len(res) == 0:
171# continue
172# yield dev_name, res
173# yield None, None
174#
175#
176
177