mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-10 20:26:48 +00:00
fix(storages): pools are measured when shown, and only on a host's own pages
libvirt measures a pool's size and free space only when the pool is refreshed and keeps those figures until the next refresh. The pool lists read them without a refresh, so they showed a pool's space as of whenever libvirt last refreshed it: two hosts sharing one pool's storage told different free space for it, each its own refresh's. On a test host, a 1 GiB file left libvirt's free space unchanged while df showed 1 GiB less, until the pool was refreshed. get_storages_info refreshes each active pool before reading it; a refresh libvirt refuses (while a volume is cloned in the pool) leaves the last figures, as the pool pages already do. A refresh scans the pool's volumes, so pools are read only where one host's are shown: a host's overview (views.host_pools, its Storage card) and its Storages page and API. The Computes list and the new-VM dialog's host lines, which read every host at once, no longer show pools; Compute.capacity is the vCPUs and memory given.
This commit is contained in:
parent
3a4554bcbf
commit
a0a31cd3f2
10 changed files with 99 additions and 83 deletions
|
|
@ -7,11 +7,18 @@ from vrtManager.connection import wvmConnect
|
|||
|
||||
class wvmStorages(wvmConnect):
|
||||
def get_storages_info(self):
|
||||
"""Each pool's state, type, volume count, size and free space. An active
|
||||
pool is refreshed first: libvirt measures its space only when it is
|
||||
refreshed, so two hosts sharing a pool's storage told different free
|
||||
space, each as of its own last refresh."""
|
||||
get_storages = self.get_storages()
|
||||
storages = []
|
||||
for pool in get_storages:
|
||||
stg = self.get_storage(pool)
|
||||
stg_status = stg.isActive()
|
||||
if stg_status:
|
||||
with contextlib.suppress(libvirt.libvirtError): # refused while a volume is cloned in it
|
||||
stg.refresh(0)
|
||||
stg_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
||||
stg_vol = len(stg.listVolumes()) if stg_status else None
|
||||
_state, stg_size, _allocation, stg_free = stg.info()
|
||||
|
|
|
|||
|
|
@ -196,3 +196,24 @@ class StoragesInfoTestCase(unittest.TestCase):
|
|||
conn.get_storage = lambda name: pool
|
||||
(info,) = conn.get_storages_info()
|
||||
self.assertEqual((info["name"], info["size"], info["free"]), ("default", 500, 120))
|
||||
# measured now: libvirt keeps a pool's space as of its last refresh
|
||||
self.assertEqual([c[0] for c in pool.mock_calls[:2]], ["isActive", "refresh"])
|
||||
|
||||
def test_a_pool_that_refuses_a_refresh_tells_its_last_space(self):
|
||||
conn = connection(wvmStorages)
|
||||
pool = MagicMock(**{"isActive.return_value": 1, "XMLDesc.return_value": "<pool type='dir'/>",
|
||||
"listVolumes.return_value": [], "info.return_value": [2, 500, 380, 120],
|
||||
"refresh.side_effect": libvirtError("pool is busy: a volume is cloned")})
|
||||
conn.get_storages = lambda: ["default"]
|
||||
conn.get_storage = lambda name: pool
|
||||
(info,) = conn.get_storages_info()
|
||||
self.assertEqual(info["free"], 120)
|
||||
|
||||
def test_an_inactive_pool_is_not_refreshed(self):
|
||||
conn = connection(wvmStorages)
|
||||
pool = MagicMock(**{"isActive.return_value": 0, "XMLDesc.return_value": "<pool type='dir'/>",
|
||||
"info.return_value": [0, 0, 0, 0]})
|
||||
conn.get_storages = lambda: ["off"]
|
||||
conn.get_storage = lambda name: pool
|
||||
conn.get_storages_info()
|
||||
pool.refresh.assert_not_called()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue