diff --git a/nova/tests/virt/libvirt/fakelibvirt.py b/nova/tests/virt/libvirt/fakelibvirt.py index badef2922dc2..ee64936d8aa0 100644 --- a/nova/tests/virt/libvirt/fakelibvirt.py +++ b/nova/tests/virt/libvirt/fakelibvirt.py @@ -642,6 +642,9 @@ class Connection(object): def domainEventRegisterAny(self, dom, eventid, callback, opaque): self._event_callbacks[eventid] = [callback, opaque] + def registerCloseCallback(self, cb, opaque): + pass + def getCapabilities(self): """Return spoofed capabilities.""" return ''' diff --git a/nova/tests/virt/libvirt/test_libvirt.py b/nova/tests/virt/libvirt/test_libvirt.py index 3809ce3320c7..dcf51dbeba36 100644 --- a/nova/tests/virt/libvirt/test_libvirt.py +++ b/nova/tests/virt/libvirt/test_libvirt.py @@ -705,8 +705,15 @@ class LibvirtConnTestCase(test.TestCase): self.assertThat(expected, matchers.DictMatches(result)) def test_close_callback(self): - def get_lib_version_stub(): - return (1 * 1000 * 1000) + (0 * 1000) + 1 + class FakeConn(object): + 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 @@ -714,32 +721,80 @@ class LibvirtConnTestCase(test.TestCase): self.close_callback = cb 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(self.conn, 'registerCloseCallback') + self.mox.StubOutWithMock(conn._conn, 'registerCloseCallback') self.mox.StubOutWithMock(conn, 'set_host_enabled') - conn._connect(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.conn) - self.conn.registerCloseCallback( - mox.IgnoreArg(), mox.IgnoreArg()).WithSideEffects( - set_close_callback) + conn._connect(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(conn._conn) + conn._conn.registerCloseCallback( + mox.IgnoreArg(), mox.IgnoreArg() + ).WithSideEffects(set_close_callback) conn.set_host_enabled('fake-mini', True) 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) - self.conn.registerCloseCallback(mox.IgnoreArg(), mox.IgnoreArg()) + conn._conn.registerCloseCallback(mox.IgnoreArg(), mox.IgnoreArg()) self.mox.ReplayAll() # verify that the driver registers for the close callback # and re-connects after receiving the callback - conn._get_connection() + conn._get_new_connection() self.assertTrue(self.close_callback) - self.close_callback(self.conn, 1, None) + self.close_callback(conn._conn, 1, None) conn._get_connection() 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): conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) @@ -7606,18 +7661,26 @@ class LibvirtNonblockingTestCase(test.TestCase): jsonutils.to_primitive(connection._conn, convert_instances=True) def test_tpool_execute_calls_libvirt(self): - self.mox.StubOutWithMock(eventlet.tpool, 'execute') conn = libvirt.virConnect() conn.is_expected = True + + self.mox.StubOutWithMock(eventlet.tpool, 'execute') eventlet.tpool.execute( - libvirt.openAuth, 'test:///default', - mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(conn) + libvirt.openAuth, + 'test:///default', + mox.IgnoreArg(), + mox.IgnoreArg()).AndReturn(conn) eventlet.tpool.execute( conn.domainEventRegisterAny, None, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, mox.IgnoreArg(), mox.IgnoreArg()) + if hasattr(libvirt.virConnect, 'registerCloseCallback'): + eventlet.tpool.execute( + conn.registerCloseCallback, + mox.IgnoreArg(), + mox.IgnoreArg()) self.mox.ReplayAll() driver = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index a70725691ef4..ffea1ebbb681 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -323,7 +323,6 @@ MIN_LIBVIRT_VERSION = (0, 9, 6) # When the above version matches/exceeds this version # delete it & corresponding code using it MIN_LIBVIRT_HOST_CPU_VERSION = (0, 9, 10) -MIN_LIBVIRT_CLOSE_CALLBACK_VERSION = (1, 0, 1) MIN_LIBVIRT_DEVICE_CALLBACK_VERSION = (1, 1, 1) # Live snapshot requirements REQ_HYPERVISOR_LIVESNAPSHOT = "QEMU" @@ -634,7 +633,7 @@ class LibvirtDriver(driver.ComputeDriver): self._wrapped_conn = wrapped_conn try: - LOG.debug(_("Registering for lifecycle events %s") % str(self)) + LOG.debug(_("Registering for lifecycle events %s"), self) wrapped_conn.domainEventRegisterAny( None, 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"), {'uri': self.uri(), 'error': e}) - if self._has_min_version(wrapped_conn, - MIN_LIBVIRT_CLOSE_CALLBACK_VERSION): - try: - LOG.debug(_("Registering for connection events: %s") % - str(self)) - wrapped_conn.registerCloseCallback( - self._close_callback, None) - except libvirt.libvirtError as e: - LOG.warn(_("URI %(uri)s does not support connection" - " events: %(error)s"), - {'uri': self.uri(), 'error': e}) + try: + LOG.debug(_("Registering for connection events: %s") % + str(self)) + wrapped_conn.registerCloseCallback(self._close_callback, None) + except (TypeError, AttributeError) as e: + # NOTE: The registerCloseCallback of python-libvirt 1.0.1+ + # is defined with 3 arguments, and the above registerClose- + # Callback succeeds. However, the one of python-libvirt 1.0.0 + # is defined with 4 arguments and TypeError happens here. + # Then python-libvirt 0.9 does not define a method register- + # 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