33eb9ffee2
Change-Id: I8c95e7f433a6f22ae818a78ede4b12bb84cf1f5d
163 lines
5.8 KiB
Python
163 lines
5.8 KiB
Python
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import json
|
|
import os
|
|
|
|
from rally.common import cfg
|
|
from rally.common import logging
|
|
from rally.common import opts
|
|
from rally.common.plugin import plugin
|
|
from rally.task.processing import charts
|
|
|
|
import rally_openstack
|
|
|
|
|
|
if rally_openstack.__rally_version__ < (1, 5, 0):
|
|
# NOTE(andreykurilin): this is a workaround to make inheritance of
|
|
# OSProfilerChart clear.
|
|
OutputEmbeddedChart = type("OutputEmbeddedChart", (object, ), {})
|
|
OutputEmbeddedExternalChart = type("OutputEmbeddedExternalChart",
|
|
(object, ), {})
|
|
else:
|
|
OutputEmbeddedChart = charts.OutputEmbeddedChart
|
|
OutputEmbeddedExternalChart = charts.OutputEmbeddedExternalChart
|
|
|
|
|
|
OPTS = {
|
|
"openstack": [
|
|
cfg.StrOpt(
|
|
"osprofiler_chart_mode",
|
|
default=None,
|
|
help="Mode of embedding OSProfiler's chart. Can be 'text' "
|
|
"(embed only trace id), 'raw' (embed raw osprofiler's native "
|
|
"report) or a path to directory (raw osprofiler's native "
|
|
"reports for each iteration will be saved separately there "
|
|
"to decrease the size of rally report itself)")
|
|
]
|
|
}
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
CONF = cfg.CONF
|
|
|
|
|
|
def _datetime_json_serialize(obj):
|
|
if hasattr(obj, "isoformat"):
|
|
return obj.isoformat()
|
|
else:
|
|
return obj
|
|
|
|
|
|
@plugin.configure(name="OSProfiler")
|
|
class OSProfilerChart(OutputEmbeddedChart,
|
|
OutputEmbeddedExternalChart,
|
|
charts.OutputTextArea):
|
|
"""Chart for embedding OSProfiler data."""
|
|
|
|
@classmethod
|
|
def _fetch_osprofiler_data(cls, connection_str, trace_id):
|
|
from osprofiler.drivers import base
|
|
from osprofiler import opts as osprofiler_opts
|
|
|
|
opts.register_opts(osprofiler_opts.list_opts())
|
|
|
|
try:
|
|
engine = base.get_driver(connection_str)
|
|
except Exception:
|
|
msg = "Error while fetching OSProfiler results."
|
|
if logging.is_debug():
|
|
LOG.exception(msg)
|
|
else:
|
|
LOG.error(msg)
|
|
return None
|
|
|
|
return engine.get_report(trace_id)
|
|
|
|
@classmethod
|
|
def _generate_osprofiler_report(cls, osp_data):
|
|
from osprofiler import cmd
|
|
|
|
path = "%s/template.html" % os.path.dirname(cmd.__file__)
|
|
with open(path) as f:
|
|
html_obj = f.read()
|
|
|
|
osp_data = json.dumps(osp_data,
|
|
indent=4,
|
|
separators=(",", ": "),
|
|
default=_datetime_json_serialize)
|
|
return html_obj.replace("$DATA", osp_data).replace("$LOCAL", "false")
|
|
|
|
@classmethod
|
|
def _return_raw_response_for_complete_data(cls, data):
|
|
return charts.OutputTextArea.render_complete_data({
|
|
"title": data["title"],
|
|
"widget": "TextArea",
|
|
"data": [data["data"]["trace_id"]]
|
|
})
|
|
|
|
@classmethod
|
|
def render_complete_data(cls, data):
|
|
mode = CONF.openstack.osprofiler_chart_mode
|
|
|
|
if isinstance(data["data"]["trace_id"], list):
|
|
# NOTE(andreykurilin): it is an adoption for the format that we
|
|
# used before rally-openstack 1.5.0 .
|
|
data["data"]["trace_id"] = data["data"]["trace_id"][0]
|
|
|
|
if data["data"].get("conn_str") and mode != "text":
|
|
osp_data = cls._fetch_osprofiler_data(
|
|
data["data"]["conn_str"],
|
|
trace_id=data["data"]["trace_id"]
|
|
)
|
|
if not osp_data:
|
|
# for some reasons we failed to fetch data from OSProfiler's
|
|
# backend. in this case we can display just trace ID
|
|
return cls._return_raw_response_for_complete_data(data)
|
|
|
|
osp_report = cls._generate_osprofiler_report(osp_data)
|
|
title = "{0} : {1}".format(data["title"],
|
|
data["data"]["trace_id"])
|
|
|
|
if rally_openstack.__rally_version__ < (1, 5, 0):
|
|
return {
|
|
"title": title,
|
|
"widget": "EmbeddedChart",
|
|
"data": osp_report.replace("/script>", "\\/script>")
|
|
}
|
|
elif (mode and mode != "raw") and "workload_uuid" in data["data"]:
|
|
# NOTE(andreykurilin): we need to rework our charts plugin
|
|
# mechanism so it is available out of box
|
|
workload_uuid = data["data"]["workload_uuid"]
|
|
iteration = data["data"]["iteration"]
|
|
file_name = "w_%s-%s.html" % (workload_uuid, iteration)
|
|
path = os.path.join(mode, file_name)
|
|
with open(path, "w") as f:
|
|
f.write(osp_report)
|
|
return OutputEmbeddedExternalChart.render_complete_data(
|
|
{
|
|
"title": title,
|
|
"widget": "EmbeddedChart",
|
|
"data": path
|
|
}
|
|
)
|
|
else:
|
|
return OutputEmbeddedChart.render_complete_data(
|
|
{"title": title,
|
|
"widget": "EmbeddedChart",
|
|
"data": osp_report}
|
|
)
|
|
|
|
return cls._return_raw_response_for_complete_data(data)
|