Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
367 changes: 367 additions & 0 deletions test/functional/tests/upgrade_in_flight/test_cas_module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,367 @@
#
# Copyright(c) 2020 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause-Clear
#
import os
import pytest
from git import Repo
Comment thread
Ostrokrzew marked this conversation as resolved.

from api.cas import installer, git, upgrade_in_flight, version
from api.cas.cache_config import CacheMode
from api.cas.cas_module import CasModule
from api.cas.casadm import start_cache, stop_all_caches
from core.test_run import TestRun
from storage_devices.disk import DiskType, DiskTypeSet
from storage_devices.device import Device
from test_tools.dd import Dd
from test_tools.disk_utils import Filesystem
from test_tools.fs_utils import remove
from test_utils.os_utils import unload_kernel_module
from test_utils.output import CmdException
from test_utils.size import Size, Unit

cache_size = Size(1, Unit.GiB)
cache_modes_amount = len(set(list(CacheMode.__members__.values())))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

len(CacheMode) should be enough (it doesn't count DEFAULT as separate entry)

cores_per_cache = 64
core_size = Size(128, Unit.MiB)
number_of_cores_to_remove = cores_per_cache // 4

test_path = os.path.realpath(__file__)
repo = Repo(test_path, search_parent_directories=True)
cas_version_to_upgrade = version.get_upgradable_cas_versions(repo.commit())[0]


@pytest.mark.od_dependent
@pytest.mark.uninstall_cas()
@pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand]))
def test_module_usage_counter_without_cores():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For upgrade in flight tests we need a solution, that takes into account that a person who runs tests installs OpenCAS from release zip package and not from repo. After discussing the matter with Robert, we reached a conclusion, that following scenarios are possible:

  1. CAS installed from repo - test runs as is
  2. CAS installed from zip & path to different version directory provided in config - test uses current and provided sources to switch between CAS versions
  3. CAS installed from zip & no path in config - test is skipped with proper info
    Same goes for both tests here obviously.

"""
title: Validate OpenCAS module used by counter, no cores.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The title is quite ambiguous. Sounds like validating a module which is used by a counter. If 'module used by' is a name of a counter, then do what I just did - put it in ' '.

description: |
Validate OpenCAS kernel modules usage counter for cas_cache.ko and cas_disk.ko
after starting many cache instances (one for each cache mode) without adding cores.
pass_criteria:
- Cannot remove OpenCAS kernel modules when usage counter is not 0.
- OpenCAS increase and decrease cas_cache usage counter.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding/removing caches increases/decreases...

- OpenCAS usage counter is equal to amount of caches.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'number' instead of 'amount' ('amount' is for uncountable nouns)

"""
with TestRun.step("Get current OpenCAS version and install older one."):
installer.set_up_opencas()
original_commit = git.get_current_commit_hash(from_dut=True)

installer.uninstall_opencas()
installer.set_up_opencas(cas_version_to_upgrade)
Comment on lines +48 to +53

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redesign for universal repo/zip usage


with TestRun.step("Prepare cache devices."):
cache_dev = TestRun.disks['cache']
cache_dev.create_partitions([cache_size] * cache_modes_amount)

with TestRun.step("Start caches."):
caches = []
cache_modes = get_all_cache_modes()
for i, mode in enumerate(cache_modes):
caches.append(start_cache(cache_dev.partitions[i], mode))

with TestRun.step("Check module usage counters for cas_cache and cas_disk."):
module_usage_before_upgrade = check_counters()
cas_disk_usage_before_upgrade = module_usage_before_upgrade.get(CasModule.disk.value)
cas_cache_usage_before_upgrade = module_usage_before_upgrade.get(CasModule.cache.value)

if cas_disk_usage_before_upgrade != 1:
TestRun.LOGGER.error(
f"Module usage counter should show only 1 use of {CasModule.disk.value}."
)

if cas_cache_usage_before_upgrade != cache_modes_amount:
TestRun.LOGGER.error(
f"Module usage counter should show {cache_modes_amount} "
f"uses of {CasModule.cache.value}."
)

with TestRun.step("Upgrade in flight OpenCAS and check reference counters."):
installer._clean_opencas_repo()
git.checkout_cas_version(original_commit)
try:
upgrade_in_flight.upgrade_start()
except CmdException:
restore_pretest_state(original_commit)
TestRun.fail("Upgrade failed!")
Comment on lines +82 to +88

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redesign


module_usage_after_upgrade = check_counters()
cas_disk_usage_after_upgrade = module_usage_after_upgrade.get(CasModule.disk.value)
cas_cache_usage_after_upgrade = module_usage_after_upgrade.get(CasModule.cache.value)

if cas_disk_usage_after_upgrade != cas_disk_usage_before_upgrade:
TestRun.LOGGER.error(
f"Module usage counter of {CasModule.disk.value} after upgrade "
f"should equal to this before upgrade."
)

if cas_cache_usage_after_upgrade != cas_cache_usage_before_upgrade:
TestRun.LOGGER.error(
f"Module usage counter of {CasModule.cache.value} after upgrade "
f"should equal to this before upgrade."
)

with TestRun.step("Try to remove cas_cache and cas_disk modules."):
try:
unload_kernel_module(CasModule.cache.value)
unload_kernel_module(CasModule.disk.value)
Comment on lines +108 to +109

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be in separate try blocks - this way you're testing only one of the modules

except CmdException as exc:
TestRun.LOGGER.info(f"Cannot remove OpenCAS kernel modules as expected.\n{exc}")

with TestRun.step("Stop all caches and check module usage counters."):
stop_all_caches()
module_usage_after_stop = check_counters()
cas_disk_usage_after_stop = module_usage_after_stop.get(CasModule.disk.value)
cas_cache_usage_after_stop = module_usage_after_stop.get(CasModule.cache.value)

if cas_disk_usage_after_stop != cas_disk_usage_after_upgrade:
TestRun.LOGGER.error(
f"Module usage counter of {CasModule.disk.value} after stop "
f"should equal to this before upgrade."
)

if cas_cache_usage_after_stop == cas_cache_usage_after_upgrade:
TestRun.LOGGER.error(
f"Module usage counter of {CasModule.cache.value} after stop "
f"should differ from this after upgrade."
)

with TestRun.step("Try to remove cas_disk module."):
try:
unload_kernel_module(CasModule.disk.value)
except CmdException as exc:
TestRun.LOGGER.info(f"Cannot remove {CasModule.disk.value} module as expected.\n{exc}")

with TestRun.step("Try to remove cas_cache module and start OpenCAS."):
try:
unload_kernel_module(CasModule.cache.value)
start_cache(cache_dev.partitions[0], load=True)
Comment on lines +139 to +140

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you expecting the unload to succeed?

except CmdException as exc:
TestRun.LOGGER.info(f"Cannot start OpenCAS as expected.\n{exc}")

with TestRun.step("Try to remove cas_disk module."):
try:
unload_kernel_module(CasModule.disk.value)
except CmdException as exc:
TestRun.LOGGER.error(f"Cannot remove {CasModule.disk.value} module.\n{exc}")

with TestRun.step("Reinstall original OpenCAS version."):
restore_pretest_state(original_commit)


@pytest.mark.od_dependent
@pytest.mark.uninstall_cas()
@pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand]))
def test_module_usage_counter_with_cores():
"""
title: Validate OpenCAS module used by counter.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above

description: |
Validate OpenCAS kernel modules usage counter for cas_cache.ko and cas_disk.ko
after starting many cache instances (one for each cache mode) with many cores.
pass_criteria:
- Cannot remove OpenCAS kernel modules when usage counter is not 0.
- OpenCAS increase and decrease cas_cache usage counter.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above

- OpenCAS usage counter is equal to sum of cores and caches.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to the number

"""
with TestRun.step("Get current OpenCAS version and install older one."):
installer.set_up_opencas()
original_commit = git.get_current_commit_hash(from_dut=True)

installer.uninstall_opencas()
installer.set_up_opencas(cas_version_to_upgrade)
Comment on lines +169 to +173

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above


with TestRun.step("Prepare cache devices."):
cache_dev = TestRun.disks['cache']
cache_dev.create_partitions([Size(48, Unit.GiB)] + [cache_size] * cache_modes_amount)

with TestRun.step("Create filesystem on the 1st partition of cache device and mount it."):
cache_dev.partitions[0].create_filesystem(Filesystem.xfs)
cache_dev.partitions[0].mount("/mnt/images")

with TestRun.step(f"Create {cache_modes_amount * cores_per_cache} image files."):
for i in range(cache_modes_amount * cores_per_cache):
(Dd()
.output(f"/mnt/images/data{i:0>3}")
.input("/dev/zero")
.block_size(Size(8, Unit.MiB))
.count(16)
.oflag("direct")
).run()

with TestRun.step("Create loop device on created images."):
loop_devices = []
for i in range(cache_modes_amount * cores_per_cache):
TestRun.executor.run_expect_success(
f"losetup /dev/loop{i} /mnt/images/data{i:0>3}"
)
loop_devices.append(Device(f"/dev/loop{i}"))

with TestRun.step("Start caches, one for each cache mode."):
caches = []
cache_modes = get_all_cache_modes()
for i, mode in enumerate(cache_modes):
caches.append(start_cache(cache_dev.partitions[i + 1], mode, force=True))

with TestRun.step(f"Add {cores_per_cache} cores to each cache."):
cores_on_cache = {}
cores_offset = 0
for cache in caches:
cores = []
cores_on_cache[cache.cache_id] = cores
for i in range(cores_per_cache):
cores.append(cache.add_core(loop_devices[cores_offset + i]))
cores_offset += cores_per_cache

with TestRun.step("Check module usage counters for cas_cache and cas_disk."):
module_usage_before_upgrade = check_counters()
cas_disk_usage_before_upgrade = module_usage_before_upgrade.get(CasModule.disk.value)
cas_cache_usage_before_upgrade = module_usage_before_upgrade.get(CasModule.cache.value)

if cas_disk_usage_before_upgrade != 1:
TestRun.LOGGER.error(
f"Module usage counter of {CasModule.disk.value} mismatch!\n"
f"Expected: 1\n"
f"Actual: {cas_cache_usage_before_upgrade}"
)

expected_usage_before_upgrade = cache_modes_amount + (cache_modes_amount * cores_per_cache)
if cas_cache_usage_before_upgrade != expected_usage_before_upgrade:
TestRun.LOGGER.error(
f"Module usage counter of {CasModule.cache.value} mismatch!\n"
f"Expected: {expected_usage_before_upgrade}\n"
f"Actual: {cas_cache_usage_before_upgrade}"
)

with TestRun.step("Upgrade in flight OpenCAS and check reference counters."):
installer._clean_opencas_repo()
git.checkout_cas_version(original_commit)
try:
upgrade_in_flight.upgrade_start()
except CmdException:
restore_pretest_state(original_commit)
TestRun.fail("Upgrade failed!")
Comment on lines +238 to +244

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above


module_usage_after_upgrade = check_counters()
cas_disk_usage_after_upgrade = module_usage_after_upgrade.get(CasModule.disk.value)
cas_cache_usage_after_upgrade = module_usage_after_upgrade.get(CasModule.cache.value)

if cas_disk_usage_after_upgrade != cas_disk_usage_before_upgrade:
TestRun.LOGGER.error(
f"Module usage counter of {CasModule.disk.value} mismatch!\n"
f"Expected: {cas_disk_usage_before_upgrade}\n"
f"Actual: {cas_disk_usage_after_upgrade}"
)

if cas_cache_usage_after_upgrade != cas_cache_usage_before_upgrade:
TestRun.LOGGER.error(
f"Module usage counter of {CasModule.cache.value} mismatch!\n"
f"Expected: {cas_cache_usage_before_upgrade}\n"
f"Actual: {cas_cache_usage_after_upgrade}"
)

with TestRun.step("Try to remove cas_cache and cas_disk modules."):
try:
unload_kernel_module(CasModule.cache.value)
unload_kernel_module(CasModule.disk.value)
Comment on lines +266 to +267

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above

except CmdException as exc:
TestRun.LOGGER.info(f"Cannot remove OpenCAS kernel modules as expected.\n{exc}")

with TestRun.step(
f"Remove {number_of_cores_to_remove} cores from each cache "
f"and check module usage counters."
):
for cache in caches:
for core in cores_on_cache.get(cache.cache_id)[:number_of_cores_to_remove]:
cache.remove_core(core.core_id)

module_usage_after_remove = check_counters()
cas_disk_usage_after_remove = module_usage_after_remove.get(CasModule.disk.value)
cas_cache_usage_after_remove = module_usage_after_remove.get(CasModule.cache.value)

if cas_disk_usage_after_remove != cas_disk_usage_after_upgrade:
TestRun.LOGGER.error(
f"Module usage counter of {CasModule.disk.value} mismatch!\n"
f"Expected: {cas_disk_usage_after_upgrade}\n"
f"Actual: {cas_disk_usage_after_remove}"
)

expected_usage_after_remove = (
expected_usage_before_upgrade - (cache_modes_amount * number_of_cores_to_remove)
)
if cas_cache_usage_after_remove != expected_usage_after_remove:
TestRun.LOGGER.error(
f"Module usage counter of {CasModule.cache.value} mismatch!\n"
f"Expected: {expected_usage_after_remove}\n"
f"Actual: {cas_cache_usage_after_remove}"
)

with TestRun.step("Stop all caches and check module usage counters."):
stop_all_caches()
module_usage_after_stop = check_counters()
cas_disk_usage_after_stop = module_usage_after_stop.get(CasModule.disk.value)
cas_cache_usage_after_stop = module_usage_after_stop.get(CasModule.cache.value)

if cas_disk_usage_after_stop != cas_disk_usage_after_remove:
TestRun.LOGGER.error(
f"Module usage counter of {CasModule.disk.value} mismatch!\n"
f"Expected: {cas_disk_usage_after_remove}\n"
f"Actual: {cas_disk_usage_after_stop}"
)

if cas_cache_usage_after_stop == cas_cache_usage_after_remove:
TestRun.LOGGER.error(
f"Module usage counter of {CasModule.cache.value} mismatch!\n"
f"Expected: other than {cas_cache_usage_after_remove}\n"
f"Actual: {cas_cache_usage_after_stop}"
)

with TestRun.step("Try to remove cas_disk module."):
try:
unload_kernel_module(CasModule.disk.value)
except CmdException as exc:
TestRun.LOGGER.info(f"Cannot remove {CasModule.disk.value} module as expected.\n{exc}")

with TestRun.step("Try to remove cas_cache module and start OpenCAS."):
try:
unload_kernel_module(CasModule.cache.value)
start_cache(cache_dev.partitions[0], force=True)
Comment on lines +328 to +329

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above

except CmdException as exc:
TestRun.LOGGER.info(f"Cannot start OpenCAS as expected.\n{exc}")

with TestRun.step("Try to remove cas_disk module."):
try:
unload_kernel_module(CasModule.disk.value)
except CmdException as exc:
TestRun.LOGGER.error(f"Cannot remove {CasModule.disk.value} module.\n{exc}")

with TestRun.step("Reinstall original OpenCAS version."):
restore_pretest_state(original_commit)


def check_counters():
module_counter = {}

output = TestRun.executor.run_expect_success(
f"lsmod | grep -e ^{CasModule.cache.value} -e ^{CasModule.disk.value}"
)
output = output.stdout.splitlines()
for line in output:
module_counter[line.split()[0]] = int(line.split()[2])

return module_counter


def get_all_cache_modes():
modes_list = []
for mode in CacheMode:
modes_list.append(mode)
return modes_list
Comment on lines +357 to +360

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return [mode for mode in CacheModes]



def restore_pretest_state(commit):
TestRun.executor.run_expect_success("losetup -D")
remove("/mnt/images", True, True, True)
installer.uninstall_opencas()
installer.set_up_opencas(commit)