[libvirt] [libvirt-java] [PATCH 45/65] events: handle registration of domain lifecycle events

Claudio Bley cbley at av-test.de
Thu Feb 13 15:22:53 UTC 2014


Add LifecycleListener interface which needs to be implemented
when the user wishes to receive lifecycle change events on domains.

The DomainEvent class represents the kind of event that
occurred including details on that event.

Signed-off-by: Claudio Bley <cbley at av-test.de>
---
 src/main/java/org/libvirt/Connect.java             |   66 ++++++++++++++++++
 src/main/java/org/libvirt/Domain.java              |   18 +++++
 src/main/java/org/libvirt/event/CrashedDetail.java |   15 +++++
 src/main/java/org/libvirt/event/DefinedDetail.java |   17 +++++
 src/main/java/org/libvirt/event/DetailInfo.java    |    5 ++
 src/main/java/org/libvirt/event/DomainEvent.java   |   71 ++++++++++++++++++++
 .../java/org/libvirt/event/DomainEventDetail.java  |    7 ++
 .../java/org/libvirt/event/DomainEventType.java    |   60 +++++++++++++++++
 .../java/org/libvirt/event/LifecycleListener.java  |   24 +++++++
 .../java/org/libvirt/event/PMSuspendedDetail.java  |   15 +++++
 src/main/java/org/libvirt/event/ResumedDetail.java |   20 ++++++
 .../java/org/libvirt/event/ShutdownDetail.java     |   12 ++++
 src/main/java/org/libvirt/event/StartedDetail.java |   30 +++++++++
 src/main/java/org/libvirt/event/StoppedDetail.java |   40 +++++++++++
 .../java/org/libvirt/event/SuspendedDetail.java    |   40 +++++++++++
 .../java/org/libvirt/event/UndefinedDetail.java    |    7 ++
 src/main/java/org/libvirt/jna/Libvirt.java         |    7 ++
 17 files changed, 454 insertions(+)
 create mode 100644 src/main/java/org/libvirt/event/CrashedDetail.java
 create mode 100644 src/main/java/org/libvirt/event/DefinedDetail.java
 create mode 100644 src/main/java/org/libvirt/event/DetailInfo.java
 create mode 100644 src/main/java/org/libvirt/event/DomainEvent.java
 create mode 100644 src/main/java/org/libvirt/event/DomainEventDetail.java
 create mode 100644 src/main/java/org/libvirt/event/DomainEventType.java
 create mode 100644 src/main/java/org/libvirt/event/LifecycleListener.java
 create mode 100644 src/main/java/org/libvirt/event/PMSuspendedDetail.java
 create mode 100644 src/main/java/org/libvirt/event/ResumedDetail.java
 create mode 100644 src/main/java/org/libvirt/event/ShutdownDetail.java
 create mode 100644 src/main/java/org/libvirt/event/StartedDetail.java
 create mode 100644 src/main/java/org/libvirt/event/StoppedDetail.java
 create mode 100644 src/main/java/org/libvirt/event/SuspendedDetail.java
 create mode 100644 src/main/java/org/libvirt/event/UndefinedDetail.java

diff --git a/src/main/java/org/libvirt/Connect.java b/src/main/java/org/libvirt/Connect.java
index bbbd000..d82dba2 100644
--- a/src/main/java/org/libvirt/Connect.java
+++ b/src/main/java/org/libvirt/Connect.java
@@ -479,6 +479,72 @@ public class Connect {
         domainEventRegister(domain, DomainEventID.REBOOT, virCB, cb);
     }
 
+    void domainEventRegister(Domain domain, final LifecycleListener cb) throws LibvirtException {
+        if (cb == null)
+            throw new IllegalArgumentException("LifecycleCallback cannot be null");
+
+        Libvirt.VirConnectDomainEventCallback virCB = new Libvirt.VirConnectDomainEventCallback() {
+                @Override
+                public int eventCallback(ConnectionPointer virConnectPtr, DomainPointer virDomainPointer,
+                                         final int eventCode,
+                                         final int detailCode,
+                                         Pointer opaque) {
+                    assert VCP.equals(virConnectPtr);
+
+                    try {
+                        Domain dom = Domain.constructIncRef(Connect.this, virDomainPointer);
+                        DomainEventType type = getConstant(DomainEventType.class, eventCode);
+                        DomainEvent event = new DomainEvent(type, detailCode);
+
+                        cb.onLifecycleChange(dom, event);
+                    } catch (LibvirtException e) {
+                        throw new RuntimeException("libvirt error in lifecycle callback", e);
+                    }
+
+                    // always return 0, regardless of what the
+                    // callback method returned. This may need to be
+                    // changed in the future, in case the return value
+                    // is used for something by libvirt.
+                    return 0;
+                }
+            };
+
+        domainEventRegister(domain, DomainEventID.LIFECYCLE, virCB, cb);
+    }
+
+    /**
+     * Adds the specified listener to receive lifecycle events for
+     * domains of this connections.
+     *
+     * @param  l  the lifecycle listener
+     * @throws    LibvirtException on failure
+     *
+     * @see #removeLifecycleListener
+     * @see Domain#addLifecycleListener
+     * @see <a
+     *       href="http://www.libvirt.org/html/libvirt-libvirt.html#virConnectDomainEventRegisterAny"
+     *      >virConnectDomainEventRegisterAny</a>
+     */
+    public void addLifecycleListener(final LifecycleListener l) throws LibvirtException
+    {
+        domainEventRegister(null, l);
+    }
+
+    /**
+     * Removes the specified I/O error listener so that it no longer
+     * receives I/O error events.
+     *
+     * @param l    the I/O error listener
+     * @throws     LibvirtException
+     *
+     * @see <a
+     *       href="http://www.libvirt.org/html/libvirt-libvirt.html#virConnectDomainEventDeregisterAny"
+     *      >virConnectDomainEventDeregisterAny</a>
+     */
+    public void removeLifecycleListener(LifecycleListener l) throws LibvirtException {
+        domainEventDeregister(DomainEventID.LIFECYCLE, l);
+    }
+
     /**
      * Adds the specified reboot listener to receive reboot events for
      * domains of this connection.
diff --git a/src/main/java/org/libvirt/Domain.java b/src/main/java/org/libvirt/Domain.java
index 010fee0..fb59781 100644
--- a/src/main/java/org/libvirt/Domain.java
+++ b/src/main/java/org/libvirt/Domain.java
@@ -14,6 +14,7 @@ import org.libvirt.jna.virDomainMemoryStats;
 import org.libvirt.jna.virSchedParameter;
 import org.libvirt.jna.virVcpuInfo;
 import org.libvirt.event.RebootListener;
+import org.libvirt.event.LifecycleListener;
 import static org.libvirt.Library.libvirt;
 import static org.libvirt.ErrorHandler.processError;
 import static org.libvirt.ErrorHandler.processErrorIfZero;
@@ -1064,6 +1065,23 @@ public class Domain {
     }
 
     /**
+     * Adds the specified listener to receive lifecycle events for this domain.
+     *
+     * @param  l   the lifecycle listener
+     * @throws LibvirtException on failure
+     *
+     * @see Connect#addLifecycleListener
+     * @see Connect#removeLifecycleListener
+     * @see <a
+     *       href="http://www.libvirt.org/html/libvirt-libvirt.html#virConnectDomainEventRegisterAny"
+     *      >virConnectDomainEventRegisterAny</a>
+     */
+    public void addLifecycleListener(final LifecycleListener l) throws LibvirtException
+    {
+        virConnect.domainEventRegister(this, l);
+    }
+
+    /**
      * Revert the domain to a given snapshot.
      *
      * @see <a href=
diff --git a/src/main/java/org/libvirt/event/CrashedDetail.java b/src/main/java/org/libvirt/event/CrashedDetail.java
new file mode 100644
index 0000000..638a901
--- /dev/null
+++ b/src/main/java/org/libvirt/event/CrashedDetail.java
@@ -0,0 +1,15 @@
+package org.libvirt.event;
+
+/**
+ * Details about a CRASHED domain event
+ *
+ * @see DomainEvent
+ */
+public enum CrashedDetail implements DomainEventDetail {
+    /**
+     * Guest was panicked.
+     */
+    PANICKED,
+
+    UNKNOWN
+}
diff --git a/src/main/java/org/libvirt/event/DefinedDetail.java b/src/main/java/org/libvirt/event/DefinedDetail.java
new file mode 100644
index 0000000..f0220f0
--- /dev/null
+++ b/src/main/java/org/libvirt/event/DefinedDetail.java
@@ -0,0 +1,17 @@
+package org.libvirt.event;
+
+import org.libvirt.Domain;
+
+public enum DefinedDetail implements DomainEventDetail {
+    /**
+     * Newly created config file.
+     */
+    ADDED,
+
+    /**
+     * Changed config file.
+     */
+    UPDATED,
+
+    UNKNOWN
+}
diff --git a/src/main/java/org/libvirt/event/DetailInfo.java b/src/main/java/org/libvirt/event/DetailInfo.java
new file mode 100644
index 0000000..c2572b9
--- /dev/null
+++ b/src/main/java/org/libvirt/event/DetailInfo.java
@@ -0,0 +1,5 @@
+package org.libvirt.event;
+
+// public interface DetailInfo {
+//     <T extends Enum<T>> T detail(final DomainEventDetail d);
+// }
diff --git a/src/main/java/org/libvirt/event/DomainEvent.java b/src/main/java/org/libvirt/event/DomainEvent.java
new file mode 100644
index 0000000..21fac60
--- /dev/null
+++ b/src/main/java/org/libvirt/event/DomainEvent.java
@@ -0,0 +1,71 @@
+package org.libvirt.event;
+
+/**
+ * Contains information about a life cycle change of a domain.
+ * <p>
+ * This includes the domain event that occurred together with
+ * further details about that event.
+ * <p>
+ * Usage:
+ * <pre>{@code
+ * int onLifecycleChange(Domain dom, DomainEvent info) {
+ *     switch (info.getType()) {
+ *         case STARTED:
+ *             StartedDetail detail = info.getDetail();
+ *
+ *             switch (detail) {
+ *                 case BOOTED:
+ *                     ...
+ *                     break;
+ *                 ...
+ *             }
+ *         }
+ *     }
+ * }}</pre>
+ * <p>
+ * Note, that a ClassCastException will be thrown at runtime when
+ * assigning to the wrong detail enumeration type:
+ * <pre>{@code
+ * DomainEvent info;
+ *
+ * if (info.getType() == DomainEventType.STARTED) {
+ *     // info.getDetails() returns a StartedDetail enum
+ *     StoppedDetail detail = info.getDetail(); // throws ClassCastException
+ * }}</pre>
+ *
+ * @see LifecycleListener
+ * @since 1.5.2
+ */
+public final class DomainEvent {
+    private final DomainEventType type;
+    private final int detail;
+
+    public DomainEvent(DomainEventType type, int code) {
+        this.type = type;
+        this.detail = code;
+    }
+
+    /**
+     * Returns the type of event which occurred.
+     */
+    public DomainEventType getType() {
+        return this.type;
+    }
+
+    /**
+     * Returns the corresponding domain event detail in regard to
+     * the DomainEventType of this instance.
+     *
+     * @return a constant of one of the enums implementing the
+     *         {@link DomainEventDetail} interface
+     */
+    public <T extends Enum<T> & DomainEventDetail> T getDetail() {
+        return this.type.obtain(this.detail);
+    }
+
+    @Override
+    public String toString() {
+        Object d = this.type.safeAt(this.detail);
+        return this.type + " (" + d + ")";
+    }
+}
diff --git a/src/main/java/org/libvirt/event/DomainEventDetail.java b/src/main/java/org/libvirt/event/DomainEventDetail.java
new file mode 100644
index 0000000..59ef5aa
--- /dev/null
+++ b/src/main/java/org/libvirt/event/DomainEventDetail.java
@@ -0,0 +1,7 @@
+package org.libvirt.event;
+
+/**
+ * A common interface for all domain event detail enums.
+ */
+public interface DomainEventDetail {
+}
diff --git a/src/main/java/org/libvirt/event/DomainEventType.java b/src/main/java/org/libvirt/event/DomainEventType.java
new file mode 100644
index 0000000..b675d8b
--- /dev/null
+++ b/src/main/java/org/libvirt/event/DomainEventType.java
@@ -0,0 +1,60 @@
+package org.libvirt.event;
+
+/**
+ * Enum constants representing the type of event occurred on
+ * a domain
+ */
+public enum DomainEventType {
+    /** A domain was defined */
+    DEFINED(DefinedDetail.values()),
+
+    /** A domain was undefined */
+    UNDEFINED(UndefinedDetail.values()),
+
+    /** A domain was started */
+    STARTED(StartedDetail.values()),
+
+    /** A domain was suspended */
+    SUSPENDED(SuspendedDetail.values()),
+
+    /** A domain was resumed */
+    RESUMED(ResumedDetail.values()),
+
+    /** A domain was stopped */
+    STOPPED(StoppedDetail.values()),
+
+    /** A domain was shut down */
+    SHUTDOWN(ShutdownDetail.values()),
+
+    /** A domain was PM suspended */
+    PMSUSPENDED(PMSuspendedDetail.values()),
+
+    /** A domain crashed */
+    CRASHED(CrashedDetail.values()),
+
+    /**
+     * An unknown event occured
+     *
+     * This can happen if upstream libvirt adds more event types
+     * that this library does not yet know about.
+     */
+    UNKNOWN(null);
+
+    private final Object[] details;
+
+    DomainEventType(Object[] d) {
+        details = d;
+    }
+
+    @SuppressWarnings("unchecked")
+    <T extends Enum<T>> T obtain(final int detail) {
+        return (T)safeAt(detail);
+    }
+
+    // this method is only necessary for OpenJDK 6 which does not
+    // compile calls to `obtain(d)` in some circumstances
+    Object safeAt(final int detail) {
+        final int index = Math.min(this.details.length - 1, detail);
+        return this.details[index];
+    }
+}
diff --git a/src/main/java/org/libvirt/event/LifecycleListener.java b/src/main/java/org/libvirt/event/LifecycleListener.java
new file mode 100644
index 0000000..78d7419
--- /dev/null
+++ b/src/main/java/org/libvirt/event/LifecycleListener.java
@@ -0,0 +1,24 @@
+package org.libvirt.event;
+
+import org.libvirt.Domain;
+
+/**
+ * Interface for receiving events occurring on a domain.
+ *
+ * @see <a href="http://libvirt.org/html/libvirt-libvirt.html#virConnectDomainEventCallback">virConnectDomainEventCallback</a>
+ */
+public interface LifecycleListener extends EventListener {
+
+    /**
+     * This method gets called when a change in the lifecycle
+     * of a domain occurs.
+     *
+     * @param domain  the domain on which the event occurred
+     * @param event   contains information about the type of event
+     *                that occurred and details about that event
+     *
+     * @return the return value is currently ignored.
+     */
+    int onLifecycleChange(Domain domain,
+                          DomainEvent event);
+}
diff --git a/src/main/java/org/libvirt/event/PMSuspendedDetail.java b/src/main/java/org/libvirt/event/PMSuspendedDetail.java
new file mode 100644
index 0000000..05e5ee0
--- /dev/null
+++ b/src/main/java/org/libvirt/event/PMSuspendedDetail.java
@@ -0,0 +1,15 @@
+package org.libvirt.event;
+
+public enum PMSuspendedDetail implements DomainEventDetail {
+    /**
+     * Guest was PM suspended to memory.
+     */
+    MEMORY,
+
+    /**
+     * Guest was PM suspended to disk.
+     */
+    DISK,
+
+    UNKNOWN
+}
diff --git a/src/main/java/org/libvirt/event/ResumedDetail.java b/src/main/java/org/libvirt/event/ResumedDetail.java
new file mode 100644
index 0000000..55bcf4a
--- /dev/null
+++ b/src/main/java/org/libvirt/event/ResumedDetail.java
@@ -0,0 +1,20 @@
+package org.libvirt.event;
+
+public enum ResumedDetail implements DomainEventDetail {
+    /**
+     * Normal resume due to admin unpause.
+     */
+    UNPAUSED,
+
+    /**
+     * Resumed for completion of migration.
+     */
+    MIGRATED,
+
+    /**
+     * Resumed from snapshot.
+     */
+    FROM_SNAPSHOT,
+
+    UNKNOWN
+}
diff --git a/src/main/java/org/libvirt/event/ShutdownDetail.java b/src/main/java/org/libvirt/event/ShutdownDetail.java
new file mode 100644
index 0000000..8975831
--- /dev/null
+++ b/src/main/java/org/libvirt/event/ShutdownDetail.java
@@ -0,0 +1,12 @@
+package org.libvirt.event;
+
+public enum ShutdownDetail implements DomainEventDetail {
+    /**
+     * Guest finished shutdown sequence.
+     */
+    FINISHED,
+
+    UNKNOWN
+}
+
+
diff --git a/src/main/java/org/libvirt/event/StartedDetail.java b/src/main/java/org/libvirt/event/StartedDetail.java
new file mode 100644
index 0000000..12c52bc
--- /dev/null
+++ b/src/main/java/org/libvirt/event/StartedDetail.java
@@ -0,0 +1,30 @@
+package org.libvirt.event;
+
+public enum StartedDetail implements DomainEventDetail {
+    /**
+     * Normal startup from boot.
+     */
+    BOOTED,
+
+    /**
+     * Incoming migration from another host.
+     */
+    MIGRATED,
+
+    /**
+     * Restored from a state file.
+     */
+    RESTORED,
+
+    /**
+     * Restored from snapshot
+     */
+    FROM_SNAPSHOT,
+
+    /**
+     * Started due to wakeup event.
+     */
+    WAKEUP,
+
+    UNKNOWN
+}
diff --git a/src/main/java/org/libvirt/event/StoppedDetail.java b/src/main/java/org/libvirt/event/StoppedDetail.java
new file mode 100644
index 0000000..53e25e9
--- /dev/null
+++ b/src/main/java/org/libvirt/event/StoppedDetail.java
@@ -0,0 +1,40 @@
+package org.libvirt.event;
+
+public enum StoppedDetail implements DomainEventDetail {
+    /**
+     * Normal shutdown.
+     */
+    SHUTDOWN,
+
+    /**
+     * Forced poweroff from host.
+     */
+    DESTROYED,
+
+    /**
+     * Guest crashed.
+     */
+    CRASHED,
+
+    /**
+     * Migrated off to another host.
+     */
+    MIGRATED,
+
+    /**
+     * Saved to a state file.
+     */
+    SAVED,
+
+    /**
+     * Host emulator/mgmt failed.
+     */
+    FAILED,
+
+    /**
+     * Offline snapshot was loaded.
+     */
+    FROM_SNAPSHOT,
+
+    UNKNOWN
+}
diff --git a/src/main/java/org/libvirt/event/SuspendedDetail.java b/src/main/java/org/libvirt/event/SuspendedDetail.java
new file mode 100644
index 0000000..9862052
--- /dev/null
+++ b/src/main/java/org/libvirt/event/SuspendedDetail.java
@@ -0,0 +1,40 @@
+package org.libvirt.event;
+
+public enum SuspendedDetail implements DomainEventDetail {
+    /**
+     * Normal suspend due to admin pause.
+     */
+    PAUSED,
+
+    /**
+     * Suspended for offline migration.
+     */
+    MIGRATED,
+
+    /**
+     * Suspended due to a disk I/O error.
+     */
+    IOERROR,
+
+    /**
+     * Suspended due to a watchdog firing.
+     */
+    WATCHDOG,
+
+    /**
+     * Restored from paused state file.
+     */
+    RESTORED,
+
+    /**
+     * Restored from paused snapshot.
+     */
+    FROM_SNAPSHOT,
+
+    /**
+     * Suspended after failure during libvirt API call.
+     */
+    API_ERROR,
+
+    UNKNOWN
+}
diff --git a/src/main/java/org/libvirt/event/UndefinedDetail.java b/src/main/java/org/libvirt/event/UndefinedDetail.java
new file mode 100644
index 0000000..ec814f1
--- /dev/null
+++ b/src/main/java/org/libvirt/event/UndefinedDetail.java
@@ -0,0 +1,7 @@
+package org.libvirt.event;
+
+public enum UndefinedDetail implements DomainEventDetail {
+    REMOVED,
+
+    UNKNOWN
+}
diff --git a/src/main/java/org/libvirt/jna/Libvirt.java b/src/main/java/org/libvirt/jna/Libvirt.java
index 913fe08..5bb9fa0 100644
--- a/src/main/java/org/libvirt/jna/Libvirt.java
+++ b/src/main/java/org/libvirt/jna/Libvirt.java
@@ -89,6 +89,13 @@ public interface Libvirt extends Library {
         void eventCallback(ConnectionPointer virConnectPtr, DomainPointer virDomainPointer, Pointer opaque);
     }
 
+    interface VirConnectDomainEventCallback extends VirDomainEventCallback {
+        int eventCallback(ConnectionPointer virConnectPtr, DomainPointer virDomainPointer,
+                          int event,
+                          int detail,
+                          Pointer opaque);
+    }
+
     /**
      * Error callback
      */
-- 
1.7.9.5




More information about the libvir-list mailing list