#! /usr/bin/env python
-import logging
-import argparse
-import shared_utils
import json
import urlparse
-logger = logging.getLogger('create_kibana_dashboards')
-logger.setLevel(logging.DEBUG)
-file_handler = logging.FileHandler('/var/log/{}.log'.format(__name__))
-file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s'))
-logger.addHandler(file_handler)
+import argparse
-_installers = {'fuel', 'apex', 'compass', 'joid'}
+import conf_utils
+import logger_utils
+import shared_utils
+
+logger = logger_utils.KibanaDashboardLogger('elastic2kibana').get
-# see class VisualizationState for details on format
-_testcases = [
- ('functest', 'Tempest',
- [
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.duration"
- }
- }
- ],
- "type": "line",
- "metadata": {
- "label": "Tempest duration",
- "test_family": "VIM"
- }
- },
-
- {
- "metrics": [
- {
- "type": "sum",
- "params": {
- "field": "details.tests"
- }
- },
- {
- "type": "sum",
- "params": {
- "field": "details.failures"
- }
- }
- ],
- "type": "histogram",
- "metadata": {
- "label": "Tempest nr of tests/failures",
- "test_family": "VIM"
- }
- },
-
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.success_percentage"
- }
- }
- ],
- "type": "line",
- "metadata": {
- "label": "Tempest success percentage",
- "test_family": "VIM"
- }
- }
- ]
- ),
-
- ('functest', 'Rally',
- [
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.duration"
- }
- }
- ],
- "type": "line",
- "metadata": {
- "label": "Rally duration",
- "test_family": "VIM"
- }
- },
-
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.tests"
- }
- }
- ],
- "type": "histogram",
- "metadata": {
- "label": "Rally nr of tests",
- "test_family": "VIM"
- }
- },
-
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.success_percentage"
- }
- }
- ],
- "type": "line",
- "metadata": {
- "label": "Rally success percentage",
- "test_family": "VIM"
- }
- }
- ]
- ),
-
- ('functest', 'vPing',
- [
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.duration"
- }
- }
- ],
- "type": "line",
- "metadata": {
- "label": "vPing duration",
- "test_family": "VIM"
- }
- }
- ]
- ),
-
- ('functest', 'vPing_userdata',
- [
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.duration"
- }
- }
- ],
- "type": "line",
- "metadata": {
- "label": "vPing_userdata duration",
- "test_family": "VIM"
- }
- }
- ]
- ),
-
- ('functest', 'ODL',
- [
- {
- "metrics": [
- {
- "type": "sum",
- "params": {
- "field": "details.tests"
- }
- },
- {
- "type": "sum",
- "params": {
- "field": "details.failures"
- }
- }
- ],
- "type": "histogram",
- "metadata": {
- "label": "ODL nr of tests/failures",
- "test_family": "Controller"
- }
- },
-
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.success_percentage"
- }
- }
- ],
- "type": "line",
- "metadata": {
- "label": "ODL success percentage",
- "test_family": "Controller"
- }
- }
- ]
- ),
-
- ('functest', 'ONOS',
- [
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.FUNCvirNet.duration"
- }
- }
- ],
- "type": "line",
- "metadata": {
- "label": "ONOS FUNCvirNet duration",
- "test_family": "Controller"
- }
- },
-
- {
- "metrics": [
- {
- "type": "sum",
- "params": {
- "field": "details.FUNCvirNet.tests"
- }
- },
- {
- "type": "sum",
- "params": {
- "field": "details.FUNCvirNet.failures"
- }
- }
- ],
- "type": "histogram",
- "metadata": {
- "label": "ONOS FUNCvirNet nr of tests/failures",
- "test_family": "Controller"
- }
- },
-
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.FUNCvirNetL3.duration"
- }
- }
- ],
- "type": "line",
- "metadata": {
- "label": "ONOS FUNCvirNetL3 duration",
- "test_family": "Controller"
- }
- },
-
- {
- "metrics": [
- {
- "type": "sum",
- "params": {
- "field": "details.FUNCvirNetL3.tests"
- }
- },
- {
- "type": "sum",
- "params": {
- "field": "details.FUNCvirNetL3.failures"
- }
- }
- ],
- "type": "histogram",
- "metadata": {
- "label": "ONOS FUNCvirNetL3 nr of tests/failures",
- "test_family": "Controller"
- }
- }
- ]
- ),
-
- ('functest', 'vIMS',
- [
- {
- "metrics": [
- {
- "type": "sum",
- "params": {
- "field": "details.sig_test.tests"
- }
- },
- {
- "type": "sum",
- "params": {
- "field": "details.sig_test.failures"
- }
- },
- {
- "type": "sum",
- "params": {
- "field": "details.sig_test.passed"
- }
- },
- {
- "type": "sum",
- "params": {
- "field": "details.sig_test.skipped"
- }
- }
- ],
- "type": "histogram",
- "metadata": {
- "label": "vIMS nr of tests/failures/passed/skipped",
- "test_family": "Features"
- }
- },
-
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.vIMS.duration"
- }
- },
- {
- "type": "avg",
- "params": {
- "field": "details.orchestrator.duration"
- }
- },
- {
- "type": "avg",
- "params": {
- "field": "details.sig_test.duration"
- }
- }
- ],
- "type": "histogram",
- "metadata": {
- "label": "vIMS/ochestrator/test duration",
- "test_family": "Features"
- }
- }
- ]
- ),
-
- ('promise', 'promise',
- [
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.duration"
- }
- }
- ],
- "type": "line",
- "metadata": {
- "label": "promise duration",
- "test_family": "Features"
- }
- },
-
- {
- "metrics": [
- {
- "type": "sum",
- "params": {
- "field": "details.tests"
- }
- },
- {
- "type": "sum",
- "params": {
- "field": "details.failures"
- }
- }
- ],
- "type": "histogram",
- "metadata": {
- "label": "promise nr of tests/failures",
- "test_family": "Features"
- }
- }
- ]
- ),
-
- ('doctor', 'doctor-notification',
- [
- {
- "metrics": [
- {
- "type": "avg",
- "params": {
- "field": "details.duration"
- }
- }
- ],
- "type": "line",
- "metadata": {
- "label": "doctor-notification duration",
- "test_family": "Features"
- }
- }
- ]
- )
-]
+_installers = {'fuel', 'apex', 'compass', 'joid'}
class KibanaDashboard(dict):
- def __init__(self, project_name, case_name, installer, pod, versions, visualization_detail):
+ def __init__(self, project_name, case_name, family, installer, pod, scenarios, visualization):
super(KibanaDashboard, self).__init__()
self.project_name = project_name
self.case_name = case_name
+ self.family = family
self.installer = installer
self.pod = pod
- self.versions = versions
- self.visualization_detail = visualization_detail
+ self.scenarios = scenarios
+ self.visualization = visualization
self._visualization_title = None
self._kibana_visualizations = []
self._kibana_dashboard = None
self._create()
def _create_visualizations(self):
- for version in self.versions:
+ for scenario in self.scenarios:
self._kibana_visualizations.append(KibanaVisualization(self.project_name,
self.case_name,
self.installer,
self.pod,
- version,
- self.visualization_detail))
+ scenario,
+ self.visualization))
self._visualization_title = self._kibana_visualizations[0].vis_state_title
for visualization in self._kibana_visualizations:
url = urlparse.urljoin(base_elastic_url, '/.kibana/visualization/{}'.format(visualization.id))
logger.debug("publishing visualization '{}'".format(url))
- shared_utils.publish_json(visualization, es_user, es_passwd, url)
+ shared_utils.publish_json(visualization, es_creds, url)
def _construct_panels(self):
size_x = 6
},
separators=(',', ':'))
self['uiStateJSON'] = "{}"
- self['version'] = 1
+ self['scenario'] = 1
self['timeRestore'] = False
self['kibanaSavedObjectMeta'] = {
'searchSourceJSON': json.dumps({
},
separators=(',', ':'))
}
- self['metadata'] = self.visualization_detail['metadata']
+
+ label = self.case_name
+ if 'label' in self.visualization:
+ label += " %s" % self.visualization.get('label')
+ label += " %s" % self.visualization.get('name')
+ self['metadata'] = {
+ "label": label,
+ "test_family": self.family
+ }
def _publish(self):
url = urlparse.urljoin(base_elastic_url, '/.kibana/dashboard/{}'.format(self.id))
logger.debug("publishing dashboard '{}'".format(url))
- shared_utils.publish_json(self, es_user, es_passwd, url)
+ shared_utils.publish_json(self, es_creds, url)
def publish(self):
self._publish_visualizations()
]
"""
- def __init__(self, project_name, case_name, installer, pod, version):
+ def __init__(self, project_name, case_name, installer, pod, scenario):
super(KibanaSearchSourceJSON, self).__init__()
self["filter"] = [
{"match": {"project_name": {"query": project_name, "type": "phrase"}}},
{"match": {"case_name": {"query": case_name, "type": "phrase"}}},
{"match": {"installer": {"query": installer, "type": "phrase"}}},
- {"match": {"version": {"query": version, "type": "phrase"}}}
+ {"match": {"scenario": {"query": scenario, "type": "phrase"}}}
]
if pod != 'all':
self["filter"].append({"match": {"pod_name": {"query": pod, "type": "phrase"}}})
class VisualizationState(dict):
- def __init__(self, input_dict):
- """
- dict structure:
- {
- "metrics":
- [
- {
- "type": type, # default sum
- "params": {
- "field": field # mandatory, no default
- },
- {metric2}
- ],
- "segments":
- [
- {
- "type": type, # default date_histogram
- "params": {
- "field": field # default creation_date
- },
- {segment2}
- ],
- "type": type, # default area
- "mode": mode, # default grouped for type 'histogram', stacked for other types
- "metadata": {
- "label": "Tempest duration",# mandatory, no default
- "test_family": "VIM" # mandatory, no default
- }
- }
-
- default modes:
- type histogram: grouped
- type area: stacked
-
- :param input_dict:
- :return:
- """
+ def __init__(self, visualization):
super(VisualizationState, self).__init__()
- metrics = input_dict['metrics']
- segments = [] if 'segments' not in input_dict else input_dict['segments']
-
- graph_type = 'area' if 'type' not in input_dict else input_dict['type']
- self['type'] = graph_type
-
- if 'mode' not in input_dict:
- if graph_type == 'histogram':
- mode = 'grouped'
- else:
- # default
- mode = 'stacked'
+ name = visualization.get('name')
+ fields = visualization.get('fields')
+
+ if name == 'tests_failures':
+ mode = 'grouped'
+ metric_type = 'sum'
+ self['type'] = 'histogram'
else:
- mode = input_dict['mode']
+ # duration or success_percentage
+ mode = 'stacked'
+ metric_type = 'avg'
+ self['type'] = 'line'
+
self['params'] = {
"shareYAxis": True,
"addTooltip": True,
self['aggs'] = []
i = 1
- for metric in metrics:
+ for field in fields:
self['aggs'].append({
"id": str(i),
- "type": 'sum' if 'type' not in metric else metric['type'],
+ "type": metric_type,
"schema": "metric",
"params": {
- "field": metric['params']['field']
+ "field": field.get('field')
}
})
i += 1
- if len(segments) > 0:
- for segment in segments:
- self['aggs'].append({
- "id": str(i),
- "type": 'date_histogram' if 'type' not in segment else segment['type'],
- "schema": "metric",
- "params": {
- "field": "creation_date" if ('params' not in segment or 'field' not in segment['params'])
- else segment['params']['field'],
- "interval": "auto",
- "customInterval": "2h",
- "min_doc_count": 1,
- "extended_bounds": {}
- }
- })
- i += 1
- else:
- self['aggs'].append({
+ self['aggs'].append({
"id": str(i),
"type": 'date_histogram',
"schema": "segment",
"params": {
- "field": "creation_date",
+ "field": "start_date",
"interval": "auto",
"customInterval": "2h",
"min_doc_count": 1,
class KibanaVisualization(dict):
- def __init__(self, project_name, case_name, installer, pod, version, detail):
+ def __init__(self, project_name, case_name, installer, pod, scenario, visualization):
"""
We need two things
1. filter created from
case_name
installer
pod
- version
+ scenario
2. visualization state
field for y axis (metric) with type (avg, sum, etc.)
field for x axis (segment) with type (date_histogram)
:return:
"""
super(KibanaVisualization, self).__init__()
- vis_state = VisualizationState(detail)
+ vis_state = VisualizationState(visualization)
self.vis_state_title = vis_state['title']
self['title'] = '{} {} {} {} {} {}'.format(project_name,
case_name,
self.vis_state_title,
installer,
pod,
- version)
+ scenario)
self.id = self['title'].replace(' ', '-').replace('/', '-')
self['visState'] = json.dumps(vis_state, separators=(',', ':'))
self['uiStateJSON'] = "{}"
self['description'] = "Kibana visualization for project_name '{}', case_name '{}', data '{}', installer '{}'," \
- " pod '{}' and version '{}'".format(project_name,
+ " pod '{}' and scenario '{}'".format(project_name,
case_name,
self.vis_state_title,
installer,
pod,
- version)
- self['version'] = 1
+ scenario)
+ self['scenario'] = 1
self['kibanaSavedObjectMeta'] = {"searchSourceJSON": json.dumps(KibanaSearchSourceJSON(project_name,
case_name,
installer,
pod,
- version),
+ scenario),
separators=(',', ':'))}
-def _get_pods_and_versions(project_name, case_name, installer):
+def _get_pods_and_scenarios(project_name, case_name, installer):
query_json = json.JSONEncoder().encode({
"query": {
"bool": {
}
})
- elastic_data = shared_utils.get_elastic_data(urlparse.urljoin(base_elastic_url, '/test_results/mongo2elastic'),
- es_user, es_passwd, query_json)
+ elastic_data = shared_utils.get_elastic_docs(urlparse.urljoin(base_elastic_url, '/test_results/mongo2elastic'),
+ es_creds, query_json)
- pods_and_versions = {}
+ pods_and_scenarios = {}
for data in elastic_data:
pod = data['pod_name']
- if pod in pods_and_versions:
- pods_and_versions[pod].add(data['version'])
+ if pod in pods_and_scenarios:
+ pods_and_scenarios[pod].add(data['scenario'])
else:
- pods_and_versions[pod] = {data['version']}
+ pods_and_scenarios[pod] = {data['scenario']}
- if 'all' in pods_and_versions:
- pods_and_versions['all'].add(data['version'])
+ if 'all' in pods_and_scenarios:
+ pods_and_scenarios['all'].add(data['scenario'])
else:
- pods_and_versions['all'] = {data['version']}
+ pods_and_scenarios['all'] = {data['scenario']}
- return pods_and_versions
+ return pods_and_scenarios
def construct_dashboards():
"""
iterate over testcase and installer
1. get available pods for each testcase/installer pair
- 2. get available version for each testcase/installer/pod tuple
+ 2. get available scenario for each testcase/installer/pod tuple
3. construct KibanaInput and append
:return: list of KibanaDashboards
"""
kibana_dashboards = []
- for project_name, case_name, visualization_details in _testcases:
- for installer in _installers:
- pods_and_versions = _get_pods_and_versions(project_name, case_name, installer)
- for visualization_detail in visualization_details:
- for pod, versions in pods_and_versions.iteritems():
- kibana_dashboards.append(KibanaDashboard(project_name, case_name, installer, pod, versions,
- visualization_detail))
+ for project, case_dicts in conf_utils.testcases_yaml.items():
+ for case in case_dicts:
+ case_name = case.get('name')
+ visualizations = case.get('visualizations')
+ family = case.get('test_family')
+ for installer in _installers:
+ pods_and_scenarios = _get_pods_and_scenarios(project, case_name, installer)
+ for visualization in visualizations:
+ for pod, scenarios in pods_and_scenarios.iteritems():
+ kibana_dashboards.append(KibanaDashboard(project,
+ case_name,
+ family,
+ installer,
+ pod,
+ scenarios,
+ visualization))
return kibana_dashboards
parser = argparse.ArgumentParser(description='Create Kibana dashboards from data in elasticsearch')
parser.add_argument('-e', '--elasticsearch-url', default='http://localhost:9200',
help='the url of elasticsearch, defaults to http://localhost:9200')
+
parser.add_argument('-js', '--generate_js_inputs', action='store_true',
help='Use this argument to generate javascript inputs for kibana landing page')
+
parser.add_argument('--js_path', default='/usr/share/nginx/html/kibana_dashboards/conf.js',
help='Path of javascript file with inputs for kibana landing page')
+
parser.add_argument('-k', '--kibana_url', default='https://testresults.opnfv.org/kibana/app/kibana',
help='The url of kibana for javascript inputs')
- parser.add_argument('-u', '--elasticsearch-username',
- help='the username for elasticsearch')
-
- parser.add_argument('-p', '--elasticsearch-password',
- help='the password for elasticsearch')
+ parser.add_argument('-u', '--elasticsearch-username', default=None,
+ help='The username with password for elasticsearch in format username:password')
args = parser.parse_args()
base_elastic_url = args.elasticsearch_url
generate_inputs = args.generate_js_inputs
input_file_path = args.js_path
kibana_url = args.kibana_url
- es_user = args.elasticsearch_username
- es_passwd = args.elasticsearch_password
+ es_creds = args.elasticsearch_username
dashboards = construct_dashboards()