diff options
author | Tibor Frank <tifrank@cisco.com> | 2019-04-01 16:31:38 +0200 |
---|---|---|
committer | Tibor Frank <tifrank@cisco.com> | 2019-04-04 11:39:23 +0200 |
commit | d45c3f997201a6f17b39b3e5ceb82b332852149f (patch) | |
tree | 845236245b530243b178271d039160860704e1a9 /resources/tools/presentation/generator_alerts.py | |
parent | ab635019fd3d5420a31fbd68c1549d0be2323104 (diff) |
Trending: Alerts
Change-Id: I1c744f4eeefe3082be02daa681bfc032d6db4d15
Signed-off-by: Tibor Frank <tifrank@cisco.com>
Diffstat (limited to 'resources/tools/presentation/generator_alerts.py')
-rw-r--r-- | resources/tools/presentation/generator_alerts.py | 226 |
1 files changed, 164 insertions, 62 deletions
diff --git a/resources/tools/presentation/generator_alerts.py b/resources/tools/presentation/generator_alerts.py index 83dfe2eb17..ce5d8035e9 100644 --- a/resources/tools/presentation/generator_alerts.py +++ b/resources/tools/presentation/generator_alerts.py @@ -17,6 +17,7 @@ import logging from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from os.path import isdir +from collections import OrderedDict from utils import execute_command from errors import PresentationError @@ -151,6 +152,8 @@ class Alerting(object): text=text, html=html) elif alert_data["way"] == "jenkins": + self._generate_email_body(alert_data) + # TODO: Remove when not needed self._generate_files_for_jenkins(alert_data) else: raise AlertingError("Alert with way '{0}' is not implemented.". @@ -203,82 +206,181 @@ class Alerting(object): if smtp_server: smtp_server.quit() - def _create_alert_message(self, alert): - """Create the message which is used in the generated alert. + def _get_compressed_failed_tests(self, alert, test_set, sort=True): + """Return the dictionary with compressed faild tests. The compression is + done by grouping the tests from the same area but with different NICs, + frame sizes and number of processor cores. + + For example, the failed tests: + 10ge2p1x520-64b-1c-ethip4udp-ip4scale4000-udpsrcscale15-nat44-mrr + 10ge2p1x520-64b-2c-ethip4udp-ip4scale4000-udpsrcscale15-nat44-mrr + 10ge2p1x520-64b-4c-ethip4udp-ip4scale4000-udpsrcscale15-nat44-mrr + 10ge2p1x520-imix-1c-ethip4udp-ip4scale4000-udpsrcscale15-nat44-mrr + 10ge2p1x520-imix-2c-ethip4udp-ip4scale4000-udpsrcscale15-nat44-mrr + 10ge2p1x520-imix-4c-ethip4udp-ip4scale4000-udpsrcscale15-nat44-mrr + + will be represented as: + ethip4udp-ip4scale4000-udpsrcscale15-nat44 \ + (10ge2p1x520, 64b, imix, 1c, 2c, 4c) + + Structure of returned data: + + { + "trimmed_TC_name_1": { + "nics": [], + "framesizes": [], + "cores": [] + } + ... + "trimmed_TC_name_N": { + "nics": [], + "framesizes": [], + "cores": [] + } + } - :param alert: Message is created for this alert. + :param alert: Files are created for this alert. + :param test_set: Specifies which set of tests will be included in the + result. Its name is the same as the name of file with failed tests. + :param sort: If True, the failed tests are sorted alphabetically. :type alert: dict - :returns: Message in the ASCII text and HTML format. - :rtype: tuple(str, str) + :type test_set: str + :type sort: bool + :returns: CSIT build number, VPP version, Number of failed tests, + Compressed failed tests. + :rtype: tuple(str, str, int, OrderedDict) """ - if alert["type"] == "failed-tests": - text = "" - html = "<html><body>" - for item in alert["include"]: - file_name = "{path}/{name}".format( - path=self._path_failed_tests, name=item) - try: - with open("{0}.txt".format(file_name), 'r') as txt_file: - text += "{0}:\n\n".format( - item.replace("failed-tests-", "")) - text += txt_file.read() + "\n" * 2 - except IOError: - logging.error("Not possible to read the file '{0}.txt'.". - format(file_name)) - try: - with open("{0}.rst".format(file_name), 'r') as rst_file: - html += "<h2>{0}:</h2>".format( - item.replace("failed-tests-", "")) - html += rst_file.readlines()[2].\ - replace("../trending", alert.get("url", "")) - html += "<br>" * 3 - except IOError: - logging.error("Not possible to read the file '{0}.rst'.". - format(file_name)) - html += "</body></html>" + directory = self.configs[alert["way"]]["output-dir"] + failed_tests = OrderedDict() + version = "" + try: + with open("{0}/{1}.txt".format(directory, test_set), 'r') as f_txt: + for idx, line in enumerate(f_txt): + if idx == 0: + build = line[:-1] + continue + if idx == 1: + version = line[:-1] + continue + try: + test = line[:-1].split('-') + nic = test[0] + framesize = test[1] + cores = test[2] + name = '-'.join(test[3:-1]) + except IndexError: + continue + if failed_tests.get(name, None) is None: + failed_tests[name] = dict(nics=list(), + framesizes=list(), + cores=list()) + if nic not in failed_tests[name]["nics"]: + failed_tests[name]["nics"].append(nic) + if framesize not in failed_tests[name]["framesizes"]: + failed_tests[name]["framesizes"].append(framesize) + if cores not in failed_tests[name]["cores"]: + failed_tests[name]["cores"].append(cores) + except IOError as err: + logging.error(repr(err)) + return None, None, None, None + if sort: + sorted_failed_tests = OrderedDict() + keys = [k for k in failed_tests.keys()] + keys.sort() + for key in keys: + sorted_failed_tests[key] = failed_tests[key] + return build, version, idx-1, sorted_failed_tests else: + return build, version, idx-1, failed_tests + + def _generate_email_body(self, alert): + """Create the file which is used in the generated alert. + + :param alert: Files are created for this alert. + :type alert: dict + """ + + if alert["type"] != "failed-tests": raise AlertingError("Alert of type '{0}' is not implemented.". format(alert["type"])) - return text, html + + config = self.configs[alert["way"]] + + text = "" + for idx, test_set in enumerate(alert.get("include", [])): + build, version, nr, failed_tests = \ + self._get_compressed_failed_tests(alert, test_set) + if build is None: + continue + text += ("\n\n{topo}-{arch}, " + "{nr} tests failed, " + "CSIT build: {link}/{build}, " + "VPP version: {version}\n\n". + format(topo=test_set.split('-')[-2], + arch=test_set.split('-')[-1], + nr=nr, + link=alert["urls"][idx], + build=build, + version=version)) + max_len_name = 0 + max_len_nics = 0 + max_len_framesizes = 0 + max_len_cores = 0 + for name, params in failed_tests.items(): + failed_tests[name]["nics"] = ",".join(sorted(params["nics"])) + failed_tests[name]["framesizes"] = \ + ",".join(sorted(params["framesizes"])) + failed_tests[name]["cores"] = ",".join(sorted(params["cores"])) + if len(name) > max_len_name: + max_len_name = len(name) + if len(failed_tests[name]["nics"]) > max_len_nics: + max_len_nics = len(failed_tests[name]["nics"]) + if len(failed_tests[name]["framesizes"]) > max_len_framesizes: + max_len_framesizes = len(failed_tests[name]["framesizes"]) + if len(failed_tests[name]["cores"]) > max_len_cores: + max_len_cores = len(failed_tests[name]["cores"]) + + for name, params in failed_tests.items(): + text += "{name} {nics} {frames} {cores}\n".format( + name=name + " " * (max_len_name - len(name)), + nics=params["nics"] + + " " * (max_len_nics - len(params["nics"])), + frames=params["framesizes"] + " " * + (max_len_framesizes - len(params["framesizes"])), + cores=params["cores"] + + " " * (max_len_cores - len(params["cores"]))) + + text += "\nFor detailed information visit: {url}\n".\ + format(url=alert["url-details"]) + file_name = "{0}/{1}".format(config["output-dir"], + config["output-file"]) + logging.info("Writing the file '{0}.txt' ...".format(file_name)) + + try: + with open("{0}.txt".format(file_name), 'w') as txt_file: + txt_file.write(text) + except IOError: + logging.error("Not possible to write the file '{0}.txt'.". + format(file_name)) def _generate_files_for_jenkins(self, alert): """Create the file which is used in the generated alert. + # TODO: Remove when not needed. + :param alert: Files are created for this alert. :type alert: dict """ config = self.configs[alert["way"]] - if alert["type"] == "failed-tests": - text, html = self._create_alert_message(alert) - file_name = "{0}/{1}".format(config["output-dir"], - config["output-file"]) - logging.info("Writing the file '{0}.txt' ...".format(file_name)) - try: - with open("{0}.txt".format(file_name), 'w') as txt_file: - txt_file.write(text) - except IOError: - logging.error("Not possible to write the file '{0}.txt'.". - format(file_name)) - logging.info("Writing the file '{0}.html' ...".format(file_name)) - try: - with open("{0}.html".format(file_name), 'w') as html_file: - html_file.write(html) - except IOError: - logging.error("Not possible to write the file '{0}.html'.". - format(file_name)) - - zip_file = config.get("zip-output", None) - if zip_file: - logging.info("Writing the file '{0}/{1}' ...". - format(config["output-dir"], zip_file)) - execute_command("tar czvf {dir}/{zip} --directory={dir} " - "{input}.txt {input}.html". - format(dir=config["output-dir"], - zip=zip_file, - input=config["output-file"])) - else: - raise AlertingError("Alert of type '{0}' is not implemented.". - format(alert["type"])) + zip_file = config.get("zip-output", None) + if zip_file: + logging.info("Writing the file '{0}/{1}' ...". + format(config["output-dir"], zip_file)) + execute_command("tar czvf {dir}/{zip} --directory={dir} " + "{input}.txt". + format(dir=config["output-dir"], + zip=zip_file, + input=config["output-file"])) |