resources: virt: Cleanup cleanly on Close

Don't block accidentally on error!
This commit is contained in:
James Shubin
2017-02-22 18:05:06 -05:00
parent 1346492d72
commit 53b8a21d1e

View File

@@ -27,6 +27,7 @@ import (
"os/user" "os/user"
"path" "path"
"strings" "strings"
"sync"
"time" "time"
multierr "github.com/hashicorp/go-multierror" multierr "github.com/hashicorp/go-multierror"
@@ -91,6 +92,7 @@ type VirtRes struct {
RestartOnDiverge string `yaml:"restartondiverge"` // restart policy: "ignore", "ifneeded", "error" RestartOnDiverge string `yaml:"restartondiverge"` // restart policy: "ignore", "ifneeded", "error"
RestartOnRefresh bool `yaml:"restartonrefresh"` // restart on refresh? RestartOnRefresh bool `yaml:"restartonrefresh"` // restart on refresh?
wg *sync.WaitGroup
conn *libvirt.Connect conn *libvirt.Connect
version uint32 // major * 1000000 + minor * 1000 + release version uint32 // major * 1000000 + minor * 1000 + release
absent bool // cached state absent bool // cached state
@@ -188,15 +190,21 @@ func (obj *VirtRes) Init() error {
} }
} }
} }
obj.wg = &sync.WaitGroup{}
obj.BaseRes.kind = "Virt" obj.BaseRes.kind = "Virt"
return obj.BaseRes.Init() // call base init, b/c we're overriding return obj.BaseRes.Init() // call base init, b/c we're overriding
} }
// Close runs some cleanup code for this resource. // Close runs some cleanup code for this resource.
func (obj *VirtRes) Close() error { func (obj *VirtRes) Close() error {
// By the time that this Close method is called, the engine promises
// that the Watch loop has previously shutdown! (Assuming no bugs!)
obj.wg.Wait()
// TODO: what is the first int Close return value useful for (if at all)? // TODO: what is the first int Close return value useful for (if at all)?
_, err := obj.conn.Close() // close libvirt conn that was opened in Init _, err := obj.conn.Close() // close libvirt conn that was opened in Init
obj.conn = nil // set to nil to help catch any nil ptr bugs!
// call base close, b/c we're overriding // call base close, b/c we're overriding
if e := obj.BaseRes.Close(); err == nil { if e := obj.BaseRes.Close(); err == nil {
@@ -249,11 +257,13 @@ func (obj *VirtRes) connect() (conn *libvirt.Connect, err error) {
// Watch is the primary listener for this resource and it outputs events. // Watch is the primary listener for this resource and it outputs events.
func (obj *VirtRes) Watch() error { func (obj *VirtRes) Watch() error {
// FIXME: how will this working if we're polling?
domChan := make(chan libvirt.DomainEventType) // TODO: do we need to buffer this? domChan := make(chan libvirt.DomainEventType) // TODO: do we need to buffer this?
gaChan := make(chan *libvirt.DomainEventAgentLifecycle) gaChan := make(chan *libvirt.DomainEventAgentLifecycle)
errorChan := make(chan error) errorChan := make(chan error)
exitChan := make(chan struct{}) exitChan := make(chan struct{})
defer close(exitChan) defer close(exitChan)
obj.wg.Add(1) // don't exit without waiting for EventRunDefaultImpl
// run libvirt event loop // run libvirt event loop
// TODO: *trigger* EventRunDefaultImpl to unblock so it can shut down... // TODO: *trigger* EventRunDefaultImpl to unblock so it can shut down...
@@ -261,17 +271,22 @@ func (obj *VirtRes) Watch() error {
// bursts every 5 seconds! we can do this by writing to an event handler // bursts every 5 seconds! we can do this by writing to an event handler
// in the meantime, terminating the program causes it to exit anyways... // in the meantime, terminating the program causes it to exit anyways...
go func() { go func() {
defer obj.wg.Done()
defer log.Printf("EventRunDefaultImpl exited!")
for { for {
// TODO: can we merge this into our main for loop below? // TODO: can we merge this into our main for loop below?
select { select {
case <-exitChan: case <-exitChan:
log.Printf("EventRunDefaultImpl exited!")
return return
default: default:
} }
//log.Printf("EventRunDefaultImpl started!") //log.Printf("EventRunDefaultImpl started!")
if err := libvirt.EventRunDefaultImpl(); err != nil { if err := libvirt.EventRunDefaultImpl(); err != nil {
errorChan <- errwrap.Wrapf(err, "EventRunDefaultImpl failed") select {
case errorChan <- errwrap.Wrapf(err, "EventRunDefaultImpl failed"):
case <-exitChan:
// pass
}
return return
} }
//log.Printf("EventRunDefaultImpl looped!") //log.Printf("EventRunDefaultImpl looped!")