Browse Source

Fix asyncio.Lock usage for Python 3.9+

'with (yield from alock):' is incompatible with Python 3.9+.

Change it to 'async with alock:', and then change the affected functions
to 'async def'.

This makes the test suite pass again in a Fedora 33 VM.

QubesOS/qubes-issues#2738
Rusty Bird 3 years ago
parent
commit
a7fe59449a
4 changed files with 59 additions and 67 deletions
  1. 3 4
      qubes/api/admin.py
  2. 3 4
      qubes/storage/__init__.py
  3. 3 4
      qubes/storage/callback.py
  4. 50 55
      qubes/vm/qubesvm.py

+ 3 - 4
qubes/api/admin.py

@@ -1191,13 +1191,12 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
 
 
     @qubes.api.method('admin.vm.Remove', no_payload=True,
     @qubes.api.method('admin.vm.Remove', no_payload=True,
         scope='global', write=True)
         scope='global', write=True)
-    @asyncio.coroutine
-    def vm_remove(self):
+    async def vm_remove(self):
         self.enforce(not self.arg)
         self.enforce(not self.arg)
 
 
         self.fire_event_for_permission()
         self.fire_event_for_permission()
 
 
-        with (yield from self.dest.startup_lock):
+        async with self.dest.startup_lock:
             if not self.dest.is_halted():
             if not self.dest.is_halted():
                 raise qubes.exc.QubesVMNotHaltedError(self.dest)
                 raise qubes.exc.QubesVMNotHaltedError(self.dest)
 
 
@@ -1207,7 +1206,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
 
 
             del self.app.domains[self.dest]
             del self.app.domains[self.dest]
             try:
             try:
-                yield from self.dest.remove_from_disk()
+                await self.dest.remove_from_disk()
             except:  # pylint: disable=bare-except
             except:  # pylint: disable=bare-except
                 self.app.log.exception('Error while removing VM \'%s\' files',
                 self.app.log.exception('Error while removing VM \'%s\' files',
                     self.dest.name)
                     self.dest.name)

+ 3 - 4
qubes/storage/__init__.py

@@ -168,11 +168,10 @@ class Volume:
         >>>def start(self):
         >>>def start(self):
         >>>    pass
         >>>    pass
         '''
         '''
-        @asyncio.coroutine
         @functools.wraps(method)
         @functools.wraps(method)
-        def wrapper(self, *args, **kwargs):
-            with (yield from self._lock):  # pylint: disable=protected-access
-                return (yield from method(self, *args, **kwargs))
+        async def wrapper(self, *args, **kwargs):
+            async with self._lock:  # pylint: disable=protected-access
+                return await method(self, *args, **kwargs)
         return wrapper
         return wrapper
 
 
     def create(self):
     def create(self):

+ 3 - 4
qubes/storage/callback.py

@@ -242,15 +242,14 @@ class CallbackPool(qubes.storage.Pool):
             cmd = self._cb_conf.get('cmd')
             cmd = self._cb_conf.get('cmd')
         return bool(cmd and cmd != '-')
         return bool(cmd and cmd != '-')
 
 
-    @asyncio.coroutine
-    def _init(self, callback=True):
+    async def _init(self, callback=True):
         ''' Late storage initialization on first use for e.g. decryption on first usage request.
         ''' Late storage initialization on first use for e.g. decryption on first usage request.
         :param callback: Whether to trigger the `pre_sinit` callback or not.
         :param callback: Whether to trigger the `pre_sinit` callback or not.
         '''
         '''
-        with (yield from self._cb_init_lock):
+        async with self._cb_init_lock:
             if self._cb_requires_init:
             if self._cb_requires_init:
                 if callback:
                 if callback:
-                    yield from self._callback('pre_sinit')
+                    await self._callback('pre_sinit')
                 self._cb_requires_init = False
                 self._cb_requires_init = False
 
 
     @asyncio.coroutine
     @asyncio.coroutine

+ 50 - 55
qubes/vm/qubesvm.py

@@ -1060,12 +1060,11 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
     # methods for changing domain state
     # methods for changing domain state
     #
     #
 
 
-    @asyncio.coroutine
-    def _ensure_shutdown_handled(self):
+    async def _ensure_shutdown_handled(self):
         """Make sure previous shutdown is fully handled.
         """Make sure previous shutdown is fully handled.
         MUST NOT be called when domain is running.
         MUST NOT be called when domain is running.
         """
         """
-        with (yield from self._domain_stopped_lock):
+        async with self._domain_stopped_lock:
             # Don't accept any new stopped event's till a new VM has been
             # Don't accept any new stopped event's till a new VM has been
             # created. If we didn't received any stopped event or it wasn't
             # created. If we didn't received any stopped event or it wasn't
             # handled yet we will handle this in the next lines.
             # handled yet we will handle this in the next lines.
@@ -1086,11 +1085,10 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
                 # twice if an exception gets thrown.
                 # twice if an exception gets thrown.
                 self._domain_stopped_event_handled = True
                 self._domain_stopped_event_handled = True
 
 
-                yield from self.fire_event_async('domain-stopped')
-                yield from self.fire_event_async('domain-shutdown')
+                await self.fire_event_async('domain-stopped')
+                await self.fire_event_async('domain-shutdown')
 
 
-    @asyncio.coroutine
-    def start(self, start_guid=True, notify_function=None,
+    async def start(self, start_guid=True, notify_function=None,
               mem_required=None):
               mem_required=None):
         """Start domain
         """Start domain
 
 
@@ -1099,7 +1097,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
         :param int mem_required: FIXME
         :param int mem_required: FIXME
         """
         """
 
 
-        with (yield from self.startup_lock):
+        async with self.startup_lock:
             # check if domain wasn't removed in the meantime
             # check if domain wasn't removed in the meantime
             if self not in self.app.domains:
             if self not in self.app.domains:
                 raise qubes.exc.QubesVMNotFoundError(self.name)
                 raise qubes.exc.QubesVMNotFoundError(self.name)
@@ -1108,19 +1106,19 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
             if self.get_power_state() != 'Halted':
             if self.get_power_state() != 'Halted':
                 return self
                 return self
 
 
-            yield from self._ensure_shutdown_handled()
+            await self._ensure_shutdown_handled()
 
 
             self.log.info('Starting {}'.format(self.name))
             self.log.info('Starting {}'.format(self.name))
 
 
             try:
             try:
-                yield from self.fire_event_async('domain-pre-start',
-                                                 pre_event=True,
-                                                 start_guid=start_guid,
-                                                 mem_required=mem_required)
+                await self.fire_event_async('domain-pre-start',
+                                            pre_event=True,
+                                            start_guid=start_guid,
+                                            mem_required=mem_required)
             except Exception as exc:
             except Exception as exc:
                 self.log.error('Start failed: %s', str(exc))
                 self.log.error('Start failed: %s', str(exc))
-                yield from self.fire_event_async('domain-start-failed',
-                                                 reason=str(exc))
+                await self.fire_event_async('domain-start-failed',
+                                            reason=str(exc))
                 raise
                 raise
 
 
             qmemman_client = None
             qmemman_client = None
@@ -1135,26 +1133,26 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
                 if self.virt_mode == 'pvh' and not self.kernel:
                 if self.virt_mode == 'pvh' and not self.kernel:
                     raise qubes.exc.QubesException(
                     raise qubes.exc.QubesException(
                         'virt_mode PVH require kernel to be set')
                         'virt_mode PVH require kernel to be set')
-                yield from self.storage.verify()
+                await self.storage.verify()
 
 
                 if self.netvm is not None:
                 if self.netvm is not None:
                     # pylint: disable = no-member
                     # pylint: disable = no-member
                     if self.netvm.qid != 0:
                     if self.netvm.qid != 0:
                         if not self.netvm.is_running():
                         if not self.netvm.is_running():
-                            yield from self.netvm.start(
+                            await self.netvm.start(
                                 start_guid=start_guid,
                                 start_guid=start_guid,
                                 notify_function=notify_function)
                                 notify_function=notify_function)
 
 
-                qmemman_client = yield from asyncio.get_event_loop(). \
+                qmemman_client = await asyncio.get_event_loop(). \
                     run_in_executor(None, self.request_memory, mem_required)
                     run_in_executor(None, self.request_memory, mem_required)
 
 
-                yield from self.storage.start()
+                await self.storage.start()
 
 
             except Exception as exc:
             except Exception as exc:
                 self.log.error('Start failed: %s', str(exc))
                 self.log.error('Start failed: %s', str(exc))
                 # let anyone receiving domain-pre-start know that startup failed
                 # let anyone receiving domain-pre-start know that startup failed
-                yield from self.fire_event_async('domain-start-failed',
-                                                 reason=str(exc))
+                await self.fire_event_async('domain-start-failed',
+                                            reason=str(exc))
                 if qmemman_client:
                 if qmemman_client:
                     qmemman_client.close()
                     qmemman_client.close()
                 raise
                 raise
@@ -1179,16 +1177,16 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
                         'Failed to start an HVM qube with PCI devices assigned '
                         'Failed to start an HVM qube with PCI devices assigned '
                         '- hardware does not support IOMMU/VT-d/AMD-Vi')
                         '- hardware does not support IOMMU/VT-d/AMD-Vi')
                 self.log.error('Start failed: %s', str(exc))
                 self.log.error('Start failed: %s', str(exc))
-                yield from self.fire_event_async('domain-start-failed',
-                                                 reason=str(exc))
-                yield from self.storage.stop()
+                await self.fire_event_async('domain-start-failed',
+                                            reason=str(exc))
+                await self.storage.stop()
                 raise exc
                 raise exc
             except Exception as exc:
             except Exception as exc:
                 self.log.error('Start failed: %s', str(exc))
                 self.log.error('Start failed: %s', str(exc))
                 # let anyone receiving domain-pre-start know that startup failed
                 # let anyone receiving domain-pre-start know that startup failed
-                yield from self.fire_event_async('domain-start-failed',
-                                                 reason=str(exc))
-                yield from self.storage.stop()
+                await self.fire_event_async('domain-start-failed',
+                                            reason=str(exc))
+                await self.storage.stop()
                 raise
                 raise
 
 
             finally:
             finally:
@@ -1199,21 +1197,21 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
             self._domain_stopped_event_handled = False
             self._domain_stopped_event_handled = False
 
 
             try:
             try:
-                yield from self.fire_event_async('domain-spawn',
-                                                 start_guid=start_guid)
+                await self.fire_event_async('domain-spawn',
+                                            start_guid=start_guid)
 
 
                 self.log.info('Setting Qubes DB info for the VM')
                 self.log.info('Setting Qubes DB info for the VM')
-                yield from self.start_qubesdb()
+                await self.start_qubesdb()
                 self.create_qdb_entries()
                 self.create_qdb_entries()
                 self.start_qdb_watch()
                 self.start_qdb_watch()
 
 
                 self.log.warning('Activating the {} VM'.format(self.name))
                 self.log.warning('Activating the {} VM'.format(self.name))
                 self.libvirt_domain.resume()
                 self.libvirt_domain.resume()
 
 
-                yield from self.start_qrexec_daemon()
+                await self.start_qrexec_daemon()
 
 
-                yield from self.fire_event_async('domain-start',
-                                                 start_guid=start_guid)
+                await self.fire_event_async('domain-start',
+                                            start_guid=start_guid)
 
 
             except Exception as exc:  # pylint: disable=bare-except
             except Exception as exc:  # pylint: disable=bare-except
                 self.log.error('Start failed: %s', str(exc))
                 self.log.error('Start failed: %s', str(exc))
@@ -1221,13 +1219,13 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
                 # raised in self._kill_locked(), because the vm is not
                 # raised in self._kill_locked(), because the vm is not
                 # running or paused
                 # running or paused
                 try:
                 try:
-                    yield from self._kill_locked()
+                    await self._kill_locked()
                 except qubes.exc.QubesVMNotStartedError:
                 except qubes.exc.QubesVMNotStartedError:
                     pass
                     pass
 
 
                 # let anyone receiving domain-pre-start know that startup failed
                 # let anyone receiving domain-pre-start know that startup failed
-                yield from self.fire_event_async('domain-start-failed',
-                                                 reason=str(exc))
+                await self.fire_event_async('domain-start-failed',
+                                            reason=str(exc))
                 raise
                 raise
 
 
         return self
         return self
@@ -1255,9 +1253,8 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
         self._domain_stopped_future = \
         self._domain_stopped_future = \
             asyncio.ensure_future(self._domain_stopped_coro())
             asyncio.ensure_future(self._domain_stopped_coro())
 
 
-    @asyncio.coroutine
-    def _domain_stopped_coro(self):
-        with (yield from self._domain_stopped_lock):
+    async def _domain_stopped_coro(self):
+        async with self._domain_stopped_lock:
             assert not self._domain_stopped_event_handled
             assert not self._domain_stopped_event_handled
 
 
             # Set this immediately such that we don't generate events twice if
             # Set this immediately such that we don't generate events twice if
@@ -1265,9 +1262,9 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
             self._domain_stopped_event_handled = True
             self._domain_stopped_event_handled = True
 
 
             while self.get_power_state() == 'Dying':
             while self.get_power_state() == 'Dying':
-                yield from asyncio.sleep(0.25)
-            yield from self.fire_event_async('domain-stopped')
-            yield from self.fire_event_async('domain-shutdown')
+                await asyncio.sleep(0.25)
+            await self.fire_event_async('domain-stopped')
+            await self.fire_event_async('domain-shutdown')
 
 
     @qubes.events.handler('domain-stopped')
     @qubes.events.handler('domain-stopped')
     @asyncio.coroutine
     @asyncio.coroutine
@@ -1282,8 +1279,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
         self.fire_event('property-reset:stubdom_xid', name='stubdom_xid')
         self.fire_event('property-reset:stubdom_xid', name='stubdom_xid')
         self.fire_event('property-reset:start_time', name='start_time')
         self.fire_event('property-reset:start_time', name='start_time')
 
 
-    @asyncio.coroutine
-    def shutdown(self, force=False, wait=False, timeout=None):
+    async def shutdown(self, force=False, wait=False, timeout=None):
         """Shutdown domain.
         """Shutdown domain.
 
 
         :param force: ignored
         :param force: ignored
@@ -1298,8 +1294,8 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
             raise qubes.exc.QubesVMNotStartedError(self)
             raise qubes.exc.QubesVMNotStartedError(self)
 
 
         try:
         try:
-            yield from self.fire_event_async('domain-pre-shutdown',
-                                             pre_event=True, force=force)
+            await self.fire_event_async('domain-pre-shutdown',
+                                        pre_event=True, force=force)
 
 
             self.libvirt_domain.shutdown()
             self.libvirt_domain.shutdown()
 
 
@@ -1307,23 +1303,22 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
                 if timeout is None:
                 if timeout is None:
                     timeout = self.shutdown_timeout
                     timeout = self.shutdown_timeout
                 while timeout > 0 and not self.is_halted():
                 while timeout > 0 and not self.is_halted():
-                    yield from asyncio.sleep(0.25)
+                    await asyncio.sleep(0.25)
                     timeout -= 0.25
                     timeout -= 0.25
-                with (yield from self.startup_lock):
+                async with self.startup_lock:
                     if self.is_halted():
                     if self.is_halted():
                         # make sure all shutdown tasks are completed
                         # make sure all shutdown tasks are completed
-                        yield from self._ensure_shutdown_handled()
+                        await self._ensure_shutdown_handled()
                     else:
                     else:
                         raise qubes.exc.QubesVMShutdownTimeoutError(self)
                         raise qubes.exc.QubesVMShutdownTimeoutError(self)
         except Exception as ex:
         except Exception as ex:
-            yield from self.fire_event_async('domain-shutdown-failed',
-                                             reason=str(ex))
+            await self.fire_event_async('domain-shutdown-failed',
+                                        reason=str(ex))
             raise
             raise
 
 
         return self
         return self
 
 
-    @asyncio.coroutine
-    def kill(self):
+    async def kill(self):
         """Forcefully shutdown (destroy) domain.
         """Forcefully shutdown (destroy) domain.
 
 
         :raises qubes.exc.QubesVMNotStartedError: \
         :raises qubes.exc.QubesVMNotStartedError: \
@@ -1333,8 +1328,8 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
         if not self.is_running() and not self.is_paused():
         if not self.is_running() and not self.is_paused():
             raise qubes.exc.QubesVMNotStartedError(self)
             raise qubes.exc.QubesVMNotStartedError(self)
 
 
-        with (yield from self.startup_lock):
-            yield from self._kill_locked()
+        async with self.startup_lock:
+            await self._kill_locked()
 
 
         return self
         return self