On 12/17/19 6:41 PM, Cole Robinson wrote:
> On 12/2/19 10:03 AM, Daniel P. Berrangé wrote:
>> The driver URI scheme:
>>
>> "$drivername:///embed?root=/some/path"
>>
>> enables a new way to use the drivers by embedding them directly in the
>> calling process. To use this the process must have a thread running the
>> libvirt event loop. This URI will then cause libvirt to dynamically load
>> the driver module and call its global initialization function. This
>> syntax is applicable to any driver, but only those will have been
>> modified to support a custom root directory and embed URI path will
>> successfully open.
>>
>> The application can now make normal libvirt API calls which are all
>> serviced in-process with no RPC layer involved.
>>
>> It is required to specify an explicit root directory, and locks will be
>> acquired on this directory to avoid conflicting with another app that
>> might accidentally pick the same directory.
>>
>> Use of '/' is not explicitly forbidden, but note that the file layout
>> used underneath the embedded driver root does not match the file
>> layout used by system/session mode drivers. So this cannot be used as
>> a backdoor to interact with, or fake, the system/session mode drivers.
>>
>> Libvirt will create arbitrary files underneath this root directory. The
>> root directory can be kept untouched across connection open attempts if
>> the application needs persistence. The application is responsible for
>> purging everything underneath this root directory when finally no longer
>> required.
>>
>> Even when a virt driver is used in embedded mode, it is still possible
>> for it to in turn use functionality that calls out to other secondary
>> drivers in libvirtd. For example an embedded instance of QEMU can open
>> the network, secret or storage drivers in the system libvirtd.
>>
>> That said, the application would typically want to at least open an
>> embedded secret driver ("secret:///embed?root=/some/path"). Note that
>> multiple different embedded drivers can use the same root prefix and
>> co-operate just as they would inside a normal libvirtd daemon.
>>
>> A key thing to note is that for this to work, the application that links
>> to libvirt *MUST* be built with -Wl,--export-dynamic to ensure that
>> symbols from libvirt.so are exported & thus available to the dynamically
>> loaded driver module. If libvirt.so itself was dynamically loaded then
>> RTLD_GLOBAL must be passed to dlopen().
>>
>> Signed-off-by: Daniel P. Berrangé <[email protected]>
>> ---
>> src/driver-state.h | 1 +
>> src/driver.h | 2 ++
>> src/libvirt.c | 72 ++++++++++++++++++++++++++++++++++++++++++++--
>> 3 files changed, 73 insertions(+), 2 deletions(-)
>>
>> diff --git a/src/driver-state.h b/src/driver-state.h
>> index 1e2f6ed247..6b3f501e05 100644
>> --- a/src/driver-state.h
>> +++ b/src/driver-state.h
>> @@ -50,6 +50,7 @@ typedef virStateDriver *virStateDriverPtr;
>>
>> struct _virStateDriver {
>> const char *name;
>> + bool initialized;
>> virDrvStateInitialize stateInitialize;
>> virDrvStateCleanup stateCleanup;
>> virDrvStateReload stateReload;
>> diff --git a/src/driver.h b/src/driver.h
>> index ca82ac974b..6278aa05b3 100644
>> --- a/src/driver.h
>> +++ b/src/driver.h
>> @@ -82,6 +82,8 @@ struct _virConnectDriver {
>> bool localOnly;
>> /* Whether driver needs a server in the URI */
>> bool remoteOnly;
>> + /* Whether driver can be used in embedded mode */
>> + bool embeddable;
>> /*
>> * NULL terminated list of supported URI schemes.
>> * - Single element { NULL } list indicates no supported schemes
>> diff --git a/src/libvirt.c b/src/libvirt.c
>> index bd2952d036..17b6506faa 100644
>> --- a/src/libvirt.c
>> +++ b/src/libvirt.c
>> @@ -52,6 +52,7 @@
>> # include "rpc/virnettlscontext.h"
>> #endif
>> #include "vircommand.h"
>> +#include "virevent.h"
>> #include "virfile.h"
>> #include "virrandom.h"
>> #include "viruri.h"
>> @@ -84,6 +85,7 @@
>> #ifdef WITH_BHYVE
>> # include "bhyve/bhyve_driver.h"
>> #endif
>> +#include "access/viraccessmanager.h"
>>
>> #define VIR_FROM_THIS VIR_FROM_NONE
>>
>> @@ -676,10 +678,12 @@ virStateInitialize(bool privileged,
>> return -1;
>>
>> for (i = 0; i < virStateDriverTabCount; i++) {
>> - if (virStateDriverTab[i]->stateInitialize) {
>> + if (virStateDriverTab[i]->stateInitialize &&
>> + !virStateDriverTab[i]->initialized) {
>> virDrvStateInitResult ret;
>> VIR_DEBUG("Running global init for %s state driver",
>> virStateDriverTab[i]->name);
>> + virStateDriverTab[i]->initialized = true;
>> ret = virStateDriverTab[i]->stateInitialize(privileged,
>> root,
>> callback,
>> @@ -872,6 +876,7 @@ virConnectOpenInternal(const char *name,
>> virConnectPtr ret;
>> g_autoptr(virConf) conf = NULL;
>> char *uristr = NULL;
>> + bool embed = false;
>>
>> ret = virGetConnect();
>> if (ret == NULL)
>> @@ -962,6 +967,52 @@ virConnectOpenInternal(const char *name,
>> ret->uri) < 0) {
>> goto failed;
>> }
>> +
>> + if (STREQ(ret->uri->path, "/embed")) {
>> + const char *root = NULL;
>> + g_autofree char *regMethod = NULL;
>> + VIR_DEBUG("URI path requests %s driver embedded mode",
>> + ret->uri->scheme);
>> + if (strspn(ret->uri->scheme, "abcdefghijklmnopqrstuvwxyz") !=
>> + strlen(ret->uri->scheme)) {
>> + virReportError(VIR_ERR_NO_CONNECT,
>> + _("URI scheme '%s' for embedded driver is
>> not valid"),
>> + ret->uri->scheme);
>> + goto failed;
>> + }
>> +
>> + for (i = 0; i < ret->uri->paramsCount; i++) {
>> + virURIParamPtr var = &ret->uri->params[i];
>> + if (STREQ(var->name, "root"))
>> + root = var->value;
>> + }
>> +
>> + if (!root) {
>> + virReportError(VIR_ERR_INVALID_ARG, "%s",
>> + _("root parameter required for embedded
>> driver"));
>> + goto failed;
>> + }
>> +
>> + if (virEventRequireImpl() < 0)
>> + goto failed;
>> +
>> + regMethod = g_strdup_printf("%sRegister", ret->uri->scheme);
>> +
>> + if (virDriverLoadModule(ret->uri->scheme, regMethod, false) < 0)
>> + goto failed;
>> +
>> + if (virAccessManagerGetDefault() == NULL) {
>> + virAccessManagerPtr acl = virAccessManagerNew("none");
>> + if (!acl)
>> + goto failed;
>> + virAccessManagerSetDefault(acl);
>> + }
>> +
>> + if (virStateInitialize(geteuid() == 0, true, root, NULL, NULL)
>> < 0)
>> + goto failed;
>> +
>> + embed = true;
>> + }
>
> It would be nice if this logic was moved to a separate function
>
> I've hit a couple issues in testing, not sure if/where the fixes will
> live, so I'll just mention them here. Also the reviewed patches are
> pushable IMO
>
> I tried this code:
>
> from gi.repository import LibvirtGLib
>
> import libvirt
>
>
>
> LibvirtGLib.init(None)
>
> LibvirtGLib.event_register()
>
>
>
> conn1 = libvirt.open("qemu:///embed?root=/tmp/foo")
>
> conn2 = libvirt.open("qemu:///embed?root=/tmp/bar")
>
> print(conn1.listAllDomains())
>
> print(conn2.listAllDomains())
I didn't get this far, when I wanted to run virt-install all I can see
is the following error:
[Tue, 17 Dec 2019 20:22:39 virt-install 129850] ERROR (cli:259) this
function is not supported by the connection driver: An event loop
implementation must be registered
which I tracked to here:
<no frame> <no attribute num on current thread> $ r
/home/zippy/work/virt-manager.git/virt-install --connect
"qemu:///embed?root=/tmp/a" --name f31-uefi --ram 2048 --disk none
--boot uefi --import --debug
Starting program: /usr/bin/python
/home/zippy/work/virt-manager.git/virt-install --connect
"qemu:///embed?root=/tmp/a" --name f31-uefi --ram 2048 --disk none
--boot uefi --import --debug
process 129850 is executing new program: /usr/bin/python3.6m
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[Tue, 17 Dec 2019 20:21:34 virt-install 129850] DEBUG (cli:203) Launched
with command line: /home/zippy/work/virt-manager.git/virt-install
--connect qemu:///embed?root=/tmp/a --name f31-uefi --ram 2048 --disk
none --boot uefi --import --debug
[Tue, 17 Dec 2019 20:21:34 virt-install 129850] DEBUG (virt-install:208)
Distilled --network options: ['default']
[Tue, 17 Dec 2019 20:21:34 virt-install 129850] DEBUG (virt-install:140)
Distilled --disk options: ['none']
[Tue, 17 Dec 2019 20:21:34 virt-install 129850] DEBUG (cli:219)
Requesting libvirt URI qemu:///embed?root=/tmp/a
Breakpoint 1, virEventRequireImpl () at ../../src/util/virevent.c:268
268 if (!addHandleImpl || !addTimeoutImpl) {
virEventRequireImpl 1 $ bt
#0 0x00007ffff693ca53 in virEventRequireImpl () at
../../src/util/virevent.c:268
#1 0x00007ffff6bd2c33 in virConnectOpenInternal (name=0x7ffff710bdd0
"qemu:///embed?root=/tmp/a", auth=0x7fffffffc8a0, flags=0) at
../../src/libvirt.c:996
#2 0x00007ffff6bd38ab in virConnectOpenAuth (name=0x7ffff710bdd0
"qemu:///embed?root=/tmp/a", auth=0x7fffffffc8a0, flags=0) at
../../src/libvirt.c:1272
#3 0x00007ffff6e17b55 in libvirt_virConnectOpenAuth () at
/usr/lib64/python3.6/site-packages/libvirtmod.cpython-36m-x86_64-linux-gnu.so
But this looks weird, isn't virt-install registerin an event loop? How
else does it get events?
Michal
--
libvir-list mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/libvir-list