From: "Denis V. Lunev" <den@openvz.org>
To: Michael Roth <mdroth@linux.vnet.ibm.com>
Cc: Olga Krishtal <okrishtal@parallels.com>,
qemu-devel@nongnu.org, Semen Zolin <szolin@parallels.com>
Subject: Re: [Qemu-devel] [PATCH v2 0/8] qemu: guest agent: implement guest-exec command for Linux
Date: Fri, 9 Jan 2015 21:09:10 +0300 [thread overview]
Message-ID: <54B01946.8070404@openvz.org> (raw)
In-Reply-To: <20150109170621.8810.42855@loki>
On 09/01/15 20:06, Michael Roth wrote:
> Quoting Denis V. Lunev (2014-12-31 07:06:46)
>> hese patches for guest-agent add the functionality to execute commands on
>> a guest UNIX machine.
> Hi Denis,
>
> Glad to see these getting picked up. I did at some point hack up a rewrite
> of the original code though which has some elements might be worth considering
> incorporating into your patchset.
>
> The main one is the use of g_spawn_async_with_pipes(), which wraps fork/exec
> vs. CreateProcess() and allows for more shared code between posix/win32.
>
> It also creates the stdin/out/err FDs for you, which I suppose we could
> do ourselves manually here as well, but it also raises the question of
> whether guest-pipe-open is really necessary. In my code I ended up dropping
> it since I can't imagine a use-case outside of guest-exec, but in doing so
> also I dropped the ability to pipe one process into another...
>
> But thinking about it more I think you can still pipe one process into
> another by dup2()'ing the stdin FD returned by g_spawn_async_with_pipes()
> to whatever stdout/stderr you wish to specify from a previous process.
I do not think that this will be ever used. IMHO nobody will bind
processes in such a way. In the worst case the user will exec
something like 'sh -c "process1 | process2"'. This is better and
shorter.
> The other one worth considering is allowing cmdline to simply be a string,
> to parse it into arguments using g_shell_parse_argv(), which should also
> be cross-platform.
>
> If you do things that the core exec code ends up looking something like
> this:
>
> static GuestExecInfo *guest_exec_spawn(const char *cmdline, bool interactive,
> Error **errp)
> {
> GSpawnFlags default_flags = G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD;
> gboolean ret;
> GPid gpid;
> gchar **argv;
> gint argc;
> GError *gerr = NULL;
> gint fd_in = -1, fd_out = -1, fd_err = -1;
>
> ret = g_shell_parse_argv(cmdline, &argc, &argv, &gerr);
> if (!ret || gerr) {
> error_setg(errp, "failed to parse command: %s, %s", cmdline,
> gerr->message);
> return NULL;
> }
>
> ret = g_spawn_async_with_pipes(NULL, argv, NULL,
> default_flags, NULL, NULL, &gpid,
> interactive ? &fd_in : NULL, &fd_out, &fd_err, &gerr);
> if (gerr) {
> error_setg(errp, "failed to execute command: %s, %s", cmdline,
> gerr->message);
> return NULL;
> }
> if (!ret) {
> error_setg(errp, "failed to execute command");
> return NULL;
> }
>
> return guest_exec_info_new(gpid, cmdline, fd_in, fd_out, fd_err);
> }
>
> GuestExecResponse *qmp_guest_exec_async(const char *cmdline,
> bool has_interactive,
> bool interactive,
> Error **errp)
> {
> GuestExecResponse *ger;
> GuestExecInfo *gei;
> int32_t handle;
>
> gei = guest_exec_spawn(cmdline, has_interactive && interactive, errp);
> if (error_is_set(errp)) {
> return NULL;
> }
>
> print_gei(gei);
> ger = g_new0(GuestExecResponse, 1);
>
> if (has_interactive && interactive) {
> ger->has_handle_stdin = true;
> ger->handle_stdin =
> guest_file_handle_add_fd(gei->fd_in, "a", errp);
> if (error_is_set(errp)) {
> return NULL;
> }
> }
>
> ger->has_handle_stdout = true;
> ger->handle_stdout =
> guest_file_handle_add_fd(gei->fd_out, "r", errp);
> if (error_is_set(errp)) {
> return NULL;
> }
>
> ger->has_handle_stderr = true;
> ger->handle_stderr =
> guest_file_handle_add_fd(gei->fd_err, "r", errp);
> if (error_is_set(errp)) {
> return NULL;
> }
>
> handle = guest_exec_info_register(gei);
> ger->status = qmp_guest_exec_status(handle, false, false, false, 0, errp);
> if (error_is_set(errp)) {
> return NULL;
> }
>
> return ger;
> }
>
> Where GuestExecResponse takes the place of the original PID return, since
> we now need to fetch the stdin/stdout/stderr handles as well. In my code
> it was defined as:
>
> { 'type': 'GuestExecResponse',
> 'data': { 'status': 'GuestExecStatus',
> '*handle-stdin': 'int', '*handle-stdout': 'int',
> '*handle-stderr': 'int' } }
>
> Sorry for not just posting the patchset somewhere, the code was initially lost
> in an accidental wipe of /home so I currently only have vim backup files to
> piece it together from atm.
Frankly speaking this exact interface is not that
convenient for a real life products. The necessity
to poll exec status and to poll input/output
pipes is really boring and really affects the
performance.
Actually there are 2 major scenarios for this:
1. "Enter inside VM", i.e. the user obtains shell
inside VM and works in VM from host f.e. to setup
network
2. Execute command inside VM and collect output
in host.
For both case the proposed interface with guest
pipes is not convenient, in order to obtain interactive
shell in guest we should poll frequently (100 times
in seconds to avoid lag) and in my experience
end-users likes to run a lot of automation scripts
using this channel.
Thus we have used virtserial as a real transport for
case 1) and it is working seamlessly. This means
that we open virtserial in guest for input and output
and connect to Unix socket in host with shell application.
Poll of exec-status is necessary evil, but it does not affect
interactivity and could be done once in a second.
I would be good to have some notifications from
guest that some events are pending (input/output
data or exec status is available). But I do not know
at the moment how to implement this. At least I have
not invested resources into this as I would like
to hear some opinion from the community first.
This patchset is made mostly to initiate the discussion.
Michael, could you spend a bit of time looking
into patches 1 and 2 of the patchset. They have been
implemented and reviewed by us and could be
merged separately in advance. They provides
functional equivalent of already existing Linux (Posix)
functionality.
As for your approach, I would tend to agree with
Eric. It is not safe.
Regards,
Den
next prev parent reply other threads:[~2015-01-09 18:10 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-12-31 13:06 [Qemu-devel] [PATCH v2 0/8] qemu: guest agent: implement guest-exec command for Linux Denis V. Lunev
2014-12-31 13:06 ` [Qemu-devel] [PATCH 1/8] qga: fixed warning in qemu-ga.exe for mingw >= 4.9.1 Denis V. Lunev
2015-02-03 21:29 ` Eric Blake
2015-02-04 14:25 ` Olga Krishtal
2014-12-31 13:06 ` [Qemu-devel] [PATCH 2/8] qga: implement file commands for Windows guest Denis V. Lunev
2015-02-03 21:15 ` Michael Roth
2014-12-31 13:06 ` [Qemu-devel] [PATCH 3/8] guest agent: guest-file-open: refactoring Denis V. Lunev
2015-02-03 22:04 ` Eric Blake
2014-12-31 13:06 ` [Qemu-devel] [PATCH 4/8] guest agent: add guest-pipe-open Denis V. Lunev
2015-02-03 21:57 ` Eric Blake
2015-02-03 22:06 ` Eric Blake
2014-12-31 13:06 ` [Qemu-devel] [PATCH 5/8] guest agent: add guest-exec and guest-exec-status interfaces Denis V. Lunev
2015-02-03 21:45 ` Eric Blake
2014-12-31 13:06 ` [Qemu-devel] [PATCH 6/8] guest agent: ignore SIGPIPE signal Denis V. Lunev
2014-12-31 13:06 ` [Qemu-devel] [PATCH 7/8] guest agent: add guest-pipe-open command on Windows Denis V. Lunev
2014-12-31 13:06 ` [Qemu-devel] [PATCH 8/8] guest agent: add guest-exec and guest-exec-status interfaces " Denis V. Lunev
2015-01-09 17:06 ` [Qemu-devel] [PATCH v2 0/8] qemu: guest agent: implement guest-exec command for Linux Michael Roth
2015-01-09 17:10 ` Eric Blake
2015-01-09 18:09 ` Denis V. Lunev [this message]
2015-01-09 19:29 ` Michael Roth
2015-01-13 10:13 ` Denis V. Lunev
2015-02-03 20:24 ` Michael Roth
2015-02-03 21:31 ` Denis V. Lunev
2015-01-27 13:52 ` Denis V. Lunev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=54B01946.8070404@openvz.org \
--to=den@openvz.org \
--cc=mdroth@linux.vnet.ibm.com \
--cc=okrishtal@parallels.com \
--cc=qemu-devel@nongnu.org \
--cc=szolin@parallels.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).