Skip to content

Commit 90acbcb

Browse files
committed
Create tests for vdi_revert on file based SRs
Signed-off-by: Antoine Bartuccio <antoine.bartuccio@vates.tech>
1 parent c791234 commit 90acbcb

11 files changed

Lines changed: 480 additions & 1 deletion

File tree

lib/vdi.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,17 @@ def wait_for_coalesce(self, fn: Callable[[], R] | None = None) -> R | None:
124124
wait_for(lambda: self.get_parent() != previous_parent, msg="Waiting for coalesce", timeout_secs=10 * 60)
125125
logging.info("Coalesce done")
126126
return ret
127+
128+
def enable_cbt(self) -> None:
129+
logging.info(f"Enabling CBT on VDI {self.uuid}")
130+
self.sr.pool.master.xe('vdi-enable-cbt', {'uuid': self.uuid})
131+
132+
def disable_cbt(self) -> None:
133+
logging.info(f"Disabling CBT on VDI {self.uuid}")
134+
self.sr.pool.master.xe('vdi-disable-cbt', {'uuid': self.uuid})
135+
136+
def get_cbt_enabled(self) -> str:
137+
return self.param_get('cbt-enabled')
138+
139+
def is_cbt_enabled(self) -> bool:
140+
return self.get_cbt_enabled() == 'true'

lib/vm.py

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,252 @@ def test_snapshot_on_running_vm(self) -> None:
549549
finally:
550550
snapshot.destroy(verify=True)
551551

552+
def test_vdi_revert(self) -> None:
553+
# Successives reverts to ensure the
554+
# snapshot tree stays consistent
555+
# Created snapshot Tree
556+
# snap 1 -> snap 2
557+
# |-----> snap 3
558+
# Revert order: 1 -> 2 -> 3 -> 1 -> 1
559+
vm = self.clone()
560+
snapshots = []
561+
if not vm.is_running():
562+
vm.start()
563+
vm.wait_for_vm_running_and_ssh_up()
564+
try:
565+
snap_1 = vm.snapshot()
566+
snapshots.append(snap_1)
567+
568+
snap_2_file = f"/root/{uuid.uuid4()}"
569+
vm.ssh_touch_file(snap_2_file)
570+
snap_2 = vm.snapshot()
571+
snapshots.append(snap_2)
572+
573+
snap_1.revert()
574+
vm.start()
575+
vm.wait_for_vm_running_and_ssh_up()
576+
vm.ssh(f'test ! -f {snap_2_file}')
577+
578+
snap_3_file = f"/root/{uuid.uuid4()}"
579+
vm.ssh_touch_file(snap_3_file)
580+
snap_3 = vm.snapshot()
581+
snapshots.append(snap_3)
582+
583+
snap_2.revert()
584+
vm.start()
585+
vm.wait_for_vm_running_and_ssh_up()
586+
vm.ssh(f'test ! -f {snap_3_file}')
587+
vm.ssh(f'test -f {snap_2_file}')
588+
589+
snap_3.revert()
590+
vm.start()
591+
vm.wait_for_vm_running_and_ssh_up()
592+
vm.ssh(f'test ! -f {snap_2_file}')
593+
vm.ssh(f'test -f {snap_3_file}')
594+
595+
snap_1.revert()
596+
vm.start()
597+
vm.wait_for_vm_running_and_ssh_up()
598+
vm.ssh(f'test ! -f {snap_2_file}')
599+
vm.ssh(f'test ! -f {snap_3_file}')
600+
601+
tmp_file = f"/root/{uuid.uuid4()}"
602+
vm.ssh_touch_file(tmp_file)
603+
snap_1.revert()
604+
vm.start()
605+
vm.wait_for_vm_running_and_ssh_up()
606+
vm.ssh(f'test ! -f {snap_2_file}')
607+
vm.ssh(f'test ! -f {snap_3_file}')
608+
vm.ssh(f'test ! -f {tmp_file}')
609+
610+
finally:
611+
for snap in snapshots:
612+
snap.destroy(verify=True)
613+
vm.destroy()
614+
615+
def test_vdi_revert_cbt(self):
616+
snapshots = []
617+
vm = self.clone()
618+
sr = vm.get_sr()
619+
620+
if not vm.is_running():
621+
vm.start()
622+
vm.wait_for_vm_running_and_ssh_up()
623+
snap_no_cbt_file = f"/root/{uuid.uuid4()}"
624+
vm.ssh_touch_file(snap_no_cbt_file)
625+
snap_no_cbt = vm.snapshot()
626+
snapshots.append(snap_no_cbt)
627+
628+
try:
629+
vm.vdis[0].enable_cbt()
630+
assert len(vm.vdis) == 1
631+
snap_cbt_file = f"/root/{uuid.uuid4()}"
632+
vm.ssh_touch_file(snap_cbt_file)
633+
snap_cbt = vm.snapshot()
634+
snapshots.append(snap_cbt)
635+
636+
before_revert_file = f"/root/{uuid.uuid4()}"
637+
vm.ssh_touch_file(before_revert_file)
638+
639+
# CBT -> CBT
640+
snap_cbt.revert()
641+
vm.start()
642+
vm.wait_for_vm_running_and_ssh_up()
643+
vm.ssh(f'test ! -f {before_revert_file}')
644+
vm.ssh(f'test -f {snap_no_cbt_file}')
645+
vm.ssh(f'test -f {snap_cbt_file}')
646+
assert vm.vdis[0].is_cbt_enabled()
647+
assert VDI(snap_cbt.vdi_uuids()[0], sr=sr).is_cbt_enabled()
648+
assert not VDI(snap_no_cbt.vdi_uuids()[0], sr=sr).is_cbt_enabled()
649+
650+
# CBT -> no CBT
651+
snap_no_cbt.revert()
652+
vm.start()
653+
vm.wait_for_vm_running_and_ssh_up()
654+
vm.ssh(f'test ! -f {before_revert_file}')
655+
vm.ssh(f'test -f {snap_no_cbt_file}')
656+
vm.ssh(f'test ! -f {snap_cbt_file}')
657+
assert not vm.vdis[0].is_cbt_enabled()
658+
assert VDI(snap_cbt.vdi_uuids()[0], sr=sr).is_cbt_enabled()
659+
assert not VDI(snap_no_cbt.vdi_uuids()[0], sr=sr).is_cbt_enabled()
660+
661+
# no CBT -> CBT
662+
snap_cbt.revert()
663+
vm.start()
664+
vm.wait_for_vm_running_and_ssh_up()
665+
vm.ssh(f'test ! -f {before_revert_file}')
666+
vm.ssh(f'test -f {snap_no_cbt_file}')
667+
vm.ssh(f'test -f {snap_cbt_file}')
668+
assert vm.vdis[0].is_cbt_enabled()
669+
assert VDI(snap_cbt.vdi_uuids()[0], sr=sr).is_cbt_enabled()
670+
assert not VDI(snap_no_cbt.vdi_uuids()[0], sr=sr).is_cbt_enabled()
671+
672+
finally:
673+
for snap in snapshots:
674+
snap.destroy(verify=True)
675+
vm.destroy()
676+
677+
def test_vdi_revert_journal_cbt(self, request: pytest.FixtureRequest, fistpoint: str, host: Host | None = None):
678+
from lib.fistpoint import FistPoint # noqa: I001 Avoid circular import
679+
host_uuid = host.uuid if host else None
680+
681+
request.getfixturevalue("exit_on_fistpoint")
682+
vm = self.clone()
683+
sr = vm.get_sr()
684+
685+
snapshots = []
686+
if not vm.is_running():
687+
vm.start(host_uuid)
688+
vm.wait_for_vm_running_and_ssh_up()
689+
690+
snap_no_cbt_file = f"/root/{uuid.uuid4()}"
691+
vm.ssh_touch_file(snap_no_cbt_file)
692+
snap_no_cbt = vm.snapshot()
693+
snapshots.append(snap_no_cbt)
694+
695+
vm.vdis[0].enable_cbt()
696+
snap_cbt_file = f"/root/{uuid.uuid4()}"
697+
vm.ssh_touch_file(snap_cbt_file)
698+
snap_cbt = vm.snapshot()
699+
snapshots.append(snap_cbt)
700+
701+
before_revert_file = f"/root/{uuid.uuid4()}"
702+
vm.ssh_touch_file(before_revert_file)
703+
try:
704+
# CBT -> CBT
705+
with FistPoint(vm.host, fistpoint), pytest.raises(commands.SSHCommandFailed):
706+
snap_cbt.revert()
707+
vm.start(host_uuid)
708+
vm.wait_for_vm_running_and_ssh_up()
709+
vm.ssh(f'test -f {before_revert_file}')
710+
vm.ssh(f'test -f {snap_no_cbt_file}')
711+
vm.ssh(f'test -f {snap_cbt_file}')
712+
assert vm.vdis[0].is_cbt_enabled()
713+
assert VDI(snap_cbt.vdi_uuids()[0], sr=sr).is_cbt_enabled()
714+
assert not VDI(snap_no_cbt.vdi_uuids()[0], sr=sr).is_cbt_enabled()
715+
716+
# CBT -> no CBT
717+
with FistPoint(vm.host, fistpoint), pytest.raises(commands.SSHCommandFailed):
718+
snap_no_cbt.revert()
719+
vm.start(host_uuid)
720+
vm.wait_for_vm_running_and_ssh_up()
721+
vm.ssh(f'test -f {before_revert_file}')
722+
vm.ssh(f'test -f {snap_no_cbt_file}')
723+
vm.ssh(f'test -f {snap_cbt_file}')
724+
assert vm.vdis[0].is_cbt_enabled()
725+
assert VDI(snap_cbt.vdi_uuids()[0], sr=sr).is_cbt_enabled()
726+
assert not VDI(snap_no_cbt.vdi_uuids()[0], sr=sr).is_cbt_enabled()
727+
728+
# no CBT -> CBT
729+
snap_no_cbt.revert()
730+
with FistPoint(vm.host, fistpoint), pytest.raises(commands.SSHCommandFailed):
731+
snap_cbt.revert()
732+
vm.start(host_uuid)
733+
vm.wait_for_vm_running_and_ssh_up()
734+
vm.ssh(f'test ! -f {before_revert_file}')
735+
vm.ssh(f'test -f {snap_no_cbt_file}')
736+
vm.ssh(f'test ! -f {snap_cbt_file}')
737+
assert not vm.vdis[0].is_cbt_enabled()
738+
assert VDI(snap_cbt.vdi_uuids()[0], sr=sr).is_cbt_enabled()
739+
assert not VDI(snap_no_cbt.vdi_uuids()[0], sr=sr).is_cbt_enabled()
740+
741+
finally:
742+
for snap in snapshots:
743+
snap.destroy(verify=True)
744+
vm.destroy()
745+
746+
def test_vdi_revert_journal(self, request: pytest.FixtureRequest, fistpoint: str, host: Host | None = None):
747+
from lib.fistpoint import FistPoint # noqa: I001 Avoid circular import
748+
request.getfixturevalue("exit_on_fistpoint")
749+
vm = self.clone()
750+
snap = vm.snapshot()
751+
host_uuid = host.uuid if host else None
752+
if not vm.is_running():
753+
vm.start(host_uuid)
754+
vm.wait_for_vm_running_and_ssh_up()
755+
try:
756+
file = f"/root/{uuid.uuid4()}"
757+
vm.ssh_touch_file(file)
758+
759+
with FistPoint(host if host else vm.host, fistpoint), pytest.raises(commands.SSHCommandFailed):
760+
snap.revert()
761+
762+
vm.start(host_uuid)
763+
vm.wait_for_vm_running_and_ssh_up()
764+
vm.ssh(f'test -f {file}')
765+
766+
snap.revert()
767+
vm.start(host_uuid)
768+
vm.wait_for_vm_running_and_ssh_up()
769+
vm.ssh(f'test ! -f {file}')
770+
finally:
771+
snap.destroy(verify=True)
772+
vm.destroy()
773+
774+
def test_critical_journal_revert(self, request: pytest.FixtureRequest, host: Host, fistpoint: str):
775+
from lib.fistpoint import FistPoint # noqa: I001 Avoid circular import
776+
vm = self.clone()
777+
sr = vm.get_sr()
778+
request.getfixturevalue("exit_on_fistpoint")
779+
snap = vm.snapshot()
780+
sr.param_set("other-config", "false", "auto-scan") # Avoid journals being run during tests unexpectedly
781+
try:
782+
with FistPoint(vm.host, fistpoint), pytest.raises(commands.SSHCommandFailed):
783+
snap.revert()
784+
785+
with pytest.raises(
786+
commands.SSHCommandFailed,
787+
check=lambda e: (
788+
"The SR is not available [opterr=Critical journals are pending. A scan is required.]" in e.stdout
789+
),
790+
):
791+
vm.start(on=host.uuid)
792+
finally:
793+
sr.scan() # Force journals to be processed
794+
sr.param_remove("other-config", "auto-scan")
795+
snap.destroy(verify=True)
796+
vm.destroy()
797+
552798
def get_messages(self, name: str) -> List[str]:
553799
args: dict[str, str | bool | dict[str, str]] = {
554800
'obj-uuid': self.uuid,

tests/storage/cephfs/test_cephfs_sr.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,29 @@ def test_snapshot(self, vm_on_cephfs_sr: VM) -> None:
4545
finally:
4646
vm.shutdown(verify=True)
4747

48+
@pytest.mark.small_vm
49+
@pytest.mark.big_vm
50+
def test_revert(self, vm_on_cephfs_sr: VM) -> None:
51+
vm_on_cephfs_sr.test_vdi_revert()
52+
53+
@pytest.mark.small_vm
54+
@pytest.mark.big_vm
55+
@pytest.mark.parametrize(
56+
"fistpoint",
57+
[
58+
"FileSR_revert_create_insert",
59+
"FileSR_revert_create_src",
60+
"FileSR_revert_create_dest",
61+
]
62+
)
63+
def test_revert_journal(self, vm_on_cephfs_sr: VM, request: pytest.FixtureRequest, fistpoint: str):
64+
vm_on_cephfs_sr.test_vdi_revert_journal(request, fistpoint, vm_on_cephfs_sr.host.pool.master)
65+
66+
@pytest.mark.small_vm
67+
@pytest.mark.big_vm
68+
def test_critical_journal_revert(self, vm_on_cephfs_sr: VM, request: pytest.FixtureRequest, hostA2: Host) -> None:
69+
vm_on_cephfs_sr.test_critical_journal_revert(request, hostA2, "FileSR_revert_create_src")
70+
4871
# *** tests with reboots (longer tests).
4972

5073
@pytest.mark.reboot

tests/storage/ext/test_ext_sr.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,34 @@ def test_snapshot(self, vm_on_ext_sr: VM) -> None:
6262
finally:
6363
vm.shutdown(verify=True)
6464

65+
@pytest.mark.small_vm
66+
@pytest.mark.big_vm
67+
def test_revert(self, vm_on_ext_sr: VM) -> None:
68+
vm_on_ext_sr.test_vdi_revert()
69+
70+
@pytest.mark.small_vm
71+
@pytest.mark.big_vm
72+
def test_revert_cbt(self, vm_on_ext_sr: VM) -> None:
73+
vm_on_ext_sr.test_vdi_revert_cbt()
74+
75+
@pytest.mark.small_vm
76+
@pytest.mark.big_vm
77+
def test_revert_journal_cbt(self, vm_on_ext_sr: VM, request: pytest.FixtureRequest):
78+
vm_on_ext_sr.test_vdi_revert_journal_cbt(request, "FileSR_revert_create_src")
79+
80+
@pytest.mark.small_vm
81+
@pytest.mark.big_vm
82+
@pytest.mark.parametrize(
83+
"fistpoint",
84+
[
85+
"FileSR_revert_create_insert",
86+
"FileSR_revert_create_src",
87+
"FileSR_revert_create_dest",
88+
]
89+
)
90+
def test_revert_journal(self, vm_on_ext_sr: VM, request: pytest.FixtureRequest, fistpoint: str):
91+
vm_on_ext_sr.test_vdi_revert_journal(request, fistpoint)
92+
6593
@pytest.mark.small_vm
6694
@pytest.mark.parametrize("vdi_op", ["snapshot", "clone"])
6795
def test_coalesce(self, storage_test_vm: VM, vdi_on_ext_sr: VDI, vdi_op: CoalesceOperation, defer: Defer) -> None:

tests/storage/glusterfs/test_glusterfs_sr.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,34 @@ def test_volume_stopped(self, host: Host, glusterfs_sr: SR) -> None:
6161
if not volume_running:
6262
host.ssh('gluster --mode=script volume start vol0')
6363

64+
@pytest.mark.small_vm
65+
@pytest.mark.big_vm
66+
def test_revert(self, vm_on_glusterfs_sr: VM) -> None:
67+
vm_on_glusterfs_sr.test_vdi_revert()
68+
69+
@pytest.mark.small_vm
70+
@pytest.mark.big_vm
71+
@pytest.mark.parametrize(
72+
"fistpoint",
73+
[
74+
"FileSR_revert_create_insert",
75+
"FileSR_revert_create_src",
76+
"FileSR_revert_create_dest",
77+
]
78+
)
79+
def test_revert_journal(self, vm_on_glusterfs_sr: VM, request: pytest.FixtureRequest, fistpoint: str):
80+
vm_on_glusterfs_sr.test_vdi_revert_journal(request, fistpoint, vm_on_glusterfs_sr.host.pool.master)
81+
82+
@pytest.mark.small_vm
83+
@pytest.mark.big_vm
84+
def test_critical_journal_revert(
85+
self,
86+
vm_on_glusterfs_sr: VM,
87+
request: pytest.FixtureRequest,
88+
hostA2: Host,
89+
) -> None:
90+
vm_on_glusterfs_sr.test_critical_journal_revert(request, hostA2, "FileSR_revert_create_src")
91+
6492
# *** tests with reboots (longer tests).
6593

6694
@pytest.mark.reboot

0 commit comments

Comments
 (0)