1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00

fix(storages): a new NFS pool starts when its mount point does not exist

create_storage_netfs started the pool without a build, so a netfs pool
whose target directory was missing failed to mount ("mount point ... does
not exist"): the page showed the error and the pool stayed defined and
inactive. It now starts with VIR_STORAGE_POOL_CREATE_WITH_BUILD, as the
dir and logical pools do, which makes the mount point.

The Vagrant computes export /srv/wvcnfs to 127.0.0.1, and the live pool
test creates an NFS pool on it at a missing mount point when
TEST_LIBVIRT_NFS_EXPORT is set.
This commit is contained in:
catborise 2026-10-19 11:57:13 +03:00
parent f13a90c047
commit baeb023da2
4 changed files with 40 additions and 19 deletions

View file

@ -703,19 +703,20 @@ export TEST_LIBVIRT_LOGIN=root TEST_LIBVIRT_PASSWORD= # login/password for TCP
export TEST_LIBVIRT_GUEST_IMAGE=/var/lib/libvirt/images/linux.qcow2 # optional, see below
export TEST_LIBVIRT_LVM_DEVICE=/dev/vdb # optional: an empty disk of 4 GiB or more on the host, wiped by the LVM tests
export TEST_LIBVIRT_ISCSI_TARGET=iqn.2026-10.test.wvc:lun # optional: a target on the host's 127.0.0.1, open to any initiator, with a LUN
export TEST_LIBVIRT_NFS_EXPORT=/srv/wvcnfs # optional: a directory the host exports to its 127.0.0.1 over NFS
python manage.py test
```
`TEST_LIBVIRT_GUEST_IMAGE` enables the tests that need a guest OS (disk and NIC hot-unplug, vCPU hotplug, guest agent, ACPI power off). It must be an installed, BIOS-bootable Linux qcow2 image with qemu-guest-agent, in a storage pool of the host other than `wvc-test`; the tests boot copies of it from overlays and only read the image. Shut down any VM using it first.
Two disposable compute nodes for these tests come from the `Vagrantfile`: AlmaLinux 10 with nested KVM, set up by `dev/libvirt-bootstrap.sh` (with this checkout's gstfsd), a SASL user for TCP (`wvc`, password `wvc-test`) and your `~/.ssh/id_ed25519.pub` for root; migration runs between them, and each has an empty second disk (`/dev/vdb`) for the LVM tests and serves a 1 GiB iSCSI LUN on 127.0.0.1 for the iSCSI test. They accept TLS logins (SASL) with certificates from a throwaway CA that `vagrant up` makes in `.vagrant/tls`; the TLS run takes its client certificate from there through `HOME`. It needs Vagrant with the `vagrant-libvirt` plugin, a KVM host with `qemu-kvm` and `cyrus-sasl-md5`, and a user in the `libvirt` group. On a host that also runs Docker, let the VMs' network (the bridge of `virsh net-info vagrant-libvirt`, `virbr1` here) through Docker's forward rules (`sudo iptables -I DOCKER-USER -i virbr1 -j ACCEPT` and `sudo iptables -I DOCKER-USER -o virbr1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT`).
Two disposable compute nodes for these tests come from the `Vagrantfile`: AlmaLinux 10 with nested KVM, set up by `dev/libvirt-bootstrap.sh` (with this checkout's gstfsd), a SASL user for TCP (`wvc`, password `wvc-test`) and your `~/.ssh/id_ed25519.pub` for root; migration runs between them, and each has an empty second disk (`/dev/vdb`) for the LVM tests and serves a 1 GiB iSCSI LUN on 127.0.0.1 for the iSCSI test and an NFS export (`/srv/wvcnfs`) to 127.0.0.1 for the NFS pool test. They accept TLS logins (SASL) with certificates from a throwaway CA that `vagrant up` makes in `.vagrant/tls`; the TLS run takes its client certificate from there through `HOME`. It needs Vagrant with the `vagrant-libvirt` plugin, a KVM host with `qemu-kvm` and `cyrus-sasl-md5`, and a user in the `libvirt` group. On a host that also runs Docker, let the VMs' network (the bridge of `virsh net-info vagrant-libvirt`, `virbr1` here) through Docker's forward rules (`sudo iptables -I DOCKER-USER -i virbr1 -j ACCEPT` and `sudo iptables -I DOCKER-USER -o virbr1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT`).
```bash
vagrant up --provider=libvirt
C1=$(vagrant ssh compute1 -c "hostname -I" | awk '{print $1}') C2=$(vagrant ssh compute2 -c "hostname -I" | awk '{print $1}')
for h in $C1 $C2; do ssh-keygen -R $h; ssh -o StrictHostKeyChecking=accept-new root@$h true; done # new VMs, new host keys
export TEST_LIBVIRT_HOST=$C1 TEST_LIBVIRT_TYPE=1 TEST_LIBVIRT_LOGIN=wvc TEST_LIBVIRT_PASSWORD=wvc-test
export TEST_LIBVIRT_SSH_HOST=$C2 TEST_LIBVIRT_SSH_LOGIN=root TEST_LIBVIRT_MIGRATE_ADDRESS=$C2 TEST_LIBVIRT_LVM_DEVICE=/dev/vdb TEST_LIBVIRT_ISCSI_TARGET=iqn.2026-10.test.wvc:lun
export TEST_LIBVIRT_SSH_HOST=$C2 TEST_LIBVIRT_SSH_LOGIN=root TEST_LIBVIRT_MIGRATE_ADDRESS=$C2 TEST_LIBVIRT_LVM_DEVICE=/dev/vdb TEST_LIBVIRT_ISCSI_TARGET=iqn.2026-10.test.wvc:lun TEST_LIBVIRT_NFS_EXPORT=/srv/wvcnfs
python manage.py test
HOME=$PWD/.vagrant/tls TEST_LIBVIRT_TYPE=3 TEST_LIBVIRT_SSH_HOST= python manage.py test # compute1 again, over TLS
vagrant destroy -f

6
Vagrantfile vendored
View file

@ -4,6 +4,7 @@
# key for root (SASL user wvc, password wvc-test). The empty second disk
# /dev/vdb is for the LVM tests (TEST_LIBVIRT_LVM_DEVICE); each also serves a
# 1 GiB iSCSI LUN on 127.0.0.1 for the iSCSI tests (TEST_LIBVIRT_ISCSI_TARGET),
# exports /srv/wvcnfs to 127.0.0.1 for the NFS pool test (TEST_LIBVIRT_NFS_EXPORT),
# and accepts TLS logins (SASL) with a certificate from a throwaway CA.
# The CA is made here once; each compute signs its own certificate with it.
@ -60,6 +61,11 @@ Vagrant.configure(2) do |config|
targetcli /iscsi/$T/tpg1 set attribute generate_node_acls=1 demo_mode_write_protect=0
targetcli saveconfig
}
dnf -y install nfs-utils
install -d /srv/wvcnfs
echo "/srv/wvcnfs 127.0.0.1(rw,no_root_squash)" > /etc/exports.d/wvc.exports
systemctl enable --now nfs-server
exportfs -r
install -D -m 644 /tmp/wvc/cacert.pem /etc/pki/CA/cacert.pem
install -d /etc/pki/libvirt/private
echo "subjectAltName=IP:$(hostname -I | cut -d' ' -f1)" > /tmp/wvc/ext

View file

@ -1,6 +1,7 @@
"""Live check that a directory pool created on the storages page starts
when its directory does not exist yet: libvirt builds it. Runs only with
TEST_LIBVIRT_HOST set."""
"""Live check that a directory or NFS pool created on the storages page
starts when its directory does not exist yet: libvirt builds it. Runs only
with TEST_LIBVIRT_HOST set; the NFS case needs TEST_LIBVIRT_NFS_EXPORT, a
directory the host exports to its 127.0.0.1 (the Vagrant computes do)."""
import os
import unittest
@ -13,8 +14,7 @@ from django.urls import reverse
from instances.tests import livetest
from vrtManager.connection import connection_manager
POOL = livetest.PREFIX + "dir"
PATH = f"/var/lib/libvirt/{POOL}"
P = livetest.PREFIX
@unittest.skipUnless(livetest.enabled(), "Set TEST_LIBVIRT_HOST to run the live libvirt tests")
@ -27,27 +27,40 @@ class LivePoolsTestCase(TestCase):
type=int(os.environ.get("TEST_LIBVIRT_TYPE", 1)),
)
self.conn = connection_manager.get_connection(*args.values())
self.remove_pool()
self.addCleanup(self.remove_pool)
self.compute = Compute.objects.create(name="live-pools", **args)
self.client.force_login(get_user_model().objects.create_superuser("live-pools", "lp@example.com", "x"))
def remove_pool(self):
def remove_pool(self, name):
try:
pool = self.conn.storagePoolLookupByName(POOL)
pool = self.conn.storagePoolLookupByName(name)
except libvirt.libvirtError:
return
if pool.isActive():
pool.destroy()
pool.destroy() # unmounts an NFS pool
pool.delete(0) # removes the directory
pool.undefine()
def test_a_missing_directory_is_built(self):
response = self.client.post(
reverse("storages", args=[self.compute.id]),
{"create": "", "name": POOL, "stg_type": "dir", "target": PATH},
def assert_created(self, data):
self.remove_pool(data["name"])
self.addCleanup(self.remove_pool, data["name"])
response = self.client.post(reverse("storages", args=[self.compute.id]), {"create": "", **data})
self.assertRedirects(
response, reverse("storage", args=[self.compute.id, data["name"]]), fetch_redirect_response=False
)
self.assertRedirects(response, reverse("storage", args=[self.compute.id, POOL]), fetch_redirect_response=False)
pool = self.conn.storagePoolLookupByName(POOL)
pool = self.conn.storagePoolLookupByName(data["name"])
self.assertTrue(pool.isActive())
self.assertTrue(pool.autostart())
def test_a_missing_directory_is_built(self):
self.assert_created({"name": P + "dir", "stg_type": "dir", "target": f"/var/lib/libvirt/{P}dir"})
@unittest.skipUnless(os.environ.get("TEST_LIBVIRT_NFS_EXPORT"), "Set TEST_LIBVIRT_NFS_EXPORT to run the NFS pool test")
def test_a_missing_mount_point_is_built(self):
self.assert_created({
"name": P + "nfs",
"stg_type": "netfs",
"netfs_host": "127.0.0.1",
"source": os.environ["TEST_LIBVIRT_NFS_EXPORT"],
"source_format": "nfs",
"target": f"/var/lib/libvirt/{P}nfs",
})

View file

@ -101,7 +101,8 @@ class wvmStorages(wvmConnect):
"""
self.define_storage(xml, 0)
stg = self.get_storage(name)
stg.create(0)
# builds the mount point
stg.create(libvirt.VIR_STORAGE_POOL_CREATE_WITH_BUILD)
stg.setAutostart(1)
return stg