connection: Add infrastructure to blacklist failing objects

It happens every now and then that a libvirt bug means calling XMLDesc
on an object will always fail. For example:

https://bugzilla.redhat.com/show_bug.cgi?id=1225771

We don't handle this very well and it can bleed into many other parts of
the code in a bad way. So if the initial polling of the object fails,
blacklist it entirely and ignore it for all future polling.
This commit is contained in:
Cole Robinson 2015-09-17 15:48:42 -04:00
parent 053cda8de7
commit a9d3cbd6cc
2 changed files with 40 additions and 3 deletions

View File

@ -54,6 +54,7 @@ class _ObjectList(vmmGObject):
vmmGObject.__init__(self)
self._objects = []
self._blacklist = []
self._lock = threading.Lock()
def _cleanup(self):
@ -69,6 +70,29 @@ class _ObjectList(vmmGObject):
finally:
self._lock.release()
def _blacklist_key(self, obj):
return str(obj.__class__) + obj.get_connkey()
def add_blacklist(self, obj):
"""
Add an object to the blacklist. Basically a list of objects we
choose not to poll, because they threw an error at init time
:param obj: vmmLibvirtObject to blacklist
:returns: True if object added, False if object was already in list
"""
if self.in_blacklist(obj):
return False
self._blacklist.append(self._blacklist_key(obj))
return True
def in_blacklist(self, obj):
"""
:param obj: vmmLibvirtObject to check
:returns: True if object is in the blacklist
"""
return self._blacklist_key(obj) in self._blacklist
def remove(self, obj):
"""
Remove an object from the list.
@ -82,6 +106,10 @@ class _ObjectList(vmmGObject):
# Identity check is sufficient here, since we should never be
# asked to remove an object that wasn't at one point in the list.
if obj not in self._objects:
if self.in_blacklist(obj):
self._blacklist.remove(self._blacklist_key(obj))
return True
return False
self._objects.remove(obj)
@ -990,13 +1018,19 @@ class vmmConnection(vmmGObject):
self.emit("nodedev-removed", obj.get_connkey())
obj.cleanup()
def _new_object_cb(self, obj):
def _new_object_cb(self, obj, initialize_failed):
if not self._backend.is_open():
return
try:
class_name = obj.class_name()
if initialize_failed:
logging.debug("Blacklisting %s=%s", class_name, obj.get_name())
if self._objects.add_blacklist(obj) is False:
logging.debug("Object already blacklisted?")
return
if not self._objects.add(obj):
logging.debug("New %s=%s requested, but it's already tracked.",
class_name, obj.get_name())
@ -1074,6 +1108,7 @@ class vmmConnection(vmmGObject):
gone_objects.extend(gone)
preexisting_objects.extend([o for o in master if o not in new])
new = [n for n in new if not self._objects.in_blacklist(n)]
return new
new_vms = _process_objects(self._update_vms(pollvm))

View File

@ -28,7 +28,7 @@ from .baseclass import vmmGObject
class vmmLibvirtObject(vmmGObject):
__gsignals__ = {
"state-changed": (GObject.SignalFlags.RUN_FIRST, None, []),
"initialized": (GObject.SignalFlags.RUN_FIRST, None, []),
"initialized": (GObject.SignalFlags.RUN_FIRST, None, [bool]),
}
_STATUS_ACTIVE = 1
@ -185,14 +185,16 @@ class vmmLibvirtObject(vmmGObject):
if self.__initialized:
return
initialize_failed = False
try:
self._init_libvirt_state()
except:
logging.debug("Error initializing libvirt state for %s", self,
exc_info=True)
initialize_failed = True
self.__initialized = True
self.idle_emit("initialized")
self.idle_emit("initialized", initialize_failed)
###################