mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Add volume support to virt._get_disks
If a virtual machine has disks of volume types, they will now be reported by the virt._get_disk() function and all the user-exposed functions using it like virt.get_disks(), virt.vm_info() and virt.full_info().
This commit is contained in:
parent
a7218588ae
commit
f7e88a79af
2 changed files with 198 additions and 43 deletions
|
@ -452,7 +452,7 @@ def _get_loader(dom):
|
|||
return out
|
||||
|
||||
|
||||
def _get_disks(dom):
|
||||
def _get_disks(conn, dom):
|
||||
"""
|
||||
Get domain disks from a libvirt domain object.
|
||||
"""
|
||||
|
@ -463,49 +463,98 @@ def _get_disks(dom):
|
|||
if source is None:
|
||||
continue
|
||||
target = elem.find("target")
|
||||
driver = elem.find("driver")
|
||||
if target is None:
|
||||
continue
|
||||
qemu_target = None
|
||||
extra_properties = None
|
||||
if "dev" in target.attrib:
|
||||
qemu_target = source.get("file", "")
|
||||
if not qemu_target:
|
||||
disk_type = elem.get("type")
|
||||
if disk_type == "file":
|
||||
qemu_target = source.get("file", "")
|
||||
if qemu_target.startswith("/dev/zvol/"):
|
||||
disks[target.get("dev")] = {"file": qemu_target, "zfs": True}
|
||||
continue
|
||||
# Extract disk sizes, snapshots, backing files
|
||||
if elem.get("device", "disk") != "cdrom":
|
||||
try:
|
||||
stdout = subprocess.Popen(
|
||||
[
|
||||
"qemu-img",
|
||||
"info",
|
||||
"-U",
|
||||
"--output",
|
||||
"json",
|
||||
"--backing-chain",
|
||||
qemu_target,
|
||||
],
|
||||
shell=False,
|
||||
stdout=subprocess.PIPE,
|
||||
).communicate()[0]
|
||||
qemu_output = salt.utils.stringutils.to_str(stdout)
|
||||
output = _parse_qemu_img_info(qemu_output)
|
||||
extra_properties = output
|
||||
except TypeError:
|
||||
disk.update({"file": "Does not exist"})
|
||||
elif disk_type == "block":
|
||||
qemu_target = source.get("dev", "")
|
||||
if (
|
||||
not qemu_target
|
||||
and "protocol" in source.attrib
|
||||
and "name" in source.attrib
|
||||
): # for rbd network
|
||||
qemu_target = "{0}:{1}".format(
|
||||
source.get("protocol"), source.get("name")
|
||||
)
|
||||
elif qemu_target.startswith("/dev/zvol/"):
|
||||
disks[target.get("dev")] = {"file": qemu_target, "zfs": True}
|
||||
continue
|
||||
elif disk_type == "network":
|
||||
qemu_target = source.get("protocol")
|
||||
source_name = source.get("name")
|
||||
if source_name:
|
||||
qemu_target = "{0}:{1}".format(qemu_target, source_name)
|
||||
elif disk_type == "volume":
|
||||
pool_name = source.get("pool")
|
||||
volume_name = source.get("volume")
|
||||
qemu_target = "{}/{}".format(pool_name, volume_name)
|
||||
pool = conn.storagePoolLookupByName(pool_name)
|
||||
vol = pool.storageVolLookupByName(volume_name)
|
||||
vol_info = vol.info()
|
||||
extra_properties = {
|
||||
"virtual size": vol_info[1],
|
||||
"disk size": vol_info[2],
|
||||
}
|
||||
|
||||
backing_files = [
|
||||
{
|
||||
"file": node.find("source").get("file"),
|
||||
"file format": node.find("format").get("type"),
|
||||
}
|
||||
for node in elem.findall(".//backingStore[source]")
|
||||
]
|
||||
|
||||
if backing_files:
|
||||
# We had the backing files in a flat list, nest them again.
|
||||
extra_properties["backing file"] = backing_files[0]
|
||||
parent = extra_properties["backing file"]
|
||||
for sub_backing_file in backing_files[1:]:
|
||||
parent["backing file"] = sub_backing_file
|
||||
parent = sub_backing_file
|
||||
|
||||
else:
|
||||
# In some cases the backing chain is not displayed by the domain definition
|
||||
# Try to see if we have some of it in the volume definition.
|
||||
vol_desc = ElementTree.fromstring(vol.XMLDesc())
|
||||
backing_path = vol_desc.find("./backingStore/path")
|
||||
backing_format = vol_desc.find("./backingStore/format")
|
||||
if backing_path is not None:
|
||||
extra_properties["backing file"] = {"file": backing_path.text}
|
||||
if backing_format is not None:
|
||||
extra_properties["backing file"][
|
||||
"file format"
|
||||
] = backing_format.get("type")
|
||||
|
||||
if not qemu_target:
|
||||
continue
|
||||
|
||||
disk = {"file": qemu_target, "type": elem.get("device")}
|
||||
|
||||
driver = elem.find("driver")
|
||||
if driver is not None and driver.get("type") == "qcow2":
|
||||
try:
|
||||
stdout = subprocess.Popen(
|
||||
[
|
||||
"qemu-img",
|
||||
"info",
|
||||
"-U",
|
||||
"--output",
|
||||
"json",
|
||||
"--backing-chain",
|
||||
disk["file"],
|
||||
],
|
||||
shell=False,
|
||||
stdout=subprocess.PIPE,
|
||||
).communicate()[0]
|
||||
qemu_output = salt.utils.stringutils.to_str(stdout)
|
||||
output = _parse_qemu_img_info(qemu_output)
|
||||
disk.update(output)
|
||||
except TypeError:
|
||||
disk.update({"file": "Does not exist"})
|
||||
disk = {
|
||||
"file": qemu_target,
|
||||
"type": elem.get("device"),
|
||||
}
|
||||
if driver is not None and "type" in driver.attrib:
|
||||
disk["file format"] = driver.get("type")
|
||||
if extra_properties:
|
||||
disk.update(extra_properties)
|
||||
|
||||
disks[target.get("dev")] = disk
|
||||
return disks
|
||||
|
@ -2429,7 +2478,7 @@ def vm_info(vm_=None, **kwargs):
|
|||
salt '*' virt.vm_info
|
||||
"""
|
||||
|
||||
def _info(dom):
|
||||
def _info(conn, dom):
|
||||
"""
|
||||
Compute the infos of a domain
|
||||
"""
|
||||
|
@ -2437,7 +2486,7 @@ def vm_info(vm_=None, **kwargs):
|
|||
return {
|
||||
"cpu": raw[3],
|
||||
"cputime": int(raw[4]),
|
||||
"disks": _get_disks(dom),
|
||||
"disks": _get_disks(conn, dom),
|
||||
"graphics": _get_graphics(dom),
|
||||
"nics": _get_nics(dom),
|
||||
"uuid": _get_uuid(dom),
|
||||
|
@ -2453,10 +2502,10 @@ def vm_info(vm_=None, **kwargs):
|
|||
info = {}
|
||||
conn = __get_conn(**kwargs)
|
||||
if vm_:
|
||||
info[vm_] = _info(_get_domain(conn, vm_))
|
||||
info[vm_] = _info(conn, _get_domain(conn, vm_))
|
||||
else:
|
||||
for domain in _get_domain(conn, iterable=True):
|
||||
info[domain.name()] = _info(domain)
|
||||
info[domain.name()] = _info(conn, domain)
|
||||
conn.close()
|
||||
return info
|
||||
|
||||
|
@ -2676,7 +2725,7 @@ def get_disks(vm_, **kwargs):
|
|||
salt '*' virt.get_disks <domain>
|
||||
"""
|
||||
conn = __get_conn(**kwargs)
|
||||
disks = _get_disks(_get_domain(conn, vm_))
|
||||
disks = _get_disks(conn, _get_domain(conn, vm_))
|
||||
conn.close()
|
||||
return disks
|
||||
|
||||
|
@ -3653,7 +3702,7 @@ def purge(vm_, dirs=False, removables=False, **kwargs):
|
|||
"""
|
||||
conn = __get_conn(**kwargs)
|
||||
dom = _get_domain(conn, vm_)
|
||||
disks = _get_disks(dom)
|
||||
disks = _get_disks(conn, dom)
|
||||
if (
|
||||
VIRT_STATE_NAME_MAP.get(dom.info()[0], "unknown") != "shutdown"
|
||||
and dom.destroy() != 0
|
||||
|
|
|
@ -4668,3 +4668,109 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
|
|||
"vol1.qcow2",
|
||||
"/path/to/file",
|
||||
)
|
||||
|
||||
def test_get_disks(self):
|
||||
"""
|
||||
Test the virt.get_disks function
|
||||
"""
|
||||
# test with volumes
|
||||
vm_def = """<domain type='kvm' id='3'>
|
||||
<name>srv01</name>
|
||||
<devices>
|
||||
<disk type='volume' device='disk'>
|
||||
<driver name='qemu' type='qcow2' cache='none' io='native'/>
|
||||
<source pool='default' volume='srv01_system'/>
|
||||
<backingStore/>
|
||||
<target dev='vda' bus='virtio'/>
|
||||
<alias name='virtio-disk0'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
|
||||
</disk>
|
||||
<disk type='volume' device='disk'>
|
||||
<driver name='qemu' type='qcow2' cache='none' io='native'/>
|
||||
<source pool='default' volume='srv01_data'/>
|
||||
<backingStore type='file' index='1'>
|
||||
<format type='qcow2'/>
|
||||
<source file='/var/lib/libvirt/images/vol01'/>
|
||||
<backingStore/>
|
||||
</backingStore>
|
||||
<target dev='vdb' bus='virtio'/>
|
||||
<alias name='virtio-disk1'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
|
||||
</disk>
|
||||
<disk type='volume' device='disk'>
|
||||
<driver name='qemu' type='qcow2' cache='none' io='native'/>
|
||||
<source pool='default' volume='vm05_system'/>
|
||||
<backingStore type='file' index='1'>
|
||||
<format type='qcow2'/>
|
||||
<source file='/var/lib/libvirt/images/vm04_system.qcow2'/>
|
||||
<backingStore type='file' index='2'>
|
||||
<format type='raw'/>
|
||||
<source file='/var/testsuite-data/disk-image-template.raw'/>
|
||||
<backingStore/>
|
||||
</backingStore>
|
||||
</backingStore>
|
||||
<target dev='vdc' bus='virtio'/>
|
||||
<alias name='virtio-disk0'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
|
||||
</disk>
|
||||
</devices>
|
||||
</domain>
|
||||
"""
|
||||
self.set_mock_vm("srv01", vm_def)
|
||||
|
||||
pool_mock = MagicMock()
|
||||
pool_mock.storageVolLookupByName.return_value.info.return_value = [
|
||||
0,
|
||||
1234567,
|
||||
12345,
|
||||
]
|
||||
pool_mock.storageVolLookupByName.return_value.XMLDesc.side_effect = [
|
||||
"<volume />",
|
||||
"""
|
||||
<volume>
|
||||
<backingStore>
|
||||
<path>/var/lib/libvirt/images/vol01</path>
|
||||
<format type="qcow2"/>
|
||||
</backingStore>
|
||||
</volume>""",
|
||||
]
|
||||
self.mock_conn.storagePoolLookupByName.return_value = pool_mock
|
||||
|
||||
self.assertDictEqual(
|
||||
virt.get_disks("srv01"),
|
||||
{
|
||||
"vda": {
|
||||
"type": "disk",
|
||||
"file": "default/srv01_system",
|
||||
"file format": "qcow2",
|
||||
"disk size": 12345,
|
||||
"virtual size": 1234567,
|
||||
},
|
||||
"vdb": {
|
||||
"type": "disk",
|
||||
"file": "default/srv01_data",
|
||||
"file format": "qcow2",
|
||||
"disk size": 12345,
|
||||
"virtual size": 1234567,
|
||||
"backing file": {
|
||||
"file": "/var/lib/libvirt/images/vol01",
|
||||
"file format": "qcow2",
|
||||
},
|
||||
},
|
||||
"vdc": {
|
||||
"type": "disk",
|
||||
"file": "default/vm05_system",
|
||||
"file format": "qcow2",
|
||||
"disk size": 12345,
|
||||
"virtual size": 1234567,
|
||||
"backing file": {
|
||||
"file": "/var/lib/libvirt/images/vm04_system.qcow2",
|
||||
"file format": "qcow2",
|
||||
"backing file": {
|
||||
"file": "/var/testsuite-data/disk-image-template.raw",
|
||||
"file format": "raw",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue