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

More tests for zfs-ng SMAPIv3 driver #214

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
21 changes: 19 additions & 2 deletions lib/vdi.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
import logging

class VDI:
def __init__(self, sr, uuid):
def __init__(self, sr, uuid, snapshot_of=None):
self.uuid = uuid
self.snapshot_of = snapshot_of
# TODO: use a different approach when migration is possible
self.sr = sr

def resize(self, size):
return self.sr.pool.master.xe('vdi-resize', {'uuid': self.uuid,
'disk-size': str(size)})

def snapshot(self):
logging.info(f"Create snapshot of {self}")
return VDI(self.sr,
self.sr.pool.master.xe('vdi-snapshot', {'uuid': self.uuid}),
snapshot_of=self)

def clone(self):
logging.info(f"Create clone of {self}")
return VDI(self.sr,
self.sr.pool.master.xe('vdi-clone', {'uuid': self.uuid}))

def destroy(self):
logging.info("Destroy %s", self)
self.sr.pool.master.xe('vdi-destroy', {'uuid': self.uuid})

def __str__(self):
return f"VDI {self.uuid} on SR {self.sr.uuid}"
return (f"VDI {self.uuid} on SR {self.sr.uuid}"
f"{f' (snapshot of {self.snapshot_of})' if self.snapshot_of else ''}")
252 changes: 244 additions & 8 deletions tests/storage/zfsvol/test_zfsvol_sr.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,48 @@ class TestZfsvolSRCreateDestroy:
"""

def test_create_and_destroy_sr(self, host, sr_disk_wiped):
# Create and destroy tested in the same test to leave the host as unchanged as possible
sr = host.sr_create('zfs-vol', "ZFS-local-SR-test", {'device': '/dev/' + sr_disk_wiped}, verify=True)
# import a VM in order to detect vm import issues here rather than in the vm_on_xfs_fixture used in
# the next tests, because errors in fixtures break teardown
vm = host.import_vm(vm_image('mini-linux-x86_64-bios'), sr_uuid=sr.uuid)
vm.destroy(verify=True)
sr.destroy(verify=True)
# Create and destroy tested in the same test to leave the host
# as unchanged as possible
sr = host.sr_create('zfs-vol', "ZFS-local-SR-test",
{'device': '/dev/' + sr_disk_wiped}, verify=True)
try:
# import a VM in order to detect vm import issues here
# rather than in the vm_on_xfs_fixture used in the next
# tests, because errors in fixtures break teardown
vm = host.import_vm(vm_image('mini-linux-x86_64-bios'), sr_uuid=sr.uuid)
vm.destroy(verify=True)
finally:
sr.destroy(verify=True)

@pytest.mark.usefixtures("zfsvol_sr")
class TestZfsvolVm:
class TestZfsvolSrBasics:
def test_vdi_resize(self, vdi_on_zfsvol_sr):
logging.info("Resize up")
vdi_on_zfsvol_sr.resize(1024 * 1024)
logging.info("Attempt to resize down")
try:
vdi_on_zfsvol_sr.resize(64 * 1024)
except Exception as e:
if "shrinking not allowed" in str(e):
# properly refused
pass
else:
logging.error("unexpected error on downsize attempt: %s", e)
raise

@pytest.mark.xfail # needs support for cloning non-snapshots
def test_vdi_clone(self, vdi_on_zfsvol_sr):
clone = vdi_on_zfsvol_sr.clone()
clone.destroy()

def test_vdi_snap_clone(self, vdi_on_zfsvol_sr):
snap = vdi_on_zfsvol_sr.snapshot()
clone = snap.clone()
clone.destroy()
snap.destroy()

@pytest.mark.usefixtures("zfsvol_sr")
class TestZfsvolVm:
@pytest.mark.xfail
@pytest.mark.quicktest
def test_quicktest(self, zfsvol_sr):
Expand All @@ -56,6 +87,74 @@ def test_snapshot(self, vm_on_zfsvol_sr):
finally:
vm.shutdown(verify=True)

@pytest.mark.small_vm
@pytest.mark.big_vm
def test_snapshots_revert(self, vm_on_zfsvol_sr):
vm = vm_on_zfsvol_sr
vm.start()
vm.wait_for_os_booted()
vm.wait_for_vm_running_and_ssh_up()

snap1, snap2, snap3 = None, None, None
snap1 = vm.snapshot()
vm.ssh_touch_file(f"/{snap1.uuid}")
snap2 = vm.snapshot()
vm.ssh_touch_file(f"/{snap2.uuid}")
snap3 = vm.snapshot()

# we are in "snap3" state, check all 6 "from A to B"
# combinations
snap1.revert()
vm.start()
vm.wait_for_vm_running_and_ssh_up()
logging.info("Check files state")
vm.ssh([f"test ! -f /{snap1.uuid}"])
vm.ssh([f"test ! -f /{snap2.uuid}"])
snap2.revert()
vm.start()
vm.wait_for_vm_running_and_ssh_up()
logging.info("Check files state")
vm.ssh([f"test -f /{snap1.uuid}"])
vm.ssh([f"test ! -f /{snap2.uuid}"])
snap3.revert()
vm.start()
vm.wait_for_vm_running_and_ssh_up()
logging.info("Check files state")
vm.ssh([f"test -f /{snap1.uuid}"])
vm.ssh([f"test -f /{snap2.uuid}"])
snap2.revert()
vm.start()
vm.wait_for_vm_running_and_ssh_up()
logging.info("Check files state")
vm.ssh([f"test -f /{snap1.uuid}"])
vm.ssh([f"test ! -f /{snap2.uuid}"])
snap1.revert()
vm.start()
vm.wait_for_vm_running_and_ssh_up()
logging.info("Check files state")
vm.ssh([f"test ! -f /{snap1.uuid}"])
vm.ssh([f"test ! -f /{snap2.uuid}"])
snap3.revert()
vm.start()
vm.wait_for_vm_running_and_ssh_up()
logging.info("Check files state")
vm.ssh([f"test -f /{snap1.uuid}"])
vm.ssh([f"test -f /{snap2.uuid}"])

# FIXME: we don't support snapshot destruction yet
# snap1.destroy(verify=True)
# snap2.destroy(verify=True)
# snap3.destroy(verify=True)

def get_messages(self, name):
args = {
'obj-uuid': self.uuid,
'name': name,
'params': 'uuid',
}

lines = self.host.xe('message-list', args).splitlines()

# *** tests with reboots (longer tests).

@pytest.mark.reboot
Expand All @@ -71,3 +170,140 @@ def test_reboot(self, vm_on_zfsvol_sr, host, zfsvol_sr):
vm.shutdown(verify=True)

# *** End of tests with reboots

@pytest.mark.usefixtures("zfsvol_sr")
class TestZfsngSrSingleVdiDestroy:
"Destruction tests of a single VDI involved in various topologies"
def test_vdi_destroy_with_snap_but_no_clones(self, zfsvol_sr):
vdi = zfsvol_sr.create_vdi('ZFS-local-VDI-test')
snap = vdi.snapshot()
vdi.destroy()

def test_vdi_destroy_with_several_snaps_but_no_clones(self, zfsvol_sr):
vdi = zfsvol_sr.create_vdi('ZFS-local-VDI-test')
snaps = []
for i in range(3):
snaps.append(vdi.snapshot())
vdi.destroy()

def test_vdi_destroy_with_snap_and_clone(self, zfsvol_sr):
vdi = zfsvol_sr.create_vdi('ZFS-local-VDI-test')
snap = vdi.snapshot()
clone = snap.clone()
vdi.destroy()

def test_vdi_destroy_with_snap_and_several_clones(self, zfsvol_sr):
vdi = zfsvol_sr.create_vdi('ZFS-local-VDI-test')
snap = vdi.snapshot()
clones = []
for i in range(3):
clones.append(snap.clone())
vdi.destroy()

# FIXME below should be independent from SR type and label

def create_vdi_and_snaps_chain(sr, vdi_label):
"Create a chain of alternating VDI snapshots and clones on first host."
vdis = [sr.create_vdi(vdi_label)]
for i in range(2):
vdis.append(vdis[-1].snapshot())
vdis.append(vdis[-1].clone())
return vdis

def create_vdi_chain(sr, vdi_label):
"Create a chain of alternating VDI snapshots and clones on first host."
vdis = [sr.create_vdi(vdi_label)]
for i in range(2):
vdis.append(vdis[-1].clone())
return vdis

def teardown_vdi_chain(sr, vdis, order):
"Destroy a list of VDIs in order specified by a sequence of VDIs indices."
for i in order:
vdi = vdis[i]
logging.debug("zfs state: %r", sr.main_host().ssh(
"zfs list -Hp -t all -o name,origin".split()))
try:
vdi.destroy()
except Exception:
logging.error("failed to destroy %s", vdi)
raise

@pytest.mark.usefixtures("zfsvol_sr")
class TestZfsvolSrVdiChainSnapDestroy:
"VDI chain destruction tests with alternating snap/clone"
def test_vdi_and_snaps_teardown(self, zfsvol_sr):
"Destroy snapshot chain in reverse order of creation"
vdis = create_vdi_and_snaps_chain(zfsvol_sr, 'ZFS-local-VDI-test')
assert len(vdis) == 5
for (i, is_snap) in enumerate([False, True, False, True, False]):
assert (vdis[i].snapshot_of is not None) == is_snap, \
f"vdis[{i}] should {'' if is_snap else 'not '}be a snapshot"
teardown_vdi_chain(zfsvol_sr, vdis, (4, 3, 2, 1, 0))

def test_vdi_and_snaps_destroy_first_vdi(self, zfsvol_sr):
"Destroy first-created VDI, then the rest in reverse order of creation"
vdis = create_vdi_and_snaps_chain(zfsvol_sr, 'ZFS-local-VDI-test')
teardown_vdi_chain(zfsvol_sr, vdis, (0, 4, 3, 2, 1))

@pytest.mark.xfail # needs GC of unused extra non-snapshots
def test_vdi_and_snaps_destroy_intermediate_vdi(self, zfsvol_sr):
"Destroy second-created VDI, then the rest in reverse order of creation"
vdis = create_vdi_and_snaps_chain(zfsvol_sr, 'ZFS-local-VDI-test')
teardown_vdi_chain(zfsvol_sr, vdis, (2, 4, 3, 1, 0))

# orderings expected to work on first proto

def test_vdi_and_snaps_destroy_01432(self, zfsvol_sr):
vdis = create_vdi_and_snaps_chain(zfsvol_sr, 'ZFS-local-VDI-test')
teardown_vdi_chain(zfsvol_sr, vdis, (0, 1, 4, 3, 2))

def test_vdi_and_snaps_destroy_01234(self, zfsvol_sr):
vdis = create_vdi_and_snaps_chain(zfsvol_sr, 'ZFS-local-VDI-test')
teardown_vdi_chain(zfsvol_sr, vdis, (0, 1, 2, 3, 4))

def test_vdi_and_snaps_destroy_23410(self, zfsvol_sr):
vdis = create_vdi_and_snaps_chain(zfsvol_sr, 'ZFS-local-VDI-test')
teardown_vdi_chain(zfsvol_sr, vdis, (2, 3, 4, 1, 0))

def test_vdi_and_snaps_destroy_23014(self, zfsvol_sr):
vdis = create_vdi_and_snaps_chain(zfsvol_sr, 'ZFS-local-VDI-test')
teardown_vdi_chain(zfsvol_sr, vdis, (2, 3, 0, 1, 4))

# other topologies

def test_destroy_vdi_with_snap_with_multiple_clones(self, zfsvol_sr):
base_vdi = zfsvol_sr.create_vdi('ZFS-local-VDI-test')
snap = base_vdi.snapshot()
clones = [snap.clone(), snap.clone()]

base_vdi.destroy()

@pytest.mark.xfail
@pytest.mark.usefixtures("zfsvol_sr")
class TestZfsvolSrVdiChainDestroy:
"VDI chain destruction tests with just clones and no snaps"
def test_destroy_210(self, zfsvol_sr):
vdis = create_vdi_chain(zfsvol_sr, 'ZFS-local-VDI-test')
assert len(vdis) == 3
teardown_vdi_chain(zfsvol_sr, vdis, (2, 1, 0))

def test_destroy_201(self, zfsvol_sr):
vdis = create_vdi_chain(zfsvol_sr, 'ZFS-local-VDI-test')
teardown_vdi_chain(zfsvol_sr, vdis, (2, 0, 1))

def test_destroy_012(self, zfsvol_sr):
vdis = create_vdi_chain(zfsvol_sr, 'ZFS-local-VDI-test')
teardown_vdi_chain(zfsvol_sr, vdis, (0, 1, 2))

def test_destroy_021(self, zfsvol_sr):
vdis = create_vdi_chain(zfsvol_sr, 'ZFS-local-VDI-test')
teardown_vdi_chain(zfsvol_sr, vdis, (0, 2, 1))

def test_destroy_102(self, zfsvol_sr):
vdis = create_vdi_chain(zfsvol_sr, 'ZFS-local-VDI-test')
teardown_vdi_chain(zfsvol_sr, vdis, (1, 0, 2))

def test_destroy_120(self, zfsvol_sr):
vdis = create_vdi_chain(zfsvol_sr, 'ZFS-local-VDI-test')
teardown_vdi_chain(zfsvol_sr, vdis, (1, 2, 0))
Loading