utils/QubesWatch: use timers to retry QubesDB watch registration

QubesWatch._register_watches is called from libvirt event callback,
asynchronously to qvm-start. This means that `qubesdb-daemon` may
not be running or populated yet.

If first QubesDB connection (or watch registration) fails, schedule next
try using timers in libvirt event API (as it is base of QubesWatch
mainloop), instead of some sleep loop. This way other events will be
processed in the meantime.

QubesOS/qubes-issues#1110
This commit is contained in:
Marek Marczykowski-Górecki 2015-09-25 20:37:44 +02:00
parent 4a4d16feb9
commit 5f0d564051
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724

View File

@ -790,29 +790,41 @@ class QubesWatch(object):
name = libvirt_domain.name() name = libvirt_domain.name()
if name in self._qdb: if name in self._qdb:
return return
if not libvirt_domain.isActive():
return
# open separate connection to Qubes DB: # open separate connection to Qubes DB:
# 1. to not confuse pull() with responses to real commands sent from # 1. to not confuse pull() with responses to real commands sent from
# other threads (like read, write etc) with watch events # other threads (like read, write etc) with watch events
# 2. to not think whether QubesDB is thread-safe (it isn't) # 2. to not think whether QubesDB is thread-safe (it isn't)
while libvirt_domain.isActive() and name not in self._qdb:
try: try:
self._qdb[name] = QubesDB(name) self._qdb[name] = QubesDB(name)
except Error as e: except Error as e:
if e.args[0] != 2: if e.args[0] != 2:
raise raise
time.sleep(0.5) libvirt.virEventAddTimeout(500, self._retry_register_watches,
if name not in self._qdb: libvirt_domain)
# domain no longer active
return return
else: else:
name = "dom0" name = "dom0"
self._qdb[name] = QubesDB(name) self._qdb[name] = QubesDB(name)
try:
self._qdb[name].watch('/qubes-block-devices') self._qdb[name].watch('/qubes-block-devices')
except Error as e:
if e.args[0] == 102: # Connection reset by peer
# QubesDB daemon not running - most likely we've connected to
# stale daemon which just exited; retry later
libvirt.virEventAddTimeout(500, self._retry_register_watches,
libvirt_domain)
return
self._qdb_events[name] = libvirt.virEventAddHandle( self._qdb_events[name] = libvirt.virEventAddHandle(
self._qdb[name].watch_fd(), self._qdb[name].watch_fd(),
libvirt.VIR_EVENT_HANDLE_READABLE, libvirt.VIR_EVENT_HANDLE_READABLE,
self._qdb_handler, name) self._qdb_handler, name)
def _retry_register_watches(self, timer, libvirt_domain):
libvirt.virRemoveTimeout(timer)
self._register_watches(libvirt_domain)
def _unregister_watches(self, libvirt_domain): def _unregister_watches(self, libvirt_domain):
name = libvirt_domain.name() name = libvirt_domain.name()
if name in self._qdb_events: if name in self._qdb_events: