changeset 758:d11ef8024d7c

Make all times be generated by the server. This eliminates a number of inconsistencies you'll see when the clocks on the slaves are skewed from the master.
author wbell
date Sat, 24 Apr 2010 14:28:41 +0000
parents 3fbc7672640e
children 306419d32527
files bitten/master.py bitten/slave.py bitten/tests/master.py
diffstat 3 files changed, 11 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/bitten/master.py
+++ b/bitten/master.py
@@ -281,13 +281,14 @@
         db = self.env.get_db_cnx()
 
         step = BuildStep(self.env, build=build.id, name=stepname)
-        try:
-            step.started = int(_parse_iso_datetime(elem.attr['time']))
-            step.stopped = step.started + float(elem.attr['duration'])
-        except ValueError, e:
-            self.log.error('Error parsing build step timestamp: %s', e,
-                           exc_info=True)
-            self._send_error(req, HTTP_BAD_REQUEST, e.args[0])
+
+        # not a great way to determine the start/stop time of the
+        # step, but it's a server time, which eliminates a bunch
+        # of skew issues.
+        now = int(time.time())
+        step.started = now - float(elem.attr['duration'])
+        step.stopped = now
+
         if elem.attr['status'] == 'failure':
             self.log.warning('Build %s step %s failed', build.id, stepname)
             step.status = BuildStep.FAILURE
@@ -375,14 +376,3 @@
                             'Location': req.abs_href.builds(
                                     build.id, 'steps', stepname)})
 
-
-def _parse_iso_datetime(string):
-    """Minimal parser for ISO date-time strings.
-    
-    Return the time as floating point number. Only handles UTC timestamps
-    without time zone information."""
-    try:
-        string = string.split('.', 1)[0] # strip out microseconds
-        return calendar.timegm(time.strptime(string, '%Y-%m-%dT%H:%M:%S'))
-    except ValueError, e:
-        raise ValueError('Invalid ISO date/time %r' % string)
--- a/bitten/slave.py
+++ b/bitten/slave.py
@@ -325,8 +325,8 @@
 
     def _execute_step(self, build_url, recipe, step):
         failed = False
-        started = datetime.utcnow()
-        xml = xmlio.Element('result', step=step.id, time=started.isoformat())
+        started = int(time.time())
+        xml = xmlio.Element('result', step=step.id)
         try:
             for type, category, generator, output in \
                     step.execute(recipe.ctxt):
@@ -347,7 +347,7 @@
         except Exception, e:
             log.error('Internal error in build step %r', step.id, exc_info=True)
             failed = True
-        xml.attr['duration'] = (datetime.utcnow() - started).seconds
+        xml.attr['duration'] = (time.time() - started)
         if failed:
             xml.attr['status'] = 'failure'
         else:
--- a/bitten/tests/master.py
+++ b/bitten/tests/master.py
@@ -913,42 +913,6 @@
         self.assertEquals(400, outheaders['Status'])
         self.assertEquals('XML parser error', outbody.getvalue())
 
-    def test_process_build_step_invalid_datetime(self):
-        recipe = """<build>
-  <step id="foo">
-  </step>
-</build>"""
-        BuildConfig(self.env, 'test', path='somepath', active=True,
-                    recipe=recipe).insert()
-        build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42,
-                      started=42, status=Build.IN_PROGRESS)
-        build.slave_info[Build.TOKEN] = '123';
-        build.insert()
-
-        inbody = StringIO("""<result step="foo" status="success"
-                                     time="sometime tomorrow maybe"
-                                     duration="3.45">
-</result>""")
-        outheaders = {}
-        outbody = StringIO()
-        req = Mock(method='POST', base_path='',
-                   path_info='/builds/%d/steps/' % build.id,
-                   href=Href('/trac'), remote_addr='127.0.0.1', args={},
-                   perm=PermissionCache(self.env, 'hal'),
-                   read=inbody.read,
-                   send_response=lambda x: outheaders.setdefault('Status', x),
-                   send_header=lambda x, y: outheaders.setdefault(x, y),
-                   write=outbody.write,
-                   incookie=Cookie('trac_auth=123'))
-
-        module = BuildMaster(self.env)
-        assert module.match_request(req)
-
-        self.assertRaises(RequestDone, module.process_request, req)
-
-        self.assertEquals(400, outheaders['Status'])
-        self.assertEquals("Invalid ISO date/time 'sometime tomorrow maybe'",
-                             outbody.getvalue())
 
     def test_process_build_step_no_post(self):
         BuildConfig(self.env, 'test', path='somepath', active=True,
Copyright (C) 2012-2017 Edgewall Software