2323import com .cloud .agent .properties .AgentPropertiesFileHandler ;
2424import org .apache .log4j .Logger ;
2525import org .libvirt .Connect ;
26+ import org .libvirt .Library ;
2627import org .libvirt .LibvirtException ;
2728
2829import com .cloud .hypervisor .Hypervisor ;
@@ -34,6 +35,7 @@ public class LibvirtConnection {
3435
3536 static private Connect s_connection ;
3637 static private String s_hypervisorURI ;
38+ static private Thread libvirtEventThread ;
3739
3840 static public Connect getConnection () throws LibvirtException {
3941 return getConnection (s_hypervisorURI );
@@ -45,6 +47,8 @@ static public Connect getConnection(String hypervisorURI) throws LibvirtExceptio
4547
4648 if (conn == null ) {
4749 s_logger .info ("No existing libvirtd connection found. Opening a new one" );
50+
51+ setupEventListener ();
4852 conn = new Connect (hypervisorURI , false );
4953 s_logger .debug ("Successfully connected to libvirt at: " + hypervisorURI );
5054 s_connections .put (hypervisorURI , conn );
@@ -53,7 +57,15 @@ static public Connect getConnection(String hypervisorURI) throws LibvirtExceptio
5357 conn .getVersion ();
5458 } catch (LibvirtException e ) {
5559 s_logger .error ("Connection with libvirtd is broken: " + e .getMessage ());
60+
61+ try {
62+ conn .close ();
63+ } catch (LibvirtException closeEx ) {
64+ s_logger .debug ("Ignoring error while trying to close broken connection:" + closeEx .getMessage ());
65+ }
66+
5667 s_logger .debug ("Opening a new libvirtd connection to: " + hypervisorURI );
68+ setupEventListener ();
5769 conn = new Connect (hypervisorURI , false );
5870 s_connections .put (hypervisorURI , conn );
5971 }
@@ -101,4 +113,33 @@ static String getHypervisorURI(String hypervisorType) {
101113
102114 return "qemu:///system" ;
103115 }
116+
117+ /**
118+ * Set up Libvirt event handling and polling. This is not specific to a connection object instance, but needs
119+ * to be done prior to creating connections. See the Libvirt documentation for virEventRegisterDefaultImpl and
120+ * virEventRunDefaultImpl or the libvirt-java Library Javadoc for more information.
121+ * @throws LibvirtException
122+ */
123+ private static synchronized void setupEventListener () throws LibvirtException {
124+ if (libvirtEventThread == null || !libvirtEventThread .isAlive ()) {
125+ // Registers a default event loop, must be called before connecting to hypervisor
126+ Library .initEventLoop ();
127+ libvirtEventThread = new Thread (() -> {
128+ while (true ) {
129+ try {
130+ // This blocking call contains a loop of its own that will process events until the event loop is stopped or exception is thrown.
131+ Library .runEventLoop ();
132+ } catch (LibvirtException e ) {
133+ s_logger .error ("LibvirtException was thrown in event loop: " , e );
134+ } catch (InterruptedException e ) {
135+ s_logger .error ("Libvirt event loop was interrupted: " , e );
136+ }
137+ }
138+ });
139+
140+ // Process events in separate thread. Failure to run event loop regularly will cause connections to close due to keepalive timeout.
141+ libvirtEventThread .setDaemon (true );
142+ libvirtEventThread .start ();
143+ }
144+ }
104145}
0 commit comments