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,29 @@ static String getHypervisorURI(String hypervisorType) {
101113
102114 return "qemu:///system" ;
103115 }
116+
117+ // stand up libvirt event handling and polling. This is not specific to a connection object instance, but needs to
118+ // exist prior to creating connections.
119+ private static synchronized void setupEventListener () throws LibvirtException {
120+ if (libvirtEventThread == null || !libvirtEventThread .isAlive ()) {
121+ // Registers a default event loop, must be called before connecting to hypervisor
122+ Library .initEventLoop ();
123+ libvirtEventThread = new Thread (() -> {
124+ while (true ) {
125+ try {
126+ // This blocking call contains a loop of its own that will process events until the event loop is stopped or exception is thrown.
127+ Library .runEventLoop ();
128+ } catch (LibvirtException e ) {
129+ s_logger .error ("LibvirtException was thrown in event loop: " , e );
130+ } catch (InterruptedException e ) {
131+ s_logger .error ("Libvirt event loop was interrupted: " , e );
132+ }
133+ }
134+ });
135+
136+ // Process events in separate thread. Failure to run event loop regularly will cause connections to close due to keepalive timeout.
137+ libvirtEventThread .setDaemon (true );
138+ libvirtEventThread .start ();
139+ }
140+ }
104141}
0 commit comments