blob: 0a1bbe9ede88c5b3e992eb5d432276899e87d8bc [file] [log] [blame]
koder aka kdanilov962ee5f2016-12-19 02:40:08 +02001import array
2import logging
koder aka kdanilov3af3c332016-12-19 17:12:34 +02003import collections
koder aka kdanilov962ee5f2016-12-19 02:40:08 +02004from typing import List, Dict, Tuple
koder aka kdanilov39e449e2016-12-17 15:15:26 +02005
koder aka kdanilov962ee5f2016-12-19 02:40:08 +02006from . import utils
koder aka kdanilov70227062016-11-26 23:23:21 +02007from .test_run_class import TestRun
8from . import sensors_rpc_plugin
koder aka kdanilov39e449e2016-12-17 15:15:26 +02009from .stage import Stage, StepOrder
koder aka kdanilov70227062016-11-26 23:23:21 +020010
11plugin_fname = sensors_rpc_plugin.__file__.rsplit(".", 1)[0] + ".py"
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020012SENSORS_PLUGIN_CODE = open(plugin_fname, "rb").read() # type: bytes
koder aka kdanilov70227062016-11-26 23:23:21 +020013
14
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020015logger = logging.getLogger("wally")
koder aka kdanilov70227062016-11-26 23:23:21 +020016
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020017
18# TODO(koder): in case if node has more than one role sensor settings might be incorrect
koder aka kdanilov39e449e2016-12-17 15:15:26 +020019class StartSensorsStage(Stage):
20 priority = StepOrder.START_SENSORS
21 config_block = 'sensors'
koder aka kdanilov70227062016-11-26 23:23:21 +020022
koder aka kdanilov39e449e2016-12-17 15:15:26 +020023 def run(self, ctx: TestRun) -> None:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020024 if array.array('L').itemsize != 8:
25 message = "Python array.array('L') items should be 8 bytes in size, not {}." + \
26 " Can't provide sensors on this platform. Disable sensors in config and retry"
27 logger.critical(message.format(array.array('L').itemsize))
28 raise utils.StopTestError()
koder aka kdanilov39e449e2016-12-17 15:15:26 +020029
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020030 # TODO: need carefully fix this
31 # sensors config is:
32 # role:
33 # sensor: [str]
34 # or
35 # role:
36 # sensor:
37 # allowed: [str]
38 # dissallowed: [str]
39 # params: Any
koder aka kdanilov39e449e2016-12-17 15:15:26 +020040 per_role_config = {} # type: Dict[str, Dict[str, str]]
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020041
42 for name, val in ctx.config.sensors.roles_mapping.raw().items():
koder aka kdanilov39e449e2016-12-17 15:15:26 +020043 if isinstance(val, str):
44 val = {vl.strip(): ".*" for vl in val.split(",")}
45 elif isinstance(val, list):
46 val = {vl: ".*" for vl in val}
47 per_role_config[name] = val
48
49 if 'all' in per_role_config:
50 all_vl = per_role_config.pop('all')
51 all_roles = set(per_role_config)
52
53 for node in ctx.nodes:
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020054 all_roles.update(node.info.roles) # type: ignore
koder aka kdanilov39e449e2016-12-17 15:15:26 +020055
56 for name, vals in list(per_role_config.items()):
57 new_vals = all_vl.copy()
58 new_vals.update(vals)
59 per_role_config[name] = new_vals
koder aka kdanilov70227062016-11-26 23:23:21 +020060
61 for node in ctx.nodes:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020062 node_cfg = {} # type: Dict[str, Dict[str, str]]
koder aka kdanilov39e449e2016-12-17 15:15:26 +020063 for role in node.info.roles:
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020064 node_cfg.update(per_role_config.get(role, {})) # type: ignore
koder aka kdanilov70227062016-11-26 23:23:21 +020065
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020066 nid = node.info.node_id()
koder aka kdanilov39e449e2016-12-17 15:15:26 +020067 if node_cfg:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020068 # ceph requires additional settings
69 if 'ceph' in node_cfg:
70 node_cfg['ceph'].update(node.info.params['ceph'])
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020071 node_cfg['ceph']['osds'] = [osd.id for osd in node.info.params['ceph-osds']] # type: ignore
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020072
73 logger.debug("Setting up sensort RPC plugin for node %s", nid)
74 node.upload_plugin("sensors", SENSORS_PLUGIN_CODE)
75 ctx.sensors_run_on.add(nid)
76 logger.debug("Start monitoring node %s", nid)
77 node.conn.sensors.start(node_cfg)
78 else:
79 logger.debug("Skip monitoring node %s, as no sensors selected", nid)
80
81
82def collect_sensors_data(ctx: TestRun, stop: bool = False):
83 for node in ctx.nodes:
84 node_id = node.info.node_id()
85 if node_id in ctx.sensors_run_on:
86
87 if stop:
88 func = node.conn.sensors.stop
89 else:
90 func = node.conn.sensors.get_updates
91
koder aka kdanilov3af3c332016-12-19 17:12:34 +020092 # TODO: data is unpacked/repacked here with no reason
93 for path, value in sensors_rpc_plugin.unpack_rpc_updates(func()):
94 ctx.storage.append(value, "metric", node_id, path)
koder aka kdanilov70227062016-11-26 23:23:21 +020095
96
koder aka kdanilov39e449e2016-12-17 15:15:26 +020097class CollectSensorsStage(Stage):
98 priority = StepOrder.COLLECT_SENSORS
99 config_block = 'sensors'
koder aka kdanilov70227062016-11-26 23:23:21 +0200100
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200101 def run(self, ctx: TestRun) -> None:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200102 collect_sensors_data(ctx, True)
koder aka kdanilov70227062016-11-26 23:23:21 +0200103
104
105# def delta(func, only_upd=True):
106# prev = {}
107# while True:
108# for dev_name, vals in func():
109# if dev_name not in prev:
110# prev[dev_name] = {}
111# for name, (val, _) in vals.items():
112# prev[dev_name][name] = val
113# else:
114# dev_prev = prev[dev_name]
115# res = {}
116# for stat_name, (val, accum_val) in vals.items():
117# if accum_val:
118# if stat_name in dev_prev:
119# delta = int(val) - int(dev_prev[stat_name])
120# if not only_upd or 0 != delta:
121# res[stat_name] = str(delta)
122# dev_prev[stat_name] = val
123# elif not only_upd or '0' != val:
124# res[stat_name] = val
125#
126# if only_upd and len(res) == 0:
127# continue
128# yield dev_name, res
129# yield None, None
130#
131#
132
133