blob: 60830a10a5db111de821a08d553191661a4722fb [file] [log] [blame]
kdanylov aka koder45183182017-04-30 23:55:40 +03001import bz2
koder aka kdanilov962ee5f2016-12-19 02:40:08 +02002import array
3import logging
4from typing import List, Dict, Tuple
koder aka kdanilov39e449e2016-12-17 15:15:26 +02005
koder aka kdanilova732a602017-02-01 20:29:56 +02006import numpy
7
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +03008from cephlib import sensors_rpc_plugin
9
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020010from . import utils
koder aka kdanilov70227062016-11-26 23:23:21 +020011from .test_run_class import TestRun
koder aka kdanilova732a602017-02-01 20:29:56 +020012from .result_classes import DataSource
koder aka kdanilov39e449e2016-12-17 15:15:26 +020013from .stage import Stage, StepOrder
koder aka kdanilova732a602017-02-01 20:29:56 +020014from .hlstorage import ResultStorage
koder aka kdanilov70227062016-11-26 23:23:21 +020015
kdanylov aka koder150b2192017-04-01 16:53:01 +030016
koder aka kdanilov70227062016-11-26 23:23:21 +020017plugin_fname = sensors_rpc_plugin.__file__.rsplit(".", 1)[0] + ".py"
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020018SENSORS_PLUGIN_CODE = open(plugin_fname, "rb").read() # type: bytes
koder aka kdanilov70227062016-11-26 23:23:21 +020019
20
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020021logger = logging.getLogger("wally")
koder aka kdanilov70227062016-11-26 23:23:21 +020022
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020023
koder aka kdanilova732a602017-02-01 20:29:56 +020024sensor_units = {
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030025 "system-cpu.idle": "",
26 "system-cpu.nice": "",
27 "system-cpu.user": "",
28 "system-cpu.sys": "",
29 "system-cpu.iowait": "",
30 "system-cpu.irq": "",
31 "system-cpu.sirq": "",
32 "system-cpu.steal": "",
33 "system-cpu.guest": "",
34
koder aka kdanilova732a602017-02-01 20:29:56 +020035 "system-cpu.procs_blocked": "",
36 "system-cpu.procs_queue_x10": "",
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030037
koder aka kdanilova732a602017-02-01 20:29:56 +020038 "net-io.recv_bytes": "B",
39 "net-io.recv_packets": "",
40 "net-io.send_bytes": "B",
41 "net-io.send_packets": "",
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030042
koder aka kdanilova732a602017-02-01 20:29:56 +020043 "block-io.io_queue": "",
44 "block-io.io_time": "ms",
45 "block-io.reads_completed": "",
46 "block-io.rtime": "ms",
47 "block-io.sectors_read": "B",
48 "block-io.sectors_written": "B",
49 "block-io.writes_completed": "",
kdanylov aka koder150b2192017-04-01 16:53:01 +030050 "block-io.wtime": "ms",
51 "block-io.weighted_io_time": "ms"
koder aka kdanilova732a602017-02-01 20:29:56 +020052}
53
54
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020055# TODO(koder): in case if node has more than one role sensor settings might be incorrect
koder aka kdanilov39e449e2016-12-17 15:15:26 +020056class StartSensorsStage(Stage):
57 priority = StepOrder.START_SENSORS
58 config_block = 'sensors'
koder aka kdanilov70227062016-11-26 23:23:21 +020059
koder aka kdanilov39e449e2016-12-17 15:15:26 +020060 def run(self, ctx: TestRun) -> None:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020061 if array.array('L').itemsize != 8:
62 message = "Python array.array('L') items should be 8 bytes in size, not {}." + \
63 " Can't provide sensors on this platform. Disable sensors in config and retry"
64 logger.critical(message.format(array.array('L').itemsize))
65 raise utils.StopTestError()
koder aka kdanilov39e449e2016-12-17 15:15:26 +020066
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020067 # TODO: need carefully fix this
68 # sensors config is:
69 # role:
70 # sensor: [str]
71 # or
72 # role:
73 # sensor:
74 # allowed: [str]
75 # dissallowed: [str]
76 # params: Any
koder aka kdanilov39e449e2016-12-17 15:15:26 +020077 per_role_config = {} # type: Dict[str, Dict[str, str]]
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020078
79 for name, val in ctx.config.sensors.roles_mapping.raw().items():
koder aka kdanilov39e449e2016-12-17 15:15:26 +020080 if isinstance(val, str):
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030081 val = {vl.strip(): (".*" if vl.strip() != 'ceph' else {}) for vl in val.split(",")}
koder aka kdanilov39e449e2016-12-17 15:15:26 +020082 elif isinstance(val, list):
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +030083 val = {vl: (".*" if vl != 'ceph' else {}) for vl in val}
koder aka kdanilov39e449e2016-12-17 15:15:26 +020084 per_role_config[name] = val
85
86 if 'all' in per_role_config:
87 all_vl = per_role_config.pop('all')
88 all_roles = set(per_role_config)
89
90 for node in ctx.nodes:
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020091 all_roles.update(node.info.roles) # type: ignore
koder aka kdanilov39e449e2016-12-17 15:15:26 +020092
93 for name, vals in list(per_role_config.items()):
94 new_vals = all_vl.copy()
95 new_vals.update(vals)
96 per_role_config[name] = new_vals
koder aka kdanilov70227062016-11-26 23:23:21 +020097
98 for node in ctx.nodes:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020099 node_cfg = {} # type: Dict[str, Dict[str, str]]
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200100 for role in node.info.roles:
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +0200101 node_cfg.update(per_role_config.get(role, {})) # type: ignore
koder aka kdanilov70227062016-11-26 23:23:21 +0200102
koder aka kdanilov108ac362017-01-19 20:17:16 +0200103 nid = node.node_id
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200104 if node_cfg:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200105 # ceph requires additional settings
106 if 'ceph' in node_cfg:
107 node_cfg['ceph'].update(node.info.params['ceph'])
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +0300108 node_cfg['ceph']['osds'] = [osd['id'] for osd in node.info.params['ceph-osds']] # type: ignore
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200109
kdanylov aka koder0e0cfcb2017-03-27 22:19:09 +0300110 logger.debug("Setting up sensors RPC plugin for node %s", nid)
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200111 node.upload_plugin("sensors", SENSORS_PLUGIN_CODE)
112 ctx.sensors_run_on.add(nid)
113 logger.debug("Start monitoring node %s", nid)
114 node.conn.sensors.start(node_cfg)
115 else:
116 logger.debug("Skip monitoring node %s, as no sensors selected", nid)
117
118
119def collect_sensors_data(ctx: TestRun, stop: bool = False):
koder aka kdanilova732a602017-02-01 20:29:56 +0200120 rstorage = ResultStorage(ctx.storage)
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200121 for node in ctx.nodes:
koder aka kdanilov108ac362017-01-19 20:17:16 +0200122 node_id = node.node_id
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200123 if node_id in ctx.sensors_run_on:
124
125 if stop:
126 func = node.conn.sensors.stop
127 else:
128 func = node.conn.sensors.get_updates
129
koder aka kdanilova732a602017-02-01 20:29:56 +0200130 # TODO: units should came along with data
kdanylov aka koder150b2192017-04-01 16:53:01 +0300131 # TODO: process raw sensors data
132
kdanylov aka koder45183182017-04-30 23:55:40 +0300133 for path, value, is_array in sensors_rpc_plugin.unpack_rpc_updates(func()):
koder aka kdanilova732a602017-02-01 20:29:56 +0200134 if path == 'collected_at':
kdanylov aka koder45183182017-04-30 23:55:40 +0300135 ds = DataSource(node_id=node_id, metric='collected_at', tag='csv')
136 rstorage.append_sensor(numpy.array(value), ds, 'us')
koder aka kdanilova732a602017-02-01 20:29:56 +0200137 else:
138 sensor, dev, metric = path.split(".")
kdanylov aka koder45183182017-04-30 23:55:40 +0300139 ds = DataSource(node_id=node_id, metric=metric, dev=dev, sensor=sensor, tag='csv')
140 if is_array:
141 units = sensor_units["{}.{}".format(sensor, metric)]
142 rstorage.append_sensor(numpy.array(value), ds, units)
143 else:
144 if metric == 'historic':
145 rstorage.put_sensor_raw(bz2.compress(value), ds(tag='bin'))
146 else:
147 assert metric in ('perf_dump', 'historic_js')
148 rstorage.put_sensor_raw(value, ds(tag='js'))
kdanylov aka kodercdfcdaf2017-04-29 10:03:39 +0300149
koder aka kdanilov70227062016-11-26 23:23:21 +0200150
151
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200152class CollectSensorsStage(Stage):
153 priority = StepOrder.COLLECT_SENSORS
154 config_block = 'sensors'
koder aka kdanilov70227062016-11-26 23:23:21 +0200155
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200156 def run(self, ctx: TestRun) -> None:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200157 collect_sensors_data(ctx, True)
koder aka kdanilov70227062016-11-26 23:23:21 +0200158
159
160# def delta(func, only_upd=True):
161# prev = {}
162# while True:
163# for dev_name, vals in func():
164# if dev_name not in prev:
165# prev[dev_name] = {}
166# for name, (val, _) in vals.items():
167# prev[dev_name][name] = val
168# else:
169# dev_prev = prev[dev_name]
170# res = {}
171# for stat_name, (val, accum_val) in vals.items():
172# if accum_val:
173# if stat_name in dev_prev:
174# delta = int(val) - int(dev_prev[stat_name])
175# if not only_upd or 0 != delta:
176# res[stat_name] = str(delta)
177# dev_prev[stat_name] = val
178# elif not only_upd or '0' != val:
179# res[stat_name] = val
180#
181# if only_upd and len(res) == 0:
182# continue
183# yield dev_name, res
184# yield None, None
185#
186#
187
188