<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://bugzilla.yoctoproject.org/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.6"
          urlbase="https://bugzilla.yoctoproject.org/"
          
          maintainer="it-coreprojects-helpdesk@linuxfoundation.org"
>

    <bug>
          <bug_id>10225</bug_id>
          
          <creation_ts>2016-09-06 09:58:17 +0000</creation_ts>
          <short_desc>Signs of a race in do_testimage</short_desc>
          <delta_ts>2017-12-06 17:10:15 +0000</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>10</classification_id>
          <classification>QA/Testing</classification>
          <product>Build Testing</product>
          <component>general</component>
          <version>2.2</version>
          <rep_platform>x86</rep_platform>
          <op_sys>Multiple</op_sys>
          <bug_status>RESOLVED</bug_status>
          <resolution>FIXED</resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords></keywords>
          <priority>High</priority>
          <bug_severity>normal</bug_severity>
          <target_milestone>2.2 M4</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Joshua Lock">joshuagloe</reporter>
          <assigned_to name="Aníbal Limón">anibal.limon</assigned_to>
          <cc>alejandro.hernandez</cc>
    
    <cc>anibal.limon</cc>
    
    <cc>leonardo.sandoval.gonzalez</cc>
    
    <cc>liezhi.yang</cc>
    
    <cc>meta.mr.watcher</cc>
    
    <cc>meta.watcher</cc>
          
          
          <cf_os>---</cf_os>
          <cf_regression_type>---</cf_regression_type>
          
          <cf_docchange>No (bug/feature does not impact docs)</cf_docchange>

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>65817</commentid>
    <comment_count>0</comment_count>
    <who name="Joshua Lock">joshuagloe</who>
    <bug_when>2016-09-06 09:58:17 +0000</bug_when>
    <thetext>nightly-x86-lsb failed during oe-selftest on a builder in the new build cluster, we haven&apos;t seen this failure on the current cluster and a FileNotFound Exception seems likely to be a race.

http://autobuilder.yocto.io:8010/builders/nightly-x86-lsb/builds/39/steps/Running%20Sanity%20Tests/logs/stdio

Copy of stack trace below:

ERROR: core-image-lsb-1.0-r0 do_testimage: Error executing a python function in exec_python_func() autogenerated:

The stack trace of python calls that resulted in this exception/failure was:
File: &apos;exec_python_func() autogenerated&apos;, lineno: 2, function: &lt;module&gt;
     0001:
 *** 0002:do_testimage(d)
     0003:
File: &apos;/home/pokybuild/yocto-autobuilder/yocto-worker/nightly-x86-lsb/build/meta/classes/testimage.bbclass&apos;, lineno: 104, function: do_testimage
     0100:    netstat -an
     0101:}
     0102:
     0103:python do_testimage() {
 *** 0104:    testimage_main(d)
     0105:}
     0106:
     0107:addtask testimage
     0108:do_testimage[nostamp] = &quot;1&quot;
File: &apos;/home/pokybuild/yocto-autobuilder/yocto-worker/nightly-x86-lsb/build/meta/classes/testimage.bbclass&apos;, lineno: 152, function: testimage_main
     0148:        if d.getVar(&apos;VIRTUAL-RUNTIME_init_manager&apos;, &apos;&apos;) == &apos;systemd&apos;:
     0149:            bootparams = &apos;systemd.log_level=debug systemd.log_target=console&apos;
     0150:        target.start(extra_bootparams=bootparams)
     0151:        starttime = time.time()
 *** 0152:        result = tc.runTests()
     0153:        stoptime = time.time()
     0154:        if result.wasSuccessful():
     0155:            bb.plain(&quot;%s - Ran %d test%s in %.3fs&quot; % (pn, result.testsRun, result.testsRun != 1 and &quot;s&quot; or &quot;&quot;, stoptime - starttime))
     0156:            msg = &quot;%s - OK - All required tests passed&quot; % pn
File: &apos;/home/pokybuild/yocto-autobuilder/yocto-worker/nightly-x86-lsb/build/meta/lib/oeqa/oetest.py&apos;, lineno: 401, function: runTests
     0397:        runner = unittest.TextTestRunner(verbosity=2)
     0398:        if &apos;bb&apos; in sys.modules:
     0399:            runner.stream.write = custom_verbose
     0400:
 *** 0401:        return runner.run(self.suite)
     0402:
     0403:class RuntimeTestContext(TestContext):
     0404:    def __init__(self, d, target, exported=False):
     0405:        super(RuntimeTestContext, self).__init__(d, exported)
File: &apos;/usr/lib/python3.5/unittest/runner.py&apos;, lineno: 176, function: run
     0172:            startTestRun = getattr(result, &apos;startTestRun&apos;, None)
     0173:            if startTestRun is not None:
     0174:                startTestRun()
     0175:            try:
 *** 0176:                test(result)
     0177:            finally:
     0178:                stopTestRun = getattr(result, &apos;stopTestRun&apos;, None)
     0179:                if stopTestRun is not None:
     0180:                    stopTestRun()
File: &apos;/usr/lib/python3.5/unittest/suite.py&apos;, lineno: 84, function: __call__
     0080:                self._removed_tests += test.countTestCases()
     0081:            self._tests[index] = None
     0082:
     0083:    def __call__(self, *args, **kwds):
 *** 0084:        return self.run(*args, **kwds)
     0085:
     0086:    def debug(self):
     0087:        &quot;&quot;&quot;Run the tests without collecting errors in a TestResult&quot;&quot;&quot;
     0088:        for test in self:
File: &apos;/usr/lib/python3.5/unittest/suite.py&apos;, lineno: 122, function: run
     0118:                    getattr(result, &apos;_moduleSetUpFailed&apos;, False)):
     0119:                    continue
     0120:
     0121:            if not debug:
 *** 0122:                test(result)
     0123:            else:
     0124:                test.debug()
     0125:
     0126:            if self._cleanup:
File: &apos;/usr/lib/python3.5/unittest/suite.py&apos;, lineno: 84, function: __call__
     0080:                self._removed_tests += test.countTestCases()
     0081:            self._tests[index] = None
     0082:
     0083:    def __call__(self, *args, **kwds):
 *** 0084:        return self.run(*args, **kwds)
     0085:
     0086:    def debug(self):
     0087:        &quot;&quot;&quot;Run the tests without collecting errors in a TestResult&quot;&quot;&quot;
     0088:        for test in self:
File: &apos;/usr/lib/python3.5/unittest/suite.py&apos;, lineno: 122, function: run
     0118:                    getattr(result, &apos;_moduleSetUpFailed&apos;, False)):
     0119:                    continue
     0120:
     0121:            if not debug:
 *** 0122:                test(result)
     0123:            else:
     0124:                test.debug()
     0125:
     0126:            if self._cleanup:
File: &apos;/usr/lib/python3.5/unittest/suite.py&apos;, lineno: 84, function: __call__
     0080:                self._removed_tests += test.countTestCases()
     0081:            self._tests[index] = None
     0082:
     0083:    def __call__(self, *args, **kwds):
 *** 0084:        return self.run(*args, **kwds)
     0085:
     0086:    def debug(self):
     0087:        &quot;&quot;&quot;Run the tests without collecting errors in a TestResult&quot;&quot;&quot;
     0088:        for test in self:
File: &apos;/usr/lib/python3.5/unittest/suite.py&apos;, lineno: 122, function: run
     0118:                    getattr(result, &apos;_moduleSetUpFailed&apos;, False)):
     0119:                    continue
     0120:
     0121:            if not debug:
 *** 0122:                test(result)
     0123:            else:
     0124:                test.debug()
     0125:
     0126:            if self._cleanup:
File: &apos;/usr/lib/python3.5/unittest/case.py&apos;, lineno: 648, function: __call__
     0644:        # even though we no longer us it internally
     0645:        return outcome.success
     0646:
     0647:    def __call__(self, *args, **kwds):
 *** 0648:        return self.run(*args, **kwds)
     0649:
     0650:    def debug(self):
     0651:        &quot;&quot;&quot;Run the test without collecting errors in a TestResult&quot;&quot;&quot;
     0652:        self.setUp()
File: &apos;/home/pokybuild/yocto-autobuilder/yocto-worker/nightly-x86-lsb/build/meta/lib/oeqa/utils/decorators.py&apos;, lineno: 194, function: run
     0190:            local_log.results(&quot;Testcase &quot;+str(test_case)+&quot;: PASSED&quot;)
     0191:
     0192:        # Create symlink to the current log
     0193:        if os.path.lexists(linkfile):
 *** 0194:            os.remove(linkfile)
     0195:        os.symlink(logfile, linkfile)
     0196:
     0197:    original_class.run = run
     0198:
Exception: FileNotFoundError: [Errno 2] No such file or directory: &apos;/home/pokybuild/yocto-autobuilder/yocto-worker/nightly-x86-lsb/build/build/results-bitbake-worker.log&apos;

ERROR: core-image-lsb-1.0-r0 do_testimage: Function failed: do_testimage
ERROR: Logfile of failure stored in: /home/pokybuild/yocto-autobuilder/yocto-worker/nightly-x86-lsb/build/build/tmp/work/qemux86-poky-linux/core-image-lsb/1.0-r0/temp/log.do_testimage.13132
ERROR: Task (/home/pokybuild/yocto-autobuilder/yocto-worker/nightly-x86-lsb/build/meta/recipes-extended/images/core-image-lsb.bb:do_testimage) failed with exit code &apos;1&apos;</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>65839</commentid>
    <comment_count>1</comment_count>
    <who name="Alejandro Hernandez">alejandro.hernandez</who>
    <bug_when>2016-09-06 21:13:35 +0000</bug_when>
    <thetext>This sure looks like a race condition, since the file does exist, I&apos;m guessing it was created afterwards:

ls -l /home/pokybuild/yocto-autobuilder/yocto-worker/nightly-x86-lsb/build/build/results-bitbake-worker.log

lrwxrwxrwx 1 pokybuild users 116 Sep  5 15:13 /home/pokybuild/yocto-autobuilder/yocto-worker/nightly-x86-lsb/build/build/results-bitbake-worker.log -&gt; /home/pokybuild/yocto-autobuilder/yocto-worker/nightly-x86-lsb/build/build/results-bitbake-worker.20160905220801.log</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>65841</commentid>
    <comment_count>2</comment_count>
    <who name="Alejandro Hernandez">alejandro.hernandez</who>
    <bug_when>2016-09-06 21:29:57 +0000</bug_when>
    <thetext>The line where it fails is inside an if, that&apos;s supposed to check that:

     0192:        # Create symlink to the current log
     0193:        if os.path.lexists(linkfile):
 *** 0194:            os.remove(linkfile)


According to python&apos;s documentation:

os.path.lexists:

Return True if path refers to an existing path. Returns True for broken symbolic links. Equivalent to exists() on platforms lacking os.lstat().

So it could return true for a broken link, but that still doesn&apos;t explain why the os.remove() would fail for a broken link.

Or this is a very specific race, where the file is removed, an maybe recreated by some other process just after checking if it existed</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>65856</commentid>
    <comment_count>3</comment_count>
    <who name="Robert Yang">liezhi.yang</who>
    <bug_when>2016-09-07 07:15:38 +0000</bug_when>
    <thetext>(In reply to comment #2)
&gt; The line where it fails is inside an if, that&apos;s supposed to check that:
&gt; 
&gt;      0192:        # Create symlink to the current log
&gt;      0193:        if os.path.lexists(linkfile):
&gt;  *** 0194:            os.remove(linkfile)
&gt; 
&gt; 
&gt; According to python&apos;s documentation:
&gt; 
&gt; os.path.lexists:
&gt; 
&gt; Return True if path refers to an existing path. Returns True for broken
&gt; symbolic links. Equivalent to exists() on platforms lacking os.lstat().
&gt; 
&gt; So it could return true for a broken link, but that still doesn&apos;t explain
&gt; why the os.remove() would fail for a broken link.
&gt; 
&gt; Or this is a very specific race, where the file is removed, an maybe
&gt; recreated by some other process just after checking if it existed

It should be a race issue, for example:
bitbake &lt;image1&gt; &lt;image2&gt; -c testimage

Then two testimage may handle it at the same, I think that we can rename results-bitbake-worker.log to something liek core-image-minimal-testimage.log to fix the problem.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>65876</commentid>
    <comment_count>4</comment_count>
    <who name="Alejandro Hernandez">alejandro.hernandez</who>
    <bug_when>2016-09-07 15:22:54 +0000</bug_when>
    <thetext>(In reply to comment #3)

&gt; 
&gt; It should be a race issue, for example:
&gt; bitbake &lt;image1&gt; &lt;image2&gt; -c testimage
&gt; 
&gt; Then two testimage may handle it at the same, I think that we can rename
&gt; results-bitbake-worker.log to something liek
&gt; core-image-minimal-testimage.log to fix the problem.

I see no harm in renaming the worker log to some image-specific name, and I agree I believ this would likely fix the issue.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>65920</commentid>
    <comment_count>5</comment_count>
    <who name="Joshua Lock">joshuagloe</who>
    <bug_when>2016-09-08 12:55:39 +0000</bug_when>
    <thetext>(In reply to comment #4)
&gt; (In reply to comment #3)
&gt; 
&gt; &gt; 
&gt; &gt; It should be a race issue, for example:
&gt; &gt; bitbake &lt;image1&gt; &lt;image2&gt; -c testimage
&gt; &gt; 
&gt; &gt; Then two testimage may handle it at the same, I think that we can rename
&gt; &gt; results-bitbake-worker.log to something liek
&gt; &gt; core-image-minimal-testimage.log to fix the problem.
&gt; 
&gt; I see no harm in renaming the worker log to some image-specific name, and I
&gt; agree I believ this would likely fix the issue.

It&apos;s a reasonable solution, one I was also considering. The trouble is how do we get the name of the target bitbake was invoked with into the decorator that sets up the log filename?

AFAICT the decorator and the classes it decorates have no idea what the target the parent bitbake process was invoked with is.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>66043</commentid>
    <comment_count>6</comment_count>
    <who name="Aníbal Limón">anibal.limon</who>
    <bug_when>2016-09-12 16:21:02 +0000</bug_when>
    <thetext>(In reply to comment #5)
&gt; (In reply to comment #4)
&gt; &gt; (In reply to comment #3)
&gt; &gt; 
&gt; &gt; &gt; 
&gt; &gt; &gt; It should be a race issue, for example:
&gt; &gt; &gt; bitbake &lt;image1&gt; &lt;image2&gt; -c testimage
&gt; &gt; &gt; 
&gt; &gt; &gt; Then two testimage may handle it at the same, I think that we can rename
&gt; &gt; &gt; results-bitbake-worker.log to something liek
&gt; &gt; &gt; core-image-minimal-testimage.log to fix the problem.
&gt; &gt; 
&gt; &gt; I see no harm in renaming the worker log to some image-specific name, and I
&gt; &gt; agree I believ this would likely fix the issue.
&gt; 
&gt; It&apos;s a reasonable solution, one I was also considering. The trouble is how
&gt; do we get the name of the target bitbake was invoked with into the decorator
&gt; that sets up the log filename?
&gt; 
&gt; AFAICT the decorator and the classes it decorates have no idea what the
&gt; target the parent bitbake process was invoked with is.

Another possible solution will be usage of bb.utils.lock before and after the soft link related code.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>66107</commentid>
    <comment_count>7</comment_count>
    <who name="Aníbal Limón">anibal.limon</who>
    <bug_when>2016-09-13 20:27:25 +0000</bug_when>
    <thetext>At,

http://lists.openembedded.org/pipermail/openembedded-core/2016-September/126472.html</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>66225</commentid>
    <comment_count>8</comment_count>
    <who name="Aníbal Limón">anibal.limon</who>
    <bug_when>2016-09-15 19:04:18 +0000</bug_when>
    <thetext>Merged at,

http://git.yoctoproject.org/cgit/cgit.cgi/poky/commit/?id=62c45ffbc7c239b6d50931a0fc46f9a67635b1b1</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>