[libvirt-users] Callback re-registration after libvirtd restart

Hi all, I'm using libvirt-go and I following code to listen for lifecycle events: func event_listen() { log.Printf("event_listen %s", conf.Libvirt.LocalUrl) hv, err := libvirt.NewConnect(conf.Libvirt.LocalUrl) lifecycleCallback := func(c *libvirt.Connect, d *libvirt.Domain, event *libvirt.DomainEventLifecycle) { event_message(c, d, "lifecycle", event) } _, err = hv.DomainEventLifecycleRegister(nil, lifecycleCallback) if err != nil { log.Printf("unable to register event callback") return } log.Printf("Libvirt event listener started") go func() { for err == nil { err = libvirt.EventRunDefaultImpl() log.Printf("EventRunDefaultImpl err: %+v", err) } time.Sleep(time.Second) event_listen() }() } It works ok until I restart libvirtd (service libvirtd restart). After that, the inner go func waits some time and continues without error. But the callback is not working anymore. My question is, how can I detect hv reconnect (I guess it's happening in background) so I know when to reinitialize callbacks? Thanks. BR Daniel Kucera.

On Wed, May 17, 2017 at 03:08:23PM +0200, Daniel Kučera wrote:
Hi all,
I'm using libvirt-go and I following code to listen for lifecycle events:
func event_listen() { log.Printf("event_listen %s", conf.Libvirt.LocalUrl) hv, err := libvirt.NewConnect(conf.Libvirt.LocalUrl)
lifecycleCallback := func(c *libvirt.Connect, d *libvirt.Domain, event *libvirt.DomainEventLifecycle) { event_message(c, d, "lifecycle", event) }
_, err = hv.DomainEventLifecycleRegister(nil, lifecycleCallback) if err != nil { log.Printf("unable to register event callback") return }
log.Printf("Libvirt event listener started")
go func() { for err == nil { err = libvirt.EventRunDefaultImpl() log.Printf("EventRunDefaultImpl err: %+v", err) } time.Sleep(time.Second) event_listen() }()
}
It works ok until I restart libvirtd (service libvirtd restart). After that, the inner go func waits some time and continues without error. But the callback is not working anymore.
My question is, how can I detect hv reconnect (I guess it's happening in background) so I know when to reinitialize callbacks?
There is a separate event you can listen to that notifies when the connection is closed. See the RegisterCloseCallback() method on the Connect object. Basically register a callback there, and when it fires, unregister your existing domain event callbacks, and close your existing Connect object handle. Then fire a goroutine that loops once every few seconds trying to open a new Connect object, and when that succeeds register new domain event callbacks. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Hi Daniel, I tried that but it doesn't work: func libvirt_close_callback(conn *libvirt.Connect, reason libvirt.ConnectCloseReason){ log.Printf("close callback: %+v", reason) } func event_listen() { log.Printf("event_listen %s", conf.Libvirt.LocalUrl) hv, err := libvirt.NewConnect(conf.Libvirt.LocalUrl) err = hv.RegisterCloseCallback(libvirt_close_callback) if err != nil { log.Printf("unable to register close callback") return } ... The callback fires only when I kill my app, ^CGot signal:%!(EXTRA syscall.Signal=interrupt) close callback: 0 but not when I restart libvirtd. I tried using both local and remote connect URIs: qemu+ssh://10.130.16.101/system, qemu+ssh://localhost/system, qemu+ssh:///system Thanks. D. 2017-05-17 15:24 GMT+02:00 Daniel P. Berrange <berrange@redhat.com>:
On Wed, May 17, 2017 at 03:08:23PM +0200, Daniel Kučera wrote:
Hi all,
I'm using libvirt-go and I following code to listen for lifecycle events:
func event_listen() { log.Printf("event_listen %s", conf.Libvirt.LocalUrl) hv, err := libvirt.NewConnect(conf.Libvirt.LocalUrl)
lifecycleCallback := func(c *libvirt.Connect, d *libvirt.Domain, event *libvirt.DomainEventLifecycle) { event_message(c, d, "lifecycle", event) }
_, err = hv.DomainEventLifecycleRegister(nil, lifecycleCallback) if err != nil { log.Printf("unable to register event callback") return }
log.Printf("Libvirt event listener started")
go func() { for err == nil { err = libvirt.EventRunDefaultImpl() log.Printf("EventRunDefaultImpl err: %+v", err) } time.Sleep(time.Second) event_listen() }()
}
It works ok until I restart libvirtd (service libvirtd restart). After that, the inner go func waits some time and continues without error. But the callback is not working anymore.
My question is, how can I detect hv reconnect (I guess it's happening in background) so I know when to reinitialize callbacks?
There is a separate event you can listen to that notifies when the connection is closed. See the RegisterCloseCallback() method on the Connect object.
Basically register a callback there, and when it fires, unregister your existing domain event callbacks, and close your existing Connect object handle. Then fire a goroutine that loops once every few seconds trying to open a new Connect object, and when that succeeds register new domain event callbacks.
Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/ dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/ dberrange :|

On Wed, May 17, 2017 at 03:41:09PM +0200, Daniel Kučera wrote:
Hi Daniel,
I tried that but it doesn't work:
func libvirt_close_callback(conn *libvirt.Connect, reason libvirt.ConnectCloseReason){ log.Printf("close callback: %+v", reason) }
func event_listen() { log.Printf("event_listen %s", conf.Libvirt.LocalUrl) hv, err := libvirt.NewConnect(conf.Libvirt.LocalUrl)
err = hv.RegisterCloseCallback(libvirt_close_callback) if err != nil { log.Printf("unable to register close callback") return } ...
The callback fires only when I kill my app,
Looks like you are missing a call to libvirt.EventRegisterDefaultImpl(), which must be the first you do do before even connecting to libvirt. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

No, I'm not, I'm calling it sooner: func libvirt_start() { libvirt.EventRegisterDefaultImpl() event_listen() } S pozdravom / Best regards Daniel Kucera. 2017-05-17 15:47 GMT+02:00 Daniel P. Berrange <berrange@redhat.com>:
On Wed, May 17, 2017 at 03:41:09PM +0200, Daniel Kučera wrote:
Hi Daniel,
I tried that but it doesn't work:
func libvirt_close_callback(conn *libvirt.Connect, reason libvirt.ConnectCloseReason){ log.Printf("close callback: %+v", reason) }
func event_listen() { log.Printf("event_listen %s", conf.Libvirt.LocalUrl) hv, err := libvirt.NewConnect(conf.Libvirt.LocalUrl)
err = hv.RegisterCloseCallback(libvirt_close_callback) if err != nil { log.Printf("unable to register close callback") return } ...
The callback fires only when I kill my app,
Looks like you are missing a call to libvirt.EventRegisterDefaultImpl(), which must be the first you do do before even connecting to libvirt.
Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/ dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/ dberrange :|

On Wed, May 17, 2017 at 03:49:45PM +0200, Daniel Kučera wrote:
No, I'm not, I'm calling it sooner:
func libvirt_start() { libvirt.EventRegisterDefaultImpl() event_listen() }
Well the following example works as expected for me package main import ( "github.com/libvirt/libvirt-go" "log" ) func libvirt_close_callback(conn *libvirt.Connect, reason libvirt.ConnectCloseReason) { log.Printf("In here") } func main() { libvirt.EventRegisterDefaultImpl() hv, err := libvirt.NewConnect("qemu:///session") err = hv.RegisterCloseCallback(libvirt_close_callback) if err != nil { log.Printf("unable to register close callback") return } for { libvirt.EventRunDefaultImpl() } } Printing out "In here" immediately when I kill libvirtd Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

2017-05-17 15:52 GMT+02:00 Daniel P. Berrange <berrange@redhat.com>:
On Wed, May 17, 2017 at 03:49:45PM +0200, Daniel Kučera wrote:
No, I'm not, I'm calling it sooner:
func libvirt_start() { libvirt.EventRegisterDefaultImpl() event_listen() }
Well the following example works as expected for me
package main
import ( "github.com/libvirt/libvirt-go" "log" )
func libvirt_close_callback(conn *libvirt.Connect, reason libvirt.ConnectCloseReason) { log.Printf("In here") }
func main() { libvirt.EventRegisterDefaultImpl()
hv, err := libvirt.NewConnect("qemu:///session")
err = hv.RegisterCloseCallback(libvirt_close_callback) if err != nil { log.Printf("unable to register close callback") return }
for { libvirt.EventRunDefaultImpl() }
}
Printing out "In here" immediately when I kill libvirtd
Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/ dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/ dberrange :|
Okay, with qemu:///session I'm getting CloseCallback but now I'm not getting LifecycleCallback :( S pozdravom / Best regards Daniel Kucera.
participants (3)
-
Daniel Kučera
-
Daniel Kučera
-
Daniel P. Berrange