From cb7f191bd2347f26a9e71713c0f7a91b4f4e2061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Marczewski?= Date: Wed, 29 Jul 2020 10:00:20 +0200 Subject: [PATCH] qvm-start-daemon: convert to async/await syntax --- ci/requirements.txt | 1 + qubesadmin/tests/tools/qvm_start_daemon.py | 13 +++--- qubesadmin/tools/qvm_start_daemon.py | 46 +++++++--------------- 3 files changed, 23 insertions(+), 37 deletions(-) diff --git a/ci/requirements.txt b/ci/requirements.txt index 99d1a075..d89e9448 100644 --- a/ci/requirements.txt +++ b/ci/requirements.txt @@ -9,3 +9,4 @@ mock lxml PyYAML xcffib +asynctest diff --git a/qubesadmin/tests/tools/qvm_start_daemon.py b/qubesadmin/tests/tools/qvm_start_daemon.py index bf61f55d..43079c83 100644 --- a/qubesadmin/tests/tools/qvm_start_daemon.py +++ b/qubesadmin/tests/tools/qvm_start_daemon.py @@ -23,9 +23,10 @@ import tempfile import unittest.mock import re - import asyncio +import asynctest + import qubesadmin.tests import qubesadmin.tools.qvm_start_daemon from qubesadmin.tools.qvm_start_daemon import GUI_DAEMON_OPTIONS @@ -207,7 +208,7 @@ def test_013_common_args_guid_config(self): } ''') - @unittest.mock.patch('asyncio.create_subprocess_exec') + @asynctest.patch('asyncio.create_subprocess_exec') def test_020_start_gui_for_vm(self, proc_mock): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) @@ -238,7 +239,7 @@ def test_020_start_gui_for_vm(self, proc_mock): self.assertAllCalled() - @unittest.mock.patch('asyncio.create_subprocess_exec') + @asynctest.patch('asyncio.create_subprocess_exec') def test_021_start_gui_for_vm_hvm(self, proc_mock): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) @@ -307,7 +308,7 @@ def test_022_start_gui_for_vm_hvm_stubdom(self): pidfile.flush() self.addCleanup(pidfile.close) - patch_proc = unittest.mock.patch('asyncio.create_subprocess_exec') + patch_proc = asynctest.patch('asyncio.create_subprocess_exec') patch_args = unittest.mock.patch.object(self.launcher, 'common_guid_args', lambda vm: []) @@ -350,7 +351,7 @@ def test_030_start_gui_for_stubdomain(self): None)] = \ b'2\x00QubesFeatureNotFoundError\x00\x00Feature not set\x00' proc_mock = unittest.mock.Mock() - with unittest.mock.patch('asyncio.create_subprocess_exec', + with asynctest.patch('asyncio.create_subprocess_exec', lambda *args: self.mock_coroutine(proc_mock, *args)): with unittest.mock.patch.object(self.launcher, @@ -384,7 +385,7 @@ def test_031_start_gui_for_stubdomain_forced(self): None)] = \ b'0\x001' proc_mock = unittest.mock.Mock() - with unittest.mock.patch('asyncio.create_subprocess_exec', + with asynctest.patch('asyncio.create_subprocess_exec', lambda *args: self.mock_coroutine(proc_mock, *args)): with unittest.mock.patch.object(self.launcher, diff --git a/qubesadmin/tools/qvm_start_daemon.py b/qubesadmin/tools/qvm_start_daemon.py index 291de09e..804ade25 100644 --- a/qubesadmin/tools/qvm_start_daemon.py +++ b/qubesadmin/tools/qvm_start_daemon.py @@ -32,20 +32,12 @@ import daemon.pidfile import qubesadmin +import qubesadmin.events import qubesadmin.exc import qubesadmin.tools import qubesadmin.vm from . import xcffibhelpers -have_events = False -try: - # pylint: disable=wrong-import-position - import qubesadmin.events - - have_events = True -except ImportError: - pass - GUI_DAEMON_PATH = '/usr/bin/qubes-guid' PACAT_DAEMON_PATH = '/usr/bin/pacat-simple-vchan' QUBES_ICON_DIR = '/usr/share/icons/hicolor/128x128/devices' @@ -331,8 +323,7 @@ def __init__(self, app: qubesadmin.app.QubesBase): self.started_processes = {} self.kde = False - @asyncio.coroutine - def send_monitor_layout(self, vm, layout=None, startup=False): + async def send_monitor_layout(self, vm, layout=None, startup=False): """Send monitor layout to a given VM This function is a coroutine. @@ -367,7 +358,7 @@ def send_monitor_layout(self, vm, layout=None, startup=False): pass try: - yield from asyncio.get_event_loop(). \ + await asyncio.get_event_loop(). \ run_in_executor(None, functools.partial( vm.run_service_for_stdio, @@ -476,8 +467,7 @@ def pacat_domid(vm): else vm.xid return xid - @asyncio.coroutine - def start_gui_for_vm(self, vm, monitor_layout=None): + async def start_gui_for_vm(self, vm, monitor_layout=None): """Start GUI daemon (qubes-guid) connected directly to a VM This function is a coroutine. @@ -503,13 +493,12 @@ def start_gui_for_vm(self, vm, monitor_layout=None): vm.log.info('Starting GUI') - yield from asyncio.create_subprocess_exec(*guid_cmd) + await asyncio.create_subprocess_exec(*guid_cmd) - yield from self.send_monitor_layout(vm, layout=monitor_layout, + await self.send_monitor_layout(vm, layout=monitor_layout, startup=True) - @asyncio.coroutine - def start_gui_for_stubdomain(self, vm, force=False): + async def start_gui_for_stubdomain(self, vm, force=False): """Start GUI daemon (qubes-guid) connected to a stubdomain This function is a coroutine. @@ -533,10 +522,9 @@ def start_gui_for_stubdomain(self, vm, force=False): guid_cmd = self.common_guid_args(vm) guid_cmd.extend(['-d', str(vm.stubdom_xid), '-t', str(vm.xid)]) - yield from asyncio.create_subprocess_exec(*guid_cmd) + await asyncio.create_subprocess_exec(*guid_cmd) - @asyncio.coroutine - def start_audio_for_vm(self, vm): + async def start_audio_for_vm(self, vm): """Start AUDIO daemon (pacat-simple-vchan) connected directly to a VM This function is a coroutine. @@ -547,10 +535,9 @@ def start_audio_for_vm(self, vm): pacat_cmd = [PACAT_DAEMON_PATH, '-l', self.pacat_domid(vm), vm.name] vm.log.info('Starting AUDIO') - yield from asyncio.create_subprocess_exec(*pacat_cmd) + await asyncio.create_subprocess_exec(*pacat_cmd) - @asyncio.coroutine - def start_gui(self, vm, force_stubdom=False, monitor_layout=None): + async def start_gui(self, vm, force_stubdom=False, monitor_layout=None): """Start GUI daemon regardless of start event. This function is a coroutine. @@ -566,16 +553,15 @@ def start_gui(self, vm, force_stubdom=False, monitor_layout=None): return if vm.virt_mode == 'hvm': - yield from self.start_gui_for_stubdomain(vm, force=force_stubdom) + await self.start_gui_for_stubdomain(vm, force=force_stubdom) if not vm.features.check_with_template('gui', True): return if not os.path.exists(self.guid_pidfile(vm.xid)): - yield from self.start_gui_for_vm(vm, monitor_layout=monitor_layout) + await self.start_gui_for_vm(vm, monitor_layout=monitor_layout) - @asyncio.coroutine - def start_audio(self, vm): + async def start_audio(self, vm): """Start AUDIO daemon regardless of start event. This function is a coroutine. @@ -592,7 +578,7 @@ def start_audio(self, vm): xid = self.pacat_domid(vm) if not os.path.exists(self.pacat_pidfile(xid)): - yield from self.start_audio_for_vm(vm) + await self.start_audio_for_vm(vm) def on_domain_spawn(self, vm, _event, **kwargs): """Handler of 'domain-spawn' event, starts GUI daemon for stubdomain""" @@ -718,8 +704,6 @@ def main(args=None): if args.kde: launcher.kde = True if args.watch: - if not have_events: - parser.error('--watch option require Python >= 3.5') with daemon.pidfile.TimeoutPIDLockFile(args.pidfile): loop = asyncio.get_event_loop() # pylint: disable=no-member