[Libguestfs] Extending the nbdkit python plugin

Daniel P. Berrangé berrange at redhat.com
Thu Nov 21 14:17:43 UTC 2019


On Thu, Nov 21, 2019 at 01:57:28PM +0000, Richard W.M. Jones wrote:
> We have an nbdkit plugin that lets you write NBD servers in Python.
> An example of an existing Python plugin is here:
> 
>   https://github.com/libguestfs/nbdkit/blob/master/plugins/python/example.py#L1
> 
> This morning I tried to modify the plugin to use the newer nbdkit API
> (version 2).  One of the things that would change would be passing
> flags parameters to some functions, eg:
> 
>   def pwrite (h, buf, offset):
> 
> might become one of these possibilities (where flags is a bitmask):
> 
>   def pwrite (h, buf, offset, flags):
>   def pwrite (h, buf, offset, flags=0):
> 
> The problem is if we did this it would break all existing Python
> plugins.  While we don't guarantee the nbdkit API for non-C languages,
> we do nevertheless have Python plugins that we care about such as the
> rhv-upload-plugin used by virt-v2v.  Having a flag day which breaks
> all existing plugins is very awkward.
> 
> I tried to simply pass the extra arguments from the C code to the
> Python code, and existing plugins break with:
> 
> nbdkit: python[1]: error: ./test.py: pwrite: error: pwrite() takes 3 positional arguments but 4 were given
> 
> One possibility is that we could introspect the plugin to find out how
> many parameters it takes.  This is possible, but very difficult from
> C.  (See https://stackoverflow.com/a/41188411 for how to do it from
> Python).

You can do the introspection in python instead of C.

Instead of having the C code directly call the python plugin code,
write a shim plugin impl that uses the new API contract. This shim
python plugin then introspects the real python plugin and calls it
with the appropriate API contract (if possible).

> Another possibility is we could encourage existing Python plugins to
> add **kwargs to all functions where we might plausibly add extra
> parameters in future, ie. the above would become:
> 
>   def pwrite (h, buf, offset, **kwargs):
> 
> This still requires all Python plugins to change, but at least they
> would remain backwards compatible with old and new nbdkit.  However I
> couldn't actually work out how to make this work because:
> 
>   >>> def test(a, **kwargs):
>   ...   pass
>   ... 
>   >>> test(1)
>   >>> test(1,2)
>   Traceback (most recent call last):
>     File "<stdin>", line 1, in <module>
>   TypeError: test() takes 1 positional argument but 2 were given
> 
> Yet another possibility is the Python plugin itself should declare
> which version of the API it wants, and the C code can then pass the
> correct parameters.  (This is in fact how nbdkit C plugins work).
> This pushes a bunch of work into the C code, but I guess we can deal
> with that.

I would define a new 'api_version()' method for your python
plugins.

Existing plugins don't implement that of course so when your
C code invokes that it'll get an exception, and can assume
the classic API contract for pwrite().

If the plugin implements  'api_version()' returning '1' (or
whatever), then this should inform the C code that the plugin
has the 4 arg variant of pwrite().

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|




More information about the Libguestfs mailing list