Commit 1a33421d authored by Daniel P. Berrange's avatar Daniel P. Berrange

Add node device event binding

Signed-off-by: default avatarDaniel P. Berrange <[email protected]>
parent 8910819e
package libvirt
import (
"fmt"
"unsafe"
)
/*
#cgo pkg-config: libvirt
#include <libvirt/libvirt.h>
#include "node_device_events_cfuncs.h"
*/
import "C"
type NodeDeviceEventGenericCallback func(c *Connect, d *NodeDevice)
type NodeDeviceEventLifecycle struct {
Event NodeDeviceEventLifecycleType
// TODO: we can make Detail typesafe somehow ?
Detail int
}
type NodeDeviceEventLifecycleCallback func(c *Connect, n *NodeDevice, event *NodeDeviceEventLifecycle)
//export nodeDeviceEventLifecycleCallback
func nodeDeviceEventLifecycleCallback(c C.virConnectPtr, s C.virNodeDevicePtr,
event int, detail int,
goCallbackId int) {
node_device := &NodeDevice{ptr: s}
connection := &Connect{ptr: c}
eventDetails := &NodeDeviceEventLifecycle{
Event: NodeDeviceEventLifecycleType(event),
Detail: detail,
}
callbackFunc := getCallbackId(goCallbackId)
callback, ok := callbackFunc.(NodeDeviceEventLifecycleCallback)
if !ok {
panic("Inappropriate callback type called")
}
callback(connection, node_device, eventDetails)
}
//export nodeDeviceEventGenericCallback
func nodeDeviceEventGenericCallback(c C.virConnectPtr, d C.virNodeDevicePtr,
goCallbackId int) {
node_device := &NodeDevice{ptr: d}
connection := &Connect{ptr: c}
callbackFunc := getCallbackId(goCallbackId)
callback, ok := callbackFunc.(NodeDeviceEventGenericCallback)
if !ok {
panic("Inappropriate callback type called")
}
callback(connection, node_device)
}
func (c *Connect) NodeDeviceEventLifecycleRegister(device *NodeDevice, callback NodeDeviceEventLifecycleCallback) (int, error) {
goCallBackId := registerCallbackId(callback)
callbackPtr := unsafe.Pointer(C.nodeDeviceEventLifecycleCallback_cgo)
var cdevice C.virNodeDevicePtr
if device != nil {
cdevice = device.ptr
}
ret := C.virConnectNodeDeviceEventRegisterAny_cgo(c.ptr, cdevice,
C.VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE,
C.virConnectNodeDeviceEventGenericCallback(callbackPtr),
C.long(goCallBackId))
if ret == -1 {
freeCallbackId(goCallBackId)
return 0, GetLastError()
}
return int(ret), nil
}
func (c *Connect) NodeDeviceEventUpdateRegister(device *NodeDevice, callback NodeDeviceEventGenericCallback) (int, error) {
goCallBackId := registerCallbackId(callback)
callbackPtr := unsafe.Pointer(C.nodeDeviceEventGenericCallback_cgo)
var cdevice C.virNodeDevicePtr
if device != nil {
cdevice = device.ptr
}
ret := C.virConnectNodeDeviceEventRegisterAny_cgo(c.ptr, cdevice,
C.VIR_NODE_DEVICE_EVENT_ID_UPDATE,
C.virConnectNodeDeviceEventGenericCallback(callbackPtr),
C.long(goCallBackId))
if ret == -1 {
freeCallbackId(goCallBackId)
return 0, GetLastError()
}
return int(ret), nil
}
func (c *Connect) NodeDeviceEventDeregister(callbackId int) error {
// Deregister the callback
if i := int(C.virConnectNodeDeviceEventDeregisterAny(c.ptr, C.int(callbackId))); i != 0 {
return GetLastError()
}
return nil
}
func (e NodeDeviceEventLifecycle) String() string {
var event string
switch e.Event {
case NODE_DEVICE_EVENT_CREATED:
event = "created"
case NODE_DEVICE_EVENT_DELETED:
event = "deleted"
default:
event = "unknown"
}
return fmt.Sprintf("NodeDevice event=%q", event)
}
package libvirt
/*
#cgo pkg-config: libvirt
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#include "node_device_events_cfuncs.h"
#include "callbacks_cfuncs.h"
#include <stdint.h>
extern void nodeDeviceEventLifecycleCallback(virConnectPtr, virNodeDevicePtr, int, int, int);
void nodeDeviceEventLifecycleCallback_cgo(virConnectPtr c, virNodeDevicePtr d,
int event, int detail, void *data)
{
nodeDeviceEventLifecycleCallback(c, d, event, detail, (int)(intptr_t)data);
}
extern void nodeDeviceEventGenericCallback(virConnectPtr, virNodeDevicePtr, int);
void nodeDeviceEventGenericCallback_cgo(virConnectPtr c, virNodeDevicePtr d, void *data)
{
nodeDeviceEventGenericCallback(c, d, (int)(intptr_t)data);
}
int virConnectNodeDeviceEventRegisterAny_cgo(virConnectPtr c, virNodeDevicePtr d,
int eventID, virConnectNodeDeviceEventGenericCallback cb,
long goCallbackId) {
void* id = (void*)goCallbackId;
return virConnectNodeDeviceEventRegisterAny(c, d, eventID, cb, id, freeGoCallback_cgo);
}
*/
import "C"
#ifndef NODE_DEVICE_EVENTS_CFUNCS_H__
#define NODE_DEVICE_EVENTS_CFUNCS_H__
void nodeDeviceEventLifecycleCallback_cgo(virConnectPtr c, virNodeDevicePtr d,
int event, int detail, void* data);
void nodeDeviceEventGenericCallback_cgo(virConnectPtr c, virNodeDevicePtr d, void* data);
int virConnectNodeDeviceEventRegisterAny_cgo(virConnectPtr c, virNodeDevicePtr d,
int eventID, virConnectNodeDeviceEventGenericCallback cb,
long goCallbackId);
#endif /* NODE_DEVICE_EVENTS_CFUNCS_H__ */
package libvirt
import (
"fmt"
"testing"
"time"
)
func init() {
EventRegisterDefaultImpl()
}
func TestNodeDeviceEventRegister(t *testing.T) {
if true {
return
}
callbackId := -1
conn := buildTestConnection()
defer func() {
if callbackId >= 0 {
if err := conn.NodeDeviceEventDeregister(callbackId); err != nil {
t.Errorf("got `%v` on NodeDeviceEventDeregister instead of nil", err)
}
}
if res, _ := conn.CloseConnection(); res != 0 {
t.Errorf("CloseConnection() == %d, expected 0", res)
}
}()
defName := time.Now().String()
nbEvents := 0
callback := func(c *Connect, d *NodeDevice, event *NodeDeviceEventLifecycle) {
if event.Event == NODE_DEVICE_EVENT_CREATED {
domName, _ := d.GetName()
if defName != domName {
t.Fatalf("Name was not '%s': %s", defName, domName)
}
}
eventString := fmt.Sprintf("%s", event)
expected := "NodeDevice event=\"started\" detail=\"booted\""
if eventString != expected {
t.Errorf("event == %q, expected %q", eventString, expected)
}
nbEvents++
}
callbackId, err := conn.NodeDeviceEventLifecycleRegister(nil, callback)
if err != nil {
t.Error(err)
return
}
// Test a minimally valid xml
xml := `<device>
<name>` + defName + `</name>
</device>`
dom, err := conn.DeviceCreateXML(xml, 0)
if err != nil {
t.Error(err)
return
}
// This is blocking as long as there is no message
EventRunDefaultImpl()
if nbEvents == 0 {
t.Fatal("At least one event was expected")
}
defer func() {
dom.Destroy()
dom.Free()
}()
// Check that the internal context entry was added, and that there only is
// one.
goCallbackLock.Lock()
if len(goCallbacks) != 1 {
t.Errorf("goCallbacks should hold one entry, got %+v", goCallbacks)
}
goCallbackLock.Unlock()
// Deregister the event
if err := conn.NodeDeviceEventDeregister(callbackId); err != nil {
t.Fatal("Event deregistration failed with: %v", err)
}
callbackId = -1 // Don't deregister twice
// Check that the internal context entries was removed
goCallbackLock.Lock()
if len(goCallbacks) > 0 {
t.Errorf("goCallbacks entry wasn't removed: %+v", goCallbacks)
}
goCallbackLock.Unlock()
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment