[libvirt] Libvirt PHP binding

Radek Hladik radek at eadresa.cz
Tue Apr 14 13:56:28 UTC 2009


Hi,

I am trying to develop PHP binding for Libvirt API. As discussed 
previously on the list the best way is to create a ZEND extension. There 
is a great tutorial on the net ( http://devzone.zend.com/tag/Extension ) 
and PHP provides a lot of macros and functions to make extension writing 
easier.
I've implemented functions for connecting, listing domains, getting info 
about domains and node, dumping domain XML, some basic domain life-cycle 
actions and very basic error reporting. Before moving to other functions 
I need to solve a few issues :-)

The biggest issue is that PHP used from webserver can (and usually does) 
run multithread. One thread can process more than one request and the 
threads can run in parallel. PHP/ZEND provides "tools" to solve this. It 
provides "request-global" variables, resources (containers for objects 
like file handles or connection pointers) and much more. In single 
threaded environment (like calling from command line) all these fallback 
to usual behavior. In addition ZEND has its own memory manager to be 
able to better manage the memory on per request basis (functions are 
called emalloc(), efree(),...). One can still use malloc() and free() 
but this is bypassing the ZEND memory manager. Free()ing emalloced 
memory or vice versa leads to crash.

So one thing is that every memory allocated by libvirt (using malloc()) 
I need to copy to memory allocated using emalloc(). Also every memory, 
that would be free()ed by libvirt I need to malloc() and copy from 
emmaloc()ed memory. The first one is done by simple macro:

#define RECREATE_STRING_WITH_E(str_out, str_in) \	
	 str_out = estrndup(str_in, strlen(str_in)); \
	 free(str_in);	

The second case I encountered only on authentication callback and I use 
simple strndup() to copy it for libvirt.

When running from command line everything seems to work fine. This is of 
course singlethreaded and potential resource leaks need not to cause a 
problem. However when running from webserver, the result is much more 
interesting. When connecting to qemu:///system (via local socket) using
<?
libvirt_connect($uri,true);
?>
I can crash the libvirt daemon after cca 10 page reloads - sometimes 
with message
Apr 13 15:32:44 kvmtest kernel: libvirtd[8263]: segfault at 4 ip 
00000039d7223fc0 sp 00007fa6fbc29a88 error 6 in 
libdbus-1.so.3.4.0[39d7200000+3c000]
in system log, sometimes without any message.
(When running the same script from command line it worked for 1000 
executions without noticing a problem).

When connecting to qemu+tcp:///system using credentials (explained later):
<?
libvirt_connect($uri,true,Array(VIR_CRED_AUTHNAME=>"fred",VIR_CRED_PASSPHRASE=>"fred"));
?>

It works but httpd processes open a lot pipes and after a few hours with 
page refreshing every 10 sec I even ran into error:
[Mon Apr 13 02:40:26 2009] [error] [client 10.38.25.152] PHP Warning: 
libvirt_connect()  unable to make pipe: Too many open files

Next issue I am not sure about is callbacks. I need them mainly for 
authentication. As PHP is intended to run the whole script 
non-interactively at most times, I've created this solution. When 
calling the libvirt_connect() PHP function you can provide list of 
credentials in form of an array 
Array(VIR_CRED_AUTHNAME=>"fred",VIR_CRED_PASSPHRASE=>"fred"). This PHP 
array is parsed to C array and this prepopulated array is passed to my 
authentication callback function. That function receives the requested 
credential, looks it up in the provided array and returns it. I think 
this suits more the PHP nature but in future I may provide real callback 
solution.
Little trouble is that libvirt free()s the values returned by callback 
so I need to copy them to malloc()ed memory.
I am not sure about multithread safety of callback functions but I think 
that if the function only obtains the parameters via cbdata and operates 
only with them then it should be safe. However sometimes I get error:
[Mon Apr 13 14:19:48 2009] [error] [client 10.38.25.152] PHP Warning: 
libvirt_connect(): Failed to collect auth credentials
and I need to restart http daemon for a few times to make it work again.

The last trouble is with error callback, where I am not sure whether it 
is thread safe. I need to call PHP function for reporting error, storing 
the error in "global" variable for next use and the PHP may even 
terminate the whole processing of the request...

And if you are still reading then I can point you to 
http://phplibvirt.cybersales.cz/ where you can download the source code 
and browse the documentation - you can find there list of implemented 
functions and brief instructions how to install the extension. But be 
warned it really can crash your libvirt and maybe apache! For 
completeness: I use Fedora 10 with some rawhide updates:
httpd-2.2.11-6.x86_64
php-5.2.9-1.fc11.x86_64
php-devel-5.2.9-1.fc11.x86_64
libvirt-0.6.0-2.fc11.x86_64
qemu-0.9.1-12.fc11.x86_64
libvirt-devel-0.6.0-2.fc11.x86_64
php-cli-5.2.9-1.fc11.x86_64
kvm-83-5.fc10.x86_64
php-common-5.2.9-1.fc11.x86_64


Radek




More information about the libvir-list mailing list