Skip to content

Commit 7228071

Browse files
author
Marcus Sorensen
committed
Fix libvirt domain event listener by properly processing events
1 parent 9d4f071 commit 7228071

File tree

2 files changed

+38
-15
lines changed

2 files changed

+38
-15
lines changed

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@
8585
import org.libvirt.DomainInfo.DomainState;
8686
import org.libvirt.DomainInterfaceStats;
8787
import org.libvirt.DomainSnapshot;
88-
import org.libvirt.Library;
8988
import org.libvirt.LibvirtException;
9089
import org.libvirt.MemoryStatistic;
9190
import org.libvirt.Network;
@@ -3694,20 +3693,7 @@ private StartupStorageCommand createLocalStoragePool(String localStoragePath, St
36943693
}
36953694

36963695
private void setupLibvirtEventListener() {
3697-
final Thread libvirtListenerThread = new Thread(() -> {
3698-
try {
3699-
Library.runEventLoop();
3700-
} catch (LibvirtException e) {
3701-
s_logger.error("LibvirtException was thrown in event loop: ", e);
3702-
} catch (InterruptedException e) {
3703-
s_logger.error("Libvirt event loop was interrupted: ", e);
3704-
}
3705-
});
3706-
37073696
try {
3708-
libvirtListenerThread.setDaemon(true);
3709-
libvirtListenerThread.start();
3710-
37113697
Connect conn = LibvirtConnection.getConnection();
37123698
conn.addLifecycleListener(this::onDomainLifecycleChange);
37133699

@@ -3727,7 +3713,7 @@ private int onDomainLifecycleChange(Domain domain, DomainEvent domainEvent) {
37273713
* Checking for this helps us differentiate between events where cloudstack or admin stopped the VM vs guest
37283714
* initiated, and avoid pushing extra updates for actions we are initiating without a need for extra tracking */
37293715
DomainEventDetail detail = domainEvent.getDetail();
3730-
if (StoppedDetail.SHUTDOWN.equals(detail) || StoppedDetail.CRASHED.equals(detail)) {
3716+
if (StoppedDetail.SHUTDOWN.equals(detail) || StoppedDetail.CRASHED.equals(detail) || StoppedDetail.FAILED.equals(detail)) {
37313717
s_logger.info("Triggering out of band status update due to completed self-shutdown or crash of VM");
37323718
_agentStatusUpdater.triggerUpdate();
37333719
} else {

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtConnection.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.cloud.agent.properties.AgentPropertiesFileHandler;
2424
import org.apache.log4j.Logger;
2525
import org.libvirt.Connect;
26+
import org.libvirt.Library;
2627
import org.libvirt.LibvirtException;
2728

2829
import 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

Comments
 (0)