resources: Improve the state/cache system

Refactor the state cache into the engine. This makes resource writing
less error prone, and paves the way for better notifications.
This commit is contained in:
James Shubin
2016-11-25 12:30:29 -05:00
parent ba6044e9e8
commit b0a8fc165c
13 changed files with 95 additions and 176 deletions

View File

@@ -129,19 +129,35 @@ func (g *Graph) Process(v *Vertex) error {
if changed, err := obj.SendRecv(obj); err != nil {
return errwrap.Wrapf(err, "could not SendRecv in Process")
} else if changed {
obj.StateOK(false) // invalidate cache
obj.StateOK(false) // invalidate cache, mark as dirty
}
if global.DEBUG {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), !obj.Meta().Noop)
}
var checkOK bool
var err error
if obj.IsStateOK() { // check cached state, to skip CheckApply
checkOK, err = true, nil
} else {
// if this fails, don't UpdateTimestamp()
checkok, err := obj.CheckApply(!obj.Meta().Noop)
if checkok && err != nil { // should never return this way
log.Fatalf("%s[%s]: CheckApply(): %t, %+v", obj.Kind(), obj.GetName(), checkok, err)
checkOK, err = obj.CheckApply(!obj.Meta().Noop)
}
if checkOK && err != nil { // should never return this way
log.Fatalf("%s[%s]: CheckApply(): %t, %+v", obj.Kind(), obj.GetName(), checkOK, err)
}
if global.DEBUG {
log.Printf("%s[%s]: CheckApply(): %t, %v", obj.Kind(), obj.GetName(), checkok, err)
log.Printf("%s[%s]: CheckApply(): %t, %v", obj.Kind(), obj.GetName(), checkOK, err)
}
if !checkok { // if state *was* not ok, we had to have apply'ed
// if CheckApply ran without noop and without error, state should be good
if !obj.Meta().Noop && err == nil { // aka !obj.Meta().Noop || checkOK
obj.StateOK(true) // reset
}
if !checkOK { // if state *was* not ok, we had to have apply'ed
if err != nil { // error during check or apply
ok = false
} else {
@@ -189,7 +205,7 @@ func (g *Graph) Worker(v *Vertex) error {
// the Watch() function about which graph it is
// running on, which isolates things nicely...
obj := v.Res
chanProcess := make(chan event.Event)
processChan := make(chan event.Event)
go func() {
running := false
var timer = time.NewTimer(time.Duration(math.MaxInt64)) // longest duration
@@ -205,14 +221,14 @@ func (g *Graph) Worker(v *Vertex) error {
// event loop will keep running and change state,
// causing the converged timeout to fire!
select {
case event, ok := <-chanProcess: // must use like this
case event, ok := <-processChan: // must use like this
if running && ok {
// we got an event that wasn't a close,
// while we were waiting for the timer!
// if this happens, it might be a bug:(
log.Fatalf("%s[%s]: Worker: Unexpected event: %+v", v.Kind(), v.GetName(), event)
}
if !ok { // chanProcess closed, let's exit
if !ok { // processChan closed, let's exit
break Loop // no event, so no ack!
}
@@ -245,7 +261,7 @@ func (g *Graph) Worker(v *Vertex) error {
running = false
log.Printf("%s[%s]: CheckApply delay expired!", v.Kind(), v.GetName())
// re-send this failed event, to trigger a CheckApply()
go func() { chanProcess <- saved }()
go func() { processChan <- saved }()
// TODO: should we send a fake event instead?
//saved = nil
}
@@ -308,14 +324,14 @@ func (g *Graph) Worker(v *Vertex) error {
// NOTE: we can avoid the send if running Watch guarantees
// one CheckApply event on startup!
//if pendingSendEvent { // TODO: should this become a list in the future?
// if exit, err := obj.DoSend(chanProcess, ""); exit || err != nil {
// if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
// return err // we exit or bubble up a NACK...
// }
//}
}
// TODO: reset the watch retry count after some amount of success
e := v.Res.Watch(chanProcess)
e := v.Res.Watch(processChan)
if e == nil { // exit signal
err = nil // clean exit
break
@@ -339,7 +355,7 @@ func (g *Graph) Worker(v *Vertex) error {
// by getting the Watch resource to send one event once it's up!
//v.SendEvent(eventPoke, false, false)
}
close(chanProcess)
close(processChan)
return err
}

View File

@@ -210,7 +210,7 @@ func (obj *ExecRes) Watch(processChan chan event.Event) error {
startup = true // startup finished
send = false
// it is okay to invalidate the clean state on poke too
obj.isStateOK = false // something made state dirty
obj.StateOK(false) // something made state dirty
if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK...
}
@@ -221,12 +221,11 @@ func (obj *ExecRes) Watch(processChan chan event.Event) error {
// CheckApply checks the resource state and applies the resource if the bool
// input is true. It returns error info and if the state check passed or not.
// TODO: expand the IfCmd to be a list of commands
func (obj *ExecRes) CheckApply(apply bool) (checkok bool, err error) {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
func (obj *ExecRes) CheckApply(apply bool) (checkOK bool, err error) {
// if there is a watch command, but no if command, run based on state
if obj.WatchCmd != "" && obj.IfCmd == "" {
if obj.isStateOK {
if obj.IsStateOK() { // FIXME: this is done by engine now...
return true, nil
}
@@ -264,7 +263,7 @@ func (obj *ExecRes) CheckApply(apply bool) (checkok bool, err error) {
// if there is no watcher and no onlyif check, assume we should run
} else { // if obj.WatchCmd == "" && obj.IfCmd == "" {
// just run if state is dirty
if obj.isStateOK {
if obj.IsStateOK() { // FIXME: this is done by engine now...
return true, nil
}
}
@@ -331,11 +330,11 @@ func (obj *ExecRes) CheckApply(apply bool) (checkok bool, err error) {
}
// XXX: return based on exit value!!
// the state tracking is for exec resources that can't "detect" their
// The state tracking is for exec resources that can't "detect" their
// state, and assume it's invalid when the Watch() function triggers.
// if we apply state successfully, we should reset it here so that we
// If we apply state successfully, we should reset it here so that we
// know that we have applied since the state was set not ok by event!
obj.isStateOK = true // reset
// This now happens automatically after the engine runs CheckApply().
return false, nil // success
}

View File

@@ -169,7 +169,6 @@ func (obj *FileRes) Watch(processChan chan event.Event) error {
var send = false // send event?
var exit = false
var dirty = false
for {
if global.DEBUG {
@@ -190,14 +189,14 @@ func (obj *FileRes) Watch(processChan chan event.Event) error {
log.Printf("%s[%s]: Event(%s): %v", obj.Kind(), obj.GetName(), event.Body.Name, event.Body.Op)
}
send = true
dirty = true
obj.StateOK(false) // dirty
case event := <-obj.Events():
cuid.SetConverged(false)
if exit, send = obj.ReadEvent(&event); exit {
return nil // exit
}
//dirty = false // these events don't invalidate state
//obj.StateOK(false) // dirty // these events don't invalidate state
case <-cuid.ConvergedTimer():
cuid.SetConverged(true) // converged!
@@ -206,18 +205,13 @@ func (obj *FileRes) Watch(processChan chan event.Event) error {
case <-Startup(startup):
cuid.SetConverged(false)
send = true
dirty = true
obj.StateOK(false) // dirty
}
// do all our event sending all together to avoid duplicate msgs
if send {
startup = true // startup finished
send = false
// only invalid state on certain types of events
if dirty {
dirty = false
obj.isStateOK = false // something made state dirty
}
if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK...
}
@@ -645,11 +639,6 @@ func (obj *FileRes) contentCheckApply(apply bool) (checkOK bool, _ error) {
// CheckApply checks the resource state and applies the resource if the bool
// input is true. It returns error info and if the state check passed or not.
func (obj *FileRes) CheckApply(apply bool) (checkOK bool, _ error) {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
if obj.isStateOK { // cache the state
return true, nil
}
checkOK = true
@@ -673,10 +662,6 @@ func (obj *FileRes) CheckApply(apply bool) (checkOK bool, _ error) {
// checkOK = false
//}
// if we did work successfully, or are in a good state, then state is ok
if apply || checkOK {
obj.isStateOK = true
}
return checkOK, nil // w00t
}

View File

@@ -143,7 +143,6 @@ func (obj *HostnameRes) Watch(processChan chan event.Event) error {
bus.Signal(signals)
var send = false // send event?
var dirty = false
for {
obj.SetState(ResStateWatching) // reset
@@ -151,7 +150,7 @@ func (obj *HostnameRes) Watch(processChan chan event.Event) error {
case <-signals:
cuid.SetConverged(false)
send = true
dirty = true
obj.StateOK(false) // dirty
case event := <-obj.Events():
cuid.SetConverged(false)
@@ -160,7 +159,7 @@ func (obj *HostnameRes) Watch(processChan chan event.Event) error {
return nil // exit
}
send = true
dirty = true
obj.StateOK(false) // dirty
case <-cuid.ConvergedTimer():
cuid.SetConverged(true) // converged!
@@ -175,11 +174,7 @@ func (obj *HostnameRes) Watch(processChan chan event.Event) error {
if send {
startup = true // startup finished
send = false
if dirty {
dirty = false
obj.isStateOK = false // something made state dirty
}
// only do this on certain types of events
if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK...
}
@@ -223,12 +218,6 @@ func updateHostnameProperty(object dbus.BusObject, expectedValue, property, sett
// CheckApply method for Hostname resource.
func (obj *HostnameRes) CheckApply(apply bool) (checkOK bool, err error) {
log.Printf("%v[%v]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
if obj.isStateOK { // cached state
return true, nil
}
conn, err := util.SystemBusPrivateUsable()
if err != nil {
return false, errwrap.Wrap(err, "Failed to connect to the private system bus")
@@ -260,10 +249,6 @@ func (obj *HostnameRes) CheckApply(apply bool) (checkOK bool, err error) {
checkOK = checkOK && propertyCheckOK
}
if apply || checkOK {
obj.isStateOK = true
}
return checkOK, nil
}

View File

@@ -125,16 +125,15 @@ func (obj *MsgRes) Watch(processChan chan event.Event) error {
return nil // exit
}
/*
// TODO: invalidate cached state on poke events
obj.logStateOK = false
if obj.Journal {
obj.journalStateOK = false
}
if obj.Syslog {
obj.syslogStateOK = false
}
*/
//obj.logStateOK = false
//if obj.Journal {
// obj.journalStateOK = false
//}
//if obj.Syslog {
// obj.syslogStateOK = false
//}
//obj.updateStateOK()
send = true
case <-cuid.ConvergedTimer():
@@ -205,7 +204,7 @@ func (obj *MsgRes) Compare(res Res) bool {
return true
}
// IsAllStateOK derives a compound state from all internal cache flags that apply to this resource.
// isAllStateOK derives a compound state from all internal cache flags that apply to this resource.
func (obj *MsgRes) isAllStateOK() bool {
if obj.Journal && !obj.journalStateOK {
return false
@@ -216,6 +215,11 @@ func (obj *MsgRes) isAllStateOK() bool {
return obj.logStateOK
}
// updateStateOK sets the global state so it can be read by the engine.
func (obj *MsgRes) updateStateOK() {
obj.StateOK(obj.isAllStateOK())
}
// JournalPriority converts a string description to a numeric priority.
// XXX: Have Validate() make sure it actually is one of these.
func (obj *MsgRes) journalPriority() journal.Priority {
@@ -243,15 +247,16 @@ func (obj *MsgRes) journalPriority() journal.Priority {
// CheckApply method for Msg resource.
// Every check leads to an apply, meaning that the message is flushed to the journal.
func (obj *MsgRes) CheckApply(apply bool) (bool, error) {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
if obj.isAllStateOK() {
return true, nil
}
// isStateOK() done by engine, so we updateStateOK() to pass in value
//if obj.isAllStateOK() {
// return true, nil
//}
if !obj.logStateOK {
log.Printf("%s[%s]: Body: %s", obj.Kind(), obj.GetName(), obj.Body)
obj.logStateOK = true
obj.updateStateOK()
}
if !apply {
@@ -262,10 +267,12 @@ func (obj *MsgRes) CheckApply(apply bool) (bool, error) {
return false, err
}
obj.journalStateOK = true
obj.updateStateOK()
}
if obj.Syslog && !obj.syslogStateOK {
// TODO: implement syslog client
obj.syslogStateOK = true
obj.updateStateOK()
}
return false, nil
}

View File

@@ -19,7 +19,6 @@ package resources
import (
"encoding/gob"
"log"
"time"
"github.com/purpleidea/mgmt/event"
@@ -102,8 +101,6 @@ func (obj *NoopRes) Watch(processChan chan event.Event) error {
if send {
startup = true // startup finished
send = false
// only do this on certain types of events
//obj.isStateOK = false // something made state dirty
if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK...
}
@@ -112,8 +109,7 @@ func (obj *NoopRes) Watch(processChan chan event.Event) error {
}
// CheckApply method for Noop resource. Does nothing, returns happy!
func (obj *NoopRes) CheckApply(apply bool) (checkok bool, err error) {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
func (obj *NoopRes) CheckApply(apply bool) (checkOK bool, err error) {
return true, nil // state is always okay
}

View File

@@ -138,7 +138,6 @@ func (obj *NspawnRes) Watch(processChan chan event.Event) error {
var send = false
var exit = false
var dirty = false
for {
obj.SetState(ResStateWatching)
@@ -155,7 +154,7 @@ func (obj *NspawnRes) Watch(processChan chan event.Event) error {
return fmt.Errorf("Unknown event: %s", event.Name)
}
send = true
dirty = true
obj.StateOK(false) // dirty
}
case event := <-obj.Events():
@@ -171,18 +170,13 @@ func (obj *NspawnRes) Watch(processChan chan event.Event) error {
case <-Startup(startup):
cuid.SetConverged(false)
send = true
dirty = true
obj.StateOK(false) // dirty
}
// do all our event sending all together to avoid duplicate msgs
if send || !obj.isStateOK {
if send {
startup = true // startup finished
send = false
// only invalid state on certain types of events
if dirty {
dirty = false
obj.isStateOK = false // something made state dirty
}
if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK...
}
@@ -193,15 +187,7 @@ func (obj *NspawnRes) Watch(processChan chan event.Event) error {
// CheckApply is run to check the state and, if apply is true, to apply the
// necessary changes to reach the desired state. this is run before Watch and
// again if watch finds a change occurring to the state
func (obj *NspawnRes) CheckApply(apply bool) (checkok bool, err error) {
if global.DEBUG {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
}
if obj.isStateOK { // cache the state
return true, nil
}
func (obj *NspawnRes) CheckApply(apply bool) (checkOK bool, err error) {
// this resource depends on systemd ensure that it's running
if !systemdUtil.IsRunningSystemd() {
return false, errors.New("Systemd is not running.")
@@ -241,11 +227,10 @@ func (obj *NspawnRes) CheckApply(apply bool) (checkok bool, err error) {
if global.DEBUG {
log.Printf("%s[%s]: CheckApply() in valid state", obj.Kind(), obj.GetName())
}
obj.isStateOK = true // state is ok
return true, nil
}
// end of state checking. if we're here, checkok is false
// end of state checking. if we're here, checkOK is false
if !apply {
return false, nil
}
@@ -271,7 +256,6 @@ func (obj *NspawnRes) CheckApply(apply bool) (checkok bool, err error) {
}
}
obj.isStateOK = true // state is now good
return false, nil
}

View File

@@ -21,7 +21,6 @@ import (
"crypto/rand"
"encoding/gob"
"fmt"
"log"
"math/big"
"os"
"path"
@@ -239,8 +238,6 @@ func (obj *PasswordRes) Watch(processChan chan event.Event) error {
if send {
startup = true // startup finished
send = false
// only do this on certain types of events
//obj.isStateOK = false // something made state dirty
if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK...
}
@@ -249,9 +246,7 @@ func (obj *PasswordRes) Watch(processChan chan event.Event) error {
}
// CheckApply method for Password resource. Does nothing, returns happy!
func (obj *PasswordRes) CheckApply(apply bool) (checkok bool, err error) {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
func (obj *PasswordRes) CheckApply(apply bool) (checkOK bool, err error) {
return true, nil
}

View File

@@ -141,7 +141,6 @@ func (obj *PkgRes) Watch(processChan chan event.Event) error {
var send = false // send event?
var exit = false
var dirty = false
for {
if global.DEBUG {
@@ -165,14 +164,14 @@ func (obj *PkgRes) Watch(processChan chan event.Event) error {
}
send = true
dirty = true
obj.StateOK(false) // dirty
case event := <-obj.Events():
cuid.SetConverged(false)
if exit, send = obj.ReadEvent(&event); exit {
return nil // exit
}
dirty = false // these events don't invalidate state
//obj.StateOK(false) // these events don't invalidate state
case <-cuid.ConvergedTimer():
cuid.SetConverged(true) // converged!
@@ -181,18 +180,13 @@ func (obj *PkgRes) Watch(processChan chan event.Event) error {
case <-Startup(startup):
cuid.SetConverged(false)
send = true
dirty = true
obj.StateOK(false) // dirty
}
// do all our event sending all together to avoid duplicate msgs
if send {
startup = true // startup finished
send = false
// only invalid state on certain types of events
if dirty {
dirty = false
obj.isStateOK = false // something made state dirty
}
if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK...
}
@@ -264,16 +258,8 @@ func (obj *PkgRes) pkgMappingHelper(bus *packagekit.Conn) (map[string]*packageki
// CheckApply checks the resource state and applies the resource if the bool
// input is true. It returns error info and if the state check passed or not.
func (obj *PkgRes) CheckApply(apply bool) (checkok bool, err error) {
log.Printf("%s: CheckApply(%t)", obj.fmtNames(obj.getNames()), apply)
if obj.State == "" { // TODO: Validate() should replace this check!
log.Fatalf("%s: Package state is undefined!", obj.fmtNames(obj.getNames()))
}
if obj.isStateOK { // cache the state
return true, nil
}
func (obj *PkgRes) CheckApply(apply bool) (checkOK bool, err error) {
log.Printf("%s: Check", obj.fmtNames(obj.getNames()))
bus := packagekit.NewBus()
if bus == nil {
@@ -309,12 +295,10 @@ func (obj *PkgRes) CheckApply(apply bool) (checkok bool, err error) {
fallthrough
case "newest":
if validState {
obj.isStateOK = true // reset
return true, nil // state is correct, exit!
}
default: // version string
if obj.State == data.Version && data.Version != "" {
obj.isStateOK = true // reset
return true, nil
}
}
@@ -358,7 +342,6 @@ func (obj *PkgRes) CheckApply(apply bool) (checkok bool, err error) {
return false, err // fail
}
log.Printf("%s: Set: %v success!", obj.fmtNames(util.StrListIntersection(applyPackages, obj.getNames())), obj.State)
obj.isStateOK = true // reset
return false, nil // success
}

View File

@@ -221,7 +221,7 @@ func (obj *BaseRes) Init() error {
if obj.kind == "" {
return fmt.Errorf("Resource did not set kind!")
}
obj.events = make(chan event.Event) // unbuffered chan size to avoid stale events
obj.events = make(chan event.Event) // unbuffered chan to avoid stale events
return nil
}

View File

@@ -119,7 +119,6 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
var svc = fmt.Sprintf("%s.service", obj.Name) // systemd name
var send = false // send event?
var exit = false
var dirty = false
var invalid = false // does the svc exist or not?
var previous bool // previous invalid value
set := conn.NewSubscriptionSet() // no error should be returned
@@ -150,7 +149,7 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
if previous != invalid { // if invalid changed, send signal
send = true
dirty = true
obj.StateOK(false) // dirty
}
if invalid {
@@ -173,7 +172,7 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
return nil // exit
}
if event.GetActivity() {
dirty = true
obj.StateOK(false) // dirty
}
case <-cuid.ConvergedTimer():
@@ -183,7 +182,7 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
case <-Startup(startup):
cuid.SetConverged(false)
send = true
dirty = true
obj.StateOK(false) // dirty
}
} else {
if !activeSet {
@@ -216,7 +215,7 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
log.Printf("Svc[%s]->Stopped", svc)
}
send = true
dirty = true
obj.StateOK(false) // dirty
case err := <-subErrors:
cuid.SetConverged(false)
@@ -228,7 +227,7 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
return nil // exit
}
if event.GetActivity() {
dirty = true
obj.StateOK(false) // dirty
}
case <-cuid.ConvergedTimer():
@@ -238,17 +237,13 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
case <-Startup(startup):
cuid.SetConverged(false)
send = true
dirty = true
obj.StateOK(false) // dirty
}
}
if send {
startup = true // startup finished
send = false
if dirty {
dirty = false
obj.isStateOK = false // something made state dirty
}
if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK...
}
@@ -258,13 +253,7 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
// CheckApply checks the resource state and applies the resource if the bool
// input is true. It returns error info and if the state check passed or not.
func (obj *SvcRes) CheckApply(apply bool) (checkok bool, err error) {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
if obj.isStateOK { // cache the state
return true, nil
}
func (obj *SvcRes) CheckApply(apply bool) (checkOK bool, err error) {
if !systemdUtil.IsRunningSystemd() {
return false, fmt.Errorf("Systemd is not running.")
}
@@ -301,7 +290,6 @@ func (obj *SvcRes) CheckApply(apply bool) (checkok bool, err error) {
var startupOK = true // XXX: DETECT AND SET
if stateOK && startupOK {
obj.isStateOK = true
return true, nil // we are in the correct state
}
@@ -349,7 +337,6 @@ func (obj *SvcRes) CheckApply(apply bool) (checkok bool, err error) {
// XXX: also set enabled on boot
obj.isStateOK = true
return false, nil // success
}

View File

@@ -114,7 +114,6 @@ func (obj *TimerRes) Watch(processChan chan event.Event) error {
if send {
startup = true // startup finished
send = false
//obj.isStateOK = false
if exit, err := obj.DoSend(processChan, "timer ticked"); exit || err != nil {
return err // we exit or bubble up a NACK...
}
@@ -162,6 +161,5 @@ func (obj *TimerRes) Compare(res Res) bool {
// CheckApply method for Timer resource. Does nothing, returns happy!
func (obj *TimerRes) CheckApply(apply bool) (bool, error) {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
return true, nil // state is always okay
}

View File

@@ -206,7 +206,6 @@ func (obj *VirtRes) Watch(processChan chan event.Event) error {
var send = false
var exit = false
var dirty = false
for {
select {
@@ -215,37 +214,37 @@ func (obj *VirtRes) Watch(processChan chan event.Event) error {
switch event {
case libvirt.VIR_DOMAIN_EVENT_DEFINED:
if obj.Transient {
dirty = true
obj.StateOK(false) // dirty
send = true
}
case libvirt.VIR_DOMAIN_EVENT_UNDEFINED:
if !obj.Transient {
dirty = true
obj.StateOK(false) // dirty
send = true
}
case libvirt.VIR_DOMAIN_EVENT_STARTED:
fallthrough
case libvirt.VIR_DOMAIN_EVENT_RESUMED:
if obj.State != "running" {
dirty = true
obj.StateOK(false) // dirty
send = true
}
case libvirt.VIR_DOMAIN_EVENT_SUSPENDED:
if obj.State != "paused" {
dirty = true
obj.StateOK(false) // dirty
send = true
}
case libvirt.VIR_DOMAIN_EVENT_STOPPED:
fallthrough
case libvirt.VIR_DOMAIN_EVENT_SHUTDOWN:
if obj.State != "shutoff" {
dirty = true
obj.StateOK(false) // dirty
send = true
}
case libvirt.VIR_DOMAIN_EVENT_PMSUSPENDED:
fallthrough
case libvirt.VIR_DOMAIN_EVENT_CRASHED:
dirty = true
obj.StateOK(false) // dirty
send = true
}
@@ -266,17 +265,12 @@ func (obj *VirtRes) Watch(processChan chan event.Event) error {
case <-Startup(startup):
cuid.SetConverged(false)
send = true
dirty = true
obj.StateOK(false) // dirty
}
if send {
startup = true // startup finished
send = false
// only invalid state on certain types of events
if dirty {
dirty = false
obj.isStateOK = false // something made state dirty
}
if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK...
}
@@ -379,12 +373,6 @@ func (obj *VirtRes) domainCreate() (libvirt.VirDomain, bool, error) {
// CheckApply checks the resource state and applies the resource if the bool
// input is true. It returns error info and if the state check passed or not.
func (obj *VirtRes) CheckApply(apply bool) (bool, error) {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
if obj.isStateOK { // cache the state
return true, nil
}
var err error
obj.conn, err = obj.connect()
if err != nil {
@@ -399,7 +387,6 @@ func (obj *VirtRes) CheckApply(apply bool) (bool, error) {
} else if virErr, ok := err.(libvirt.VirError); ok && virErr.Code == libvirt.VIR_ERR_NO_DOMAIN {
// domain not found
if obj.absent {
obj.isStateOK = true
return true, nil
}
@@ -538,9 +525,6 @@ func (obj *VirtRes) CheckApply(apply bool) (bool, error) {
}
}
if apply || checkOK {
obj.isStateOK = true
}
return checkOK, nil // w00t
}