extras-buildsys/builder builder.py,1.41,1.42
Daniel Williams (dcbw)
fedora-extras-commits at redhat.com
Tue Sep 13 18:43:03 UTC 2005
Author: dcbw
Update of /cvs/fedora/extras-buildsys/builder
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv15037/builder
Modified Files:
builder.py
Log Message:
2005-09-13 Dan Williams <dcbw at redhat.com>
* builder/builder.py
- Try to tighten up child process handling to not
leave defunct mock processes around
Index: builder.py
===================================================================
RCS file: /cvs/fedora/extras-buildsys/builder/builder.py,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -r1.41 -r1.42
--- builder.py 1 Sep 2005 19:54:49 -0000 1.41
+++ builder.py 13 Sep 2005 18:43:01 -0000 1.42
@@ -82,6 +82,7 @@
self.buildarch = buildarch
self._starttime = time.time()
self._endtime = 0
+ self._mockstarttime = 0
self._uniqid = uniqid
self._status = 'init'
self._die = False
@@ -136,28 +137,34 @@
def endtime(self):
return self._endtime
- def die(self, sig=15):
+ def die(self):
if self.is_done_status() or self._done_status == 'killed':
return True
self._die = True
return True
def _handle_death(self):
- self._log("Killing build process...\n")
self._die = False
+ self._done_status = 'killed'
+ self._log("Killing build process...\n")
+
# Don't try to kill a running cleanup process
if self._status != 'cleanup' and self._childpid:
try:
- os.kill(self._childpid, 15)
+ os.kill(self._childpid, 9)
except OSError, e:
self._log("Couldn't kill process %d: %s\n" % (self._childpid, e))
-
- self._log("Killed.\n");
- self._done_status = 'killed'
-
- # Don't start cleanup over top of an existing cleanup process
- if self._status != 'cleanup':
+ else:
+ # Ensure child process is reaped
+ self._log("Waiting for mock process %d to exit...\n" % self._childpid)
+ try:
+ (pid, status) = os.waitpid(self._childpid, 0)
+ except OSError, e:
+ pass
+ self._log("Mock process %d exited.\n" % self._childpid)
+ self._childpid = 0
self._start_cleanup()
+ self._log("Killed.\n");
def _log(self, string):
if string and self._log_fd:
@@ -169,14 +176,6 @@
sys.stdout.write(s + string)
sys.stdout.flush()
- def _start_srpm_download(self):
- self._status = 'downloading'
- self._log("Starting download of %s.\n" % self._srpm_url)
- target_dir = os.path.dirname(self._srpm_path)
- dl_thread = FileDownloader.FileDownloader(self.dl_callback, self._srpm_url, self._srpm_url,
- target_dir, ['.src.rpm'], certs)
- dl_thread.start()
-
def dl_callback(self, dl_status, cb_data):
url = cb_data
if dl_status == 'done':
@@ -230,45 +229,9 @@
self._mock_log = os.path.join(self._result_dir, "mock-output.log")
self._childpid = ExecUtils.exec_with_redirect(cmd, args, None, self._mock_log, self._mock_log)
+ self._mockstarttime = time.time()
self._status = 'prepping'
- # Poll a bit to wait for mock to write out the status file if
- # its not there yet.
- start_time = time.time()
- mockstatusfile = os.path.join(self._state_dir, 'status')
- while not os.path.exists(mockstatusfile):
- try:
- time.sleep(0.5)
- except KeyboardInterrupt:
- pass
-
- # if mock exited with an error report that error and not
- # the missing status file.
- (aux_pid, status) = os.waitpid(self._childpid, os.WNOHANG)
- status = os.WEXITSTATUS(status)
- if aux_pid:
- # If mock exits anywhere here, something is wrong no matter
- # what it's exit status
- self._childpid = 0
- self._copy_mock_output_to_log()
- self._status = 'failed'
- break
-
- # Kill mock after 15s if it didn't dump the status file
- if time.time() - start_time > 15:
- self._copy_mock_output_to_log()
- self._log("Timed out waiting for the mock status file! %s\n" % mockstatusfile)
- try:
- self._log("Killing mock...\n")
- os.kill(self._childpid, 15)
- except OSError, e:
- self._log("Couldn't kill mock process %d: %s\n" % (self._childpid, e))
- else:
- self._log("Killed.\n")
-
- self._status = 'failed'
- break
-
def _start_cleanup(self):
self._log("Cleaning up the buildroot...\n")
@@ -288,7 +251,6 @@
self._log(" %s\n" % string.join(args))
self._childpid = ExecUtils.exec_with_redirect(cmd, args, None, None, None)
-
self._status = 'cleanup'
def _mock_is_prepping(self):
@@ -377,8 +339,7 @@
if self._status == 'done':
self._log("Job completed successfully.\n")
elif self._status == 'failed':
- if self._childpid:
- self._log("Job failed due to mock errors! Please see output in root.log and build.log\n")
+ self._log("Job failed due to mock errors! Please see output in root.log and build.log\n")
elif self._status == 'killed':
self._log("Job failed because it was killed.\n")
@@ -387,7 +348,12 @@
self._log_fd = None
def _status_init(self):
- self._start_srpm_download()
+ self._log("Starting download of %s.\n" % self._srpm_url)
+ self._status = 'downloading'
+ target_dir = os.path.dirname(self._srpm_path)
+ dl_thread = FileDownloader.FileDownloader(self.dl_callback, self._srpm_url, self._srpm_url,
+ target_dir, ['.src.rpm'], certs)
+ dl_thread.start()
def _status_downloading(self):
pass
@@ -403,27 +369,44 @@
self._log("Waiting for repository to unlock before starting the build...\n")
self._repo_locked_msg = True
- def _status_prepping(self):
- if not self._mock_config and self._mock_is_prepping():
- self._mock_config = self._read_mock_config()
- if not self._mock_using_repo():
- self._status = 'building'
-
- def _status_building(self):
+ def _watch_mock(self, good_exit, bad_exit):
(aux_pid, status) = os.waitpid(self._childpid, os.WNOHANG)
status = os.WEXITSTATUS(status)
if aux_pid:
self._childpid = 0
if status == 0:
- self._done_status = 'done'
+ self._done_status = good_exit
elif status > 0:
- self._done_status = 'failed'
+ self._done_status = bad_exit
+ self._copy_mock_output_to_log()
self._start_cleanup()
+ def _status_prepping(self):
+ self._watch_mock('failed', 'failed')
+
+ # We need to make sure that mock has dumped the status file withing a certain
+ # amount of time, otherwise we can't tell what it's doing
+ mockstatusfile = os.path.join(self._state_dir, 'status')
+ if not os.path.exists(mockstatusfile):
+ # something is wrong if mock takes more than 15s to write the status file
+ if time.time() > self._mockstarttime + 15:
+ self._mockstarttime = 0
+ self._log("Timed out waiting for the mock status file! %s\n" % mockstatusfile)
+ self.die()
+ else:
+ if not self._mock_config and self._mock_is_prepping():
+ self._mock_config = self._read_mock_config()
+ if not self._mock_using_repo():
+ self._status = 'building'
+
+ def _status_building(self):
+ self._watch_mock('done', 'failed')
+
def _status_cleanup(self):
(aux_pid, status) = os.waitpid(self._childpid, os.WNOHANG)
if aux_pid:
+ self._childpid = 0
# Mock exited
self._status = self._done_status
if self._mock_config:
@@ -461,6 +444,8 @@
time.sleep(3)
self._endtime = time.time()
+ if self._childpid:
+ self._log("ERROR: childpid was !NULL (%d)" % self._childpid)
self._controller.notify_job_done(self)
def _find_files(self):
@@ -790,8 +775,6 @@
if __name__ == '__main__':
-# state={'opts': True, 'host': None, 'archs': [],
-# 'daemon': False, 'pidfile': None, 'logfile': None}
usage = "Usage: %s [-p <pidfile>] [-l <logfile>] [-d] -c <configfile>" % sys.argv[0]
parser = OptionParser(usage=usage)
More information about the fedora-extras-commits
mailing list