diff --git a/qubesadmin/tests/tools/qvm_start_gui.py b/qubesadmin/tests/tools/qvm_start_gui.py index b20503d..bd0a52e 100644 --- a/qubesadmin/tests/tools/qvm_start_gui.py +++ b/qubesadmin/tests/tools/qvm_start_gui.py @@ -268,6 +268,10 @@ class TC_00_qvm_start_gui(qubesadmin.tests.QubesTestCase): self.assertAllCalled() def test_030_start_gui_for_stubdomain(self): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + self.addCleanup(loop.close) + self.app.expected_calls[ ('dom0', 'admin.vm.List', None, None)] = \ b'0\x00test-vm class=AppVM state=Running\n' @@ -277,11 +281,16 @@ class TC_00_qvm_start_gui(qubesadmin.tests.QubesTestCase): self.app.expected_calls[ ('test-vm', 'admin.vm.property.Get', 'stubdom_xid', None)] = \ b'0\x00default=False type=int 3001' - with unittest.mock.patch('asyncio.create_subprocess_exec') as proc_mock: + self.app.expected_calls[ + ('test-vm', 'admin.vm.feature.CheckWithTemplate', 'gui', None)] = \ + b'2\x00QubesFeatureNotFoundError\x00\x00Feature not set\x00' + proc_mock = unittest.mock.Mock() + with unittest.mock.patch('asyncio.create_subprocess_exec', + lambda *args: self.mock_coroutine(proc_mock, *args)): with unittest.mock.patch.object(self.launcher, 'common_guid_args', lambda vm: []): - self.launcher.start_gui_for_stubdomain( - self.app.domains['test-vm']) + loop.run_until_complete(self.launcher.start_gui_for_stubdomain( + self.app.domains['test-vm'])) # common arguments dropped for simplicity proc_mock.assert_called_once_with('-d', '3001', '-t', '3000') @@ -326,7 +335,7 @@ class TC_00_qvm_start_gui(qubesadmin.tests.QubesTestCase): self.launcher, 'start_gui_for_vm', functools.partial( self.mock_coroutine, mock_start_vm)) patch_start_stubdomain = unittest.mock.patch.object( - self.launcher, 'start_gui_for_stubdomain', lambda vm_: + self.launcher, 'start_gui_for_stubdomain', lambda vm_, force: self.mock_coroutine(mock_start_stubdomain, vm_)) try: patch_start_vm.start() diff --git a/qubesadmin/tools/qvm_start_gui.py b/qubesadmin/tools/qvm_start_gui.py index cf2651b..bba5030 100644 --- a/qubesadmin/tools/qvm_start_gui.py +++ b/qubesadmin/tools/qvm_start_gui.py @@ -207,16 +207,28 @@ class GUILauncher(object): yield from self.send_monitor_layout(vm, layout=monitor_layout, startup=True) - def start_gui_for_stubdomain(self, vm): + @asyncio.coroutine + def start_gui_for_stubdomain(self, vm, force=False): '''Start GUI daemon (qubes-guid) connected to a stubdomain This function is a coroutine. ''' + want_stubdom = force + # if no 'gui' feature set at all, assume no gui agent installed + if not want_stubdom and \ + vm.features.check_with_template('gui', None) is None: + want_stubdom = True + if not want_stubdom and vm.debug: + want_stubdom = True + if not want_stubdom: + return + if os.path.exists(self.guid_pidfile(vm.stubdom_xid)): + return vm.log.info('Starting GUI (stubdomain)') guid_cmd = self.common_guid_args(vm) guid_cmd.extend(['-d', str(vm.stubdom_xid), '-t', str(vm.xid)]) - return asyncio.create_subprocess_exec(*guid_cmd) + yield from asyncio.create_subprocess_exec(*guid_cmd) @asyncio.coroutine def start_gui(self, vm, force_stubdom=False, monitor_layout=None): @@ -232,9 +244,8 @@ class GUILauncher(object): return if vm.virt_mode == 'hvm': - if force_stubdom or not os.path.exists(self.guid_pidfile(vm.xid)): - if not os.path.exists(self.guid_pidfile(vm.stubdom_xid)): - yield from self.start_gui_for_stubdomain(vm) + yield from self.start_gui_for_stubdomain(vm, + force=force_stubdom) if not os.path.exists(self.guid_pidfile(vm.xid)): yield from self.start_gui_for_vm(vm, monitor_layout=monitor_layout)