tools: add qvm-run --service
Make it convenient wrapper around qrexec-client{-vm}, which would start a VM, wait for user session etc.
This commit is contained in:
parent
f5e102177c
commit
38abd81ea8
@ -63,6 +63,12 @@ Options
|
|||||||
Run the command without GUI forwarding enabled. Can be switched back with
|
Run the command without GUI forwarding enabled. Can be switched back with
|
||||||
:option:`--gui`.
|
:option:`--gui`.
|
||||||
|
|
||||||
|
.. option:: --service
|
||||||
|
|
||||||
|
Start RPC service instead of shell command. Specify name of the service in
|
||||||
|
place of *COMMAND* argument. You can also specify service argument, appending
|
||||||
|
it to the service name after `+` character.
|
||||||
|
|
||||||
.. option:: --colour-output=COLOUR, --color-output=COLOR
|
.. option:: --colour-output=COLOUR, --color-output=COLOR
|
||||||
|
|
||||||
Mark the qube output with given ANSI colour (ie. "31" for red). The exact
|
Mark the qube output with given ANSI colour (ie. "31" for red). The exact
|
||||||
|
@ -262,3 +262,35 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase):
|
|||||||
('test-vm', 'qubes.VMShell', b'command; exit\n')
|
('test-vm', 'qubes.VMShell', b'command; exit\n')
|
||||||
])
|
])
|
||||||
self.assertAllCalled()
|
self.assertAllCalled()
|
||||||
|
|
||||||
|
def test_007_run_service_with_gui(self):
|
||||||
|
self.app.expected_calls[
|
||||||
|
('dom0', 'admin.vm.List', None, None)] = \
|
||||||
|
b'0\x00test-vm class=AppVM state=Running\n'
|
||||||
|
self.app.expected_calls[
|
||||||
|
('test-vm', 'admin.vm.property.Get', 'default_user', None)] = \
|
||||||
|
b'0\x00default=yes type=str user'
|
||||||
|
# self.app.expected_calls[
|
||||||
|
# ('test-vm', 'admin.vm.List', None, None)] = \
|
||||||
|
# b'0\x00test-vm class=AppVM state=Running\n'
|
||||||
|
ret = qubesadmin.tools.qvm_run.main(
|
||||||
|
['--service', 'test-vm', 'service.name'],
|
||||||
|
app=self.app)
|
||||||
|
self.assertEqual(ret, 0)
|
||||||
|
# make sure we have the same instance below
|
||||||
|
self.assertEqual(self.app.service_calls, [
|
||||||
|
('test-vm', 'qubes.WaitForSession', {
|
||||||
|
'stdout': subprocess.DEVNULL,
|
||||||
|
'stderr': subprocess.DEVNULL,
|
||||||
|
}),
|
||||||
|
('test-vm', 'qubes.WaitForSession', b'user'),
|
||||||
|
('test-vm', 'service.name', {
|
||||||
|
'filter_esc': True,
|
||||||
|
'localcmd': None,
|
||||||
|
'stdout': subprocess.DEVNULL,
|
||||||
|
'stderr': subprocess.DEVNULL,
|
||||||
|
'user': None,
|
||||||
|
}),
|
||||||
|
('test-vm', 'service.name', b''),
|
||||||
|
])
|
||||||
|
self.assertAllCalled()
|
||||||
|
@ -86,6 +86,10 @@ parser.add_argument('--no-filter-escape-chars',
|
|||||||
help='do not filter terminal escape sequences; DANGEROUS when output is a'
|
help='do not filter terminal escape sequences; DANGEROUS when output is a'
|
||||||
' terminal emulator')
|
' terminal emulator')
|
||||||
|
|
||||||
|
parser.add_argument('--service',
|
||||||
|
action='store_true', dest='service',
|
||||||
|
help='run a qrexec service (named by COMMAND) instead of shell command')
|
||||||
|
|
||||||
parser.add_argument('cmd', metavar='COMMAND',
|
parser.add_argument('cmd', metavar='COMMAND',
|
||||||
help='command to run')
|
help='command to run')
|
||||||
|
|
||||||
@ -136,7 +140,7 @@ def main(args=None, app=None):
|
|||||||
run_kwargs['stderr'] = None
|
run_kwargs['stderr'] = None
|
||||||
|
|
||||||
if isinstance(args.app, qubesadmin.app.QubesLocal) and \
|
if isinstance(args.app, qubesadmin.app.QubesLocal) and \
|
||||||
not args.passio and not args.localcmd:
|
not args.passio and not args.localcmd and args.service:
|
||||||
# wait=False works only in dom0; but it's still useful, to save on
|
# wait=False works only in dom0; but it's still useful, to save on
|
||||||
# simultaneous vchan connections
|
# simultaneous vchan connections
|
||||||
run_kwargs['wait'] = False
|
run_kwargs['wait'] = False
|
||||||
@ -172,13 +176,20 @@ def main(args=None, app=None):
|
|||||||
if args.passio and not args.localcmd:
|
if args.passio and not args.localcmd:
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
loop.add_signal_handler(signal.SIGCHLD, loop.stop)
|
loop.add_signal_handler(signal.SIGCHLD, loop.stop)
|
||||||
proc = vm.run_service('qubes.VMShell',
|
if args.service:
|
||||||
user=args.user,
|
proc = vm.run_service(args.cmd,
|
||||||
localcmd=args.localcmd,
|
user=args.user,
|
||||||
filter_esc=args.filter_esc,
|
localcmd=args.localcmd,
|
||||||
**run_kwargs)
|
filter_esc=args.filter_esc,
|
||||||
proc.stdin.write(vm.prepare_input_for_vmshell(args.cmd))
|
**run_kwargs)
|
||||||
proc.stdin.flush()
|
else:
|
||||||
|
proc = vm.run_service('qubes.VMShell',
|
||||||
|
user=args.user,
|
||||||
|
localcmd=args.localcmd,
|
||||||
|
filter_esc=args.filter_esc,
|
||||||
|
**run_kwargs)
|
||||||
|
proc.stdin.write(vm.prepare_input_for_vmshell(args.cmd))
|
||||||
|
proc.stdin.flush()
|
||||||
if args.passio and not args.localcmd:
|
if args.passio and not args.localcmd:
|
||||||
asyncio.ensure_future(loop.connect_read_pipe(
|
asyncio.ensure_future(loop.connect_read_pipe(
|
||||||
functools.partial(DataCopyProtocol, proc.stdin,
|
functools.partial(DataCopyProtocol, proc.stdin,
|
||||||
|
Loading…
Reference in New Issue
Block a user