Skip to content
Open
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
10 changes: 10 additions & 0 deletions lib/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import itertools
import logging
import os
import random
import string
import sys
import time
import traceback
Expand Down Expand Up @@ -238,6 +240,14 @@ def url_download(url: str, filename: str) -> None:
fd.write(chunk)
os.rename(tempfilename, filename)

def randid(length=6):
"""
Generates a random string of a specified length.
The string consists of lowercase letters, uppercase letters, and digits.
"""
characters = string.ascii_lowercase + string.digits
return ''.join(random.choices(characters, k=length))

@overload
def _param_get(host: 'lib.host.Host', xe_prefix: str, uuid: str, param_name: str, key: Optional[str] = ...,
accept_unknown_key: Literal[False] = ...) -> str:
Expand Down
6 changes: 5 additions & 1 deletion lib/sr.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from lib.common import (
GiB,
prefix_object_name,
randid,
safe_split,
strtobool,
wait_for,
Expand Down Expand Up @@ -167,7 +168,10 @@ def get_type(self) -> str:
self._type = self.pool.master.xe("sr-param-get", {"uuid": self.uuid, "param-name": "type"})
return self._type

def create_vdi(self, name_label: str, virtual_size: int = 1 * GiB, image_format: Optional[str] = None) -> VDI:
def create_vdi(
self, name_label: str | None = None, virtual_size: int = 1 * GiB, image_format: Optional[str] = None
) -> VDI:
name_label = name_label or f'test-vdi-{randid()}'
logging.info("Create VDI %r on SR %s", name_label, self.uuid)
args = {
'name-label': prefix_object_name(name_label),
Expand Down
10 changes: 10 additions & 0 deletions lib/vm.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

import pytest

import logging
import os
import tempfile
Expand Down Expand Up @@ -345,6 +347,14 @@ def destroy_vdi(self, vdi_uuid: str) -> None:
super().destroy_vdi(vdi_uuid)
break

def destroy_vdi_by_name(self, name: str) -> None:
for vdi in self.vdis:
if vdi.name() == name:
self.vdis.remove(vdi)
super().destroy_vdi(vdi.uuid)
return
raise pytest.fail(f"No VDI named '{name}' in vm {self.uuid}")

def create_vdis_list(self) -> None:
""" Used to redo the VDIs list of the VM when reverting a snapshot. """
try:
Expand Down
83 changes: 72 additions & 11 deletions tests/storage/storage.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
from __future__ import annotations

import logging

from lib.commands import SSHCommandFailed
from lib.common import strtobool, wait_for, wait_for_not
from lib.common import GiB, strtobool, wait_for, wait_for_not
from lib.host import Host
from lib.sr import SR
from lib.vdi import VDI
from lib.vm import VM

from typing import TYPE_CHECKING, Literal

if TYPE_CHECKING:
from lib.host import Host
from lib.vm import VM
from typing import Literal

RANDSTREAM_1GIB_CHECKSUM = '65280014'

def try_to_create_sr_with_missing_device(sr_type, label, host):
try:
Expand All @@ -23,40 +24,100 @@ def try_to_create_sr_with_missing_device(sr_type, label, host):
return
assert False, 'SR creation should not have succeeded!'

def cold_migration_then_come_back(vm, prov_host, dest_host, dest_sr):
def cold_migration_then_come_back(vm: VM, prov_host: Host, dest_host: Host, dest_sr: SR):
""" Storage migration of a shutdown VM, then migrate it back. """
prov_sr = vm.get_sr()
vdi_name = None

if not vm.is_windows:
# the vdi will be destroyed with the vm
vdi = prov_sr.create_vdi(virtual_size=1 * GiB)
vdi_name = vdi.name()
vm.connect_vdi(vdi, 'xvdb')
vm.start()
vm.wait_for_vm_running_and_ssh_up()
install_randstream(vm)
logging.info("Generate /dev/xvdb content")
vm.ssh("randstream generate -v /dev/xvdb")
logging.info("Validate /dev/xvdb")
vm.ssh(f"randstream validate -v --expected-checksum {RANDSTREAM_1GIB_CHECKSUM} /dev/xvdb")
vm.shutdown(verify=True)

assert vm.is_halted()

# Move the VM to another host of the pool
vm.migrate(dest_host, dest_sr)
wait_for(lambda: vm.all_vdis_on_sr(dest_sr), "Wait for all VDIs on destination SR")

# Start VM to make sure it works
vm.start(on=dest_host.uuid)
vm.wait_for_os_booted()
if vm.is_windows:
vm.wait_for_os_booted()
else:
vm.wait_for_vm_running_and_ssh_up()
logging.info("Validate /dev/xvdb")
vm.ssh(f"randstream validate -v --expected-checksum {RANDSTREAM_1GIB_CHECKSUM} /dev/xvdb")
vm.shutdown(verify=True)

# Migrate it back to the provenance SR
vm.migrate(prov_host, prov_sr)
wait_for(lambda: vm.all_vdis_on_sr(prov_sr), "Wait for all VDIs back on provenance SR")

# Start VM to make sure it works
vm.start(on=prov_host.uuid)
vm.wait_for_os_booted()
if vm.is_windows:
vm.wait_for_os_booted()
else:
vm.wait_for_vm_running_and_ssh_up()
logging.info("Validate /dev/xvdb")
vm.ssh(f"randstream validate -v --expected-checksum {RANDSTREAM_1GIB_CHECKSUM} /dev/xvdb")
vm.shutdown(verify=True)

def live_storage_migration_then_come_back(vm, prov_host, dest_host, dest_sr):
if vdi_name is not None:
vm.destroy_vdi_by_name(vdi_name)

def live_storage_migration_then_come_back(vm: VM, prov_host: Host, dest_host: Host, dest_sr: SR):
prov_sr = vm.get_sr()
vdi_name = None

if not vm.is_windows:
vdi = prov_sr.create_vdi(virtual_size=1 * GiB)
vdi_name = vdi.name()
vm.connect_vdi(vdi, 'xvdb')

# start VM
vm.start(on=prov_host.uuid)
vm.wait_for_os_booted()
if vm.is_windows:
vm.wait_for_os_booted()
else:
vm.wait_for_vm_running_and_ssh_up()
install_randstream(vm)
logging.info("Generate /dev/xvdb content")
vm.ssh("randstream generate -v /dev/xvdb")
logging.info("Validate /dev/xvdb")
vm.ssh(f"randstream validate -v --expected-checksum {RANDSTREAM_1GIB_CHECKSUM} /dev/xvdb")

# Move the VM to another host of the pool
vm.migrate(dest_host, dest_sr)
wait_for(lambda: vm.all_vdis_on_sr(dest_sr), "Wait for all VDIs on destination SR")
wait_for(lambda: vm.is_running_on_host(dest_host), "Wait for VM to be running on destination host")
if not vm.is_windows:
logging.info("Validate /dev/xvdb")
vm.ssh(f"randstream validate -v --expected-checksum {RANDSTREAM_1GIB_CHECKSUM} /dev/xvdb")

# Migrate it back to the provenance SR
vm.migrate(prov_host, prov_sr)
wait_for(lambda: vm.all_vdis_on_sr(prov_sr), "Wait for all VDIs back on provenance SR")
wait_for(lambda: vm.is_running_on_host(prov_host), "Wait for VM to be running on provenance host")
if not vm.is_windows:
logging.info("Validate /dev/xvdb")
vm.ssh(f"randstream validate -v --expected-checksum {RANDSTREAM_1GIB_CHECKSUM} /dev/xvdb")

vm.shutdown(verify=True)

if vdi_name is not None:
vm.destroy_vdi_by_name(vdi_name)

def vdi_is_open(vdi):
sr = vdi.sr

Expand Down