def run_once(self, disks=None, gigabytes=None, chunk_mb=None): """ Runs one iteration of disktest. :param disks: List of directories (usually mountpoints) to be passed to the test. :param gigabytes: Disk space that will be used for the test to run. :param chunk_mb: Size of the portion of the disk used to run the test. Cannot be larger than the total amount of free RAM. """ os.chdir(self.disk_srcdir) if chunk_mb is None: chunk_mb = utils_memory.memtotal() / 1024 / 8 if disks is None: disks = [self.tmpdir] if gigabytes is None: free = 100 # cap it at 100GB by default for disk in disks: free = min(utils.freespace(disk) / 1024 ** 3, free) gigabytes = free logging.info("Resizing to %s GB", gigabytes) sys.stdout.flush() self.chunk_mb = chunk_mb self.memory_mb = utils_memory.memtotal() / 1024 / 8 if self.memory_mb > chunk_mb: raise error.TestError("Too much RAM (%dMB) for this test to work" % self.memory_mb) chunks = (1024 * gigabytes) / chunk_mb logging.info("Total of disk chunks that will be used: %s", chunks) for i in range(chunks): pids = [] for disk in disks: pid = self.test_one_disk_chunk(disk, i) pids.append(pid) errors = [] for pid in pids: (junk, retval) = os.waitpid(pid, 0) if (retval != 0): errors.append(retval) if errors: raise error.TestError("Errors from children: %s" % errors)
def run_once(self, disks=None, gigabytes=None, chunk_mb=None): """ Runs one iteration of disktest. @param disks: List of directories (usually mountpoints) to be passed to the test. @param gigabytes: Disk space that will be used for the test to run. @param chunk_mb: Size of the portion of the disk used to run the test. Cannot be larger than the total amount of free RAM. """ os.chdir(self.disk_srcdir) if chunk_mb is None: chunk_mb = utils.memtotal() / 1024 / 8 if disks is None: disks = [self.tmpdir] if gigabytes is None: free = 100 # cap it at 100GB by default for disk in disks: free = min(utils.freespace(disk) / 1024**3, free) gigabytes = free logging.info("Resizing to %s GB", gigabytes) sys.stdout.flush() self.chunk_mb = chunk_mb self.memory_mb = utils.memtotal() / 1024 / 8 if self.memory_mb > chunk_mb: raise error.TestError("Too much RAM (%dMB) for this test to work" % self.memory_mb) chunks = (1024 * gigabytes) / chunk_mb logging.info("Total of disk chunks that will be used: %s", chunks) for i in range(chunks): pids = [] for disk in disks: pid = self.test_one_disk_chunk(disk, i) pids.append(pid) errors = [] for pid in pids: (junk, retval) = os.waitpid(pid, 0) if (retval != 0): errors.append(retval) if errors: raise error.TestError("Errors from children: %s" % errors)
def run_once(self, args='', stress_length=60): if not args: # We will use 2 workers of each type for each CPU detected threads = 2 * utils.count_cpus() # Sometimes the default memory used by each memory worker (256 M) # might make our machine go OOM and then funny things might start to # happen. Let's avoid that. mb = (utils_memory.freememtotal() + utils_memory.read_from_meminfo('SwapFree') / 2) memory_per_thread = (mb * 1024) / threads # Even though unlikely, it's good to prevent from allocating more # disk than this machine actually has on its autotest directory # (limit the amount of disk used to max of 90 % of free space) free_disk = utils.freespace(self.srcdir) file_size_per_thread = 1024 ** 2 if (0.9 * free_disk) < file_size_per_thread * threads: file_size_per_thread = (0.9 * free_disk) / threads # Number of CPU workers spinning on sqrt() args = '--cpu %d ' % threads # Number of IO workers spinning on sync() args += '--io %d ' % threads # Number of Memory workers spinning on malloc()/free() args += '--vm %d ' % threads # Amount of memory used per each worker args += '--vm-bytes %d ' % memory_per_thread # Number of HD workers spinning on write()/ulink() args += '--hdd %d ' % threads # Size of the files created by each worker in bytes args += '--hdd-bytes %d ' % file_size_per_thread # Time for which the stress test will run args += '--timeout %d ' % stress_length # Verbose flag args += '--verbose' utils.system(self.srcdir + '/src/stress ' + args)
def stop(self): # if no maximum usage rate was set, we don't need to # generate any warnings if not self.max_mb_per_hour: return final_space = utils.freespace(self.device) used_space = self.initial_space - final_space stop_time = time.time() total_time = stop_time - self.start_time # round up the time to one minute, to keep extremely short # tests from generating false positives due to short, badly # timed bursts of activity total_time = max(total_time, 60.0) # determine the usage rate bytes_per_sec = used_space / total_time mb_per_sec = bytes_per_sec / 1024 ** 2 mb_per_hour = mb_per_sec * 60 * 60 if mb_per_hour > self.max_mb_per_hour: msg = "disk space on %s was consumed at a rate of %.2f MB/hour" msg %= (self.device, mb_per_hour) self.func(msg)
def stop(self): # if no maximum usage rate was set, we don't need to # generate any warnings if not self.max_mb_per_hour: return final_space = utils.freespace(self.device) used_space = self.initial_space - final_space stop_time = time.time() total_time = stop_time - self.start_time # round up the time to one minute, to keep extremely short # tests from generating false positives due to short, badly # timed bursts of activity total_time = max(total_time, 60.0) # determine the usage rate bytes_per_sec = used_space / total_time mb_per_sec = bytes_per_sec / 1024 ** 2 mb_per_hour = mb_per_sec * 60 * 60 if mb_per_hour > self.max_mb_per_hour: msg = ("disk space on %s was consumed at a rate of %.2f MB/hour") msg %= (self.device, mb_per_hour) self.func(msg)
def backup_image(self, params, root_dir, action, good=True, skip_existing=False): """ Backup or restore a disk image, depending on the action chosen. :param params: Dictionary containing the test parameters. :param root_dir: Base directory for relative filenames. :param action: Whether we want to backup or restore the image. :param good: If we are backing up a good image(we want to restore it) or a bad image (we are saving a bad image for posterior analysis). :note: params should contain: image_name -- the name of the image file, without extension image_format -- the format of the image (qcow2, raw etc) """ def backup_raw_device(src, dst): if os.path.exists(src): utils.system("dd if=%s of=%s bs=4k conv=sync" % (src, dst)) else: logging.info("No source %s, skipping dd...", src) def backup_image_file(src, dst): logging.debug("Copying %s -> %s", src, dst) if os.path.isfile(dst) and os.path.isfile(src): os.unlink(dst) if os.path.isfile(src): shutil.copy(src, dst) else: logging.info("No source file %s, skipping copy...", src) def get_backup_set(filename, backup_dir, action, good): """ Get all sources and destinations required for each backup. """ if not os.path.isdir(backup_dir): os.makedirs(backup_dir) basename = os.path.basename(filename) bkp_set = [] if good: src = filename dst = os.path.join(backup_dir, "%s.backup" % basename) if action == 'backup': bkp_set = [[src, dst]] elif action == 'restore': bkp_set = [[dst, src]] else: # We have to make 2 backups, one of the bad image, another one # of the good image src_bad = filename src_good = os.path.join(backup_dir, "%s.backup" % basename) hsh = utils_misc.generate_random_string(4) dst_bad = (os.path.join(backup_dir, "%s.bad.%s" % (basename, hsh))) dst_good = (os.path.join(backup_dir, "%s.good.%s" % (basename, hsh))) if action == 'backup': bkp_set = [[src_bad, dst_bad], [src_good, dst_good]] elif action == 'restore': bkp_set = [[src_good, src_bad]] if not bkp_set: logging.error("No backup sets for action: %s, state: %s", action, good) return bkp_set image_filename = self.image_filename backup_dir = params.get("backup_dir", "") if not os.path.isabs(backup_dir): backup_dir = os.path.join(root_dir, backup_dir) if params.get('image_raw_device') == 'yes': iname = "raw_device" iformat = params.get("image_format", "qcow2") ifilename = "%s.%s" % (iname, iformat) ifilename = utils_misc.get_path(root_dir, ifilename) backup_set = get_backup_set(ifilename, backup_dir, action, good) backup_func = backup_raw_device else: backup_set = get_backup_set(image_filename, backup_dir, action, good) backup_func = backup_image_file if action == 'backup': image_dir = os.path.dirname(image_filename) image_dir_disk_free = utils.freespace(image_dir) backup_size = 0 for src, dst in backup_set: if os.path.isfile(src): backup_size += os.path.getsize(src) minimum_disk_free = 1.2 * backup_size if image_dir_disk_free < minimum_disk_free: image_dir_disk_free_gb = float(image_dir_disk_free) / 10 ** 9 backup_size_gb = float(backup_size) / 10 ** 9 minimum_disk_free_gb = float(minimum_disk_free) / 10 ** 9 logging.error("Free space on %s: %.1f GB", image_dir, image_dir_disk_free_gb) logging.error("Backup size: %.1f GB", backup_size_gb) logging.error("Minimum free space acceptable: %.1f GB", minimum_disk_free_gb) logging.error("Available disk space is not sufficient for a" "full backup. Skipping backup...") return for src, dst in backup_set: if action == 'backup' and skip_existing and os.path.exists(dst): continue backup_func(src, dst)
def start(self): self.initial_space = utils.freespace(self.device) self.start_time = time.time()
def backup_image(self, params, root_dir, action, good=True, skip_existing=False): """ Backup or restore a disk image, depending on the action chosen. :param params: Dictionary containing the test parameters. :param root_dir: Base directory for relative filenames. :param action: Whether we want to backup or restore the image. :param good: If we are backing up a good image(we want to restore it) or a bad image (we are saving a bad image for posterior analysis). :note: params should contain: image_name -- the name of the image file, without extension image_format -- the format of the image (qcow2, raw etc) """ def backup_raw_device(src, dst): if os.path.exists(src): utils.system("dd if=%s of=%s bs=4k conv=sync" % (src, dst)) else: logging.info("No source %s, skipping dd...", src) def backup_image_file(src, dst): logging.debug("Copying %s -> %s", src, dst) if os.path.isfile(dst) and os.path.isfile(src): os.unlink(dst) if os.path.isfile(src): shutil.copy(src, dst) else: logging.info("No source file %s, skipping copy...", src) def get_backup_set(filename, backup_dir, action, good): """ Get all sources and destinations required for each backup. """ if not os.path.isdir(backup_dir): os.makedirs(backup_dir) basename = os.path.basename(filename) bkp_set = [] if good: src = filename dst = os.path.join(backup_dir, "%s.backup" % basename) if action == 'backup': bkp_set = [[src, dst]] elif action == 'restore': bkp_set = [[dst, src]] else: # We have to make 2 backups, one of the bad image, another one # of the good image src_bad = filename src_good = os.path.join(backup_dir, "%s.backup" % basename) hsh = utils_misc.generate_random_string(4) dst_bad = (os.path.join(backup_dir, "%s.bad.%s" % (basename, hsh))) dst_good = (os.path.join(backup_dir, "%s.good.%s" % (basename, hsh))) if action == 'backup': bkp_set = [[src_bad, dst_bad], [src_good, dst_good]] elif action == 'restore': bkp_set = [[src_good, src_bad]] if not bkp_set: logging.error("No backup sets for action: %s, state: %s", action, good) return bkp_set image_filename = self.image_filename backup_dir = params.get("backup_dir", "") if not os.path.isabs(backup_dir): backup_dir = os.path.join(root_dir, backup_dir) if params.get('image_raw_device') == 'yes': iname = "raw_device" iformat = params.get("image_format", "qcow2") ifilename = "%s.%s" % (iname, iformat) ifilename = utils_misc.get_path(root_dir, ifilename) backup_set = get_backup_set(ifilename, backup_dir, action, good) backup_func = backup_raw_device else: backup_set = get_backup_set(image_filename, backup_dir, action, good) backup_func = backup_image_file if action == 'backup': image_dir = os.path.dirname(image_filename) image_dir_disk_free = utils.freespace(image_dir) backup_size = 0 for src, dst in backup_set: if os.path.isfile(src): backup_size += os.path.getsize(src) minimum_disk_free = 1.2 * backup_size if image_dir_disk_free < minimum_disk_free: image_dir_disk_free_gb = float(image_dir_disk_free) / 10**9 backup_size_gb = float(backup_size) / 10**9 minimum_disk_free_gb = float(minimum_disk_free) / 10**9 logging.error("Free space on %s: %.1f GB", image_dir, image_dir_disk_free_gb) logging.error("Backup size: %.1f GB", backup_size_gb) logging.error("Minimum free space acceptable: %.1f GB", minimum_disk_free_gb) logging.error("Available disk space is not sufficient for a" "full backup. Skipping backup...") return for src, dst in backup_set: if action == 'backup' and skip_existing and os.path.exists(dst): continue backup_func(src, dst)
def backup_image(self, params, root_dir, action, good=True): """ Backup or restore a disk image, depending on the action chosen. @param params: Dictionary containing the test parameters. @param root_dir: Base directory for relative filenames. @param action: Whether we want to backup or restore the image. @param good: If we are backing up a good image(we want to restore it) or a bad image (we are saving a bad image for posterior analysis). @note: params should contain: image_name -- the name of the image file, without extension image_format -- the format of the image (qcow2, raw etc) """ def backup_raw_device(src, dst): utils.system("dd if=%s of=%s bs=4k conv=sync" % (src, dst)) def backup_image_file(src, dst): logging.debug("Copying %s -> %s", src, dst) shutil.copy(src, dst) def get_backup_name(filename, backup_dir, good): if not os.path.isdir(backup_dir): os.makedirs(backup_dir) basename = os.path.basename(filename) if good: backup_filename = "%s.backup" % basename else: backup_filename = "%s.bad.%s" % (basename, virt_utils.generate_random_string(4)) return os.path.join(backup_dir, backup_filename) image_filename = self.image_filename backup_dir = params.get("backup_dir") if params.get("image_raw_device") == "yes": iname = "raw_device" iformat = params.get("image_format", "qcow2") ifilename = "%s.%s" % (iname, iformat) ifilename = virt_utils.get_path(root_dir, ifilename) image_filename_backup = get_backup_name(ifilename, backup_dir, good) backup_func = backup_raw_device else: image_filename_backup = get_backup_name(image_filename, backup_dir, good) backup_func = backup_image_file if action == "backup": image_dir = os.path.dirname(image_filename) image_dir_disk_free = utils.freespace(image_dir) image_filename_size = os.path.getsize(image_filename) image_filename_backup_size = 0 if os.path.isfile(image_filename_backup): image_filename_backup_size = os.path.getsize(image_filename_backup) disk_free = image_dir_disk_free + image_filename_backup_size minimum_disk_free = 1.2 * image_filename_size if disk_free < minimum_disk_free: image_dir_disk_free_gb = float(image_dir_disk_free) / 10 ** 9 minimum_disk_free_gb = float(minimum_disk_free) / 10 ** 9 logging.error( "Dir %s has %.1f GB free, less than the minimum " "required to store a backup, defined to be 120%% " "of the backup size, %.1f GB. Skipping backup...", image_dir, image_dir_disk_free_gb, minimum_disk_free_gb, ) return if good: # In case of qemu-img check return 1, we will make 2 backups, # one for investigation and other, to use as a 'pristine' # image for further tests state = "good" else: state = "bad" logging.info("Backing up %s image file %s", state, image_filename) src, dst = image_filename, image_filename_backup elif action == "restore": if not os.path.isfile(image_filename_backup): logging.error("Image backup %s not found, skipping restore...", image_filename_backup) return logging.info("Restoring image file %s from backup", image_filename) src, dst = image_filename_backup, image_filename backup_func(src, dst)
def backup_image(self, params, root_dir, action, good=True): """ Backup or restore a disk image, depending on the action chosen. @param params: Dictionary containing the test parameters. @param root_dir: Base directory for relative filenames. @param action: Whether we want to backup or restore the image. @param good: If we are backing up a good image(we want to restore it) or a bad image (we are saving a bad image for posterior analysis). @note: params should contain: image_name -- the name of the image file, without extension image_format -- the format of the image (qcow2, raw etc) """ def backup_raw_device(src, dst): utils.system("dd if=%s of=%s bs=4k conv=sync" % (src, dst)) def backup_image_file(src, dst): logging.debug("Copying %s -> %s", src, dst) shutil.copy(src, dst) def get_backup_name(filename, backup_dir, good): if not os.path.isdir(backup_dir): os.makedirs(backup_dir) basename = os.path.basename(filename) if good: backup_filename = "%s.backup" % basename else: backup_filename = ( "%s.bad.%s" % (basename, virt_utils.generate_random_string(4))) return os.path.join(backup_dir, backup_filename) image_filename = self.image_filename backup_dir = params.get("backup_dir") if params.get('image_raw_device') == 'yes': iname = "raw_device" iformat = params.get("image_format", "qcow2") ifilename = "%s.%s" % (iname, iformat) ifilename = virt_utils.get_path(root_dir, ifilename) image_filename_backup = get_backup_name(ifilename, backup_dir, good) backup_func = backup_raw_device else: image_filename_backup = get_backup_name(image_filename, backup_dir, good) backup_func = backup_image_file if action == 'backup': image_dir = os.path.dirname(image_filename) image_dir_disk_free = utils.freespace(image_dir) image_filename_size = os.path.getsize(image_filename) image_filename_backup_size = 0 if os.path.isfile(image_filename_backup): image_filename_backup_size = os.path.getsize( image_filename_backup) disk_free = image_dir_disk_free + image_filename_backup_size minimum_disk_free = 1.2 * image_filename_size if disk_free < minimum_disk_free: image_dir_disk_free_gb = float(image_dir_disk_free) / 10**9 minimum_disk_free_gb = float(minimum_disk_free) / 10**9 logging.error( "Dir %s has %.1f GB free, less than the minimum " "required to store a backup, defined to be 120%% " "of the backup size, %.1f GB. Skipping backup...", image_dir, image_dir_disk_free_gb, minimum_disk_free_gb) return if good: # In case of qemu-img check return 1, we will make 2 backups, # one for investigation and other, to use as a 'pristine' # image for further tests state = 'good' else: state = 'bad' logging.info("Backing up %s image file %s", state, image_filename) src, dst = image_filename, image_filename_backup elif action == 'restore': if not os.path.isfile(image_filename_backup): logging.error('Image backup %s not found, skipping restore...', image_filename_backup) return logging.info("Restoring image file %s from backup", image_filename) src, dst = image_filename_backup, image_filename backup_func(src, dst)