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
 | 
			
		||||
   :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
 | 
			
		||||
 | 
			
		||||
   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')
 | 
			
		||||
        ])
 | 
			
		||||
        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'
 | 
			
		||||
        ' 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',
 | 
			
		||||
    help='command to run')
 | 
			
		||||
 | 
			
		||||
@ -136,7 +140,7 @@ def main(args=None, app=None):
 | 
			
		||||
        run_kwargs['stderr'] = None
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
        # simultaneous vchan connections
 | 
			
		||||
        run_kwargs['wait'] = False
 | 
			
		||||
@ -172,13 +176,20 @@ def main(args=None, app=None):
 | 
			
		||||
                if args.passio and not args.localcmd:
 | 
			
		||||
                    loop = asyncio.new_event_loop()
 | 
			
		||||
                    loop.add_signal_handler(signal.SIGCHLD, loop.stop)
 | 
			
		||||
                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.service:
 | 
			
		||||
                    proc = vm.run_service(args.cmd,
 | 
			
		||||
                        user=args.user,
 | 
			
		||||
                        localcmd=args.localcmd,
 | 
			
		||||
                        filter_esc=args.filter_esc,
 | 
			
		||||
                        **run_kwargs)
 | 
			
		||||
                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:
 | 
			
		||||
                    asyncio.ensure_future(loop.connect_read_pipe(
 | 
			
		||||
                        functools.partial(DataCopyProtocol, proc.stdin,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user