def create_partitions(device,
                      sizes: [],
                      partition_table_type=PartitionTable.gpt):
    from storage_devices.partition import Partition
    if create_partition_table(device, partition_table_type):
        device.partition_table = partition_table_type
        partition_type = PartitionType.primary

        partition_number_offset = 0
        for s in sizes:
            size = Size(
                s.get_value(device.block_size) - device.block_size.value,
                device.block_size)
            if partition_table_type == PartitionTable.msdos and \
                    len(sizes) > 4 and len(device.partitions) == 3:
                create_partition(device, Size.zero(), 4,
                                 PartitionType.extended, Unit.MebiByte, True)
                partition_type = PartitionType.logical
                partition_number_offset = 1

            partition_number = len(
                device.partitions) + 1 + partition_number_offset
            if create_partition(device, size, partition_number, partition_type,
                                Unit.MebiByte, True):
                new_part = Partition(device, partition_type, partition_number)
                dd = Dd().input("/dev/zero") \
                    .output(new_part.system_path) \
                    .count(1) \
                    .block_size(Size(1, Unit.Blocks4096)) \
                    .oflag("direct")
                dd.run()
                device.partitions.append(new_part)
示例#2
0
def run_dd(target_path, count, seek):
    dd = Dd() \
        .input("/dev/zero") \
        .output(target_path) \
        .block_size(Size(1, Unit.Blocks4096)) \
        .count(count) \
        .oflag("direct") \
        .seek(seek)
    dd.run()
    TestRun.LOGGER.info(f"dd command:\n{dd}")
示例#3
0
def create_partition(
        device,
        part_size,
        part_number,
        part_type: PartitionType = PartitionType.primary,
        unit=Unit.MebiByte,
        aligned: bool = True):
    TestRun.LOGGER.info(
        f"Creating {part_type.name} partition on device: {device.path}")

    begin = get_first_partition_offset(device, aligned)
    for part in device.partitions:
        begin += part.size
        if part.type == PartitionType.logical:
            begin += Size(1, Unit.MebiByte if not aligned else device.block_size)

    if part_type == PartitionType.logical:
        begin += Size(1, Unit.MebiByte if not aligned else device.block_size)

    end = (begin + part_size) if part_size != Size.zero() else '100%'

    cmd = f'parted --script {device.path} mkpart ' \
          f'{part_type.name} ' \
          f'{begin.get_value(unit)}{unit_to_string(unit)} ' \
          f'{end.get_value(unit)}{unit_to_string(unit)}'
    output = TestRun.executor.run(cmd)

    if output.exit_code != 0:
        TestRun.executor.run_expect_success("partprobe")

    TestRun.executor.run_expect_success("udevadm settle")
    if not check_partition_after_create(
            part_size,
            part_number,
            device.path,
            part_type,
            aligned):
        raise Exception("Could not create partition!")

    if part_type != PartitionType.extended:
        from storage_devices.partition import Partition
        new_part = Partition(device,
                             part_type,
                             part_number,
                             begin,
                             end if type(end) is Size else device.size)
        dd = Dd().input("/dev/zero") \
                 .output(new_part.path) \
                 .count(1) \
                 .block_size(Size(1, Unit.Blocks4096)) \
                 .oflag("direct")
        dd.run()
        device.partitions.append(new_part)

    TestRun.LOGGER.info(f"Successfully created {part_type.name} partition on {device.path}")
示例#4
0
def read_files_with_reclassification_check(cache, target_ioclass_id: int,
                                           source_ioclass_id: int,
                                           directory: Directory,
                                           with_delay: bool):
    start_time = datetime.now()
    target_occupancy_after = cache.get_io_class_statistics(
        io_class_id=target_ioclass_id).usage_stats.occupancy
    source_occupancy_after = cache.get_io_class_statistics(
        io_class_id=source_ioclass_id).usage_stats.occupancy
    files_to_reclassify = []
    target_ioclass_is_enabled = ioclass_is_enabled(cache, target_ioclass_id)

    for file in [item for item in directory.ls() if isinstance(item, File)]:
        target_occupancy_before = target_occupancy_after
        source_occupancy_before = source_occupancy_after
        time_from_start = datetime.now() - start_time
        dd = Dd().input(file.full_path).output("/dev/null").block_size(
            Size(1, Unit.Blocks4096))
        dd.run()
        target_occupancy_after = cache.get_io_class_statistics(
            io_class_id=target_ioclass_id).usage_stats.occupancy
        source_occupancy_after = cache.get_io_class_statistics(
            io_class_id=source_ioclass_id).usage_stats.occupancy

        if target_ioclass_is_enabled:
            if target_occupancy_after < target_occupancy_before:
                TestRun.LOGGER.error("Target IO class occupancy lowered!")
            elif target_occupancy_after - target_occupancy_before < file.size:
                files_to_reclassify.append(file)
                if with_delay and time_from_start <= ioclass_config.MAX_CLASSIFICATION_DELAY:
                    continue
                TestRun.LOGGER.error(
                    "Target IO class occupancy not changed properly!\n"
                    f"Expected: {file.size + target_occupancy_before}\n"
                    f"Actual: {target_occupancy_after}")
        elif target_occupancy_after > target_occupancy_before and with_delay:
            files_to_reclassify.append(file)

        if source_occupancy_after >= source_occupancy_before:
            if file not in files_to_reclassify:
                files_to_reclassify.append(file)
            if with_delay and time_from_start <= ioclass_config.MAX_CLASSIFICATION_DELAY:
                continue
            TestRun.LOGGER.error(
                "Source IO class occupancy not changed properly!\n"
                f"Before: {source_occupancy_before}\n"
                f"After: {source_occupancy_after}")

    if len(files_to_reclassify):
        TestRun.LOGGER.info("Rereading unclassified test files...")
        sync()
        drop_caches(DropCachesMode.ALL)
        for file in files_to_reclassify:
            (Dd().input(file.full_path).output("/dev/null").block_size(
                Size(1, Unit.Blocks4096)).run())
def copy_file(source, target, size, direct=None):
    dd = Dd() \
        .input(source) \
        .output(target) \
        .block_size(Size(1, Unit.Blocks4096)) \
        .count(int(size.get_value(Unit.Blocks4096)))

    if direct == "oflag":
        dd.oflag("direct")
    elif direct == "iflag":
        dd.iflag("direct")
    dd.run()
示例#6
0
def create_test_file():
    from test_utils.filesystem.file import File
    from test_tools.dd import Dd
    bs = Size(512, Unit.KibiByte)
    cnt = int(cache_size.value / bs.value)
    test_file = File.create_file(test_file_path)
    dd = Dd().output(test_file_path) \
        .input("/dev/zero") \
        .block_size(bs) \
        .count(cnt)
    dd.run()
    test_file.refresh_item()
    return test_file
示例#7
0
def create_random_test_file(target_file_path: str,
                            file_size: Size = Size(1, Unit.MebiByte),
                            random: bool = True):
    from test_utils.filesystem.file import File
    bs = Size(512, Unit.KibiByte)
    cnt = math.ceil(file_size.value / bs.value)
    file = File.create_file(target_file_path)
    dd = Dd().output(target_file_path) \
             .input("/dev/urandom" if random else "/dev/zero") \
             .block_size(bs) \
             .count(cnt) \
             .oflag("direct")
    dd.run()
    file.refresh_item()
    return file
def run_io_dir_read(path):
    dd = Dd().output("/dev/null").input(f"{path}")
    output = dd.run()
    if output.exit_code != 0:
        TestRun.fail(f"Failed to execute dd.\n {output.stdout}\n{output.stderr}")
    sync()
    drop_caches(DropCachesMode.ALL)
示例#9
0
def remove_partitions(device):
    if device.is_mounted():
        device.unmount()

    for partition in device.partitions:
        unmount(partition)

    TestProperties.LOGGER.info(f"Removing partitions from device: {device.system_path}.")
    dd = Dd().input("/dev/zero") \
        .output(device.system_path) \
        .count(1) \
        .block_size(Size(device.block_size.value, Unit.Byte))
    dd.run()
    output = TestProperties.executor.execute(f"ls {device.system_path}* -1")
    if len(output.stdout.split('\n')) > 1:
        TestProperties.LOGGER.error(f"Could not remove partitions from device {device.system_path}")
        return False
    return True
示例#10
0
def test_clean_stop_cache(cache_mode):
    """
        title: Test of the ability to stop cache in modes with lazy writes.
        description: |
          Test if OpenCAS stops cache in modes with lazy writes without data loss.
        pass_criteria:
          - Cache stopping works properly.
          - Writes to exported object and core device during OpenCAS's work are equal
          - Data on core device is correct after cache is stopped.
    """
    with TestRun.step("Prepare devices for cache and core."):
        cache_dev = TestRun.disks['cache']
        cache_dev.create_partitions([Size(256, Unit.MebiByte)])
        cache_part = cache_dev.partitions[0]
        core_dev = TestRun.disks['core']
        core_dev.create_partitions([Size(512, Unit.MebiByte)])
        core_part = core_dev.partitions[0]
        Udev.disable()

    with TestRun.step(f"Start cache in {cache_mode} mode."):
        cache = casadm.start_cache(cache_part, cache_mode)

    with TestRun.step("Add core to cache."):
        core = cache.add_core(core_part)

    with TestRun.step("Disable cleaning and sequential cutoff."):
        cache.set_cleaning_policy(CleaningPolicy.nop)
        cache.set_seq_cutoff_policy(SeqCutOffPolicy.never)

    with TestRun.step("Read IO stats before test"):
        core_disk_writes_initial = check_device_write_stats(core_part)
        exp_obj_writes_initial = check_device_write_stats(core)

    with TestRun.step("Write data to the exported object."):
        test_file_main = create_random_test_file("/tmp/test_file_main", Size(64, Unit.MebiByte))
        dd = Dd().output(core.system_path) \
            .input(test_file_main.full_path) \
            .block_size(bs) \
            .count(int(test_file_main.size / bs)) \
            .oflag("direct")
        dd.run()
        test_file_md5sum_main = test_file_main.md5sum()

    with TestRun.step("Read IO stats after write to the exported object."):
        core_disk_writes_increase = (
            check_device_write_stats(core_part) - core_disk_writes_initial
        )
        exp_obj_writes_increase = (
            check_device_write_stats(core) - exp_obj_writes_initial
        )

    with TestRun.step("Validate IO stats after write to the exported object."):
        if core_disk_writes_increase > 0:
            TestRun.LOGGER.error("Writes should occur only on the exported object.")
        if exp_obj_writes_increase != test_file_main.size.value:
            TestRun.LOGGER.error("Not all writes reached the exported object.")

    with TestRun.step("Read data from the exported object."):
        test_file_1 = File.create_file("/tmp/test_file_1")
        dd = Dd().output(test_file_1.full_path) \
            .input(core.system_path) \
            .block_size(bs) \
            .count(int(test_file_main.size / bs)) \
            .oflag("direct")
        dd.run()
        test_file_1.refresh_item()
        sync()

    with TestRun.step("Compare md5 sum of test files."):
        if test_file_md5sum_main != test_file_1.md5sum():
            TestRun.LOGGER.error("Md5 sums should be equal.")

    with TestRun.step("Read data from the core device."):
        test_file_2 = File.create_file("/tmp/test_file_2")
        dd = Dd().output(test_file_2.full_path) \
            .input(core_part.system_path) \
            .block_size(bs) \
            .count(int(test_file_main.size / bs)) \
            .oflag("direct")
        dd.run()
        test_file_2.refresh_item()
        sync()

    with TestRun.step("Compare md5 sum of test files."):
        if test_file_md5sum_main == test_file_2.md5sum():
            TestRun.LOGGER.error("Md5 sums should be different.")

    with TestRun.step("Read IO stats before stopping cache."):
        core_disk_writes_before_stop = check_device_write_stats(core_part)

    with TestRun.step("Stop cache."):
        cache.stop()

    with TestRun.step("Read IO stats after stopping cache."):
        core_disk_writes_increase = (
            check_device_write_stats(core_part) - core_disk_writes_before_stop
        )

    with TestRun.step("Validate IO stats after stopping cache."):
        if core_disk_writes_increase == 0:
            TestRun.LOGGER.error("Writes should occur on the core device after stopping cache.")
        if core_disk_writes_increase != exp_obj_writes_increase:
            TestRun.LOGGER.error("Write statistics for the core device should be equal "
                                 "to those from the exported object.")

    with TestRun.step("Read data from the core device."):
        test_file_3 = File.create_file("/tmp/test_file_2")
        dd = Dd().output(test_file_3.full_path) \
            .input(core_part.system_path) \
            .block_size(bs) \
            .count(int(test_file_main.size / bs)) \
            .oflag("direct")
        dd.run()
        test_file_3.refresh_item()
        sync()

    with TestRun.step("Compare md5 sum of test files."):
        if test_file_md5sum_main != test_file_3.md5sum():
            TestRun.LOGGER.error("Md5 sums should be equal.")

    with TestRun.step("Delete test files."):
        test_file_main.remove(True)
        test_file_1.remove(True)
        test_file_2.remove(True)
        test_file_3.remove(True)
示例#11
0
def test_clean_remove_core_with_fs(cache_mode, fs):
    """
        title: Test of the ability to remove core from cache in lazy-write modes with filesystem.
        description: |
          Test if OpenCAS removes core from cache in modes with lazy writes and with different
          filesystems without data loss.
        pass_criteria:
          - Core removing works properly.
          - Data on core device is correct after core is removed.
    """
    with TestRun.step("Prepare devices for cache and core."):
        cache_dev = TestRun.disks['cache']
        cache_dev.create_partitions([Size(256, Unit.MebiByte)])
        cache_part = cache_dev.partitions[0]
        core_dev = TestRun.disks['core']
        core_dev.create_partitions([Size(512, Unit.MebiByte)])
        core_part = core_dev.partitions[0]
        Udev.disable()

    with TestRun.step(f"Start cache in {cache_mode} mode."):
        cache = casadm.start_cache(cache_part, cache_mode)

    with TestRun.step(f"Add core with {fs.name} filesystem to cache and mount it."):
        core_part.create_filesystem(fs)
        core = cache.add_core(core_part)
        core.mount(mnt_point)

    with TestRun.step("Disable cleaning and sequential cutoff."):
        cache.set_cleaning_policy(CleaningPolicy.nop)
        cache.set_seq_cutoff_policy(SeqCutOffPolicy.never)

    with TestRun.step("Create test file and read its md5 sum."):
        test_file_main = create_random_test_file("/tmp/test_file_main", Size(64, Unit.MebiByte))
        test_file_md5sum_main = test_file_main.md5sum()

    with TestRun.step("Copy test file to the exported object."):
        test_file_1 = File.create_file(mnt_point + "test_file_1")
        dd = Dd().output(test_file_1.full_path) \
            .input(test_file_main.full_path) \
            .block_size(bs) \
            .count(int(test_file_main.size / bs)) \
            .oflag("direct")
        dd.run()
        test_file_1.refresh_item()
        sync()

    with TestRun.step("Compare md5 sum of test files."):
        if test_file_md5sum_main != test_file_1.md5sum():
            TestRun.LOGGER.error("Md5 sums should be equal.")

    with TestRun.step("Unmount and remove core."):
        core.unmount()
        core.remove_core()

    with TestRun.step("Mount core device."):
        core_part.mount(mnt_point)

    with TestRun.step("Read data from the core device."):
        test_file_2 = File.create_file("/tmp/test_file_2")
        dd = Dd().output(test_file_2.full_path) \
            .input(test_file_1.full_path) \
            .block_size(bs) \
            .count(int(test_file_1.size / bs)) \
            .oflag("direct")
        dd.run()
        test_file_2.refresh_item()
        sync()

    with TestRun.step("Compare md5 sum of test files."):
        if test_file_md5sum_main != test_file_2.md5sum():
            TestRun.LOGGER.error("Md5 sums should be equal.")

    with TestRun.step("Delete test files."):
        test_file_main.remove(True)
        test_file_1.remove(True)
        test_file_2.remove(True)

    with TestRun.step("Unmount core device."):
        core_part.unmount()
        remove(mnt_point, True, True, True)
示例#12
0
def run_io_dir_read(path):
    dd = Dd().output("/dev/null").input(f"{path}")
    dd.run()
    sync()
    drop_caches(DropCachesMode.ALL)
示例#13
0
 def padding(self, size: Size):
     dd = Dd().input("/dev/zero").output(self).count(1).block_size(size)
     dd.run()
     self.refresh_item()
def test_preserve_data_for_inactive_device():
    """
        title: Validate preserving data for inactive CAS devices.
        description: Validate that cached data for inactive CAS devices is preserved.
        pass_criteria:
          - No kernel error
          - File md5 checksums match in every iteration.
          - Cache read hits increase after reads (md5 checksum) from CAS device with attached core.
    """
    mount_dir = "/mnt/test"
    with TestRun.step("Prepare devices."):
        devices = prepare_devices([("cache", 1), ("core", 1)])
        cache_dev = devices["cache"].partitions[0]
        core_dev = devices["core"].partitions[0]
        plug_device = devices["core"]
    with TestRun.step("Start cache and add core."):
        cache = casadm.start_cache(cache_dev,
                                   cache_mode=CacheMode.WB,
                                   force=True)
        cache.set_seq_cutoff_policy(SeqCutOffPolicy.never)
        cache.set_cleaning_policy(CleaningPolicy.nop)
        core = cache.add_core(core_dev)
    with TestRun.step(
            "Create init config file using current CAS configuration."):
        InitConfig.create_init_config_from_running_configuration()
    with TestRun.step("Create filesystem on CAS device and mount it."):
        core.create_filesystem(Filesystem.ext3)
        core.mount(mount_dir)
    with TestRun.step(
            "Create a test file with random writes on mount point and count it's md5."
    ):
        file_path = f"{mount_dir}/test_file"
        test_file = File.create_file(file_path)
        dd = Dd().input("/dev/random") \
            .output(file_path) \
            .count(100) \
            .block_size(Size(1, Unit.Blocks512))
        dd.run()
        os_utils.sync()
        md5_after_create = test_file.md5sum()
        cache_stats_before_stop = cache.get_statistics()
        core_stats_before_stop = core.get_statistics()
    with TestRun.step("Unmount CAS device."):
        core.unmount()
    with TestRun.step("Stop cache without flushing dirty data."):
        cache.stop(no_data_flush=True)
    with TestRun.step("Unplug core device."):
        plug_device.unplug()
    with TestRun.step("Load cache."):
        cache = casadm.load_cache(cache_dev)
        cache_stats_after_load = cache.get_statistics()
        core_stats_after_load = core.get_statistics()
        if cache_stats_before_stop.usage_stats.clean != cache_stats_after_load.usage_stats.clean or\
                cache_stats_before_stop.usage_stats.dirty != \
                cache_stats_after_load.usage_stats.dirty or\
                core_stats_before_stop.usage_stats.clean != \
                core_stats_after_load.usage_stats.clean or\
                core_stats_before_stop.usage_stats.dirty != core_stats_after_load.usage_stats.dirty:
            TestRun.fail(
                f"Statistics after counting md5 are different than after cache load.\n"
                f"Cache stats before: {cache_stats_before_stop}\n"
                f"Cache stats after: {cache_stats_after_load}\n"
                f"Core stats before: {core_stats_before_stop}\n"
                f"Core stats after: {core_stats_after_load}")
    with TestRun.step(
            "Plug core disk using sysfs and verify this change is reflected "
            "on the cache list."):
        plug_device.plug()
        if cache.get_status() != CacheStatus.running or core.get_status(
        ) != CoreStatus.active:
            TestRun.fail(
                f"Expected cache status is running (actual - {cache.get_status()}).\n"
                f"Expected core status is active (actual - {core.get_status()})."
            )
    with TestRun.step("Mount CAS device"):
        core.mount(mount_dir)
    with TestRun.step(
            "Count md5 checksum for test file and compare it with previous value."
    ):
        cache_read_hits_before_md5 = cache.get_statistics(
        ).request_stats.read.hits
        md5_after_cache_load = test_file.md5sum()
        if md5_after_create != md5_after_cache_load:
            TestRun.fail(
                "Md5 checksum after cache load operation is different than before "
                "stopping cache.")
        else:
            TestRun.LOGGER.info(
                "Md5 checksum is identical before and after cache load operation "
                "with inactive CAS device.")
    with TestRun.step(
            "Verify that cache read hits increased after counting md5 checksum."
    ):
        cache_read_hits_after_md5 = cache.get_statistics(
        ).request_stats.read.hits
        if cache_read_hits_after_md5 - cache_read_hits_before_md5 < 0:
            TestRun.fail(
                f"Cache read hits did not increase after counting md5 checksum. "
                f"Before: {cache_read_hits_before_md5}. "
                f"After: {cache_read_hits_after_md5}.")
        else:
            TestRun.LOGGER.info("Cache read hits increased as expected.")
    with TestRun.step("Unmount CAS device and stop cache."):
        core.unmount()
        cache.stop()