[PATCH v3 0/2] allow migrations with the ext transport
[MCA: I've now adopted these patches from Sergey] 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. v2 -> v3: - fix passing of extArgs v1 -> v2: - new way of passing argv Sergey Dyasli (2): remote: allow passing argv to the ext transport remote: allow migrations with the ext transport 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.0
From: Sergey Dyasli <sergey.dyasli@nutanix.com> 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> Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com> --- 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 ec71eaed87..5c574eff37 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.0
From: Sergey Dyasli <sergey.dyasli@nutanix.com> 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> Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com> --- 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 db9eea5774..b7e1036ba4 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 5c574eff37..33b9dec196 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 64995da342..2e8c0acfb2 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 ad00570b7f..172314bd10 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.0
participants (1)
-
Mark Cave-Ayland