[PATCH v2 0/2] allow migrations with the ext transport
Hello, I have a use case for live-migration where the socket of the destination libvirtd is proxied by an mTLS WebSocket proxy. Since there is no WebSocket support in Libvirt, I've decided to use the existing ext transport and point it to a proxy binary on the source host of live-migration. While doing that, I've discovered a couple of roadblocks: 1. There is no way of passing cmdline arguments to the ext program 2. Live-migrations using ext transport fail localhost checks This short series addresses those limitations. Sergey Dyasli (2): remote: allow passing argv to the ext transport remote: allow migrations with the ext transport v1 -> v2: - new way of passing argv src/libvirt-domain.c | 8 +++++--- src/remote/remote_driver.c | 30 ++++++++++++++++++++++++++---- src/util/viruri.c | 32 ++++++++++++++++++++++++++++++++ src/util/viruri.h | 2 ++ 4 files changed, 65 insertions(+), 7 deletions(-) -- 2.43.7
Allow passing arguments to the ext program via the query parameters. The name of each argument is "argv" and it can be repeated multiple times to pass several arguments. URI example: qemu+ext:///system?command=/bin/prog&argv=192.168.0.10&argv=8080 Suggested-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Sergey Dyasli <sergey.dyasli@nutanix.com> --- v1 --> v2: - Renamed the parameters to argv which are gathered into an array now --- src/remote/remote_driver.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index ec71eaed8762..70ec3dee4443 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -805,6 +805,7 @@ static int doRemoteOpenExtractURIArgs(virConnectPtr conn, char **name, char **command, + GPtrArray *extArgs, char **sockname, char **authtype, char **sshauth, @@ -829,6 +830,13 @@ doRemoteOpenExtractURIArgs(virConnectPtr conn, EXTRACT_URI_ARG_STR("name", *name); EXTRACT_URI_ARG_STR("command", *command); + if (STRCASEEQ(var->name, "argv")) { + if (!extArgs) + extArgs = g_ptr_array_new_with_free_func(g_free); + g_ptr_array_add(extArgs, g_strdup(var->value)); + var->ignore = 1; + continue; + } EXTRACT_URI_ARG_STR("socket", *sockname); EXTRACT_URI_ARG_STR("auth", *authtype); EXTRACT_URI_ARG_STR("sshauth", *sshauth); @@ -895,6 +903,7 @@ doRemoteOpen(virConnectPtr conn, g_autofree char *tls_priority = NULL; g_autofree char *name = NULL; g_autofree char *command = NULL; + g_autoptr(GPtrArray) extArgs = NULL; g_autofree char *sockname = NULL; g_autofree char *netcat = NULL; g_autofree char *port = NULL; @@ -945,6 +954,7 @@ doRemoteOpen(virConnectPtr conn, if (doRemoteOpenExtractURIArgs(conn, &name, &command, + extArgs, &sockname, &authtype, &sshauth, @@ -1195,7 +1205,18 @@ doRemoteOpen(virConnectPtr conn, break; case REMOTE_DRIVER_TRANSPORT_EXT: { - char const *cmd_argv[] = { command, NULL }; + size_t nExtArgs = extArgs ? extArgs->len : 0; + g_autofree const char **cmd_argv = NULL; + size_t idx; + + if (!(cmd_argv = g_new0(const char *, nExtArgs + 2))) + goto error; + + cmd_argv[0] = command; + + for (idx = 0; idx < nExtArgs; idx++) + cmd_argv[idx + 1] = g_ptr_array_index(extArgs, idx); + if (!(priv->client = virNetClientNewExternal(cmd_argv))) goto error; -- 2.43.7
Add virURICheckExtCommand() in a similar fashion to the existing virURICheckUnixSocket() and use it for (1) the same host migration check and (2) in remoteConnectOpen(). This allows to migrate VMs using the ext transport, as the external command can act as a proxy to the remote libvirt. Signed-off-by: Sergey Dyasli <sergey.dyasli@nutanix.com> --- v1 -> v2: - no changes --- src/libvirt-domain.c | 8 +++++--- src/remote/remote_driver.c | 7 ++++--- src/util/viruri.c | 32 ++++++++++++++++++++++++++++++++ src/util/viruri.h | 2 ++ 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index ca110bdf8585..9d82b711a17c 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -3605,11 +3605,13 @@ virDomainMigrateCheckNotLocal(const char *dconnuri) return -1; /* - * If someone migrates explicitly to a unix socket, then they have to know - * what they are doing and it most probably was not a mistake. + * If someone migrates explicitly to a unix socket or an ext command, then + * they have to know what they are doing and it most probably was not + * a mistake. */ if ((tempuri->server && STRPREFIX(tempuri->server, "localhost")) || - (!tempuri->server && !virURICheckUnixSocket(tempuri))) { + (!tempuri->server && !virURICheckUnixSocket(tempuri) && + !virURICheckExtCommand(tempuri))) { virReportInvalidArg(dconnuri, "%s", _("Attempt to migrate guest to the same host")); return -1; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 70ec3dee4443..768cbe67f761 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -1377,15 +1377,16 @@ remoteConnectOpen(virConnectPtr conn, return VIR_DRV_OPEN_DECLINED; /* Handle deferring to local drivers if we are dealing with a default - * local URI. (Unknown local socket paths may be proxied to a remote - * host so they are treated as remote too). + * local URI. (Unknown local socket paths and commands may be proxied + * to a remote host so they are treated as remote too). * * Deferring to a local driver is needed if: * - the driver is registered in the current daemon * - if we are running monolithic libvirtd, in which case we consider * even un-registered drivers as local */ - if (!conn->uri->server && !virURICheckUnixSocket(conn->uri)) { + if (!conn->uri->server && !virURICheckUnixSocket(conn->uri) && + !virURICheckExtCommand(conn->uri)) { if (virHasDriverForURIScheme(driver)) return VIR_DRV_OPEN_DECLINED; diff --git a/src/util/viruri.c b/src/util/viruri.c index 64995da3420d..2e8c0acfb213 100644 --- a/src/util/viruri.c +++ b/src/util/viruri.c @@ -421,6 +421,38 @@ virURICheckUnixSocket(virURI *uri) } +/** + * virURICheckExtCommand: + * @uri: URI to check + * + * Check if the URI looks like it refers to a user specified command. In such + * scenario the command might do proxying to a remote server even though the URI + * looks like it is only local. + * + * The "command" parameter is looked for in case insensitive manner, by design. + * + * Returns: true if the URI might be proxied to a remote server + */ +bool +virURICheckExtCommand(virURI *uri) +{ + size_t i = 0; + + if (!uri->scheme) + return false; + + if (STRNEQ_NULLABLE(strchr(uri->scheme, '+'), "+ext")) + return false; + + for (i = 0; i < uri->paramsCount; i++) { + if (STRCASEEQ(uri->params[i].name, "command")) + return true; + } + + return false; +} + + void virURIParamsSetIgnore(virURI *uri, bool ignore, diff --git a/src/util/viruri.h b/src/util/viruri.h index ad00570b7f0d..172314bd1084 100644 --- a/src/util/viruri.h +++ b/src/util/viruri.h @@ -61,6 +61,8 @@ const char *virURIGetParam(virURI *uri, const char *name); bool virURICheckUnixSocket(virURI *uri); +bool virURICheckExtCommand(virURI *uri); + void virURIParamsSetIgnore(virURI *uri, bool ignore, const char *names[]); #define VIR_URI_SERVER(uri) ((uri) && (uri)->server ? (uri)->server : "localhost") -- 2.43.7
participants (1)
-
Sergey Dyasli