Browse Source

tools: add qvm-run --service

Make it convenient wrapper around qrexec-client{-vm}, which would start
a VM, wait for user session etc.
Marek Marczykowski-Górecki 7 years ago
parent
commit
38abd81ea8
3 changed files with 57 additions and 8 deletions
  1. 6 0
      doc/manpages/qvm-run.rst
  2. 32 0
      qubesadmin/tests/tools/qvm_run.py
  3. 19 8
      qubesadmin/tools/qvm_run.py

+ 6 - 0
doc/manpages/qvm-run.rst

@@ -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

+ 32 - 0
qubesadmin/tests/tools/qvm_run.py

@@ -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()

+ 19 - 8
qubesadmin/tools/qvm_run.py

@@ -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,