Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VM hot plugging and unplugging #11149

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 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
21 changes: 21 additions & 0 deletions ocs_ci/helpers/cnv_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
)
from ocs_ci.framework import config
from ocs_ci.utility.retry import retry
from ocs_ci.utility.utils import run_cmd

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -365,3 +366,23 @@ def run_dd_io(vm_obj, file_path, size="10240", username=None, verify=False):
file_path=file_path,
username=username,
)


def verifyvolume(vm_obj, volume_name):
"""
Verify a volume in VM.

Args:
vm_obj (str): vm obj
volume_name (str): Name of the volume to verify
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
volume_name (str): Name of the volume to verify
volume_name (str): Name of the volume (PVC) to verify

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


Returns:
str: stdout of command
Copy link
Contributor

Choose a reason for hiding this comment

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

return is bool

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


"""
cmd = f"oc get vm {vm_obj.name} -o=jsonpath='{{.spec.volumes}}'"
output = run_cmd(cmd=cmd)
Copy link
Contributor

Choose a reason for hiding this comment

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

you can replace it with vm_obj.get()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated

if volume_name in output:
f"PVC {volume_name} is visible inside the VM {vm_obj.name}"
return True
return False
8 changes: 6 additions & 2 deletions ocs_ci/ocs/cnv/virtual_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,11 +432,12 @@ def stop(self, force=False, wait=True):
self.wait_for_vm_status(status=constants.CNV_VM_STOPPED)
logger.info(f"VM: {self._vm_name} reached Stopped state")

def restart(self, wait=True):
def restart(self, wait=True, verify=True):
"""
Restart the VirtualMachine.

Args:
verify(bool): True to wait for VM ssh up after restart
wait (bool): True to wait for the VirtualMachine to reach the "Running" status.

"""
Expand All @@ -448,8 +449,11 @@ def restart(self, wait=True):
logger.info(
f"VM: {self._vm_name} reached Running state state after restart operation"
)
if verify:
self.verify_vm(verify_ssh=True)
logger.info(f"VM: {self._vm_name} ssh working successfully!")

def addvolme(self, volume_name, persist=True, serial=None):
def addvolume(self, volume_name, persist=True, serial=None):
"""
Add a volume to a VM

Expand Down
123 changes: 123 additions & 0 deletions tests/functional/workloads/cnv/test_vm_hotplug_unplug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import logging
import pytest

from ocs_ci.framework.pytest_customization.marks import magenta_squad, workloads
from ocs_ci.framework.testlib import E2ETest
from ocs_ci.helpers.cnv_helpers import cal_md5sum_vm, run_dd_io, verifyvolume
from ocs_ci.helpers.helpers import create_pvc
from ocs_ci.ocs import constants

log = logging.getLogger(__name__)


@magenta_squad
@workloads
@pytest.mark.polarion_id("OCS-")
Copy link
Contributor

Choose a reason for hiding this comment

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

polarion id

class TestVmHotPlugUnplug(E2ETest):
"""
Test case for VM hot plugging and unplugging of PVC disks.
"""

def test_vm_hot_plugging_unplugging(
self, project_factory, multi_cnv_workload, setup_cnv
):
"""
Verify that hotplugging and hot unplugging of a PVC to/from a VM works

Steps:
1. Hotplug disk to the running VM based on PVC.
2. Verify the disk is attached to VM
3. Add data to disk
a. Identify newly attached disk.
b. Create file or do dd on new disk
4. Reboot the VM,
5. After reboot check if disk is still attached.
6. Make sure newly added data on new vm disk is intact
7. Unplug(Dettach) the disk from vm
8. Verify disk is successfully detached using console or cli
9. login into VM and confirm disk is no longer listed.
10 Repeat the above tests for DVT based VM
"""

Choose a reason for hiding this comment

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

Please consider making this as common function(s) so it can be used by other tests

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As per today's discussion, we'll be updating addvolume as enhancement
https://github.com/red-hat-storage/ocs-ci/pull/11149/files#r1923196525

# Create project and get VM details
proj_obj = project_factory()
file_paths = ["/file.txt", "/new_file.txt"]
vm_objs_def, vm_objs_aggr, _, _ = multi_cnv_workload(
namespace=proj_obj.namespace
)
vm_list = vm_objs_def + vm_objs_aggr

log.info(f"Total VMs to process: {len(vm_list)}")
for index, vm_obj in enumerate(vm_list):
# Create a new PVC for hotplug
pvc_obj = create_pvc(
sc_name=constants.DEFAULT_CNV_CEPH_RBD_SC,
namespace=vm_obj.namespace,
size="20Gi",
access_mode=constants.ACCESS_MODE_RWX,
volume_mode=constants.VOLUME_MODE_BLOCK,
)
log.info(f"PVC {pvc_obj.name} created successfully")

# List disks before attaching the new volume
before_disks = vm_obj.run_ssh_cmd(
command="lsblk -o NAME,SIZE,MOUNTPOINT -P"
)
log.info(f"Disks before hotplug:\n{before_disks}")

# Hotplug the PVC to the VM
vm_obj.addvolume(volume_name=pvc_obj.name)
Copy link
Contributor

Choose a reason for hiding this comment

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

can we add multiple hot disks?

verifyvolume(vm_obj, volume_name=pvc_obj.name)
Copy link
Contributor

Choose a reason for hiding this comment

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

assert here as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

log.info(f"Hotplugged PVC {pvc_obj.name} to VM {vm_obj.name}")

# List disks after attaching the new volume
after_disks = vm_obj.run_ssh_cmd("lsblk -o NAME,SIZE,MOUNTPOINT -P")
log.info(f"Disks after hotplug:\n{after_disks}")

# Identify the newly attached disk
new_disks = set(after_disks) - set(before_disks)
log.info(f"Newly attached disks: {set(new_disks)}")

# Perform I/O operation on the new disk
log.info(
f"Running I/O operation on the newly attached disk in VM {vm_obj.name}"
)
Copy link
Contributor

Choose a reason for hiding this comment

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

from the log message, it looks like you are running IO to the newly attached disk. How are you making sure that the created file indeed goes to the new disk?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated it

source_csum = run_dd_io(vm_obj=vm_obj, file_path=file_paths[0], verify=True)

# Reboot the VM
log.info(f"Rebooting VM {vm_obj.name}")
vm_obj.restart(wait=True, verify=True)

# Verify that the disk is still attached
verifyvolume(vm_obj, volume_name=pvc_obj.name)
Copy link
Contributor

Choose a reason for hiding this comment

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

assert here if verification is not successfull

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


# Verify data persistence by checking MD5 checksum
new_csum = cal_md5sum_vm(vm_obj=vm_obj, file_path=file_paths[0])
assert (
source_csum == new_csum
), f"MD5 mismatch after reboot for VM {vm_obj.name}"

# Unplug the disk
vm_obj.removevolume(volume_name=pvc_obj.name)

# Verify the disk is detached
after_hotplug_rm_disks = vm_obj.run_ssh_cmd(
"lsblk -o NAME,SIZE,MOUNTPOINT -P"
)
log.info(f"Disks after unplugging:\n{after_hotplug_rm_disks}")

# Ensure the hotplugged disk was removed successfully
assert set(after_hotplug_rm_disks) == set(
before_disks
), f"Failed to unplug disk from VM {vm_obj.name}"

# Confirm disk removal
if not verifyvolume(vm_obj, volume_name=pvc_obj.name):
Copy link
Contributor

Choose a reason for hiding this comment

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

assert here as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

log.info(
f"Volume {pvc_obj.name} unplugged successfully from VM {vm_obj.name}"
)
run_dd_io(vm_obj=vm_obj, file_path=file_paths[1])
else:
pytest.fail(
Copy link
Contributor

Choose a reason for hiding this comment

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

can be part of assert message

f"Volume {pvc_obj.name} is still attached to VM {vm_obj.name}"
)
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ def test_vm_single_disk_hot_plugging_unplugging(self, cnv_workload, setup_cnv):
access_mode=constants.ACCESS_MODE_RWX,
volume_mode=constants.VOLUME_MODE_BLOCK,
)
vm_obj.addvolme(volume_name=pvc_obj.name)
vm_obj.addvolume(volume_name=pvc_obj.name)
Copy link
Contributor

Choose a reason for hiding this comment

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

since this test is covered with the new test in this PR, the old test can be depreciated

vm_obj.removevolume(volume_name=pvc_obj.name)
Loading