Skip to content

Commit

Permalink
Repair LINSTOR tests to support latest driver version
Browse files Browse the repository at this point in the history
Signed-off-by: Ronan Abhamon <[email protected]>
  • Loading branch information
Wescoeur committed Jul 21, 2023
1 parent 317d2dc commit d77f70d
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 126 deletions.
12 changes: 5 additions & 7 deletions jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"paths": ["tests/quicktest"],
},
"storage-main": {
"description": "tests all storage drivers (except linstor), but avoids migrations and reboots",
"description": "tests all storage drivers, but avoids migrations and reboots",
"requirements": [
"A pool with at least 3 hosts.",
"An additional free disk on every host.",
Expand All @@ -70,10 +70,10 @@
},
"paths": ["tests/storage"],
"markers": "(small_vm or no_vm) and not reboot",
"name_filter": "not migration and not linstor and not test_fsp_sr.py",
"name_filter": "not migration and not test_fsp_sr.py",
},
"storage-migrations": {
"description": "tests migrations with all storage drivers (except linstor)",
"description": "tests migrations with all storage drivers",
"requirements": [
"A pool with at least 3 hosts.",
"An additional free disk on every host.",
Expand All @@ -88,10 +88,10 @@
},
"paths": ["tests/storage"],
"markers": "",
"name_filter": "migration and not linstor",
"name_filter": "migration",
},
"storage-reboots": {
"description": "storage driver tests that involve rebooting hosts (except linstor and flaky tests)",
"description": "storage driver tests that involve rebooting hosts (except flaky tests)",
"requirements": [
"A pool with at least 3 hosts, whose master host can be rebooted (best if reboots fast).",
"An additional free disk on every host.",
Expand All @@ -105,7 +105,6 @@
},
"paths": ["tests/storage"],
"markers": "reboot and not flaky",
"name_filter": "not linstor",
},
"sb-main": {
"description": "tests uefistored/varstored and SecureBoot using a small unix VM (or no VM when none needed)",
Expand Down Expand Up @@ -230,7 +229,6 @@
}

BROKEN_TESTS = [
"tests/storage/linstor", # needs updating and fixing
"tests/misc/test_update_host.py", # doesn't test anything currently unless the host is out of date
"tests/migration/test_host_evacuate.py::TestHostEvacuateWithNetwork", # not really broken but we'll handle it later
"tests/storage/fsp", # driver not present by default. Needs test setup to be improved.
Expand Down
147 changes: 51 additions & 96 deletions tests/storage/linstor/conftest.py
Original file line number Diff line number Diff line change
@@ -1,114 +1,70 @@
import logging
import pytest

from lib.common import wait_for_not
import lib.commands as commands

GROUP_NAME = 'linstor_group'
LINSTOR_PACKAGES = ['drbd', 'kmod-drbd', 'linstor-client', 'linstor-controller', 'linstor-satellite', 'python-linstor']
# explicit import for package-scope fixtures
from pkgfixtures import pool_with_saved_yum_state

# FIXME: make fixtures robust: clean behind if something fails in a setup or teardown
GROUP_NAME = 'linstor_group'
STORAGE_POOL_NAME = f'{GROUP_NAME}/thin_device'
LINSTOR_RELEASE_PACKAGE = 'xcp-ng-release-linstor'
LINSTOR_PACKAGE = 'xcp-ng-linstor'

@pytest.fixture(scope='package')
def lvm_disks(host):
disks = []
def lvm_disk(host, sr_disk_for_all_hosts):
device = '/dev/' + sr_disk_for_all_hosts
hosts = host.pool.hosts

for host in hosts:
local_disks = host.disks()
assert len(local_disks) > 1, "at least two disks are required"
disks.append('/dev/' + local_disks[1])

for i in range(len(hosts)):
hosts[i].ssh(['pvcreate', '-ff', '-y', disks[i]])
hosts[i].ssh(['vgcreate', GROUP_NAME, disks[i]])

yield disks

for i in range(len(hosts)):
hosts[i].ssh(['vgremove', GROUP_NAME])
hosts[i].ssh(['pvremove', disks[i]])

def check_linstor_packages(host):
if not host.check_packages_available(LINSTOR_PACKAGES):
raise Exception('Unable to find LINSTOR packages in the yum repositories of {}'.format(host))

@pytest.fixture(scope='package')
def hosts_with_linstor(host, additional_repos):
master = host
hosts = master.pool.hosts

for host in hosts:
check_linstor_packages(host)

# Configure master host.
master.yum_save_state()
master.yum_install(LINSTOR_PACKAGES)
master.ssh(['systemctl', 'restart', 'linstor-satellite'])
master.ssh(['systemctl', 'restart', 'linstor-controller'])

# Waiting for startup...
try:
wait_for_not(lambda: master.ssh_with_result(['linstor', 'node', 'list']).returncode)
except Exception as e:
master.yum_restore_saved_state()
raise e

# Configure slaves.
for host in hosts[1:]:
host.yum_save_state()
host.yum_install(LINSTOR_PACKAGES)
host.ssh(['systemctl', 'restart', 'linstor-satellite'])

yield hosts

for host in hosts:
host.yum_restore_saved_state()

def delete_linstor_nodes(hosts_with_linstor):
master = hosts_with_linstor[0]
master_ip = master.pool.host_ip(master.uuid)
control_arg = '--controllers=' + master_ip

for host in hosts_with_linstor:
try:
host.ssh(['linstor', control_arg, 'node', 'delete', '`uname -n`'])
except Exception:
logging.error('Failed to delete properly node on host {}'.format(host))
pass
host.ssh(['pvcreate', '-ff', '-y', device])
except commands.SSHCommandFailed as e:
if e.stdout.endswith('Mounted filesystem?'):
host.ssh(['vgremove', '-f', GROUP_NAME, '-y'])
host.ssh(['pvcreate', '-ff', '-y', device])
elif e.stdout.endswith('excluded by a filter.'):
host.ssh(['wipefs', '-a', device])
host.ssh(['pvcreate', '-ff', '-y', device])
else:
raise e

host.ssh(['vgcreate', GROUP_NAME, device])
host.ssh(['lvcreate', '-l', '100%FREE', '-T', STORAGE_POOL_NAME])

yield device

def create_linstor_sr(hosts_with_linstor):
master = hosts_with_linstor[0]
pool = master.pool
master_ip = pool.host_ip(master.uuid)
control_arg = '--controllers=' + master_ip

delete_linstor_nodes(hosts_with_linstor)

for host in hosts_with_linstor[1:]:
host_ip = pool.host_ip(host.uuid)
host.ssh(['linstor', control_arg, 'node', 'create', '`uname -n`', host_ip, '--node-type', 'Satellite'])
master.ssh(['linstor', 'node', 'create', '`uname -n`', master_ip, '--node-type', 'Combined'])

try:
return master.sr_create('linstor', 'LINSTOR-SR-test', {
'hosts': ','.join([host.hostname() for host in hosts_with_linstor]),
'group-name': GROUP_NAME,
'redundancy': len(hosts_with_linstor),
'provisioning': 'thick'
}, shared=True)
except Exception as e:
delete_linstor_nodes(hosts_with_linstor)
raise e
for host in hosts:
host.ssh(['vgremove', '-f', GROUP_NAME])
host.ssh(['pvremove', device])

def destroy_linstor_sr(hosts_with_linstor, sr):
sr.destroy(verify=True, force=True)
delete_linstor_nodes(hosts_with_linstor)
@pytest.fixture(scope='package')
def pool_with_linstor(hostA2, lvm_disk, pool_with_saved_yum_state):
pool = pool_with_saved_yum_state
for host in pool.hosts:
if host.is_package_installed(LINSTOR_PACKAGE):
raise Exception(
f'{LINSTOR_PACKAGE} is already installed on host {host}. This should not be the case.'
)

for host in pool.hosts:
host.yum_install([LINSTOR_RELEASE_PACKAGE])
host.yum_install([LINSTOR_PACKAGE])
# Needed because the linstor driver is not in the xapi sm-plugins list
# before installing the LINSTOR packages.
host.restart_toolstack(verify=True)

yield pool

@pytest.fixture(scope='package')
def linstor_sr(hosts_with_linstor, lvm_disks):
sr = create_linstor_sr(hosts_with_linstor)
def linstor_sr(pool_with_linstor):
sr = pool_with_linstor.master.sr_create('linstor', 'LINSTOR-SR-test', {
'group-name': STORAGE_POOL_NAME,
'redundancy': str(min(len(pool_with_linstor.hosts), 3)),
'provisioning': 'thin'
}, shared=True)
yield sr
destroy_linstor_sr(hosts_with_linstor, sr)
sr.destroy()

@pytest.fixture(scope='module')
def vdi_on_linstor_sr(linstor_sr):
Expand All @@ -120,6 +76,5 @@ def vdi_on_linstor_sr(linstor_sr):
def vm_on_linstor_sr(host, linstor_sr, vm_ref):
vm = host.import_vm(vm_ref, sr_uuid=linstor_sr.uuid)
yield vm
# teardown
logging.info("<< Destroy VM")
vm.destroy(verify=True)
49 changes: 29 additions & 20 deletions tests/storage/linstor/test_linstor_sr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,31 @@
import pytest
import time

from .conftest import GROUP_NAME, create_linstor_sr, destroy_linstor_sr
from .conftest import STORAGE_POOL_NAME, LINSTOR_PACKAGE
from lib.commands import SSHCommandFailed
from lib.common import wait_for, vm_image
from tests.storage import vdi_is_open

# Requirements:
# - one XCP-ng host >= 8.2 with an additional unused disk for the SR
# - access to XCP-ng RPM repository from the host
# - a repo with the LINSTOR RPMs must be given using the command line param `--additional-repos`

class TestLinstorSRCreateDestroy:
vm = None

def test_create_sr_without_linstor(self, hosts, lvm_disks):
master = hosts[0]
"""
Tests that do not use fixtures that setup the SR or import VMs,
because they precisely need to test SR creation and destruction,
and VM import.
"""

def test_create_sr_without_linstor(self, host, lvm_disk):
# This test must be the first in the series in this module
assert not master.binary_exists('linstor'), \
assert not host.is_package_installed('python-linstor'), \
"linstor must not be installed on the host at the beginning of the tests"
try:
sr = master.sr_create('linstor', 'LINSTOR-SR-test', {
'hosts': ','.join([host.hostname() for host in hosts]),
'group-name': GROUP_NAME,
'redundancy': len(hosts),
'provisioning': 'thick'
sr = host.sr_create('linstor', 'LINSTOR-SR-test', {
'group-name': STORAGE_POOL_NAME,
'redundancy': '1',
'provisioning': 'thin'
}, shared=True)
try:
sr.destroy()
Expand All @@ -36,15 +36,19 @@ def test_create_sr_without_linstor(self, hosts, lvm_disks):
except SSHCommandFailed as e:
logging.info("SR creation failed, as expected: {}".format(e))

def test_create_and_destroy_sr(self, hosts_with_linstor, lvm_disks):
def test_create_and_destroy_sr(self, pool_with_linstor):
# Create and destroy tested in the same test to leave the host as unchanged as possible
master = hosts_with_linstor[0]
sr = create_linstor_sr(hosts_with_linstor)
master = pool_with_linstor.master
sr = master.sr_create('linstor', 'LINSTOR-SR-test', {
'group-name': STORAGE_POOL_NAME,
'redundancy': '1',
'provisioning': 'thin'
}, shared=True)
# import a VM in order to detect vm import issues here rather than in the vm_on_linstor_sr fixture used in
# the next tests, because errors in fixtures break teardown
vm = master.import_vm(vm_image('mini-linux-x86_64-bios'), sr.uuid)
vm.destroy(verify=True)
destroy_linstor_sr(hosts_with_linstor, sr)
sr.destroy(verify=True)

@pytest.mark.usefixtures("linstor_sr")
class TestLinstorSR:
Expand Down Expand Up @@ -84,11 +88,10 @@ def test_reboot(self, vm_on_linstor_sr, host, linstor_sr):

@pytest.mark.reboot
def test_linstor_missing(self, linstor_sr, host):
packages = ['python-linstor', 'linstor-client']
sr = linstor_sr
linstor_installed = True
try:
host.yum_remove(packages)
host.yum_remove(['python-linstor', 'linstor-client'])
linstor_installed = False
try:
sr.scan()
Expand All @@ -100,12 +103,18 @@ def test_linstor_missing(self, linstor_sr, host):
time.sleep(10)
logging.info("Assert PBD not attached")
assert not sr.all_pbds_attached()
host.yum_install(packages)
host.yum_install(['xcp-ng-linstor'])
linstor_installed = True

# Needed because the linstor driver is not in the xapi
# sm-plugins list because xcp-ng-linstor RPM has been
# removed by the `yum remove ...` call.
host.restart_toolstack(verify=True)

sr.plug_pbds(verify=True)
sr.scan()
finally:
if not linstor_installed:
host.yum_install(packages)
host.yum_install([LINSTOR_PACKAGE])

# *** End of tests with reboots
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
# - A VM to import to the LINSTOR SR
# And:
# - access to XCP-ng RPM repository from hostA1
# - a repo with the LINSTOR RPMs must be given using the command line param `--additional-repos`

@pytest.mark.small_vm # run with a small VM to test the features
@pytest.mark.big_vm # and ideally on a big VM to test it scales
Expand Down
6 changes: 4 additions & 2 deletions tests/storage/linstor/test_linstor_sr_intrapool_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
# - A VM to import to the LINSTOR SR
# And:
# - access to XCP-ng RPM repository from hostA1
# - a repo with the LINSTOR RPMs must be given using the command line param `--additional-repos`

@pytest.mark.small_vm # run with a small VM to test the features
@pytest.mark.big_vm # and ideally on a big VM to test it scales
@pytest.mark.big_vm # and ideally with a big VM to test it scales
@pytest.mark.usefixtures("hostA2", "local_sr_on_hostA2")
class Test:
def test_live_intrapool_shared_migration(self, host, hostA2, vm_on_linstor_sr, linstor_sr):
live_storage_migration_then_come_back(vm_on_linstor_sr, host, linstor_sr, hostA2, linstor_sr)

def test_cold_intrapool_migration(self, host, hostA2, vm_on_linstor_sr, linstor_sr, local_sr_on_hostA2):
cold_migration_then_come_back(vm_on_linstor_sr, host, linstor_sr, hostA2, local_sr_on_hostA2)

Expand Down

0 comments on commit d77f70d

Please sign in to comment.