[yocto] [[AUH] 13/17] upgradehelper: Add testimage feature.
Aníbal Limón
anibal.limon at linux.intel.com
Wed Nov 25 16:00:42 PST 2015
Testimage module implements usage of testimage class, a integration
branch is created with succesful recipe upgrades and then the next
tests are run for every machine configured,
- ptest: Recipes that support ptest are run and retrive
the result after upgrade.
- sato: Runs core-image-sato -c testimage.
The results are stored into recipe work directory and send to the
maintainer.
[YOCTO #7471]
[YOCTO #7567]
Signed-off-by: Aníbal Limón <anibal.limon at linux.intel.com>
---
modules/testimage.py | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++
upgradehelper.py | 82 +++++++++++++++++++++--
2 files changed, 261 insertions(+), 6 deletions(-)
create mode 100644 modules/testimage.py
diff --git a/modules/testimage.py b/modules/testimage.py
new file mode 100644
index 0000000..3fbbc19
--- /dev/null
+++ b/modules/testimage.py
@@ -0,0 +1,185 @@
+#!/usr/bin/env python
+# vim: set ts=4 sw=4 et:
+#
+# Copyright (c) 2015 Intel Corporation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# This module implements logic for run image tests on recipes when upgrade
+# process succeed.
+#
+
+import os
+import sys
+import shutil
+
+import logging as log
+from logging import debug as D
+from logging import info as I
+from logging import warning as W
+from logging import error as E
+from logging import critical as C
+
+from errors import *
+from utils.bitbake import *
+
+class TestImage():
+ def __init__(self, bb, git, uh_work_dir, pkgs_ctx):
+ self.bb = bb
+ self.git = git
+ self.uh_work_dir = uh_work_dir
+ self.pkgs_ctx = pkgs_ctx
+
+ os.environ['BB_ENV_EXTRAWHITE'] = os.environ['BB_ENV_EXTRAWHITE'] + \
+ " TEST_SUITES CORE_IMAGE_EXTRA_INSTALL"
+
+ def _get_ptest_pkgs(self):
+ pkgs = []
+
+ for c in self.pkgs_ctx:
+ if "ptest" in c['recipe'].get_inherits():
+ pkgs.append(c)
+
+ return pkgs
+
+ def _get_pkgs_to_install(self, pkgs, ptest=False):
+ pkgs_out = []
+
+ # for provide access to the target
+ if ptest:
+ pkgs_out.append("dropbear")
+
+ for c in pkgs:
+ pkgs_out.append(c['PN'])
+ if ptest:
+ pkgs_out.append("%s-ptest" % c['PN'])
+
+ return ' '.join(pkgs_out)
+
+ def prepare_branch(self):
+ self.git.checkout_branch("master")
+ try:
+ self.git.delete_branch("testimage")
+ self.git.delete_branch("upgrades")
+ except Error:
+ pass
+ self.git.reset_hard()
+
+ self.git.create_branch("testimage")
+ for c in self.pkgs_ctx:
+ patch_file = os.path.join(c['workdir'], c['patch_file'])
+ self.git.apply_patch(patch_file)
+
+ def _parse_ptest_log(self, log_file):
+ ptest_results = {}
+
+ with open(log_file, "r") as f:
+ pn = None
+ processing = False
+
+ for line in f:
+ if not processing:
+ m = re.search("^BEGIN: /usr/lib/(.*)/ptest$", line)
+ if m:
+ pn = m.group(1)
+ ptest_results[pn] = []
+ processing = True
+ else:
+ m = re.search("^END: $", line)
+ if m:
+ pn = None
+ processing = False
+ else:
+ ptest_results[pn].append(line)
+
+ return ptest_results
+
+ def _find_log(self, name, machine):
+ result = []
+
+ base_dir = os.path.join(os.getenv('BUILDDIR'), 'tmp', 'work')
+ for root, dirs, files in os.walk(base_dir):
+ if name in files:
+ result.append(os.path.join(root, name))
+
+ for ptest_log in result:
+ if machine in ptest_log:
+ return ptest_log
+
+ def ptest(self, machine):
+ ptest_pkgs = self._get_ptest_pkgs()
+
+ os.environ['CORE_IMAGE_EXTRA_INSTALL'] = \
+ self._get_pkgs_to_install(ptest_pkgs, True)
+ I( " building core-image-minimal for %s ..." % machine)
+ self.bb.complete("core-image-minimal", machine)
+
+ os.environ['TEST_SUITES'] = "ping ssh _ptest"
+ I( " running core-image-minimal/ptest for %s ..." % machine)
+ self.bb.complete("core-image-minimal -c testimage", machine)
+
+ ptest_log_file = self._find_log("ptest.log", machine)
+ shutil.copyfile(ptest_log_file,
+ os.path.join(self.uh_work_dir, "ptest_%s.log" % machine))
+
+ ptest_result = self._parse_ptest_log(ptest_log_file)
+ for pn in ptest_result:
+ for pkg_ctx in self.pkgs_ctx:
+ if not pn == pkg_ctx['PN']:
+ continue
+
+ if not 'ptest' in pkg_ctx:
+ pkg_ctx['ptest'] = {}
+ if not 'ptest_log' in pkg_ctx:
+ pkg_ctx['ptest_log'] = os.path.join(pkg_ctx['workdir'],
+ "ptest.log")
+
+ pkg_ctx['ptest'][machine] = True
+ with open(pkg_ctx['ptest_log'], "a+") as f:
+ f.write("BEGIN: PTEST for %s\n" % machine)
+ for line in ptest_result[pn]:
+ f.write(line)
+ f.write("END: PTEST for %s\n" % machine)
+
+ def sato(self, machine):
+ os.environ['CORE_IMAGE_EXTRA_INSTALL'] = \
+ self._get_pkgs_to_install(self.pkgs_ctx)
+
+ if 'TEST_SUITES' in os.environ:
+ del os.environ['TEST_SUITES']
+
+ I( " building core-image-sato for %s ..." % machine)
+ self.bb.complete("core-image-sato", machine)
+
+ I( " running core-image-sato/testimage for %s ..." % machine)
+ self.bb.complete("core-image-sato -c testimage", machine)
+
+ log_file = self._find_log("log.do_testimage", machine)
+ shutil.copyfile(log_file,
+ os.path.join(self.uh_work_dir, "log_%s.do_testimage" % machine))
+ for pkg_ctx in self.pkgs_ctx:
+ if not 'testimage' in pkg_ctx:
+ pkg_ctx['testimage'] = {}
+ if not 'testimage_log' in pkg_ctx:
+ pkg_ctx['testimage_log'] = os.path.join(
+ pkg_ctx['workdir'], "log.do_testimage")
+
+ pkg_ctx['testimage'][machine] = True
+ with open(log_file, "r") as lf:
+ with open(pkg_ctx['testimage_log'], "a+") as of:
+ of.write("BEGIN: TESTIMAGE for %s\n" % machine)
+ for line in lf:
+ of.write(line)
+ of.write("END: TESTIMAGE for %s\n" % machine)
diff --git a/upgradehelper.py b/upgradehelper.py
index 222909b..18db9eb 100755
--- a/upgradehelper.py
+++ b/upgradehelper.py
@@ -56,6 +56,7 @@ from utils.emailhandler import Email
from statistics import Statistics
from steps import upgrade_steps
+from testimage import TestImage
help_text = """Usage examples:
* To upgrade xmodmap recipe to the latest available version, interactively:
@@ -296,6 +297,14 @@ class Updater(object):
" - amend the patch and sign it off: git commit -s --reset-author --amend\n" \
" - send it to the list\n\n" \
+ testimage_ptest_info = \
+ "The recipe has ptest enabled and has been tested with core-image-minimal/ptest \n" \
+ "with the next machines %s. Attached is the log file.\n\n"
+
+ testimage_sato_info = \
+ "The recipe has been tested using core-image-sato testimage and succeeded with \n" \
+ "the next machines %s. Attached is the log file.\n\n" \
+
mail_footer = \
"Attached are the patch, license diff (if change) and bitbake log.\n" \
"Any problem please contact Anibal Limon <anibal.limon at intel.com>.\n\n" \
@@ -317,13 +326,22 @@ class Updater(object):
subject += " FAILED"
msg_body = mail_header % (pkg_ctx['PN'], pkg_ctx['NPV'],
self._get_status_msg(pkg_ctx['error']))
- license_diff_fn = pkg_ctx['recipe'].get_license_diff_file_name()
- if license_diff_fn:
- msg_body += license_change_info % license_diff_fn
+ if 'recipe' in pkg_ctx:
+ license_diff_fn = pkg_ctx['recipe'].get_license_diff_file_name()
+ if license_diff_fn:
+ msg_body += license_change_info % license_diff_fn
if not pkg_ctx['error']:
msg_body += next_steps_info % (', '.join(self.opts['machines']),
os.path.basename(pkg_ctx['patch_file']))
+ if self.opts['testimage']:
+ if 'ptest' in pkg_ctx:
+ machines = pkg_ctx['ptest'].keys()
+ msg_body += testimage_ptest_info % machines
+ if 'testimage' in pkg_ctx:
+ machines = pkg_ctx['testimage'].keys()
+ msg_body += testimage_sato_info % machines
+
msg_body += mail_footer
# Add possible attachments to email
@@ -336,7 +354,6 @@ class Updater(object):
# Only send email to Maintainer when recipe upgrade succeed.
if self.opts['send_email'] and not pkg_ctx['error']:
self.email_handler.send_email(to_addr, subject, msg_body, attachments, cc_addr=cc_addr)
-
# Preserve email for review purposes.
email_file = os.path.join(pkg_ctx['workdir'],
"email_summary")
@@ -355,7 +372,7 @@ class Updater(object):
try:
pkg_ctx['patch_file'] = None
- if pkg_ctx['recipe']:
+ if 'recipe' in pkg_ctx:
I(" %s: Auto commit changes ..." % pkg_ctx['PN'])
self.git.commit(pkg_ctx['recipe'].commit_msg, self.opts['author'])
@@ -471,7 +488,16 @@ class Updater(object):
I(" Building gcc runtimes ...")
for machine in self.opts['machines']:
I(" building gcc runtime for %s" % machine)
- self.bb.complete("gcc-runtime", machine)
+ try:
+ self.bb.complete("gcc-runtime", machine)
+ except Exception as e:
+ E(" Can't build gcc-runtime for %s." % machine)
+
+ if isinstance(e, Error):
+ E(e.stdout)
+ else:
+ import traceback
+ traceback.print_exc(file=sys.stdout)
pkgs_to_upgrade = self._order_pkgs_to_upgrade(
self._get_packages_to_upgrade(package_list))
@@ -491,6 +517,8 @@ class Updater(object):
pkgs_ctx[p]['base_dir'] = self.uh_recipes_all_dir
I(" ############################################################")
+ succeeded_pkgs_ctx = []
+ failed_pkgs_ctx = []
attempted_pkgs = 0
for pn, _, _ in pkgs_to_upgrade:
pkg_ctx = pkgs_ctx[pn]
@@ -505,6 +533,7 @@ class Updater(object):
I(" %s: %s" % (pkg_ctx['PN'], msg))
step(self.bb, self.git, self.opts, pkg_ctx)
+ succeeded_pkgs_ctx.append(pkg_ctx)
os.symlink(pkg_ctx['workdir'], os.path.join( \
self.uh_recipes_succeed_dir, pkg_ctx['PN']))
@@ -529,12 +558,53 @@ class Updater(object):
pkg_ctx['error'] = e
+ failed_pkgs_ctx.append(pkg_ctx)
os.symlink(pkg_ctx['workdir'], os.path.join( \
self.uh_recipes_failed_dir, pkg_ctx['PN']))
self.commit_changes(pkg_ctx)
self.statistics.update(pkg_ctx['PN'], pkg_ctx['NPV'],
pkg_ctx['MAINTAINER'], pkg_ctx['error'])
+
+ if self.opts['testimage']:
+ if len(succeeded_pkgs_ctx) > 0:
+ tim = TestImage(self.bb, self.git, self.uh_work_dir, succeeded_pkgs_ctx)
+
+ try:
+ tim.prepare_branch()
+ except Exception as e:
+ E(" testimage: Failed to prepare branch.")
+ if isinstance(e, Error):
+ E(" %s" % e.stdout)
+ exit(1)
+
+ I(" Images will test for %s." % ', '.join(self.opts['machines']))
+ for machine in self.opts['machines']:
+ I(" Testing images for %s ..." % machine)
+ try:
+ tim.ptest(machine)
+ except Exception as e:
+ E(" core-image-minimal/ptest on machine %s failed" % machine)
+ if isinstance(e, Error):
+ E(" %s" % e.stdout)
+ else:
+ import traceback
+ traceback.print_exc(file=sys.stdout)
+
+ try:
+ tim.sato(machine)
+ except Exception as e:
+ E(" core-image-sato/testimage on machine %s failed" % machine)
+ if isinstance(e, Error):
+ E(" %s" % e.stdout)
+ else:
+ import traceback
+ traceback.print_exc(file=sys.stdout)
+ else:
+ I(" Testimage was enabled but any upgrade was successful.")
+
+ for pn in pkgs_ctx.keys():
+ pkg_ctx = pkgs_ctx[pn]
self.pkg_upgrade_handler(pkg_ctx)
if attempted_pkgs > 1:
--
2.1.4
More information about the yocto
mailing list