summaryrefslogtreecommitdiff
path: root/morphlib/stagingarea.py
diff options
context:
space:
mode:
authorTiago Gomes <tiago.gomes@codethink.co.uk>2015-08-03 10:03:29 +0000
committerBaserock Gerrit <gerrit@baserock.org>2015-09-01 08:25:24 +0000
commit0b50b9ceca5fc604550537297e786d876d28508a (patch)
treecdc599c2e293ff8269e612c8b265648c9ac505d1 /morphlib/stagingarea.py
parent41cbcdf6b5c0f823ac5589faaf6da3651ad69dab (diff)
downloadmorph-0b50b9ceca5fc604550537297e786d876d28508a.tar.gz
Stop moving staging areas of failed builds
Stop moving staging areas of failed builds from the 'staging' directory to the 'failed' directory. Moving staging areas make it very difficult to debug build failures on the build essential chunks, as the paths set on the configure scripts and some environment variables (e.g. STAGE2_SYSROOT, DESTDIR) will be invalid after moving the staging area. This change will also make it easier to create scripts that chroot n environment similiar to the one where the build failure occurred. To make it still possible to safely do a build an run `morph gc` in parallel, we use flock(2) to control access to the staging area directory. Also, move the `test_supports_non_isolated_mode` test into a different class, as it requires a different SetUp() routine (the staging area is contructed with different parameters). Change-Id: I06c3c435ad05c12afabc0adc2a9d4f8a284ccc02
Diffstat (limited to 'morphlib/stagingarea.py')
-rw-r--r--morphlib/stagingarea.py42
1 files changed, 22 insertions, 20 deletions
diff --git a/morphlib/stagingarea.py b/morphlib/stagingarea.py
index 76bb3a18..c8c77229 100644
--- a/morphlib/stagingarea.py
+++ b/morphlib/stagingarea.py
@@ -20,6 +20,7 @@ import stat
import cliapp
from urlparse import urlparse
import tempfile
+import fcntl
import morphlib
@@ -58,6 +59,25 @@ class StagingArea(object):
path = full_path + os.environ['PATH'].split(':')
self.env['PATH'] = ':'.join(path)
+
+ # Keep trying until we have created a directory with an
+ # exclusive lock on it, as if the user runs `morph gc` in
+ # parallel the staging area directory could have been removed
+ # or have its exclusive lock associated with the `morph gc`
+ # process
+ while True:
+ try:
+ fd = os.open(dirname, os.O_RDONLY)
+ fcntl.flock(fd, fcntl.LOCK_EX)
+ if os.path.exists(dirname):
+ self.staging_area_fd = fd
+ break
+ else:
+ os.close(fd) # pragma: no cover
+ except OSError: # pragma: no cover
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+
# Wrapper to be overridden by unit tests.
def _mkdir(self, dirname): # pragma: no cover
os.makedirs(dirname)
@@ -170,9 +190,6 @@ class StagingArea(object):
# the other renamed its tempdir here first.
os.rename(savedir, unpacked_artifact)
- if not os.path.exists(self.dirname):
- self._mkdir(self.dirname)
-
self.hardlink_all_files(unpacked_artifact, self.dirname)
def remove(self):
@@ -185,6 +202,7 @@ class StagingArea(object):
'''
shutil.rmtree(self.dirname)
+ os.close(self.staging_area_fd)
to_mount_in_staging = (
('dev/shm', 'tmpfs', 'none'),
@@ -303,21 +321,5 @@ class StagingArea(object):
msg = morphlib.util.error_message_for_containerised_commandline(
argv, err, container_config)
raise cliapp.AppException(
- 'In staging area %s: %s' % (self._failed_location(), msg))
-
- def _failed_location(self): # pragma: no cover
- '''Path this staging area will be moved to if an error occurs.'''
- return os.path.join(self._app.settings['tempdir'], 'failed',
- os.path.basename(self.dirname))
-
- def abort(self): # pragma: no cover
- '''Handle what to do with a staging area in the case of failure.
- This may either remove it or save it for later inspection.
- '''
- # TODO: when we add the option to throw away failed builds,
- # hook it up here
-
- dest_dir = self._failed_location()
- os.rename(self.dirname, dest_dir)
- self.dirname = dest_dir
+ 'In staging area %s: %s' % (self.dirname, msg))