Handle RBD volumes as network disks in VM definition

libvirt doesn't support attaching RBD storage pool volumes to a VM.
For instance, a disk with such a source is invalid:

    <source pool='rbd-pool' volume='rbd-volume'/>

And needs to be replaced with:

    <source protocol="rbd" name="rbd-pool-name/rbd-volume">
      <host name="hostname" port="7000"/>
      <auth username='myuser'>
        <secret type='ceph' usage='mypassid'/>
      </auth>
    </source>

This means that we need to fetch the connection data from the pool
definition and convert the volume disk definition into a network one
when creating the VM.

This also means that when purging the VM we need to search for the
pool by looking in every pool's XML to delete the volume.
This commit is contained in:
Cédric Bosdonnat 2020-04-20 16:18:51 +02:00 committed by Daniel Wozniak
parent 62527d052e
commit 5ecea2bac1
3 changed files with 359 additions and 28 deletions

View file

@ -606,6 +606,7 @@ def _get_target(target, ssh):
def _gen_xml(
conn,
name,
cpu,
mem,
@ -693,10 +694,46 @@ def _gen_xml(
disk_context["source_file"] = disk["source_file"]
disk_context["type"] = "file"
elif disk.get("pool"):
# If we had no source_file, then we want a volume
disk_context["type"] = "volume"
disk_context["pool"] = disk["pool"]
disk_context["volume"] = disk["filename"]
# If we had no source_file, then we want a volume
pool_xml = ElementTree.fromstring(
conn.storagePoolLookupByName(disk["pool"]).XMLDesc()
)
pool_type = pool_xml.get("type")
if pool_type in ["rbd", "gluster", "sheepdog"]:
# libvirt can't handle rbd, gluster and sheepdog as volumes
disk_context["type"] = "network"
disk_context["protocol"] = pool_type
# Copy the hosts from the pool definition
disk_context["hosts"] = [
{"name": host.get("name"), "port": host.get("port")}
for host in pool_xml.findall(".//host")
]
dir_node = pool_xml.find("./source/dir")
# Gluster and RBD need pool/volume name
name_node = pool_xml.find("./source/name")
if name_node is not None:
disk_context["volume"] = "{}/{}".format(
name_node.text, disk_context["volume"]
)
# Copy the authentication if any for RBD
auth_node = pool_xml.find("./source/auth")
if auth_node is not None:
username = auth_node.get("username")
secret_node = auth_node.find("./secret")
usage = secret_node.get("usage")
if not usage:
# Get the usage from the UUID
uuid = secret_node.get("uuid")
usage = conn.secretLookupByUUIDString(uuid).usageID()
disk_context["auth"] = {
"type": "ceph",
"username": username,
"usage": usage,
}
else:
disk_context["type"] = "volume"
disk_context["pool"] = disk["pool"]
else:
# No source and no pool is a removable device, use file type
@ -1822,6 +1859,7 @@ def init(
boot = _handle_remote_boot_params(boot)
vm_xml = _gen_xml(
conn,
name,
cpu,
mem,
@ -2146,6 +2184,7 @@ def update(
new_desc = ElementTree.fromstring(
_gen_xml(
conn,
name,
cpu or 0,
mem or 0,
@ -3723,13 +3762,28 @@ def purge(vm_, dirs=False, removables=False, **kwargs):
directories.add(os.path.dirname(disks[disk]["file"]))
else:
# We may have a volume to delete here
matcher = re.match("^([^/]+)/(.*)$", disks[disk]["file"])
matcher = re.match(
"^(?:(?P<protocol>[^:]*):)?(?P<pool>[^/]+)/(?P<volume>.*)$",
disks[disk]["file"],
)
if matcher:
if matcher.group(1) in conn.listStoragePools():
pool = conn.storagePoolLookupByName(matcher.group(1))
if matcher.group(2) in pool.listVolumes():
volume = pool.storageVolLookupByName(matcher.group(2))
volume.delete()
pool_name = matcher.group("pool")
pool = None
if matcher.group("protocol") in ["rbd", "gluster"]:
# The pool name is not the libvirt one... we need to loop over the pool to find it
for pool_i in conn.listAllStoragePools():
pool_i_xml = ElementTree.fromstring(pool_i.XMLDesc())
if pool_i_xml.get("type") == matcher.group("protocol"):
name_node = pool_i_xml.find("source/name")
if name_node is not None and name_node.text == pool_name:
pool = pool_i
break
elif pool_name in conn.listStoragePools():
pool = conn.storagePoolLookupByName(pool_name)
if pool and matcher.group("volume") in pool.listVolumes():
volume = pool.storageVolLookupByName(matcher.group("volume"))
volume.delete()
if dirs:
for dir_ in directories:

View file

@ -35,6 +35,18 @@
{% if disk.type == 'volume' and 'pool' in disk -%}
<source pool='{{ disk.pool }}' volume='{{ disk.volume }}' />
{% endif %}
{%- if disk.type == 'network' %}
<source protocol='{{ disk.protocol }}' name='{{ disk.volume }}'>
{%- for host in disk.get('hosts') %}
<host name='{{ host.name }}'{% if host.get("port") %} port='{{ host.port }}'{% endif %}/>
{%- endfor %}
{%- if disk.get("auth") %}
<auth username='{{ disk.auth.username }}'>
<secret type='{{ disk.auth.type }}' usage='{{ disk.auth.usage}}'/>
</auth>
{%- endif %}
</source>
{%- endif %}
<target dev='{{ disk.target_dev }}' bus='{{ disk.disk_bus }}' />
{% if disk.address -%}
<address type='drive' controller='0' bus='0' target='0' unit='{{ disk.index }}' />

View file

@ -158,7 +158,9 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
"""
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml("hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64")
xml_data = virt._gen_xml(
self.mock_conn, "hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64"
)
root = ET.fromstring(xml_data)
self.assertEqual(root.find("os/boot").attrib["dev"], "hd")
self.assertEqual(root.find("os/type").attrib["arch"], "x86_64")
@ -171,7 +173,16 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml(
"hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64", boot_dev="cdrom"
self.mock_conn,
"hello",
1,
512,
diskp,
nicp,
"kvm",
"hvm",
"x86_64",
boot_dev="cdrom",
)
root = ET.fromstring(xml_data)
self.assertEqual(root.find("os/boot").attrib["dev"], "cdrom")
@ -183,6 +194,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml(
self.mock_conn,
"hello",
1,
512,
@ -204,6 +216,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml(
self.mock_conn,
"hello",
1,
512,
@ -226,6 +239,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml(
self.mock_conn,
"hello",
1,
512,
@ -248,6 +262,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml(
self.mock_conn,
"hello",
1,
512,
@ -272,6 +287,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml(
self.mock_conn,
"hello",
1,
512,
@ -297,6 +313,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml(
self.mock_conn,
"hello",
1,
512,
@ -319,6 +336,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml(
self.mock_conn,
"hello",
1,
512,
@ -340,7 +358,9 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
"""
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml("hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64")
xml_data = virt._gen_xml(
self.mock_conn, "hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64"
)
root = ET.fromstring(xml_data)
self.assertIsNone(root.find("devices/graphics"))
@ -350,7 +370,9 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
"""
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml("hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64")
xml_data = virt._gen_xml(
self.mock_conn, "hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64"
)
root = ET.fromstring(xml_data)
self.assertIsNone(root.find("os/loader"))
@ -361,6 +383,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml(
self.mock_conn,
"hello",
1,
512,
@ -394,6 +417,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml(
self.mock_conn,
"hello",
1,
512,
@ -420,6 +444,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml(
self.mock_conn,
"hello",
1,
512,
@ -608,7 +633,9 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
"""
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml("hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64",)
xml_data = virt._gen_xml(
self.mock_conn, "hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64",
)
root = ET.fromstring(xml_data)
self.assertEqual(root.attrib["type"], "kvm")
self.assertEqual(root.find("vcpu").text, "1")
@ -640,7 +667,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "vmware", [], "hello")
nicp = virt._nic_profile("default", "vmware")
xml_data = virt._gen_xml(
"hello", 1, 512, diskp, nicp, "vmware", "hvm", "x86_64",
self.mock_conn, "hello", 1, 512, diskp, nicp, "vmware", "hvm", "x86_64",
)
root = ET.fromstring(xml_data)
self.assertEqual(root.attrib["type"], "vmware")
@ -674,7 +701,16 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
virt.__grains__, {"os_family": "Suse"} # pylint: disable=no-member
):
xml_data = virt._gen_xml(
"hello", 1, 512, diskp, nicp, "xen", "xen", "x86_64", boot=None
self.mock_conn,
"hello",
1,
512,
diskp,
nicp,
"xen",
"xen",
"x86_64",
boot=None,
)
root = ET.fromstring(xml_data)
self.assertEqual(root.attrib["type"], "xen")
@ -728,7 +764,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
)
nicp = virt._nic_profile("noeffect", "vmware")
xml_data = virt._gen_xml(
"hello", 1, 512, diskp, nicp, "vmware", "hvm", "x86_64",
self.mock_conn, "hello", 1, 512, diskp, nicp, "vmware", "hvm", "x86_64",
)
root = ET.fromstring(xml_data)
self.assertEqual(root.attrib["type"], "vmware")
@ -761,7 +797,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "noeffect", "kvm", [], "hello")
nicp = virt._nic_profile("noeffect", "kvm")
xml_data = virt._gen_xml(
"hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64",
self.mock_conn, "hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64",
)
root = ET.fromstring(xml_data)
self.assertEqual(root.attrib["type"], "kvm")
@ -845,8 +881,13 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
],
"hello",
)
self.mock_conn.storagePoolLookupByName.return_value.XMLDesc.return_value = (
"<pool type='dir'/>"
)
nicp = virt._nic_profile(None, "kvm")
xml_data = virt._gen_xml("hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64",)
xml_data = virt._gen_xml(
self.mock_conn, "hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64",
)
root = ET.fromstring(xml_data)
disk = root.findall(".//disk")[0]
self.assertEqual(disk.attrib["device"], "disk")
@ -856,6 +897,116 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
self.assertEqual("hello_system", source.attrib["volume"])
self.assertEqual("myvolume", root.find(".//disk[2]/source").get("volume"))
# RBD volume usage auth test case
self.mock_conn.listStoragePools.return_value = ["test-rbd"]
self.mock_conn.storagePoolLookupByName.return_value.XMLDesc.return_value = """
<pool type='rbd'>
<name>test-rbd</name>
<uuid>ede33e0a-9df0-479f-8afd-55085a01b244</uuid>
<capacity unit='bytes'>526133493760</capacity>
<allocation unit='bytes'>589928</allocation>
<available unit='bytes'>515081306112</available>
<source>
<host name='ses2.tf.local'/>
<host name='ses3.tf.local' port='1234'/>
<name>libvirt-pool</name>
<auth type='ceph' username='libvirt'>
<secret usage='pool_test-rbd'/>
</auth>
</source>
</pool>
"""
self.mock_conn.getStoragePoolCapabilities.return_value = """
<storagepoolCapabilities>
<pool type='rbd' supported='yes'>
<volOptions>
<defaultFormat type='raw'/>
<enum name='targetFormatType'>
</enum>
</volOptions>
</pool>
</storagepoolCapabilities>
"""
diskp = virt._disk_profile(
self.mock_conn,
None,
"kvm",
[{"name": "system", "pool": "test-rbd"}],
"test-vm",
)
xml_data = virt._gen_xml(
self.mock_conn, "hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64",
)
root = ET.fromstring(xml_data)
disk = root.findall(".//disk")[0]
self.assertDictEqual(
{
"type": "network",
"device": "disk",
"source": {
"protocol": "rbd",
"name": "libvirt-pool/test-vm_system",
"host": [
{"name": "ses2.tf.local"},
{"name": "ses3.tf.local", "port": "1234"},
],
"auth": {
"username": "libvirt",
"secret": {"type": "ceph", "usage": "pool_test-rbd"},
},
},
"target": {"dev": "vda", "bus": "virtio"},
"driver": {
"name": "qemu",
"type": "raw",
"cache": "none",
"io": "native",
},
},
salt.utils.xmlutil.to_dict(disk, True),
)
# RBD volume UUID auth test case
self.mock_conn.storagePoolLookupByName.return_value.XMLDesc.return_value = """
<pool type='rbd'>
<name>test-rbd</name>
<uuid>ede33e0a-9df0-479f-8afd-55085a01b244</uuid>
<capacity unit='bytes'>526133493760</capacity>
<allocation unit='bytes'>589928</allocation>
<available unit='bytes'>515081306112</available>
<source>
<host name='ses2.tf.local'/>
<host name='ses3.tf.local' port='1234'/>
<name>libvirt-pool</name>
<auth type='ceph' username='libvirt'>
<secret uuid='some-uuid'/>
</auth>
</source>
</pool>
"""
self.mock_conn.secretLookupByUUIDString.return_value.usageID.return_value = (
"pool_test-rbd"
)
diskp = virt._disk_profile(
self.mock_conn,
None,
"kvm",
[{"name": "system", "pool": "test-rbd"}],
"test-vm",
)
xml_data = virt._gen_xml(
self.mock_conn, "hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64",
)
root = ET.fromstring(xml_data)
self.assertDictEqual(
{
"username": "libvirt",
"secret": {"type": "ceph", "usage": "pool_test-rbd"},
},
salt.utils.xmlutil.to_dict(root.find(".//disk/source/auth"), True),
)
self.mock_conn.secretLookupByUUIDString.assert_called_once_with("some-uuid")
def test_gen_xml_cdrom(self):
"""
Test virt._gen_xml(), generating a cdrom device (different disk type, no source)
@ -875,7 +1026,9 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
"hello",
)
nicp = virt._nic_profile(None, "kvm")
xml_data = virt._gen_xml("hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64",)
xml_data = virt._gen_xml(
self.mock_conn, "hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64",
)
root = ET.fromstring(xml_data)
disk = root.findall(".//disk")[0]
self.assertEqual(disk.get("type"), "file")
@ -889,7 +1042,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
diskp = virt._disk_profile(self.mock_conn, "default", "vmware", [], "hello")
nicp = virt._nic_profile("default", "vmware")
xml_data = virt._gen_xml(
"hello", 1, 512, diskp, nicp, "vmware", "hvm", "x86_64",
self.mock_conn, "hello", 1, 512, diskp, nicp, "vmware", "hvm", "x86_64",
)
root = ET.fromstring(xml_data)
controllers = root.findall(".//devices/controller")
@ -903,7 +1056,9 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
"""
diskp = virt._disk_profile(self.mock_conn, "default", "kvm", [], "hello")
nicp = virt._nic_profile("default", "kvm")
xml_data = virt._gen_xml("hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64",)
xml_data = virt._gen_xml(
self.mock_conn, "hello", 1, 512, diskp, nicp, "kvm", "hvm", "x86_64",
)
root = ET.fromstring(xml_data)
controllers = root.findall(".//devices/controller")
# There should be no controller
@ -1429,6 +1584,19 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
<alias name='virtio-disk1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x1'/>
</disk>
<disk type="network" device="disk">
<driver name='raw' type='qcow2'/>
<source protocol='rbd' name='libvirt-pool/my_vm_data2'>
<host name='ses2.tf.local'/>
<host name='ses3.tf.local' port='1234'/>
<auth username='libvirt'>
<secret type='ceph' usage='pool_test-rbd'/>
</auth>
</source>
<target dev='vdc' bus='virtio'/>
<alias name='virtio-disk2'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x2'/>
</disk>
<interface type='network'>
<mac address='52:54:00:39:02:b1'/>
<source network='default' bridge='virbr0'/>
@ -1638,14 +1806,15 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
)
self.assertListEqual(
["my_vm_data"],
["my_vm_data", "libvirt-pool/my_vm_data2"],
[
ET.fromstring(disk).find("source").get("volume")
or ET.fromstring(disk).find("source").get("name")
for disk in ret["disk"]["detached"]
],
)
self.assertEqual(devattach_mock.call_count, 2)
devdetach_mock.assert_called_once()
self.assertEqual(devdetach_mock.call_count, 2)
# Update nics case
yaml_config = """
@ -1705,7 +1874,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
devdetach_mock.reset_mock()
ret = virt.update("my_vm", disk_profile=None, disks=[])
self.assertEqual([], ret["disk"]["attached"])
self.assertEqual(2, len(ret["disk"]["detached"]))
self.assertEqual(3, len(ret["disk"]["detached"]))
devattach_mock.assert_not_called()
devdetach_mock.assert_called()
@ -1723,9 +1892,28 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
# Update with no diff case
pool_mock = MagicMock()
pool_mock.XMLDesc.return_value = "<pool type='dir'></pool>"
default_pool_desc = "<pool type='dir'></pool>"
rbd_pool_desc = """
<pool type='rbd'>
<name>test-rbd</name>
<source>
<host name='ses2.tf.local'/>
<host name='ses3.tf.local' port='1234'/>
<name>libvirt-pool</name>
<auth type='ceph' username='libvirt'>
<secret usage='pool_test-rbd'/>
</auth>
</source>
</pool>
"""
pool_mock.XMLDesc.side_effect = [
default_pool_desc,
rbd_pool_desc,
default_pool_desc,
rbd_pool_desc,
]
self.mock_conn.storagePoolLookupByName.return_value = pool_mock
self.mock_conn.listStoragePools.return_value = ["default"]
self.mock_conn.listStoragePools.return_value = ["test-rbd", "default"]
self.assertEqual(
{
"definition": False,
@ -1737,7 +1925,15 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
cpu=1,
mem=1024,
disk_profile="default",
disks=[{"name": "data", "size": 2048, "pool": "default"}],
disks=[
{"name": "data", "size": 2048, "pool": "default"},
{
"name": "data2",
"size": 4096,
"pool": "test-rbd",
"format": "raw",
},
],
nic_profile="myprofile",
interfaces=[
{
@ -2283,6 +2479,75 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin):
self.assertTrue(res)
pool_mock.storageVolLookupByName.return_value.delete.assert_called_once()
@patch("salt.modules.virt.stop", return_value=True)
@patch("salt.modules.virt.undefine")
def test_purge_rbd(self, mock_undefine, mock_stop):
"""
Test virt.purge() with RBD disks
"""
xml = """<domain type='kvm' id='7'>
<name>test-vm</name>
<devices>
<disk type="network" device="disk">
<driver name='raw' type='qcow2'/>
<source protocol='rbd' name='libvirt-pool/my_vm_data2'>
<host name='ses2.tf.local'/>
<host name='ses3.tf.local' port='1234'/>
<auth username='libvirt'>
<secret type='ceph' usage='pool_test-rbd'/>
</auth>
</source>
<target dev='vdc' bus='virtio'/>
<alias name='virtio-disk2'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x2'/>
</disk>
</devices>
</domain>
"""
self.set_mock_vm("test-vm", xml)
pool_mock = MagicMock()
pool_mock.storageVolLookupByName.return_value.info.return_value = [
0,
1234567,
12345,
]
pool_mock.XMLDesc.return_value = """
<pool type='rbd'>
<name>test-ses</name>
<source>
<host name='ses2.tf.local'/>
<name>libvirt-pool</name>
<auth type='ceph' username='libvirt'>
<secret usage='pool_test-ses'/>
</auth>
</source>
</pool>
"""
pool_mock.storageVolLookupByName.return_value.XMLDesc.return_value = [
"""
<volume type='network'>
<name>my_vm_data2</name>
<source>
</source>
<capacity unit='bytes'>536870912</capacity>
<allocation unit='bytes'>0</allocation>
<target>
<path>libvirt-pool/my_vm_data2</path>
<format type='raw'/>
</target>
</volume>
""",
]
pool_mock.listVolumes.return_value = ["my_vm_data2"]
self.mock_conn.listAllStoragePools.return_value = [pool_mock]
self.mock_conn.listStoragePools.return_value = ["default"]
with patch.dict(os.path.__dict__, {"exists": MagicMock(return_value=False)}):
res = virt.purge("test-vm")
self.assertTrue(res)
pool_mock.storageVolLookupByName.return_value.delete.assert_called_once()
@patch("salt.modules.virt.stop", return_value=True)
@patch("salt.modules.virt.undefine")
@patch("os.remove")