Bug 1687712 - blockCopy fail with bogus error: "TypeError: block params must be a dictionary"
Summary: blockCopy fail with bogus error: "TypeError: block params must be a dictionary"
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux Advanced Virtualization
Classification: Red Hat
Component: libvirt-python
Version: 8.1
Hardware: Unspecified
OS: Unspecified
unspecified
medium
Target Milestone: rc
: 8.0
Assignee: Peter Krempa
QA Contact: lcheng
URL:
Whiteboard:
Depends On: 1687114
Blocks:
TreeView+ depends on / blocked
 
Reported: 2019-03-12 08:20 UTC by Peter Krempa
Modified: 2020-11-14 05:41 UTC (History)
12 users (show)

Fixed In Version: libvirt-python-5.0.0-4.el8
Doc Type: If docs needed, set a value
Doc Text:
Clone Of: 1687114
Environment:
Last Closed: 2019-08-07 10:41:10 UTC
Type: Bug
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Product Errata RHBA-2019:2395 0 None None None 2019-08-07 10:41:46 UTC

Description Peter Krempa 2019-03-12 08:20:54 UTC
+++ This bug was initially created as a clone of Bug #1687114 +++

Description of problem:

When blockCopy is called without specifying the params argument, the call
fails with:

    TypeError: block params must be a dictionary

blockCopy is defined as:

    def blockCopy(self, disk, destxml, params=None, flags=0):
        """Copy the guest-visible contents of a disk image to a new file described by destxml """
        ret = libvirtmod.virDomainBlockCopy(self._o, disk, destxml, params, flags)
        if ret == -1: raise libvirtError ('virDomainBlockCopy() failed', dom=self)
        return ret

So when calling it without the params kwarg, params is None.

Vdsm calls blockCopy like this:

    def _startDriveReplication(self, drive):
        destxml = xmlutils.tostring(drive.getReplicaXML())
        self.log.debug("Replicating drive %s to %s", drive.name, destxml)

        flags = (libvirt.VIR_DOMAIN_BLOCK_COPY_SHALLOW |
                 libvirt.VIR_DOMAIN_BLOCK_COPY_REUSE_EXT |
                 libvirt.VIR_DOMAIN_BLOCK_COPY_TRANSIENT_JOB)

        self._dom.blockCopy(drive.name, destxml, flags=flags)

Version-Release number of selected component (if applicable):

$ rpm -q python2-libvirt
python2-libvirt-5.0.0-2.fc28.x86_64

$ rpm -q libvirt-daemon
libvirt-daemon-5.0.0-3.fc28.x86_64


How reproducible:
Always

Additional info:

I think this was broken by this patch:

commit 2b4bd07e0a2239cd9a4da49b9bd5229ac46e7875
Author: John Ferlan <jferlan>
Date:   Tue Nov 20 11:56:47 2018 -0500

    Add check for params, nparams being a dictionary
    
    If PyDict_Check fails, we should force an error rather than
    blindly continuing on.
    
    Signed-off-by: John Ferlan <jferlan>
    Reviewed-by: Pavel Hrdina <phrdina>

Adding this check:

    if (PyDict_Check(pyobj_dict)) {
        if (virPyDictToTypedParams(pyobj_dict, &params, &nparams,
                                   virPyDomainBlockCopyParams,
                                   VIR_N_ELEMENTS(virPyDomainBlockCopyParams)) < 0) {
            return NULL; 
        }     
    } else {
        PyErr_Format(PyExc_TypeError, "block params must be a dictionary");
        return NULL; 
    }

The correct check should allow dict or None.

--- Additional comment from Peter Krempa on 2019-03-12 09:17:06 CET ---

Broken in:
$ git desc --contains 2b4bd07e0a22
v4.10.0~4
Will be fixed in 5.2.0

commit 5d6228d4171c0a9d1299ad742dc878092287675a (HEAD -> master, origin/master, origin/HEAD)
Author: Nir Soffer <nirsof>
Date:   Mon Mar 11 23:34:50 2019 +0200

    Fix handling of optional params in blockCopy()
    
    Commit 2b4bd07e0a22 (Add check for params, nparams being a dictionary)
    changed the way the optional params argument is treated. If
    libvirt.virDomain.blockCopy() is called without specifying params,
    params is None, and the call will fail with:
    
        TypeError: block params must be a dictionary
    
    This is wrong as params is defined as kwarg, breaking existing libvirt
    users like oVirt. Add a check for Py_None, so we accept either a dict or
    None and fail with TypeError with anything else.
    
    Resolves: https://bugzilla.redhat.com/1687114
    
    Signed-off-by: Nir Soffer <nsoffer>

Comment 1 lcheng 2019-04-11 05:50:16 UTC
I can reproduce this issue on python3-libvirt-5.0.0-3.module+el8+2836+c71eecaf.x86_64.


Steps to reproduce:
# python
Python 3.6.8 (default, Jan 11 2019, 02:17:16) 
[GCC 8.2.1 20180905 (Red Hat 8.2.1-3)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import libvirt
>>> conn = libvirt.open()
>>> dom = conn.lookupByName('test')
>>> diskxml = "<disk><source file='/tmp/test-api-blockcopy.img'/></disk>"
>>> dom.blockCopy('vda', diskxml, libvirt.VIR_DOMAIN_BLOCK_COPY_SHALLOW)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.6/site-packages/libvirt.py", line 728, in blockCopy
    ret = libvirtmod.virDomainBlockCopy(self._o, disk, destxml, params, flags)
TypeError: block params must be a dictionary

Comment 6 lcheng 2019-06-14 11:17:50 UTC
Verified on python3-libvirt-5.0.0-4.module+el8.0.1+3317+6e0079ab.x86_64. The result is expected. Move to VERIFIED.

# python
Python 3.6.8 (default, Jan 11 2019, 02:17:16) 
[GCC 8.2.1 20180905 (Red Hat 8.2.1-3)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import libvirt
>>> conn = libvirt.open()
>>> dom = conn.lookupByName('test')
>>> domxml = dom.XMLDesc(0)
>>> diskxml = "<disk><source file='/tmp/test-api-blockcopy.img'/></disk>"
>>> dom.blockCopy('vda', diskxml, None, libvirt.VIR_DOMAIN_BLOCK_COPY_SHALLOW)
0
>>> dom.destroy()
0
>>> dom = conn.createXML(domxml, 0)
>>> dom.blockCopy('vda', diskxml, {'bandwidth': 2000}, libvirt.VIR_DOMAIN_BLOCK_COPY_SHALLOW)
0
>>> dom.destroy()
0
>>> dom = conn.createXML(domxml, 0)
>>> dom.blockCopy('vda', diskxml, {}, libvirt.VIR_DOMAIN_BLOCK_COPY_SHALLOW)
0
>>> dom.blockCopy('vda', diskxml, libvirt.VIR_DOMAIN_BLOCK_COPY_SHALLOW)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.6/site-packages/libvirt.py", line 728, in blockCopy
    ret = libvirtmod.virDomainBlockCopy(self._o, disk, destxml, params, flags)
TypeError: block params must be a dictionary

Comment 8 errata-xmlrpc 2019-08-07 10:41:10 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2019:2395


Note You need to log in before you can comment on or make changes to this bug.