qubes/app: reconnect to libvirtd after crash

Sometimes libvirt crashes. After that the connection (and all
vm.libvirt_domain-s) were unusable.

fixes QubesOS/qubes-issues#990
This commit is contained in:
Wojtek Porczyk 2016-05-05 17:19:48 +02:00
parent e3aae7bc17
commit d728f4b9ff

View File

@ -24,7 +24,9 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# #
import collections
import errno import errno
import functools
import grp import grp
import logging import logging
import os import os
@ -61,6 +63,66 @@ import qubes.vm.qubesvm
import qubes.vm.templatevm import qubes.vm.templatevm
class VirDomainWrapper(object):
def __init__(self, connection, vm):
self._connection = connection
self._vm = vm
def _reconnect_if_dead(self):
is_dead = not self._vm.connect().isAlive()
if is_dead:
self._connection._reconnect_if_dead()
self._vm = self._connection._conn.lookupByUUID(self._vm.getUUID())
return is_dead
def __getattr__(self, attrname):
attr = getattr(self._vm, attrname)
if not isinstance(attr, collections.Callable):
return attr
@functools.wraps(attr)
def wrapper(*args, **kwargs):
try:
return attr(*args, **kwargs)
except libvirt.libvirtError as e:
if self._reconnect_if_dead():
return getattr(self._vm, attrname)(*args, **kwargs)
raise
return wrapper
class VirConnectWrapper(object):
def __init__(self, uri):
self._conn = libvirt.open(uri)
def _reconnect_if_dead(self):
is_dead = not self._conn.isAlive()
if is_dead:
self._conn = libvirt.open(self._conn.getURI())
return is_dead
def _wrap_domain(self, ret):
if isinstance(ret, libvirt.virDomain):
ret = VirDomainWrapper(self, ret)
return ret
def __getattr__(self, attrname):
attr = getattr(self._conn, attrname)
if not isinstance(attr, collections.Callable):
return attr
@functools.wraps(attr)
def wrapper(*args, **kwargs):
try:
return self._wrap_domain(attr(*args, **kwargs))
except libvirt.libvirtError as e:
if self._reconnect_if_dead():
return self._wrap_domain(
getattr(self._conn, attrname)(*args, **kwargs))
raise
return wrapper
class VMMConnection(object): class VMMConnection(object):
'''Connection to Virtual Machine Manager (libvirt)''' '''Connection to Virtual Machine Manager (libvirt)'''
@ -102,9 +164,8 @@ class VMMConnection(object):
self._xs = xen.lowlevel.xs.xs() self._xs = xen.lowlevel.xs.xs()
if 'xen.lowlevel.cs' in sys.modules: if 'xen.lowlevel.cs' in sys.modules:
self._xc = xen.lowlevel.xc.xc() self._xc = xen.lowlevel.xc.xc()
self._libvirt_conn = libvirt.open(qubes.config.defaults['libvirt_uri']) self._libvirt_conn = VirConnectWrapper(
if self._libvirt_conn is None: qubes.config.defaults['libvirt_uri'])
raise qubes.exc.QubesException('Failed connect to libvirt driver')
libvirt.registerErrorHandler(self._libvirt_error_handler, None) libvirt.registerErrorHandler(self._libvirt_error_handler, None)
@property @property