6 from jinja2 import PackageLoader, Environment
8 from common import elastic_access
9 from common import logger_utils
10 from conf import testcases
11 from conf.config import APIConfig
13 logger = logger_utils.DashboardLogger('elastic2kibana').get
15 parser = argparse.ArgumentParser()
16 parser.add_argument("-c", "--config-file",
18 help="Config file location")
20 args = parser.parse_args()
21 CONF = APIConfig().parse(args.config_file)
22 base_elastic_url = CONF.elastic_url
23 generate_inputs = CONF.is_js
24 input_file_path = CONF.js_path
25 kibana_url = CONF.kibana_url
26 es_creds = CONF.elastic_creds
28 _installers = {'fuel', 'apex', 'compass', 'joid'}
31 class KibanaDashboard(dict):
32 def __init__(self, project_name, case_name, family, installer, pod, scenarios, visualization):
33 super(KibanaDashboard, self).__init__()
34 self.project_name = project_name
35 self.case_name = case_name
37 self.installer = installer
39 self.scenarios = scenarios
40 self.visualization = visualization
41 self._visualization_title = None
42 self._kibana_visualizations = []
43 self._kibana_dashboard = None
44 self._create_visualizations()
47 def _create_visualizations(self):
48 for scenario in self.scenarios:
49 self._kibana_visualizations.append(KibanaVisualization(self.project_name,
56 self._visualization_title = self._kibana_visualizations[0].vis_title
58 def _publish_visualizations(self):
59 for visualization in self._kibana_visualizations:
60 url = urlparse.urljoin(base_elastic_url, '/.kibana/visualization/{}'.format(visualization.id))
61 logger.debug("publishing visualization '{}'".format(url))
62 # logger.error("_publish_visualization: %s" % visualization)
63 elastic_access.publish_docs(url, es_creds, visualization)
65 def _construct_panels(self):
73 for visualization in self._kibana_visualizations:
75 "id": visualization.id,
76 "type": 'visualization',
77 "panelIndex": panel_index,
85 if column > max_columns:
88 return json.dumps(panels_json, separators=(',', ':'))
91 self['title'] = '{} {} {} {} {}'.format(self.project_name,
94 self._visualization_title,
96 self.id = self['title'].replace(' ', '-').replace('/', '-')
99 self['description'] = "Kibana dashboard for project_name '{}', case_name '{}', installer '{}', data '{}' and" \
100 " pod '{}'".format(self.project_name,
103 self._visualization_title,
105 self['panelsJSON'] = self._construct_panels()
106 self['optionsJSON'] = json.dumps({
109 separators=(',', ':'))
110 self['uiStateJSON'] = "{}"
112 self['timeRestore'] = False
113 self['kibanaSavedObjectMeta'] = {
114 'searchSourceJSON': json.dumps({
120 "analyze_wildcard": True
126 separators=(',', ':'))
129 label = self.case_name
130 if 'label' in self.visualization:
131 label += " %s" % self.visualization.get('label')
132 label += " %s" % self.visualization.get('name')
135 "test_family": self.family
139 url = urlparse.urljoin(base_elastic_url, '/.kibana/dashboard/{}'.format(self.id))
140 logger.debug("publishing dashboard '{}'".format(url))
141 elastic_access.publish_docs(url, es_creds, self)
144 self._publish_visualizations()
148 class KibanaSearchSourceJSON(dict):
151 {"match": {"installer": {"query": installer, "type": "phrase"}}},
152 {"match": {"project_name": {"query": project_name, "type": "phrase"}}},
153 {"match": {"case_name": {"query": case_name, "type": "phrase"}}}
157 def __init__(self, project_name, case_name, installer, pod, scenario):
158 super(KibanaSearchSourceJSON, self).__init__()
160 {"match": {"project_name": {"query": project_name, "type": "phrase"}}},
161 {"match": {"case_name": {"query": case_name, "type": "phrase"}}},
162 {"match": {"installer": {"query": installer, "type": "phrase"}}},
163 {"match": {"scenario": {"query": scenario, "type": "phrase"}}}
166 self["filter"].append({"match": {"pod_name": {"query": pod, "type": "phrase"}}})
169 class VisualizationBuilder(object):
170 def __init__(self, visualization):
171 super(VisualizationBuilder, self).__init__()
172 self.visualization = visualization
175 name = self.visualization.get('name')
176 fields = self.visualization.get('fields')
183 "field": field.get("field")
187 env = Environment(loader=PackageLoader('elastic2kibana', 'templates'))
188 env.filters['jsonify'] = json.dumps
189 template = env.get_template('{}.json'.format(name))
190 vis = template.render(aggs=aggs)
191 return json.loads(vis)
194 class KibanaVisualization(dict):
195 def __init__(self, project_name, case_name, installer, pod, scenario, visualization):
198 1. filter created from
204 2. visualization state
205 field for y axis (metric) with type (avg, sum, etc.)
206 field for x axis (segment) with type (date_histogram)
210 super(KibanaVisualization, self).__init__()
211 vis = VisualizationBuilder(visualization).build()
212 self.vis_title = vis['title']
213 self['title'] = '{} {} {} {} {} {}'.format(project_name,
219 self.id = self['title'].replace(' ', '-').replace('/', '-')
220 self['visState'] = json.dumps(vis, separators=(',', ':'))
221 self['uiStateJSON'] = "{}"
222 self['description'] = "Kibana visualization for project_name '{}', case_name '{}', metric '{}', installer '{}'," \
223 " pod '{}' and scenario '{}'".format(project_name,
230 self['kibanaSavedObjectMeta'] = {"searchSourceJSON": json.dumps(KibanaSearchSourceJSON(project_name,
235 separators=(',', ':'))}
238 def _get_pods_and_scenarios(project_name, case_name, installer):
239 query_json = json.JSONEncoder().encode({
246 {"match": {"installer": {"query": installer, "type": "phrase"}}},
247 {"match": {"project_name": {"query": project_name, "type": "phrase"}}},
248 {"match": {"case_name": {"query": case_name, "type": "phrase"}}}
254 elastic_data = elastic_access.get_docs(urlparse.urljoin(base_elastic_url, '/test_results/mongo2elastic'),
255 es_creds, query_json)
257 pods_and_scenarios = {}
259 for data in elastic_data:
260 pod = data['pod_name']
261 if pod in pods_and_scenarios:
262 pods_and_scenarios[pod].add(data['scenario'])
264 pods_and_scenarios[pod] = {data['scenario']}
266 if 'all' in pods_and_scenarios:
267 pods_and_scenarios['all'].add(data['scenario'])
269 pods_and_scenarios['all'] = {data['scenario']}
271 return pods_and_scenarios
274 def construct_dashboards():
276 iterate over testcase and installer
277 1. get available pods for each testcase/installer pair
278 2. get available scenario for each testcase/installer/pod tuple
279 3. construct KibanaInput and append
281 :return: list of KibanaDashboards
283 kibana_dashboards = []
284 for project, case_dicts in testcases.testcases_yaml.items():
285 for case in case_dicts:
286 case_name = case.get('name')
287 visualizations = case.get('visualizations')
288 family = case.get('test_family')
289 for installer in _installers:
290 pods_and_scenarios = _get_pods_and_scenarios(project, case_name, installer)
291 for visualization in visualizations:
292 for pod, scenarios in pods_and_scenarios.iteritems():
293 kibana_dashboards.append(KibanaDashboard(project,
300 return kibana_dashboards
303 def generate_js_inputs(js_file_path, kibana_url, dashboards):
305 for dashboard in dashboards:
306 dashboard_meta = dashboard['metadata']
307 test_family = dashboard_meta['test_family']
308 test_label = dashboard_meta['label']
310 if test_family not in js_dict:
311 js_dict[test_family] = {}
313 js_test_family = js_dict[test_family]
315 if test_label not in js_test_family:
316 js_test_family[test_label] = {}
318 js_test_label = js_test_family[test_label]
320 if dashboard.installer not in js_test_label:
321 js_test_label[dashboard.installer] = {}
323 js_installer = js_test_label[dashboard.installer]
324 js_installer[dashboard.pod] = kibana_url + '#/dashboard/' + dashboard.id
326 with open(js_file_path, 'w+') as js_file_fdesc:
327 js_file_fdesc.write('var kibana_dashboard_links = ')
328 js_file_fdesc.write(str(js_dict).replace("u'", "'"))
332 dashboards = construct_dashboards()
334 for kibana_dashboard in dashboards:
335 kibana_dashboard.publish()
338 generate_js_inputs(input_file_path, kibana_url, dashboards)