Browse Source

vm/qubesvm: emit event on failed startup

If VM startup failed before starting anything (even in paused state),
there will be no further event, not even domain-shutdown. This makes it
hard for event-listening applications (like domains tray) to account
domain state. Fix this by emiting domain-start-failed event in every
case of failed startup after emiting domain-pre-start.

Related QubesOS/qubes-issues#3100
Marek Marczykowski-Górecki 6 years ago
parent
commit
efe600537e
1 changed files with 30 additions and 12 deletions
  1. 30 12
      qubes/vm/qubesvm.py

+ 30 - 12
qubes/vm/qubesvm.py

@@ -839,17 +839,24 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
                 pre_event=True,
                 start_guid=start_guid, mem_required=mem_required)
 
-            yield from self.storage.verify()
-
-            if self.netvm is not None:
-                # pylint: disable = no-member
-                if self.netvm.qid != 0:
-                    if not self.netvm.is_running():
-                        yield from self.netvm.start(start_guid=start_guid,
-                            notify_function=notify_function)
-
-            qmemman_client = yield from asyncio.get_event_loop().\
-                run_in_executor(None, self.request_memory, mem_required)
+            try:
+                yield from self.storage.verify()
+
+                if self.netvm is not None:
+                    # pylint: disable = no-member
+                    if self.netvm.qid != 0:
+                        if not self.netvm.is_running():
+                            yield from self.netvm.start(start_guid=start_guid,
+                                notify_function=notify_function)
+
+                qmemman_client = yield from asyncio.get_event_loop().\
+                    run_in_executor(None, self.request_memory, mem_required)
+
+            except Exception as exc:
+                # let anyone receiving domain-pre-start know that startup failed
+                yield from self.fire_event_async('domain-start-failed',
+                    reason=str(exc))
+                raise
 
             try:
                 yield from self.storage.start()
@@ -857,6 +864,13 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
 
                 self.libvirt_domain.createWithFlags(
                     libvirt.VIR_DOMAIN_START_PAUSED)
+
+            except Exception as exc:
+                # let anyone receiving domain-pre-start know that startup failed
+                yield from self.fire_event_async('domain-start-failed',
+                    reason=str(exc))
+                raise
+
             finally:
                 if qmemman_client:
                     qmemman_client.close()
@@ -877,12 +891,16 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
                 yield from self.fire_event_async('domain-start',
                     start_guid=start_guid)
 
-            except:  # pylint: disable=bare-except
+            except Exception as exc:  # pylint: disable=bare-except
                 if self.is_running() or self.is_paused():
                     # This avoids losing the exception if an exception is
                     # raised in self.force_shutdown(), because the vm is not
                     # running or paused
                     yield from self.kill()  # pylint: disable=not-an-iterable
+
+                # let anyone receiving domain-pre-start know that startup failed
+                yield from self.fire_event_async('domain-start-failed',
+                    reason=str(exc))
                 raise
 
         return self