def testTopLevelLockFile(self): """Try a simple process-upload run. Expect it to exit earlier due the occupied lockfile """ # acquire the process-upload lockfile locally from contrib.glock import GlobalLock locker = GlobalLock('/var/lock/process-upload-insecure.lock') locker.acquire() returncode, out, err = self.runProcessUpload( extra_args=['-C', 'insecure']) # the process-upload call terminated with ERROR and # proper log message self.assertEqual(1, returncode) self.assert_( 'INFO Creating lockfile: ' '/var/lock/process-upload-insecure.lock' in err.splitlines()) self.assert_( 'INFO Lockfile /var/lock/process-upload-insecure.lock in use' in err.splitlines()) # release the locally acquired lockfile locker.release()
def setup_lock(self): """Create lockfile. Note that this will create a lockfile even if you don't actually use it. GlobalLock.__del__ is meant to clean it up though. """ self.lock = GlobalLock(self.lockfilepath, logger=self.logger)
def locateDirectories(self, fsroot): """Return a list of upload directories in a given queue. This method operates on the queue atomically, i.e. it suppresses changes in the queue directory, like new uploads, by acquiring the shared upload_queue lockfile while the directory are listed. :param fsroot: path to a 'queue' directory to be inspected. :return: a list of upload directories found in the queue alphabetically sorted. """ # Protecting listdir by a lock ensures that we only get completely # finished directories listed. See lp.poppy.hooks for the other # locking place. lockfile_path = os.path.join(fsroot, ".lock") fsroot_lock = GlobalLock(lockfile_path) mode = stat.S_IMODE(os.stat(lockfile_path).st_mode) # XXX cprov 20081024 bug=185731: The lockfile permission can only be # changed by its owner. Since we can't predict which process will # create it in production systems we simply ignore errors when trying # to grant the right permission. At least, one of the process will # be able to do so. try: os.chmod(lockfile_path, mode | stat.S_IWGRP) except OSError as err: self.log.debug('Could not fix the lockfile permission: %s' % err) try: fsroot_lock.acquire(blocking=True) dir_names = os.listdir(fsroot) finally: # Skip lockfile deletion, see similar code in lp.poppy.hooks. fsroot_lock.release(skip_delete=True) sorted_dir_names = sorted( dir_name for dir_name in dir_names if os.path.isdir(os.path.join(fsroot, dir_name))) return sorted_dir_names
def client_done_hook(self, fsroot, host, port): """A client has completed. If it authenticated then it stands a chance of having uploaded a file to the set. If not; then it is simply an aborted transaction and we remove the fsroot.""" if fsroot not in self.clients: raise PoppyInterfaceFailure("Unable to find fsroot in client set") self.logger.debug("Processing session complete in %s" % fsroot) client = self.clients[fsroot] if "distro" not in client: # Login username defines the distribution context of the upload. # So abort unauthenticated sessions by removing its contents shutil.rmtree(fsroot) return # Protect from race condition between creating the directory # and creating the distro file, and also in cases where the # temporary directory and the upload directory are not in the # same filesystem (non-atomic "rename"). lockfile_path = os.path.join(self.targetpath, ".lock") self.lock = GlobalLock(lockfile_path) # XXX cprov 20071024 bug=156795: We try to acquire the lock as soon # as possible after creating the lockfile but are still open to # a race. self.lock.acquire(blocking=True) mode = stat.S_IMODE(os.stat(lockfile_path).st_mode) # XXX cprov 20081024 bug=185731: The lockfile permission can only be # changed by its owner. Since we can't predict which process will # create it in production systems we simply ignore errors when trying # to grant the right permission. At least, one of the process will # be able to do so. try: os.chmod(lockfile_path, mode | stat.S_IWGRP) except OSError: pass try: timestamp = time.strftime("%Y%m%d-%H%M%S") path = "upload%s-%s-%06d" % (self.prefix, timestamp, self.targetcount) target_fsroot = os.path.join(self.targetpath, path) # Create file to store the distro used. self.logger.debug("Upload was targetted at %s" % client["distro"]) distro_filename = target_fsroot + ".distro" distro_file = open(distro_filename, "w") distro_file.write(client["distro"]) distro_file.close() # Move the session directory to the target directory. if os.path.exists(target_fsroot): self.logger.warn("Targeted upload already present: %s" % path) self.logger.warn("System clock skewed ?") else: try: shutil.move(fsroot, target_fsroot) except (OSError, IOError): if not os.path.exists(target_fsroot): raise # XXX cprov 20071024: We should replace os.system call by os.chmod # and fix the default permission value accordingly in poppy-upload if self.perms is not None: os.system("chmod %s -R %s" % (self.perms, target_fsroot)) # Invoke processing script, if provided. if self.cmd: cmd = self.cmd cmd = cmd.replace("@fsroot@", target_fsroot) cmd = cmd.replace("@distro@", client["distro"]) self.logger.debug("Running upload handler: %s" % cmd) os.system(cmd) finally: # We never delete the lockfile, this way the inode will be # constant while the machine is up. See comment on 'acquire' self.lock.release(skip_delete=True) self.clients.pop(fsroot) # This is mainly done so that tests know when the # post-processing hook has finished. self.logger.info(self.LOG_MAGIC)
def lock(self): self.actualLock = GlobalLock(self.lockfilename) try: self.actualLock.acquire() except LockAlreadyAcquired: raise LockError(self.lockfilename)