Separate test data vs dashboard script
[integration/test.git] / csit / scripts / generate_visState.py
1 # SPDX-License-Identifier: EPL-1.0
2 ##############################################################################
3 # Copyright (c) 2018 The Linux Foundation and others.
4 #
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Eclipse Public License v1.0
7 # which accompanies this distribution, and is available at
8 # http://www.eclipse.org/legal/epl-v10.html
9 ##############################################################################
10 import yaml
11 from copy import deepcopy as dc
12
13 import json
14
15
16 def p(x):
17     print(json.dumps(x, indent=4, sort_keys=True))
18
19
20 class visState:
21     def __init__(self):
22         self.content = {
23             'title': None,
24             'type': None,
25             'params': {
26                 'type': None,
27                 'grid': {
28                     'categoryLines': False,
29                     'style': {
30                         'color': '#eee'
31                     }
32                 },
33                 'categoryAxes': None,
34                 'valueAxes': None,
35                 'seriesParams': None,
36                 'addTooltip': True,
37                 'addLegend': True,
38                 'legendPosition': 'right',
39                 'times': [],
40                 'addTimeMarker': False
41             },
42             'aggs': None
43         }
44
45     def create(self, config):
46         temp = self.content
47         temp['title'] = config['title']
48         temp['type'] = temp['params']['type'] = config['type']
49
50         cat = categoryAxes()
51         temp['params']['categoryAxes'] = [dc(
52             cat.create()) for i in range(config['num_cat_axes'])]
53
54         val = ValueAxes()
55         temp['params']['valueAxes'] = [dc(val.create(position=i['position'],
56                                                      title=i['title']))
57                                        for _, i in
58                                        config['value_axes'].items()]
59
60         agg = aggs()
61
62         temp['aggs'] = \
63             [dc(agg.create(id=i,
64                            field=config['aggs'][i]['field'],
65                            custom_label=config['aggs'][i]['custom_label'],
66                            schema=config['aggs'][i]['schema']))
67              for i in range(1, len(config['aggs']) + 1)]
68
69         temp['params']['seriesParams'] = [seriesParams(i['data_type'],
70                                                        i['mode'],
71                                                        i['label'],
72                                                        i['agg_id'],
73                                                        i['value_axis'])
74                                           .create()
75                                           for _, i in
76                                           config['seriesParams'].items()]
77
78         return temp
79
80
81 class categoryAxes:
82     def __init__(self):
83         self.content = {
84             'id': None,
85             'type': 'category',
86             'position': 'bottom',
87             'show': True,
88             'style': {},
89             'scale': {
90                 'type': 'linear'
91             },
92             'labels': {
93                 'show': True,
94                 'truncate': 100
95             },
96             'title': {}
97         }
98         self.counter = 0
99
100     def create(self):
101         self.counter += 1
102         temp = dc(self.content)
103         temp['id'] = 'CategoryAxis-{}'.format(self.counter)
104         return temp
105
106
107 class ValueAxes:
108     def __init__(self):
109         self.content = {
110             'id': None,
111             'name': None,
112             'type': 'value',
113             'position': 'left',
114             'show': True,
115             'style': {},
116             'scale': {
117                 'type': 'linear',
118                 'mode': 'normal'
119             },
120             'labels': {
121                 'show': True,
122                 'rotate': 0,
123                 'filter': False,
124                 'truncate': 100
125             },
126             'title': {
127                 'text': None
128             }
129         }
130         self.counter = 0
131
132     def create(self, position='left', title='Value'):
133         self.counter += 1
134         temp = dc(self.content)
135         temp['id'] = 'ValueAxis-{}'.format(self.counter)
136         if position == 'left':
137             temp['name'] = 'LeftAxis-{}'.format(self.counter)
138         elif position == 'right':
139             temp['name'] = 'RightAxis-{}'.format(self.counter)
140         else:
141             # raise ValueError('Not one of left or right')
142             # assuming default
143             temp['name'] = 'LeftAxis-{}'.format(self.counter)
144
145         temp['title']['text'] = title
146
147         return temp
148
149
150 class seriesParams:
151     def __init__(self, data_type, mode, label, agg_id, value_axis):
152         self.content = {
153             'show': True,
154             'type': data_type,
155             'mode': mode,
156             'data': {
157                 'label': label,
158                 'id': str(agg_id)
159             },
160             'valueAxis': 'ValueAxis-{}'.format(value_axis),
161             'drawLinesBetweenPoints': True,
162             'showCircles': True
163         }
164
165     def create(self):
166         return self.content
167
168
169 class aggs:
170     def __init__(self):
171         self.content = {
172             'id': None,
173             'enabled': True,
174             'type': None,
175             'schema': None,
176             'params': {
177                 'field': None,
178                 'customLabel': None
179             }
180         }
181         self.counter = 0
182
183     def create(self, id, field, custom_label, schema):
184         temp = dc(self.content)
185         temp['id'] = id
186         temp['params']['field'] = field
187         temp['params']['customLabel'] = custom_label
188         temp['schema'] = schema
189         if schema == 'metric':
190             temp['type'] = 'max'
191             return temp
192         elif schema == 'segment':
193             temp['type'] = 'terms'
194             temp['params']['size'] = 20  # default
195             temp['params']['order'] = 'asc'
196             temp['params']['orderBy'] = '_term'
197         return temp
198
199
200 # generate takes both the template config and project specific config and
201 # parses and organizes as much info available from that and
202 # generates an intermediate format first which
203 # contains all necessary info to deterministically create the visState to
204 # be sent to Kibana. Hence, any error occuring in the visualizaton side
205 # must first be checked by looking at the intermediate format.
206
207 def generate(dash_config, viz_config):
208
209     format = {
210         "type": None,
211         "value_axes": {},
212         "seriesParams": {},
213         "index_pattern": None,
214         "desc": None,
215         "id": None,
216         "aggs": {},
217         "title": None,
218         "num_cat_axes": None
219     }
220
221     value_axes_format = {
222         "index": {
223             "position": None,
224             "title": None
225         }
226     }
227
228     seriesParams_format = {
229         "index": {
230             "value_axis": None,
231             "data_type": None,
232             "mode": None,
233             "label": None,
234             "agg_id": None
235         }
236     }
237
238     aggs_format = {
239         "index": {
240             "custom_label": None,
241             "field": None,
242             "schema": None
243         }
244     }
245
246     # all general description must be present in either of the config files
247     for config in [viz_config, dash_config]:
248         general_fields = ['type', 'index_pattern',
249                           'num_cat_axes', 'title', 'desc', 'id']
250         for i in general_fields:
251             try:
252                 format[i] = config[i]
253             except KeyError as e:
254                 pass
255
256     # setting any default values if available
257     mappings = {'value_axes': value_axes_format,
258                 'seriesParams': seriesParams_format, 'aggs': aggs_format}
259     for index, container in mappings.items():
260         try:
261             default_values = viz_config[index]['default']
262             for i in default_values:
263                 container['index'][i] = default_values[i]
264         except Exception:
265             pass
266
267     value_axes_counter = 1
268     for m in viz_config['value_axes']:
269         if m != "default":
270             temp = dc(value_axes_format)
271             temp[str(value_axes_counter)] = temp['index']
272             for i in ['position', 'title']:
273                 try:
274                     temp[str(value_axes_counter)
275                          ][i] = viz_config['value_axes'][m][i]
276                 except KeyError:
277                     pass
278             format['value_axes'].update(temp)
279             value_axes_counter += 1
280
281     seriesParams_fields = ['value_axis',
282                            'data_type', 'mode', 'label', 'agg_id']
283     try:
284         for m in viz_config['seriesParams']:
285             if m != 'default':
286                 temp = dc(seriesParams_format)
287                 temp[m] = temp['index']
288                 for i in seriesParams_fields:
289                     try:
290                         temp[m][i] = viz_config['seriesParams'][m][i]
291                     except KeyError:
292                         pass
293                 format['seriesParams'].update(temp)
294     except KeyError:
295         pass
296
297     agg_counter = 1
298     try:
299         for m in viz_config['aggs']:
300             if m != 'default':
301                 temp = dc(aggs_format)
302                 temp[m] = temp['index']
303                 for i in ['field', 'custom_label', 'schema']:
304                     try:
305                         temp[m][i] = viz_config['aggs'][m][i]
306                     except KeyError:
307                         pass
308                 format['aggs'].update(temp)
309     except KeyError:
310         pass
311
312     configs = []
313     try:
314         viz_config['series']
315         configs.append(viz_config)
316     except KeyError:
317         pass
318
319     try:
320         dash_config['y-axis']['series']
321         configs.append(dash_config['y-axis'])
322     except KeyError:
323         pass
324
325     for config in configs:
326         try:
327             value_axes_counter = 1
328             for key in config['value_axes']:
329
330                 value_axes_temp = dc(value_axes_format)
331                 value_axes_temp[str(value_axes_counter)
332                                 ] = value_axes_temp['index']
333
334                 for index in ['position', 'title']:
335                     try:
336                         value_axes_temp[str(
337                             value_axes_counter)][index] = \
338                             config['value_axes'][key][index]
339                     except KeyError as e:
340                         pass
341                 format['value_axes'].update(value_axes_temp)
342                 value_axes_counter += 1
343
344         except KeyError as e:
345             pass
346
347         try:
348             for key in config['series']:
349                 try:
350                     # check if this key is present or not
351                     config['series'][key]['not_in_seriesParams']
352                 except KeyError:
353                     seriesParams_temp = dc(seriesParams_format)
354                     seriesParams_temp[key] = seriesParams_temp['index']
355                     for index in ['value_axis', 'data_type', 'mode', 'label']:
356                         try:
357                             seriesParams_temp[key][index] = \
358                                 config['series'][key][index]
359                         except KeyError as e:
360                             pass
361                     seriesParams_temp[key]['agg_id'] = key
362                     format['seriesParams'].update(seriesParams_temp)
363                 finally:
364                     agg_temp = dc(aggs_format)
365                     agg_temp[key] = agg_temp['index']
366                     for index in ['field', 'schema']:
367                         try:
368                             agg_temp[key][index] = config['series'][key][index]
369                         except KeyError as e:
370                             pass
371                     agg_temp[key]['custom_label'] = \
372                         config['series'][key]['label']
373                     format['aggs'].update(agg_temp)
374         except KeyError as e:
375             print("required fields are empty!")
376
377     # to remove the default template index
378     for i in ['value_axes', 'seriesParams', 'aggs']:
379         try:
380             format[i].pop('index')
381         except KeyError:
382             # print("No default index found")
383             pass
384
385     if not config_validator(format):
386         raise ValueError('Missing required field values')
387
388     p(format)
389
390     vis = visState()
391     generated_visState = vis.create(format)
392
393     # checking incase there are None values \
394     # in the format indicating missing fields
395
396     if not config_validator(generated_visState):
397         raise KeyError('required fields are missing values!')
398     return format, generated_visState
399
400
401 # Check the generated format if it contains any key with None
402 # as it's value which indicates incomplete information
403 def config_validator(val):
404     flag = True
405     for _, i in val.items():
406         if isinstance(i, dict):
407             flag = config_validator(i)
408         if i is None:
409             return False
410     return flag
411
412
413 if __name__ == '__main__':
414     with open('viz.yaml', 'r') as f:
415         viz_config = yaml.safe_load(f)
416
417     with open('dashboard.yaml', 'r') as f:
418         dash_config = yaml.safe_load(f)
419
420     generate(dash_config['dashboard']['viz'][2],
421              viz_config['opendaylight-test-performance'])
422     # generate(dash_config['dashboard']['viz'][3],viz_config['opendaylight-test-performance'])
423     # generate(dash_config['dashboard']['viz'][1],viz_config['opendaylight-test-feature'])