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 "-t" not 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 as e: logging.error(e.result_obj) if record: self.job.record('FAIL', None, mkfs_cmd, error.format_error()) raise except Exception: 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 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 Exception: 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 Exception: 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 wipe_filesystem(job, mountpoint): wipe_cmd = 'rm -rf %s/*' % mountpoint try: utils.system(wipe_cmd) except Exception: job.record('FAIL', None, wipe_cmd, error.format_error()) raise else: job.record('GOOD', None, wipe_cmd)
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 "-t" not 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 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 aggressive. :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 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 Exception: 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 Exception: 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)
class partition(object): """ Class for handling partitions and filesystems """ def __init__(self, job, device, loop_size=0, mountpoint=None): """ @param job: A L{client.job} instance. @param device: The device in question (e.g."/dev/hda2"). If device is a file it will be mounted as loopback. If you have job config 'partition.partitions', e.g., job.config_set('partition.partitions', ["/dev/sda2", "/dev/sda3"]) you may specify a partition in the form of "partN" e.g. "part0", "part1" to refer to elements of the partition list. This is specially useful if you run a test in various machines and you don't want to hardcode device names as those may vary. @param loop_size: Size of loopback device (in MB). Defaults to 0. """ # NOTE: This code is used by IBM / ABAT. Do not remove. part = re.compile(r'^part(\d+)$') m = part.match(device) if m: number = int(m.groups()[0]) partitions = job.config_get('partition.partitions') try: device = partitions[number] except Exception: raise NameError("Partition '" + device + "' not available") self.device = device self.name = os.path.basename(device) self.job = job self.loop = loop_size self.fstype = None self.mountpoint = mountpoint self.mkfs_flags = None self.mount_options = None self.fs_tag = None if self.loop: cmd = 'dd if=/dev/zero of=%s bs=1M count=%d' % (device, loop_size) utils.system(cmd) def __repr__(self): return '<Partition: %s>' % self.device def set_fs_options(self, fs_options): """ Set filesystem options @param fs_options: A L{FsOptions} object """ self.fstype = fs_options.fstype self.mkfs_flags = fs_options.mkfs_flags self.mount_options = fs_options.mount_options self.fs_tag = fs_options.fs_tag def run_test(self, test, **dargs): self.job.run_test(test, dir=self.get_mountpoint(), **dargs) def setup_before_test(self, mountpoint_func): """ Prepare a partition for running a test. Unmounts any filesystem that's currently mounted on the partition, makes a new filesystem (according to this partition's filesystem options) and mounts it where directed by mountpoint_func. @param mountpoint_func: A callable that returns a path as a string, given a partition instance. """ mountpoint = mountpoint_func(self) if not mountpoint: raise ValueError('Don\'t know where to put this partition') self.unmount(ignore_status=True, record=False) self.mkfs() if not os.path.isdir(mountpoint): os.makedirs(mountpoint) self.mount(mountpoint) def run_test_on_partition(self, test, mountpoint_func, **dargs): """ Executes a test fs-style (umount,mkfs,mount,test) Here we unmarshal the args to set up tags before running the test. Tests are also run by first umounting, mkfsing and then mounting before executing the test. @param test: name of test to run @param mountpoint_func: function to return mount point string """ tag = dargs.get('tag') if tag: tag = '%s.%s' % (self.name, tag) elif self.fs_tag: tag = '%s.%s' % (self.name, self.fs_tag) else: tag = self.name # If there's a 'suffix' argument, append it to the tag and remove it suffix = dargs.pop('suffix', None) if suffix: tag = '%s.%s' % (tag, suffix) dargs['tag'] = test + '.' + tag def _make_partition_and_run_test(test_tag, dir=None, **dargs): self.setup_before_test(mountpoint_func) try: self.job.run_test(test, tag=test_tag, dir=mountpoint, **dargs) finally: self.unmount() self.fsck() mountpoint = mountpoint_func(self) # The tag is the tag for the group (get stripped off by run_group) # The test_tag is the tag for the test itself self.job.run_group(_make_partition_and_run_test, test_tag=tag, dir=mountpoint, **dargs) def get_mountpoint(self, open_func=open, filename=None): """ Find the mount point of this partition object. @param open_func: the function to use for opening the file containing the mounted partitions information @param filename: where to look for the mounted partitions information (default None which means it will search /proc/mounts and/or /etc/mtab) @returns a string with the mount point of the partition or None if not mounted """ if filename: for line in open_func(filename).readlines(): parts = line.split() if parts[0] == self.device or parts[1] == self.mountpoint: return parts[1] # The mountpoint where it's mounted return None # no specific file given, look in /proc/mounts res = self.get_mountpoint(open_func=open_func, filename='/proc/mounts') if not res: # sometimes the root partition is reported as /dev/root in # /proc/mounts in this case, try /etc/mtab res = self.get_mountpoint(open_func=open_func, filename='/etc/mtab') # trust /etc/mtab only about / if res != '/': res = None return res def mkfs_exec(self, fstype): """ Return the proper mkfs executable based on fs """ if fstype == 'ext4': if os.path.exists('/sbin/mkfs.ext4'): return 'mkfs' # If ext4 supported e2fsprogs is not installed we use the # autotest supplied one in tools dir which is statically linked""" auto_mkfs = os.path.join(self.job.toolsdir, 'mkfs.ext4dev') if os.path.exists(auto_mkfs): return auto_mkfs else: return 'mkfs' raise NameError('Error creating partition for filesystem type %s' % fstype) 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 except Exception: if record: self.job.record('FAIL', None, mkfs_cmd, error.format_error()) raise