Index: inventory/group_vars/taskotron-dev
===================================================================
--- inventory/group_vars/taskotron-dev
+++ inventory/group_vars/taskotron-dev
@@ -44,7 +44,7 @@
 ############################################################
 
 execdb_endpoint: execdb
-execdb_statuspush: http://resultsdb-dev01.qa.fedoraproject.org/execdb/buildbottest
+execdb_statuspush: http://resultsdb-dev01.qa.fedoraproject.org/execdb/api/v1/jobs
 execdb_server: http://resultsdb-dev01.qa.fedoraproject.org/execdb
 resultsdb_api_endpoint: resultsdb_api
 resultsdb_host: http://resultsdb-dev01.qa.fedoraproject.org/resultsdb_api/
Index: inventory/group_vars/taskotron-prod
===================================================================
--- inventory/group_vars/taskotron-prod
+++ inventory/group_vars/taskotron-prod
@@ -37,7 +37,7 @@
 ############################################################
 
 execdb_server: http://resultsdb01.qa.fedoraproject.org/execdb
-execdb_statuspush: http://resultsdb01.qa.fedoraproject.org/execdb/buildbottest
+execdb_statuspush: http://resultsdb01.qa.fedoraproject.org/execdb/api/v1/jobs
 resultsdb_external_url: https://taskotron.fedoraproject.org/resultsdb/
 resultsdb_fe_endpoint: resultsdb
 resultsdb_frontend_url: http://resultsdb01.qa.fedoraproject.org/resultsdb
Index: inventory/group_vars/taskotron-stg
===================================================================
--- inventory/group_vars/taskotron-stg
+++ inventory/group_vars/taskotron-stg
@@ -42,7 +42,7 @@
 ############################################################
 
 execdb_server: http://resultsdb-stg01.qa.fedoraproject.org/execdb
-execdb_statuspush: http://resultsdb-stg01.qa.fedoraproject.org/execdb/buildbottest
+execdb_statuspush: http://resultsdb-stg01.qa.fedoraproject.org/execdb/api/v1/jobs
 
 resultsdb_url: http://resultsdb-stg01.qa.fedoraproject.org/resultsdb_api/api/v2.0
 resultsdb_frontend_url: http://resultsdb-stg01.qa.fedoraproject.org/
Index: roles/taskotron/buildmaster-configure/templates/taskotron.master.cfg.j2
===================================================================
--- roles/taskotron/buildmaster-configure/templates/taskotron.master.cfg.j2
+++ roles/taskotron/buildmaster-configure/templates/taskotron.master.cfg.j2
@@ -35,6 +35,7 @@
 # the 'change_source' setting tells the buildmaster how it should find out
 # about source code changes.  Here we point to the buildbot clone of pyflakes.
 
+from buildbot.steps.slave import RemoveDirectory #as RemoveDirectory_orig
 #from buildbot.changes.gitpoller import GitPoller
 #c['change_source'] = []
 #c['change_source'].append(GitPoller(
@@ -171,37 +172,176 @@
 # only take place on one slave.
 
 from buildbot.process.factory import BuildFactory
-from buildbot.steps.source.git import Git
-from buildbot.steps.shell import ShellCommand
 from buildbot.process.properties import Property, Interpolate
-from buildbot.steps.slave import RemoveDirectory
-from buildbot.steps.transfer import DirectoryUpload, FileUpload
-from buildbot.steps.master import MasterShellCommand
+from build.process import results as buildbot_results
+
+from buildbot.steps.source.git import Git as Git_orig
+from buildbot.steps.shell import ShellCommand as ShellCommand_orig
+from buildbot.steps.slave import RemoveDirectory as RemoveDirectory_orig
+from buildbot.steps.transfer import DirectoryUpload as DirectoryUpload_orig
+from buildbot.steps.transfer import FileUpload as FileUpload_orig
+from buildbot.steps.master import MasterShellCommand as MasterShellCommand_orig
+
+import json
+import urllib2
+
+def map_result(result):
+    if result in [buildbot_results.SUCCESS, buildbot_results.WARNINGS]:
+       return 'COMPLETED'
+    if result in [buildbot_results.SKIPPED, buildbot_results.CANCELLED]:
+        return 'ABORTED'
+    if result == buildbot_results.EXCEPTION:
+       return 'CRASHED'
+    return 'FAILED'
+
+def report(url, data):
+        data = json.dumps(data)
+        req = urllib2.Request(url, data, {'Content-Type': 'application/json'})
+        response = urllib2.urlopen(req)
+        data = json.load(response)
+        response.close()
+        return data
+
+class JobStartStopStep(ShellCommand_orig):
+    def __init__(self, execdb_url, execdb_args, **kwargs):
+        self.execdb_url = execdb_url
+        self.execdb_args = execdb_args
+        super(self.__class__, self).__init__(**kwargs)
+
+    def start(self, **kwargs):
+        report(self.execdb_url, execdb_args)
+        return super(self.__class__, self).start(**kwargs)
+
+class Git(Git_orig):
+    def __init__(self, execdb_url, **kwargs):
+        self.execdb_url = execdb_url
+        self.execdb_step_id = None
+        super(self.__class__, self).__init__(**kwargs)
+
+    def start(self, **kwargs):
+        data = report(self.execdb_url, {"name": self.name, "description": self.name})
+        self.execdb_step_id = data['id']
+        return super(self.__class__, self).start(**kwargs)
+
+    def finished(self, results):
+        report("%s/%s" % (self.execdb_url, self.execdb_step_id), {"outcome": map_result(results)})
+        return super(self.__class__, self).finished(results)
+
+class ShellCommand(ShellCommand_orig):
+    def __init__(self, execdb_url, **kwargs):
+        self.execdb_url = execdb_url
+        self.execdb_step_id = None
+        super(self.__class__, self).__init__(**kwargs)
+
+    def start(self, **kwargs):
+        data = report(self.execdb_url, {"name": self.name, "description": self.name})
+        self.execdb_step_id = data['id']
+        return super(self.__class__, self).start(**kwargs)
+
+    def finished(self, results):
+        report("%s/%s" % (self.execdb_url, self.execdb_step_id), {"outcome": map_result(results)})
+        return super(self.__class__, self).finished(results)
+
+class RemoveDirectory(RemoveDirectory_orig):
+    def __init__(self, execdb_url, **kwargs):
+        self.execdb_url = execdb_url
+        self.execdb_step_id = None
+        super(self.__class__, self).__init__(**kwargs)
+
+    def start(self, **kwargs):
+        data = report(self.execdb_url, {"name": self.name, "description": self.name})
+        self.execdb_step_id = data['id']
+        return super(self.__class__, self).start(**kwargs)
+
+    def finished(self, results):
+        report("%s/%s" % (self.execdb_url, self.execdb_step_id), {"outcome": map_result(results)})
+        return super(self.__class__, self).finished(results)
+
+class DirectoryUpload(DirectoryUpload_orig):
+    def __init__(self, execdb_url, **kwargs):
+        self.execdb_url = execdb_url
+        self.execdb_step_id = None
+        super(self.__class__, self).__init__(**kwargs)
+
+    def start(self, **kwargs):
+        data = report(self.execdb_url, {"name": self.name, "description": self.name})
+        self.execdb_step_id = data['id']
+        return super(self.__class__, self).start(**kwargs)
+
+    def finished(self, results):
+        report("%s/%s" % (self.execdb_url, self.execdb_step_id), {"outcome": map_result(results)})
+        return super(self.__class__, self).finished(results)
+
+class FileUpload(FileUpload_orig):
+    def __init__(self, execdb_url, **kwargs):
+        self.execdb_url = execdb_url
+        self.execdb_step_id = None
+        super(self.__class__, self).__init__(**kwargs)
+
+    def start(self, **kwargs):
+        data = report(self.execdb_url, {"name": self.name, "description": self.name})
+        self.execdb_step_id = data['id']
+        return super(self.__class__, self).start(**kwargs)
+
+    def finished(self, results):
+        report("%s/%s" % (self.execdb_url, self.execdb_step_id), {"outcome": map_result(results)})
+        return super(self.__class__, self).finished(results)
+
+class MasterShellCommand(MasterShellCommand_orig):
+    def __init__(self, execdb_url, **kwargs):
+        self.execdb_url = execdb_url
+        self.execdb_step_id = None
+        super(self.__class__, self).__init__(**kwargs)
+
+    def start(self, **kwargs):
+        data = report(self.execdb_url, {"name": self.name, "description": self.name})
+        self.execdb_step_id = data['id']
+        return super(self.__class__, self).start(**kwargs)
+
+    def finished(self, results):
+        report("%s/%s" % (self.execdb_url, self.execdb_step_id), {"outcome": map_result(results)})
+        return super(self.__class__, self).finished(results)
+
 
 factory = BuildFactory()
 
+factory.addStep(JobStartStopStep(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/"),
+        execdb_args={"start": True},
+        command=["true"], name="start_job", descriptionDone=['Start ExecDB job']))
+
 {% if deployment_type in ['local'] %}
 # clean out /var/tmp/taskotron (see T253)
-factory.addStep(ShellCommand(command="rm -rf /var/tmp/taskotron/*", name="rm_tmp", descriptionDone=['Clean tmp']))
+factory.addStep(ShellCommand(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        command="rm -rf /var/tmp/taskotron/*", name="rm_tmp", descriptionDone=['Clean tmp']))
 
 # clean the log (see T230)
-factory.addStep(ShellCommand(command=["rm", "-f", "/var/log/taskotron/taskotron.log"], name="rm_log", descriptionDone=['Clean log']))
+factory.addStep(ShellCommand(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        command=["rm", "-f", "/var/log/taskotron/taskotron.log"], name="rm_log", descriptionDone=['Clean log']))
 {% endif %}
 
 {% if deployment_type in ['dev', 'stg', 'prod'] %}
 # clean out /var/tmp/taskotron (see T253)
-factory.addStep(ShellCommand(command=Interpolate("rm -rf /var/tmp/taskotron/%(prop:slavename)s/*"), name="rm_tmp", descriptionDone=['Clean tmp']))
+factory.addStep(ShellCommand(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        command=Interpolate("rm -rf /var/tmp/taskotron/%(prop:slavename)s/*"), name="rm_tmp", descriptionDone=['Clean tmp']))
 {% endif %}
 
 # check out the source
-factory.addStep(Git(repourl=Property('repo', default=Interpolate('{{ grokmirror_user }}@{{ buildmaster }}:/var/lib/git/mirror/fedoraqa/%(prop:taskname)s/')),
+factory.addStep(Git(
+                    execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+                    repourl=Property('repo', default=Interpolate('{{ grokmirror_user }}@{{ buildmaster }}:/var/lib/git/mirror/fedoraqa/%(prop:taskname)s/')),
                     branch=Property('branch', default='{{ grokmirror_default_branch }}'),
                     mode='full',
                     method='clobber',
                     shallow=True))
 
 # run the runner
-factory.addStep(ShellCommand(command=["runtask",
+factory.addStep(ShellCommand(
+                             execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+                             command=["runtask",
                                         '-i', Interpolate('%(prop:item)s'),
                                         '-t', Interpolate('%(prop:item_type)s'),
                                         '-a', Interpolate('%(prop:arch)s'),
@@ -224,26 +364,36 @@
 {% endif %}
 
 
-factory.addStep(ShellCommand(command=Interpolate('testcloud instance remove --force taskotron-%(prop:uuid)s; true'),
-                                   descriptionDone=['Make sure the minion is removed']))
+factory.addStep(ShellCommand(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        command=Interpolate('testcloud instance remove --force taskotron-%(prop:uuid)s; true'),
+        descriptionDone=['Make sure the minion is removed']))
 
 # create artifacts dir on master
-factory.addStep(MasterShellCommand(command=["mkdir", '-m', '0755', Interpolate('{{ public_artifacts_dir }}/%(prop:uuid)s')],
-                                   descriptionDone=['Create artifacs dir']))
+factory.addStep(MasterShellCommand(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        command=["mkdir", '-m', '0755', Interpolate('{{ public_artifacts_dir }}/%(prop:uuid)s')],
+        descriptionDone=['Create artifacs dir']))
 
 # copy artifacts to master
-factory.addStep(DirectoryUpload(slavesrc=Interpolate('/var/lib/taskotron/artifacts/%(prop:uuid)s/'),
-                                masterdest=Interpolate('{{ public_artifacts_dir }}/%(prop:uuid)s/task_output')))
+factory.addStep(DirectoryUpload(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        slavesrc=Interpolate('/var/lib/taskotron/artifacts/%(prop:uuid)s/'),
+        masterdest=Interpolate('{{ public_artifacts_dir }}/%(prop:uuid)s/task_output')))
 
 # gzip artifacts
-factory.addStep(MasterShellCommand(command=Interpolate('gzip -r {{ public_artifacts_dir }}/%(prop:uuid)s/task_output/*'),
-                                   descriptionDone=['gzip artifacs dir content']))
+factory.addStep(MasterShellCommand(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        command=Interpolate('gzip -r {{ public_artifacts_dir }}/%(prop:uuid)s/task_output/*'),
+        descriptionDone=['gzip artifacs dir content']))
 
 {% if deployment_type in ['local'] %}
 # copy taskotron log to master
-factory.addStep(FileUpload(slavesrc='/var/log/taskotron/taskotron.log',
-                           masterdest=Interpolate('{{ public_artifacts_dir }}/%(prop:uuid)s/taskotron.log'),
-                           mode=0644))
+factory.addStep(FileUpload(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        slavesrc='/var/log/taskotron/taskotron.log',
+        masterdest=Interpolate('{{ public_artifacts_dir }}/%(prop:uuid)s/taskotron.log'),
+        mode=0644))
 {% endif %}
 
 # move the artifacts to the correct dir on the master
@@ -255,35 +405,56 @@
     return datetime.datetime.now().strftime("%Y%m%d")
 
 # move artifacts dir
-factory.addStep(MasterShellCommand(command=Interpolate('mkdir -p -m 0755 {{ public_artifacts_dir }}/%(kw:today)s && mkdir -p -m 0755 {{ public_artifacts_dir }}/all && mv {{ public_artifacts_dir }}/%(prop:uuid)s/ {{ public_artifacts_dir }}/%(kw:today)s/ && ln -s {{ public_artifacts_dir }}/%(kw:today)s/%(prop:uuid)s {{ public_artifacts_dir }}/all/', today=today),
-                                   descriptionDone=['Move artifacs dir']))
+factory.addStep(MasterShellCommand(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        command=Interpolate('mkdir -p -m 0755 {{ public_artifacts_dir }}/%(kw:today)s && mkdir -p -m 0755 {{ public_artifacts_dir }}/all && mv {{ public_artifacts_dir }}/%(prop:uuid)s/ {{ public_artifacts_dir }}/%(kw:today)s/ && ln -s {{ public_artifacts_dir }}/%(kw:today)s/%(prop:uuid)s {{ public_artifacts_dir }}/all/', today=today),
+        descriptionDone=['Move artifacs dir']))
+
 
+factory.addStep(JobStartStopStep(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/"),
+        execdb_args={"outcome": '_COMPUTED_'},
+        command=["true"], name="end_job", descriptionDone=['End ExecDB job']))
 
 
 {% if deployment_type in ['dev', 'stg', 'prod'] %}
 # this is for package-specific tasks
 distgit_factory = BuildFactory()
 
+distgit_factory.addStep(JobStartStopStep(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/"),
+        execdb_args={"start": True},
+        command=["true"], name="start_job", descriptionDone=['Start ExecDB job']))
+
+
 # clean out /var/tmp/taskotron (see T253)
-distgit_factory.addStep(ShellCommand(command=Interpolate("rm -rf /var/tmp/taskotron/%(prop:slavename)s/*"), name="rm_tmp", descriptionDone=['Clean tmp']))
+distgit_factory.addStep(ShellCommand(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        command=Interpolate("rm -rf /var/tmp/taskotron/%(prop:slavename)s/*"), name="rm_tmp", descriptionDone=['Clean tmp']))
 
 {% if deployment_type in ['dev', 'prod'] %}
 # check out the source from prod dist-git
-distgit_factory.addStep(Git(repourl=Property('git_repo', default=Interpolate('http://pkgs02.phx2.fedoraproject.org/rpms/{}/'.format("%(prop:item)s".split('-')[0]))),
+distgit_factory.addStep(Git(
+                    execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+                    repourl=Property('git_repo', default=Interpolate('http://pkgs02.phx2.fedoraproject.org/rpms/{}/'.format("%(prop:item)s".split('-')[0]))),
                     branch=Property('git_branch', default='master'),
                     mode='full',
                     method='clobber',
                     shallow=True))
 {% else %}
 # check out the source from stg dist-git
-distgit_factory.addStep(Git(repourl=Property('git_repo', default=Interpolate('http://pkgs01.stg.phx2.fedoraproject.org/rpms/{}/'.format("%(prop:item)s".split('-')[0]))),
+distgit_factory.addStep(Git(
+                    execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+                    repourl=Property('git_repo', default=Interpolate('http://pkgs01.stg.phx2.fedoraproject.org/rpms/{}/'.format("%(prop:item)s".split('-')[0]))),
                     branch=Property('git_branch', default='master'),
                     mode='full',
                     method='clobber',
                     shallow=True))
 {% endif %}
 # run the runner
-distgit_factory.addStep(ShellCommand(command=["runtask",
+distgit_factory.addStep(ShellCommand(
+                             execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+                             command=["runtask",
                                         '-i', Interpolate('%(prop:item)s'),
                                         '-t', Interpolate('%(prop:item_type)s'),
                                         '-a', Interpolate('%(prop:arch)s'),
@@ -301,26 +472,44 @@
 ))
 
 
-distgit_factory.addStep(ShellCommand(command=Interpolate('testcloud instance remove --force taskotron-%(prop:uuid)s; true'),
-                                   descriptionDone=['Make sure the minion is removed']))
+distgit_factory.addStep(ShellCommand(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        command=Interpolate('testcloud instance remove --force taskotron-%(prop:uuid)s; true'),
+        descriptionDone=['Make sure the minion is removed']))
 
 # create artifacts dir on master
-distgit_factory.addStep(MasterShellCommand(command=["mkdir", '-m', '0755', Interpolate('{{ public_artifacts_dir }}/%(prop:uuid)s')],
-                                   descriptionDone=['Create artifacs dir']))
+distgit_factory.addStep(MasterShellCommand(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        command=["mkdir", '-m', '0755', Interpolate('{{ public_artifacts_dir }}/%(prop:uuid)s')],
+        descriptionDone=['Create artifacs dir']))
 
 # copy artifacts to master
-distgit_factory.addStep(DirectoryUpload(slavesrc=Interpolate('/var/lib/taskotron/artifacts/%(prop:uuid)s/'),
-                                masterdest=Interpolate('{{ public_artifacts_dir }}/%(prop:uuid)s/task_output')))
+distgit_factory.addStep(DirectoryUpload(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        slavesrc=Interpolate('/var/lib/taskotron/artifacts/%(prop:uuid)s/'),
+        masterdest=Interpolate('{{ public_artifacts_dir }}/%(prop:uuid)s/task_output')))
 
 # gzip artifacts
-distgit_factory.addStep(MasterShellCommand(command=Interpolate('gzip -r {{ public_artifacts_dir }}/%(prop:uuid)s/task_output/*'),
-                                   descriptionDone=['gzip artifacs dir content']))
+distgit_factory.addStep(MasterShellCommand(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        command=Interpolate('gzip -r {{ public_artifacts_dir }}/%(prop:uuid)s/task_output/*'),
+        descriptionDone=['gzip artifacs dir content']))
 
 {% endif %}
 
 # move artifacts dir
-distgit_factory.addStep(MasterShellCommand(command=Interpolate('mkdir -p -m 0755 {{ public_artifacts_dir }}/%(kw:today)s && mkdir -p -m 0755 {{ public_artifacts_dir }}/all && mv {{ public_artifacts_dir }}/%(prop:uuid)s/ {{ public_artifacts_dir }}/%(kw:today)s/ && ln -s {{ public_artifacts_dir }}/%(kw:today)s/%(prop:uuid)s {{ public_artifacts_dir }}/all/', today=today),
-                                   descriptionDone=['Move artifacs dir']))
+distgit_factory.addStep(MasterShellCommand(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/steps"),
+        command=Interpolate('mkdir -p -m 0755 {{ public_artifacts_dir }}/%(kw:today)s && mkdir -p -m 0755 {{ public_artifacts_dir }}/all && mv {{ public_artifacts_dir }}/%(prop:uuid)s/ {{ public_artifacts_dir }}/%(kw:today)s/ && ln -s {{ public_artifacts_dir }}/%(kw:today)s/%(prop:uuid)s {{ public_artifacts_dir }}/all/', today=today),
+        descriptionDone=['Move artifacs dir']))
+
+distgit_factory.addStep(JobStartStopStep(
+        execdb_url=Interpolate("{{execdb_statuspush}}/%(prop:uuid)s/"),
+        execdb_args={"outcome": '_COMPUTED_'},
+        command=["true"], name="end_job", descriptionDone=['End ExecDB job']))
+
+
+
 ####### RESOURCE LOCKS
 #
 # This is a set of resource locks to make sure that we don't have too many things
