diff --git a/qubesadmin/app.py b/qubesadmin/app.py index 52c01ac..98e6a63 100644 --- a/qubesadmin/app.py +++ b/qubesadmin/app.py @@ -494,6 +494,7 @@ class QubesLocal(QubesBase): :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 + :param int connect_timeout: qrexec client connection timeout :rtype: subprocess.Popen ''' @@ -516,6 +517,8 @@ class QubesLocal(QubesBase): user = 'DEFAULT' if not wait: qrexec_opts.extend(['-e']) + if 'connect_timeout' in kwargs: + qrexec_opts.extend(['-w', str(kwargs.pop('connect_timeout'))]) kwargs.setdefault('stdin', subprocess.PIPE) kwargs.setdefault('stdout', subprocess.PIPE) kwargs.setdefault('stderr', subprocess.PIPE) diff --git a/qubesadmin/tests/tools/qvm_run.py b/qubesadmin/tests/tools/qvm_run.py index 9f510ea..0db6950 100644 --- a/qubesadmin/tests/tools/qvm_run.py +++ b/qubesadmin/tests/tools/qvm_run.py @@ -343,6 +343,9 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase): b'0\0disp123' self.app.expected_calls[('disp123', 'admin.vm.Kill', None, None)] = \ b'0\0' + self.app.expected_calls[ + ('disp123', 'admin.vm.property.Get', 'qrexec_timeout', None)] = \ + b'0\0default=yes type=int 30' ret = qubesadmin.tools.qvm_run.main( ['--dispvm', '--service', 'test.service'], app=self.app) self.assertEqual(ret, 0) @@ -352,6 +355,7 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase): 'stdout': subprocess.DEVNULL, 'stderr': subprocess.DEVNULL, 'user': None, + 'connect_timeout': 30, }), ('disp123', 'test.service', b''), ]) @@ -364,6 +368,9 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase): b'0\0disp123' self.app.expected_calls[('disp123', 'admin.vm.Kill', None, None)] = \ b'0\0' + self.app.expected_calls[ + ('disp123', 'admin.vm.property.Get', 'qrexec_timeout', None)] = \ + b'0\0default=yes type=int 30' ret = qubesadmin.tools.qvm_run.main( ['--dispvm=test-vm', '--service', 'test.service'], app=self.app) self.assertEqual(ret, 0) @@ -373,6 +380,7 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase): 'stdout': subprocess.DEVNULL, 'stderr': subprocess.DEVNULL, 'user': None, + 'connect_timeout': 30, }), ('disp123', 'test.service', b''), ]) diff --git a/qubesadmin/tests/vm/dispvm.py b/qubesadmin/tests/vm/dispvm.py index c186b12..5ec6ca1 100644 --- a/qubesadmin/tests/vm/dispvm.py +++ b/qubesadmin/tests/vm/dispvm.py @@ -28,11 +28,14 @@ class TC_00_Dispvm(qubesadmin.tests.QubesTestCase): ('dom0', 'admin.vm.CreateDisposable', None, None)] = b'0\0disp123' self.app.expected_calls[ ('disp123', 'admin.vm.Kill', None, None)] = b'0\0' + self.app.expected_calls[ + ('disp123', 'admin.vm.property.Get', 'qrexec_timeout', None)] = \ + b'0\0default=yes type=int 30' vm = qubesadmin.vm.DispVM.from_appvm(self.app, None) (stdout, stderr) = vm.run_service_for_stdio('test.service') vm.cleanup() self.assertEqual(self.app.service_calls, [ - ('disp123', 'test.service', {}), + ('disp123', 'test.service', {'connect_timeout': 30}), ('disp123', 'test.service', b''), ]) self.assertAllCalled() @@ -44,11 +47,14 @@ class TC_00_Dispvm(qubesadmin.tests.QubesTestCase): b'0\0disp123' self.app.expected_calls[ ('disp123', 'admin.vm.Kill', None, None)] = b'0\0' + self.app.expected_calls[ + ('disp123', 'admin.vm.property.Get', 'qrexec_timeout', None)] = \ + b'0\0default=yes type=int 30' vm = qubesadmin.vm.DispVM.from_appvm(self.app, 'test-vm') (stdout, stderr) = vm.run_service_for_stdio('test.service') vm.cleanup() self.assertEqual(self.app.service_calls, [ - ('disp123', 'test.service', {}), + ('disp123', 'test.service', {'connect_timeout': 30}), ('disp123', 'test.service', b''), ]) self.assertAllCalled() diff --git a/qubesadmin/vm/__init__.py b/qubesadmin/vm/__init__.py index c08850d..bad85c4 100644 --- a/qubesadmin/vm/__init__.py +++ b/qubesadmin/vm/__init__.py @@ -350,6 +350,9 @@ class DispVMWrapper(QubesVM): 'admin.vm.CreateDisposable') dispvm = dispvm.decode('ascii') self._method_dest = dispvm + # Service call may wait for session start, give it more time + # than default 5s + kwargs['connect_timeout'] = self.qrexec_timeout return super(DispVMWrapper, self).run_service(service, **kwargs) def cleanup(self):