Add 'wait' argument to vm.run_service()

It is supported only from dom0, but it's still useful to have, to save
on simultaneous vchan connections (only waiting for MSG_DATA_EXIT_CODE).
This is especially important for Windows VMs, as qrexec-agent there have
pretty low limit on simultaneous connections (about 20).

Make qvm-run use it.
This commit is contained in:
Marek Marczykowski-Górecki 2017-05-19 17:30:46 +02:00
parent bbd0beb830
commit 938fc9348f
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
2 changed files with 27 additions and 3 deletions

View File

@ -310,7 +310,7 @@ class QubesBase(qubesadmin.base.PropertyHolder):
return self.domains[new_name]
def run_service(self, dest, service, filter_esc=False, user=None,
localcmd=None, **kwargs):
localcmd=None, wait=True, **kwargs):
'''Run qrexec service in a given destination
*kwargs* are passed verbatim to :py:meth:`subprocess.Popen`.
@ -358,7 +358,7 @@ class QubesLocal(QubesBase):
return self._parse_qubesd_response(return_data)
def run_service(self, dest, service, filter_esc=False, user=None,
localcmd=None, **kwargs):
localcmd=None, wait=True, **kwargs):
'''Run qrexec service in a given destination
:param str dest: Destination - may be a VM name or empty
@ -368,11 +368,14 @@ class QubesLocal(QubesBase):
emulator
:param str user: username to run service as
:param str localcmd: Command to connect stdin/stdout to
:param bool wait: wait for remote process to finish
:rtype: subprocess.Popen
'''
if not dest:
raise ValueError('Empty destination name allowed only from a VM')
if not wait and localcmd:
raise ValueError('wait=False incompatible with localcmd')
try:
self.qubesd_call(dest, 'admin.vm.Start')
except qubesadmin.exc.QubesVMNotHaltedError:
@ -384,6 +387,8 @@ class QubesLocal(QubesBase):
qrexec_opts.extend(['-l', localcmd])
if user is None:
user = 'DEFAULT'
if not wait:
qrexec_opts.extend(['-e'])
kwargs.setdefault('stdin', subprocess.PIPE)
kwargs.setdefault('stdout', subprocess.PIPE)
kwargs.setdefault('stderr', subprocess.PIPE)
@ -418,7 +423,7 @@ class QubesRemote(QubesBase):
return self._parse_qubesd_response(stdout)
def run_service(self, dest, service, filter_esc=False, user=None,
localcmd=None, **kwargs):
localcmd=None, wait=True, **kwargs):
'''Run qrexec service in a given destination
:param str dest: Destination - may be a VM name or empty
@ -428,6 +433,7 @@ class QubesRemote(QubesBase):
emulator
:param str user: username to run service as
:param str localcmd: Command to connect stdin/stdout to
:param bool wait: wait for process to finish
:rtype: subprocess.Popen
'''
if filter_esc:
@ -436,6 +442,18 @@ class QubesRemote(QubesBase):
if user:
raise ValueError(
'non-default user not possible for calls from VM')
if not wait and localcmd:
raise ValueError('wait=False incompatible with localcmd')
if not wait:
# qrexec-client-vm can only request service calls, which are
# started using MSG_EXEC_CMDLINE qrexec protocol message; this
# message means "start the process, pipe its stdin/out/err,
# and when it terminates, send exit code back".
# According to the protocol qrexec-client-vm needs to wait for
# MSG_DATA_EXIT_CODE, so implementing wait=False would require
# some protocol change (or protocol violation).
raise NotImplementedError(
'wait=False not implemented for calls from VM')
kwargs.setdefault('stdin', subprocess.PIPE)
kwargs.setdefault('stdout', subprocess.PIPE)
kwargs.setdefault('stderr', subprocess.PIPE)

View File

@ -135,6 +135,12 @@ def main(args=None, app=None):
run_kwargs['stdout'] = None
run_kwargs['stderr'] = None
if isinstance(args.app, qubesadmin.app.QubesLocal) and \
not args.passio and not args.localcmd:
# wait=False works only in dom0; but it's still useful, to save on
# simultaneous vchan connections
run_kwargs['wait'] = False
verbose = args.verbose - args.quiet
if args.passio:
verbose -= 1