def run(self): """Creates a single container.""" self._start_time = time.time() container = None try: container = self._factory.create_container() container.start(wait_for_network=True) except Exception as e: logging.error('Worker error: %s', error.format_error()) self._error_cb(self, e) finally: # All this has to happen atomically, otherwise race conditions can # arise w.r.t. cancellation. with self._completion_lock: self._completed = True if self._cancelled: # If the job was cancelled, destroy the container instead of # putting it in the result queue. Do not release the # throttle, as it would have been released when the # cancellation occurred. if container is not None: container.destroy() else: # Put the container in the result field. Release the # throttle so another task can be picked up. # Container may be None if errors occurred. if container is not None: self._result_cb(container)
def mount(self, mountpoint=None, fstype=None, args='', record=True): """ Mount this partition to a mount point @param mountpoint: If you have not provided a mountpoint to partition object or want to use a different one, you may specify it here. @param fstype: Filesystem type. If not provided partition object value will be used. @param args: Arguments to be passed to "mount" command. @param record: If True, output result of mount operation to autotest output. """ if fstype is None: fstype = self.fstype else: assert(self.fstype is None or self.fstype == fstype); if self.mount_options: args += ' -o ' + self.mount_options if fstype: args += ' -t ' + fstype if self.loop: args += ' -o loop' args = args.lstrip() if not mountpoint and not self.mountpoint: raise ValueError("No mountpoint specified and no default " "provided to this partition object") if not mountpoint: mountpoint = self.mountpoint mount_cmd = "mount %s %s %s" % (args, self.device, mountpoint) if list_mount_devices().count(self.device): err = 'Attempted to mount mounted device' self.job.record('FAIL', None, mount_cmd, err) raise NameError(err) if list_mount_points().count(mountpoint): err = 'Attempted to mount busy mountpoint' self.job.record('FAIL', None, mount_cmd, err) raise NameError(err) mtab = open('/etc/mtab') # We have to get an exclusive lock here - mount/umount are racy fcntl.flock(mtab.fileno(), fcntl.LOCK_EX) sys.stdout.flush() try: utils.system(mount_cmd) mtab.close() except: mtab.close() if record: self.job.record('FAIL', None, mount_cmd, error.format_error()) raise else: if record: self.job.record('GOOD', None, mount_cmd) self.fstype = fstype
def mount(self, mountpoint=None, fstype=None, args='', record=True): """ Mount this partition to a mount point @param mountpoint: If you have not provided a mountpoint to partition object or want to use a different one, you may specify it here. @param fstype: Filesystem type. If not provided partition object value will be used. @param args: Arguments to be passed to "mount" command. @param record: If True, output result of mount operation to autotest output. """ if fstype is None: fstype = self.fstype else: assert(self.fstype is None or self.fstype == fstype); if self.mount_options: args += ' -o ' + self.mount_options if fstype: args += ' -t ' + fstype if self.loop: args += ' -o loop' args = args.lstrip() if not mountpoint and not self.mountpoint: raise ValueError("No mountpoint specified and no default " "provided to this partition object") if not mountpoint: mountpoint = self.mountpoint mount_cmd = "mount %s %s %s" % (args, self.device, mountpoint) if list_mount_devices().count(self.device): err = 'Attempted to mount mounted device' self.job.record('FAIL', None, mount_cmd, err) raise NameError(err) if list_mount_points().count(mountpoint): err = 'Attempted to mount busy mountpoint' self.job.record('FAIL', None, mount_cmd, err) raise NameError(err) mtab = open('/etc/mtab') # We have to get an exclusive lock here - mount/umount are racy fcntl.flock(mtab.fileno(), fcntl.LOCK_EX) sys.stdout.flush() try: utils.system(mount_cmd) mtab.close() except: mtab.close() if record: self.job.record('FAIL', None, mount_cmd, error.format_error()) raise else: if record: self.job.record('GOOD', None, mount_cmd) self.fstype = fstype
def testCreateContainer(self): """Tests basic container creation.""" container = self.test_factory.create_container() try: container.refresh_status() except: self.fail('Invalid container:\n%s' % error.format_error())
def wipe_filesystem(job, mountpoint): wipe_cmd = 'rm -rf %s/*' % mountpoint try: utils.system(wipe_cmd) except: job.record('FAIL', None, wipe_cmd, error.format_error()) raise else: job.record('GOOD', None, wipe_cmd)
def testStop_notRunning(self): """Tests stopping the async listener when it's not running.""" try: self.assertFalse(self.listener.is_running()) # Verify that calling stop just returns False when the listener # isn't running. self.assertFalse(self.listener.stop()) except: self.fail(error.format_error())
def wipe_filesystem(job, mountpoint): wipe_cmd = 'rm -rf %s/*' % mountpoint try: utils.system(wipe_cmd) except: job.record('FAIL', None, wipe_cmd, error.format_error()) raise else: job.record('GOOD', None, wipe_cmd)
def testHostDirAccess(self): """Verifies that sudo is not required to write to the shared host dir. """ try: host_dir = lxc.SharedHostDir(self.shared_host_path) tempfile.NamedTemporaryFile(dir=host_dir.path) except OSError: self.fail('Unable to write to shared host dir.\n%s' % error.format_error()) finally: host_dir.cleanup()
def testCreate_existing(self): """Verifies that BaseImage works with existing base containers.""" with TestBaseContainer() as control: manager = BaseImage(control.container_path, control.name) self.assertIsNotNone(manager.base_container) self.assertEquals(control.container_path, manager.base_container.container_path) self.assertEquals(control.name, manager.base_container.name) try: manager.base_container.refresh_status() except error.ContainerError: self.fail('Base container was not valid.\n%s' % error.format_error())
def testHostDirNotMounted(self): """Verifies that an unmounted host dir does not cause container bucket construction to crash. """ # Create the shared host dir, but do not mount it. os.makedirs(self.shared_host_path) # Setup then destroy the HPM. This should not emit any exceptions. try: host_dir = lxc.SharedHostDir(self.shared_host_path) host_dir.cleanup() except: self.fail('SharedHostDir crashed.\n%s' % error.format_error())
def mkfs(self, fstype=None, args='', record=True): """ Format a partition to filesystem type @param fstype: the filesystem type, e.g.. "ext3", "ext2" @param args: arguments to be passed to mkfs command. @param record: if set, output result of mkfs operation to autotest output """ if list_mount_devices().count(self.device): raise NameError('Attempted to format mounted device %s' % self.device) if not fstype: if self.fstype: fstype = self.fstype else: fstype = 'ext2' if self.mkfs_flags: args += ' ' + self.mkfs_flags if fstype == 'xfs': args += ' -f' if self.loop: # BAH. Inconsistent mkfs syntax SUCKS. if fstype.startswith('ext'): args += ' -F' elif fstype == 'reiserfs': args += ' -f' # If there isn't already a '-t <type>' argument, add one. if not "-t" in args: args = "-t %s %s" % (fstype, args) args = args.strip() mkfs_cmd = "%s %s %s" % (self.mkfs_exec(fstype), args, self.device) sys.stdout.flush() try: # We throw away the output here - we only need it on error, in # which case it's in the exception utils.system_output("yes | %s" % mkfs_cmd) except error.CmdError, e: logging.error(e.result_obj) if record: self.job.record('FAIL', None, mkfs_cmd, error.format_error()) raise
def testInvalidId(self): """Verifies that corrupted ID files do not raise exceptions.""" with self.createContainer() as container: # Create a container with an empty ID file. id_path = os.path.join(container.container_path, container.name, container_module._CONTAINER_ID_FILENAME) utils.run('sudo touch %s' % id_path) try: # Verify that container creation doesn't raise exceptions. test_container = lxc.Container.create_from_existing_dir( self.test_dir, container.name) self.assertIsNone(test_container.id) except Exception: self.fail('Unexpected exception:\n%s' % error.format_error())
def mkfs(self, fstype=None, args='', record=True): """ Format a partition to filesystem type @param fstype: the filesystem type, e.g.. "ext3", "ext2" @param args: arguments to be passed to mkfs command. @param record: if set, output result of mkfs operation to autotest output """ if list_mount_devices().count(self.device): raise NameError('Attempted to format mounted device %s' % self.device) if not fstype: if self.fstype: fstype = self.fstype else: fstype = 'ext2' if self.mkfs_flags: args += ' ' + self.mkfs_flags if fstype == 'xfs': args += ' -f' if self.loop: # BAH. Inconsistent mkfs syntax SUCKS. if fstype.startswith('ext'): args += ' -F' elif fstype == 'reiserfs': args += ' -f' # If there isn't already a '-t <type>' argument, add one. if not "-t" in args: args = "-t %s %s" % (fstype, args) args = args.strip() mkfs_cmd = "%s %s %s" % (self.mkfs_exec(fstype), args, self.device) sys.stdout.flush() try: # We throw away the output here - we only need it on error, in # which case it's in the exception utils.system_output("yes | %s" % mkfs_cmd) except error.CmdError, e: logging.error(e.result_obj) if record: self.job.record('FAIL', None, mkfs_cmd, error.format_error()) raise
def testHostDirMissing(self): """Verifies that a missing host dir does not cause cleanup to crash. """ host_dir = lxc.SharedHostDir(self.shared_host_path) # Manually destroy the host path utils.run('sudo umount %(path)s && sudo rmdir %(path)s' % {'path': self.shared_host_path}) # Verify that the host path does not exist. self.assertFalse(os.path.exists(self.shared_host_path)) try: host_dir.cleanup() except: self.fail('SharedHostDir.cleanup crashed.\n%s' % error.format_error())
def testCleanup_withClones(self): """Verifies that cleanup cleans up the base image. Ensure that it works even when clones of the base image exist. """ # Do not snapshot, as snapshots of snapshots behave differently than # snapshots of full container clones. BaseImage cleanup code assumes # that the base container is not a snapshot. base = lxc.Container.clone(src=reference_container, new_name=constants.BASE, new_path=test_dir, snapshot=False) manager = BaseImage(base.container_path, base.name) clones = [] for i in range(3): clones.append( lxc.Container.clone(src=base, new_name='clone_%d' % i, snapshot=True)) # Precondition: all containers are valid. base.refresh_status() for container in clones: container.refresh_status() manager.cleanup() # Verify that all containers were cleaned up self.assertFalse( lxc_utils.path_exists(os.path.join(base.container_path, base.name))) for container in clones: if constants.SUPPORT_SNAPSHOT_CLONE: # Snapshot clones should get deleted along with the base # container. self.assertFalse( lxc_utils.path_exists( os.path.join(container.container_path, container.name))) else: # If snapshot clones aren't supported (e.g. on moblab), the # clones should not be affected by the destruction of the base # container. try: container.refresh_status() except error.ContainerError: self.fail(error.format_error())
def unmount(self, ignore_status=False, record=True): """ Umount this partition. It's easier said than done to umount a partition. We need to lock the mtab file to make sure we don't have any locking problems if we are umounting in paralllel. If there turns out to be a problem with the simple umount we end up calling umount_force to get more agressive. @param ignore_status: should we notice the umount status @param record: if True, output result of umount operation to autotest output """ mountpoint = self.get_mountpoint() if not mountpoint: # It's not even mounted to start with if record and not ignore_status: msg = 'umount for dev %s has no mountpoint' % self.device self.job.record('FAIL', None, msg, 'Not mounted') return umount_cmd = "umount " + mountpoint mtab = open('/etc/mtab') # We have to get an exclusive lock here - mount/umount are racy fcntl.flock(mtab.fileno(), fcntl.LOCK_EX) sys.stdout.flush() try: utils.system(umount_cmd) mtab.close() if record: self.job.record('GOOD', None, umount_cmd) except (error.CmdError, IOError): mtab.close() # Try the forceful umount if self.unmount_force(): return # If we are here we cannot umount this partition if record and not ignore_status: self.job.record('FAIL', None, umount_cmd, error.format_error()) raise
def unmount(self, ignore_status=False, record=True): """ Umount this partition. It's easier said than done to umount a partition. We need to lock the mtab file to make sure we don't have any locking problems if we are umounting in paralllel. If there turns out to be a problem with the simple umount we end up calling umount_force to get more agressive. @param ignore_status: should we notice the umount status @param record: if True, output result of umount operation to autotest output """ mountpoint = self.get_mountpoint() if not mountpoint: # It's not even mounted to start with if record and not ignore_status: msg = 'umount for dev %s has no mountpoint' % self.device self.job.record('FAIL', None, msg, 'Not mounted') return umount_cmd = "umount " + mountpoint mtab = open('/etc/mtab') # We have to get an exclusive lock here - mount/umount are racy fcntl.flock(mtab.fileno(), fcntl.LOCK_EX) sys.stdout.flush() try: utils.system(umount_cmd) mtab.close() if record: self.job.record('GOOD', None, umount_cmd) except (error.CmdError, IOError): mtab.close() # Try the forceful umount if self.unmount_force(): return # If we are here we cannot umount this partition if record and not ignore_status: self.job.record('FAIL', None, umount_cmd, error.format_error()) raise
def testStartStop(self): """Tests starting and stopping the async listener.""" try: self.assertFalse(self.listener.is_running()) self.listener.start() self.assertTrue(self.listener.is_running()) # Establish a connection to verify that the listener is actually # alive. host, client = self._make_connection() client.close() host.close() self.assertTrue(self.listener.stop()) self.assertFalse(self.listener.is_running()) except: self.fail(error.format_error())
def _createAndDestroyPool(self, factory, size, wait=True): """Creates a container pool, fully populates it, then destroys it. @param factory: A ContainerFactory to use for the Pool. @param size: The size of the Pool to create. @param wait: If true (the default), fail if the pool does not exit cleanly. Set this to False for tests where a clean shutdown is not expected (e.g. when exercising things like hung worker threads). """ test_pool = pool.Pool(factory, size=size) # Wait for the pool to be fully populated. if wait: factory.wait(size) # Clean up the container pool. try: test_pool.cleanup(timeout=(TEST_TIMEOUT if wait else 0)) except threading.ThreadError: self.fail('Error while cleaning up container pool:\n%s' % error.format_error())
def fsck(self, args='-fy', record=True): """ Run filesystem check @param args: arguments to filesystem check tool. Default is "-n" which works on most tools. """ # I hate reiserfstools. # Requires an explit Yes for some inane reason fsck_cmd = '%s %s %s' % (self.get_fsck_exec(), self.device, args) if self.fstype == 'reiserfs': fsck_cmd = 'yes "Yes" | ' + fsck_cmd sys.stdout.flush() try: utils.system_output(fsck_cmd) except: if record: self.job.record('FAIL', None, fsck_cmd, error.format_error()) raise error.TestError('Fsck found errors with the underlying ' 'file system') else: if record: self.job.record('GOOD', None, fsck_cmd)
def fsck(self, args='-fy', record=True): """ Run filesystem check @param args: arguments to filesystem check tool. Default is "-n" which works on most tools. """ # I hate reiserfstools. # Requires an explit Yes for some inane reason fsck_cmd = '%s %s %s' % (self.get_fsck_exec(), self.device, args) if self.fstype == 'reiserfs': fsck_cmd = 'yes "Yes" | ' + fsck_cmd sys.stdout.flush() try: utils.system_output(fsck_cmd) except: if record: self.job.record('FAIL', None, fsck_cmd, error.format_error()) raise error.TestError('Fsck found errors with the underlying ' 'file system') else: if record: self.job.record('GOOD', None, fsck_cmd)
mkfs_cmd = "%s %s %s" % (self.mkfs_exec(fstype), args, self.device) sys.stdout.flush() try: # We throw away the output here - we only need it on error, in # which case it's in the exception utils.system_output("yes | %s" % mkfs_cmd) except error.CmdError, e: logging.error(e.result_obj) if record: self.job.record('FAIL', None, mkfs_cmd, error.format_error()) raise except: if record: self.job.record('FAIL', None, mkfs_cmd, error.format_error()) raise else: if record: self.job.record('GOOD', None, mkfs_cmd) self.fstype = fstype def get_fsck_exec(self): """ Return the proper mkfs executable based on self.fstype """ if self.fstype == 'ext4': if os.path.exists('/sbin/fsck.ext4'): return 'fsck' # If ext4 supported e2fsprogs is not installed we use the
container_id = lxc.ContainerId.create(TEST_JOB_ID) container = setup_test(bucket, container_id, options.skip_cleanup) test_share(container) test_autoserv(container) if options.dut: test_ssh(container, options.dut) if options.devserver: test_ssh(container, options.devserver) # Packages are installed in TEST_SCRIPT, verify the packages are installed. test_package_install(container) logging.info('All tests passed.') if __name__ == '__main__': options = parse_options() try: main(options) except: # If the cleanup code below raises additional errors, they obfuscate the # actual error in the test. Highlight the error to aid in debugging. logging.exception('ERROR:\n%s', error.format_error()) raise finally: if not options.skip_cleanup: logging.info('Cleaning up temporary directory %s.', TEMP_DIR) try: lxc.ContainerBucket(TEMP_DIR).destroy_all() finally: utils.run('sudo rm -rf "%s"' % TEMP_DIR)
mkfs_cmd = "%s %s %s" % (self.mkfs_exec(fstype), args, self.device) sys.stdout.flush() try: # We throw away the output here - we only need it on error, in # which case it's in the exception utils.system_output("yes | %s" % mkfs_cmd) except error.CmdError, e: logging.error(e.result_obj) if record: self.job.record('FAIL', None, mkfs_cmd, error.format_error()) raise except: if record: self.job.record('FAIL', None, mkfs_cmd, error.format_error()) raise else: if record: self.job.record('GOOD', None, mkfs_cmd) self.fstype = fstype def get_fsck_exec(self): """ Return the proper mkfs executable based on self.fstype """ if self.fstype == 'ext4': if os.path.exists('/sbin/fsck.ext4'): return 'fsck' # If ext4 supported e2fsprogs is not installed we use the