Fix bug with not implemented virConnect.registerCloseCallback

The unit test test_connection_to_primitive fails many times due to
"virConnect instance has no attribute 'registerCloseCallback'".

registerCloseCallback has been added since original(community's)
python-libvirt v1.0.0, and v1.2.0 also contains the method.
However ubuntu cloud's v1.0.1 does not contain the method, and current
version check of python-libvirt does not work.
This patch tries to operate the method and catch TypeError exception if
the method does not exist instead of the version check.

Co-Authored-By: Sahid Orentino Ferdjaoui <sahid.ferdjaoui@cloudwatt.com>
Closes-Bug: #1266711
Change-Id: I4ec9ff9a684639ae5b146f400c90115c83afcda7
This commit is contained in:
Ken'ichi Ohmichi 2014-01-08 06:43:42 +09:00 committed by Sahid Orentino Ferdjaoui
parent b1cf26bab4
commit 85068cc9f6
3 changed files with 99 additions and 28 deletions

View File

@ -642,6 +642,9 @@ class Connection(object):
def domainEventRegisterAny(self, dom, eventid, callback, opaque): def domainEventRegisterAny(self, dom, eventid, callback, opaque):
self._event_callbacks[eventid] = [callback, opaque] self._event_callbacks[eventid] = [callback, opaque]
def registerCloseCallback(self, cb, opaque):
pass
def getCapabilities(self): def getCapabilities(self):
"""Return spoofed capabilities.""" """Return spoofed capabilities."""
return '''<capabilities> return '''<capabilities>

View File

@ -705,8 +705,15 @@ class LibvirtConnTestCase(test.TestCase):
self.assertThat(expected, matchers.DictMatches(result)) self.assertThat(expected, matchers.DictMatches(result))
def test_close_callback(self): def test_close_callback(self):
def get_lib_version_stub(): class FakeConn(object):
return (1 * 1000 * 1000) + (0 * 1000) + 1 def getLibVersion(self):
return (1 * 1000 * 1000) + (0 * 1000) + 1
def domainEventRegisterAny(self, *args, **kwargs):
pass
def registerCloseCallback(self, cb, opaque):
pass
self.close_callback = None self.close_callback = None
@ -714,32 +721,80 @@ class LibvirtConnTestCase(test.TestCase):
self.close_callback = cb self.close_callback = cb
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
self.stubs.Set(self.conn, "getLibVersion", get_lib_version_stub) conn._wrapped_conn = FakeConn()
self.mox.StubOutWithMock(conn, '_connect') self.mox.StubOutWithMock(conn, '_connect')
self.mox.StubOutWithMock(self.conn, 'registerCloseCallback') self.mox.StubOutWithMock(conn._conn, 'registerCloseCallback')
self.mox.StubOutWithMock(conn, 'set_host_enabled') self.mox.StubOutWithMock(conn, 'set_host_enabled')
conn._connect(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.conn) conn._connect(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(conn._conn)
self.conn.registerCloseCallback( conn._conn.registerCloseCallback(
mox.IgnoreArg(), mox.IgnoreArg()).WithSideEffects( mox.IgnoreArg(), mox.IgnoreArg()
set_close_callback) ).WithSideEffects(set_close_callback)
conn.set_host_enabled('fake-mini', True) conn.set_host_enabled('fake-mini', True)
conn.set_host_enabled('fake-mini', 'Connection to libvirt lost: 1') conn.set_host_enabled('fake-mini', 'Connection to libvirt lost: 1')
conn._connect(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.conn) conn._connect(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(conn._conn)
conn.set_host_enabled('fake-mini', True) conn.set_host_enabled('fake-mini', True)
self.conn.registerCloseCallback(mox.IgnoreArg(), mox.IgnoreArg()) conn._conn.registerCloseCallback(mox.IgnoreArg(), mox.IgnoreArg())
self.mox.ReplayAll() self.mox.ReplayAll()
# verify that the driver registers for the close callback # verify that the driver registers for the close callback
# and re-connects after receiving the callback # and re-connects after receiving the callback
conn._get_connection() conn._get_new_connection()
self.assertTrue(self.close_callback) self.assertTrue(self.close_callback)
self.close_callback(self.conn, 1, None) self.close_callback(conn._conn, 1, None)
conn._get_connection() conn._get_connection()
self.mox.UnsetStubs() self.mox.UnsetStubs()
def test_close_callback_bad_signature(self):
class FakeConn(object):
def getLibVersion(self):
return (1 * 1000 * 1000) + (0 * 1000) + 0
def domainEventRegisterAny(self, *args, **kwargs):
pass
def registerCloseCallback(self, cb, opaque, *args, **kwargs):
pass
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
conn._wrapped_conn = FakeConn()
self.mox.StubOutWithMock(conn, '_connect')
self.mox.StubOutWithMock(conn._conn, 'registerCloseCallback')
self.mox.StubOutWithMock(conn, 'set_host_enabled')
conn._connect(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(conn._conn)
conn.set_host_enabled('fake-mini', True)
conn._conn.registerCloseCallback(
mox.IgnoreArg(), mox.IgnoreArg()).AndRaise(TypeError)
self.mox.ReplayAll()
conn._get_new_connection()
def test_close_callback_not_defined(self):
class FakeConn():
def getLibVersion(self):
return (0 * 1000 * 1000) + (9 * 1000) + 0
def domainEventRegisterAny(self, *args, **kwargs):
pass
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
conn._wrapped_conn = FakeConn()
self.mox.StubOutWithMock(conn, '_connect')
self.mox.StubOutWithMock(conn, 'set_host_enabled')
conn._connect(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(
conn._wrapped_conn)
conn.set_host_enabled('fake-mini', True)
self.mox.ReplayAll()
conn._get_new_connection()
def test_cpu_features_bug_1217630(self): def test_cpu_features_bug_1217630(self):
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
@ -7606,18 +7661,26 @@ class LibvirtNonblockingTestCase(test.TestCase):
jsonutils.to_primitive(connection._conn, convert_instances=True) jsonutils.to_primitive(connection._conn, convert_instances=True)
def test_tpool_execute_calls_libvirt(self): def test_tpool_execute_calls_libvirt(self):
self.mox.StubOutWithMock(eventlet.tpool, 'execute')
conn = libvirt.virConnect() conn = libvirt.virConnect()
conn.is_expected = True conn.is_expected = True
self.mox.StubOutWithMock(eventlet.tpool, 'execute')
eventlet.tpool.execute( eventlet.tpool.execute(
libvirt.openAuth, 'test:///default', libvirt.openAuth,
mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(conn) 'test:///default',
mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn(conn)
eventlet.tpool.execute( eventlet.tpool.execute(
conn.domainEventRegisterAny, conn.domainEventRegisterAny,
None, None,
libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE,
mox.IgnoreArg(), mox.IgnoreArg(),
mox.IgnoreArg()) mox.IgnoreArg())
if hasattr(libvirt.virConnect, 'registerCloseCallback'):
eventlet.tpool.execute(
conn.registerCloseCallback,
mox.IgnoreArg(),
mox.IgnoreArg())
self.mox.ReplayAll() self.mox.ReplayAll()
driver = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) driver = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)

View File

@ -323,7 +323,6 @@ MIN_LIBVIRT_VERSION = (0, 9, 6)
# When the above version matches/exceeds this version # When the above version matches/exceeds this version
# delete it & corresponding code using it # delete it & corresponding code using it
MIN_LIBVIRT_HOST_CPU_VERSION = (0, 9, 10) MIN_LIBVIRT_HOST_CPU_VERSION = (0, 9, 10)
MIN_LIBVIRT_CLOSE_CALLBACK_VERSION = (1, 0, 1)
MIN_LIBVIRT_DEVICE_CALLBACK_VERSION = (1, 1, 1) MIN_LIBVIRT_DEVICE_CALLBACK_VERSION = (1, 1, 1)
# Live snapshot requirements # Live snapshot requirements
REQ_HYPERVISOR_LIVESNAPSHOT = "QEMU" REQ_HYPERVISOR_LIVESNAPSHOT = "QEMU"
@ -634,7 +633,7 @@ class LibvirtDriver(driver.ComputeDriver):
self._wrapped_conn = wrapped_conn self._wrapped_conn = wrapped_conn
try: try:
LOG.debug(_("Registering for lifecycle events %s") % str(self)) LOG.debug(_("Registering for lifecycle events %s"), self)
wrapped_conn.domainEventRegisterAny( wrapped_conn.domainEventRegisterAny(
None, None,
libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE,
@ -644,17 +643,23 @@ class LibvirtDriver(driver.ComputeDriver):
LOG.warn(_("URI %(uri)s does not support events: %(error)s"), LOG.warn(_("URI %(uri)s does not support events: %(error)s"),
{'uri': self.uri(), 'error': e}) {'uri': self.uri(), 'error': e})
if self._has_min_version(wrapped_conn, try:
MIN_LIBVIRT_CLOSE_CALLBACK_VERSION): LOG.debug(_("Registering for connection events: %s") %
try: str(self))
LOG.debug(_("Registering for connection events: %s") % wrapped_conn.registerCloseCallback(self._close_callback, None)
str(self)) except (TypeError, AttributeError) as e:
wrapped_conn.registerCloseCallback( # NOTE: The registerCloseCallback of python-libvirt 1.0.1+
self._close_callback, None) # is defined with 3 arguments, and the above registerClose-
except libvirt.libvirtError as e: # Callback succeeds. However, the one of python-libvirt 1.0.0
LOG.warn(_("URI %(uri)s does not support connection" # is defined with 4 arguments and TypeError happens here.
" events: %(error)s"), # Then python-libvirt 0.9 does not define a method register-
{'uri': self.uri(), 'error': e}) # CloseCallback.
LOG.debug(_("The version of python-libvirt does not support "
"registerCloseCallback or is too old: %s"), e)
except libvirt.libvirtError as e:
LOG.warn(_("URI %(uri)s does not support connection"
" events: %(error)s"),
{'uri': self.uri(), 'error': e})
return wrapped_conn return wrapped_conn