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