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

View File

@@ -210,7 +210,7 @@ func (obj *ExecRes) Watch(processChan chan event.Event) error {
startup = true // startup finished startup = true // startup finished
send = false send = false
// it is okay to invalidate the clean state on poke too // 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 { if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK... 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 // 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. // 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 // TODO: expand the IfCmd to be a list of commands
func (obj *ExecRes) CheckApply(apply bool) (checkok bool, err error) { func (obj *ExecRes) CheckApply(apply bool) (checkOK bool, err error) {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
// if there is a watch command, but no if command, run based on state // if there is a watch command, but no if command, run based on state
if obj.WatchCmd != "" && obj.IfCmd == "" { if obj.WatchCmd != "" && obj.IfCmd == "" {
if obj.isStateOK { if obj.IsStateOK() { // FIXME: this is done by engine now...
return true, nil 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 // if there is no watcher and no onlyif check, assume we should run
} else { // if obj.WatchCmd == "" && obj.IfCmd == "" { } else { // if obj.WatchCmd == "" && obj.IfCmd == "" {
// just run if state is dirty // just run if state is dirty
if obj.isStateOK { if obj.IsStateOK() { // FIXME: this is done by engine now...
return true, nil return true, nil
} }
} }
@@ -331,11 +330,11 @@ func (obj *ExecRes) CheckApply(apply bool) (checkok bool, err error) {
} }
// XXX: return based on exit value!! // 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. // 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! // 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 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 send = false // send event?
var exit = false var exit = false
var dirty = false
for { for {
if global.DEBUG { 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) log.Printf("%s[%s]: Event(%s): %v", obj.Kind(), obj.GetName(), event.Body.Name, event.Body.Op)
} }
send = true send = true
dirty = true obj.StateOK(false) // dirty
case event := <-obj.Events(): case event := <-obj.Events():
cuid.SetConverged(false) cuid.SetConverged(false)
if exit, send = obj.ReadEvent(&event); exit { if exit, send = obj.ReadEvent(&event); exit {
return nil // 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(): case <-cuid.ConvergedTimer():
cuid.SetConverged(true) // converged! cuid.SetConverged(true) // converged!
@@ -206,18 +205,13 @@ func (obj *FileRes) Watch(processChan chan event.Event) error {
case <-Startup(startup): case <-Startup(startup):
cuid.SetConverged(false) cuid.SetConverged(false)
send = true send = true
dirty = true obj.StateOK(false) // dirty
} }
// do all our event sending all together to avoid duplicate msgs // do all our event sending all together to avoid duplicate msgs
if send { if send {
startup = true // startup finished startup = true // startup finished
send = false 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 { if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK... 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 // 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. // input is true. It returns error info and if the state check passed or not.
func (obj *FileRes) CheckApply(apply bool) (checkOK bool, _ error) { 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 checkOK = true
@@ -673,10 +662,6 @@ func (obj *FileRes) CheckApply(apply bool) (checkOK bool, _ error) {
// checkOK = false // 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 return checkOK, nil // w00t
} }

View File

@@ -143,7 +143,6 @@ func (obj *HostnameRes) Watch(processChan chan event.Event) error {
bus.Signal(signals) bus.Signal(signals)
var send = false // send event? var send = false // send event?
var dirty = false
for { for {
obj.SetState(ResStateWatching) // reset obj.SetState(ResStateWatching) // reset
@@ -151,7 +150,7 @@ func (obj *HostnameRes) Watch(processChan chan event.Event) error {
case <-signals: case <-signals:
cuid.SetConverged(false) cuid.SetConverged(false)
send = true send = true
dirty = true obj.StateOK(false) // dirty
case event := <-obj.Events(): case event := <-obj.Events():
cuid.SetConverged(false) cuid.SetConverged(false)
@@ -160,7 +159,7 @@ func (obj *HostnameRes) Watch(processChan chan event.Event) error {
return nil // exit return nil // exit
} }
send = true send = true
dirty = true obj.StateOK(false) // dirty
case <-cuid.ConvergedTimer(): case <-cuid.ConvergedTimer():
cuid.SetConverged(true) // converged! cuid.SetConverged(true) // converged!
@@ -175,11 +174,7 @@ func (obj *HostnameRes) Watch(processChan chan event.Event) error {
if send { if send {
startup = true // startup finished startup = true // startup finished
send = false 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 { if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK... 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. // CheckApply method for Hostname resource.
func (obj *HostnameRes) CheckApply(apply bool) (checkOK bool, err error) { 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() conn, err := util.SystemBusPrivateUsable()
if err != nil { if err != nil {
return false, errwrap.Wrap(err, "Failed to connect to the private system bus") 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 checkOK = checkOK && propertyCheckOK
} }
if apply || checkOK {
obj.isStateOK = true
}
return checkOK, nil return checkOK, nil
} }

View File

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

View File

@@ -19,7 +19,6 @@ package resources
import ( import (
"encoding/gob" "encoding/gob"
"log"
"time" "time"
"github.com/purpleidea/mgmt/event" "github.com/purpleidea/mgmt/event"
@@ -102,8 +101,6 @@ func (obj *NoopRes) Watch(processChan chan event.Event) error {
if send { if send {
startup = true // startup finished startup = true // startup finished
send = false 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 { if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK... 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! // CheckApply method for Noop resource. Does nothing, returns happy!
func (obj *NoopRes) CheckApply(apply bool) (checkok bool, err error) { func (obj *NoopRes) CheckApply(apply bool) (checkOK bool, err error) {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
return true, nil // state is always okay 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 send = false
var exit = false var exit = false
var dirty = false
for { for {
obj.SetState(ResStateWatching) obj.SetState(ResStateWatching)
@@ -155,7 +154,7 @@ func (obj *NspawnRes) Watch(processChan chan event.Event) error {
return fmt.Errorf("Unknown event: %s", event.Name) return fmt.Errorf("Unknown event: %s", event.Name)
} }
send = true send = true
dirty = true obj.StateOK(false) // dirty
} }
case event := <-obj.Events(): case event := <-obj.Events():
@@ -171,18 +170,13 @@ func (obj *NspawnRes) Watch(processChan chan event.Event) error {
case <-Startup(startup): case <-Startup(startup):
cuid.SetConverged(false) cuid.SetConverged(false)
send = true send = true
dirty = true obj.StateOK(false) // dirty
} }
// do all our event sending all together to avoid duplicate msgs // do all our event sending all together to avoid duplicate msgs
if send || !obj.isStateOK { if send {
startup = true // startup finished startup = true // startup finished
send = false 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 { if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK... 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 // 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 // necessary changes to reach the desired state. this is run before Watch and
// again if watch finds a change occurring to the state // again if watch finds a change occurring to the state
func (obj *NspawnRes) CheckApply(apply bool) (checkok bool, err error) { 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
}
// this resource depends on systemd ensure that it's running // this resource depends on systemd ensure that it's running
if !systemdUtil.IsRunningSystemd() { if !systemdUtil.IsRunningSystemd() {
return false, errors.New("Systemd is not running.") 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 { if global.DEBUG {
log.Printf("%s[%s]: CheckApply() in valid state", obj.Kind(), obj.GetName()) log.Printf("%s[%s]: CheckApply() in valid state", obj.Kind(), obj.GetName())
} }
obj.isStateOK = true // state is ok
return true, nil 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 { if !apply {
return false, nil 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 return false, nil
} }

View File

@@ -21,7 +21,6 @@ import (
"crypto/rand" "crypto/rand"
"encoding/gob" "encoding/gob"
"fmt" "fmt"
"log"
"math/big" "math/big"
"os" "os"
"path" "path"
@@ -239,8 +238,6 @@ func (obj *PasswordRes) Watch(processChan chan event.Event) error {
if send { if send {
startup = true // startup finished startup = true // startup finished
send = false 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 { if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK... 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! // CheckApply method for Password resource. Does nothing, returns happy!
func (obj *PasswordRes) CheckApply(apply bool) (checkok bool, err error) { func (obj *PasswordRes) CheckApply(apply bool) (checkOK bool, err error) {
log.Printf("%s[%s]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)
return true, nil return true, nil
} }

View File

@@ -141,7 +141,6 @@ func (obj *PkgRes) Watch(processChan chan event.Event) error {
var send = false // send event? var send = false // send event?
var exit = false var exit = false
var dirty = false
for { for {
if global.DEBUG { if global.DEBUG {
@@ -165,14 +164,14 @@ func (obj *PkgRes) Watch(processChan chan event.Event) error {
} }
send = true send = true
dirty = true obj.StateOK(false) // dirty
case event := <-obj.Events(): case event := <-obj.Events():
cuid.SetConverged(false) cuid.SetConverged(false)
if exit, send = obj.ReadEvent(&event); exit { if exit, send = obj.ReadEvent(&event); exit {
return nil // exit return nil // exit
} }
dirty = false // these events don't invalidate state //obj.StateOK(false) // these events don't invalidate state
case <-cuid.ConvergedTimer(): case <-cuid.ConvergedTimer():
cuid.SetConverged(true) // converged! cuid.SetConverged(true) // converged!
@@ -181,18 +180,13 @@ func (obj *PkgRes) Watch(processChan chan event.Event) error {
case <-Startup(startup): case <-Startup(startup):
cuid.SetConverged(false) cuid.SetConverged(false)
send = true send = true
dirty = true obj.StateOK(false) // dirty
} }
// do all our event sending all together to avoid duplicate msgs // do all our event sending all together to avoid duplicate msgs
if send { if send {
startup = true // startup finished startup = true // startup finished
send = false 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 { if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK... 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 // 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. // 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) { func (obj *PkgRes) CheckApply(apply bool) (checkOK bool, err error) {
log.Printf("%s: CheckApply(%t)", obj.fmtNames(obj.getNames()), apply) log.Printf("%s: Check", obj.fmtNames(obj.getNames()))
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
}
bus := packagekit.NewBus() bus := packagekit.NewBus()
if bus == nil { if bus == nil {
@@ -309,12 +295,10 @@ func (obj *PkgRes) CheckApply(apply bool) (checkok bool, err error) {
fallthrough fallthrough
case "newest": case "newest":
if validState { if validState {
obj.isStateOK = true // reset
return true, nil // state is correct, exit! return true, nil // state is correct, exit!
} }
default: // version string default: // version string
if obj.State == data.Version && data.Version != "" { if obj.State == data.Version && data.Version != "" {
obj.isStateOK = true // reset
return true, nil return true, nil
} }
} }
@@ -358,7 +342,6 @@ func (obj *PkgRes) CheckApply(apply bool) (checkok bool, err error) {
return false, err // fail return false, err // fail
} }
log.Printf("%s: Set: %v success!", obj.fmtNames(util.StrListIntersection(applyPackages, obj.getNames())), obj.State) log.Printf("%s: Set: %v success!", obj.fmtNames(util.StrListIntersection(applyPackages, obj.getNames())), obj.State)
obj.isStateOK = true // reset
return false, nil // success return false, nil // success
} }

View File

@@ -221,7 +221,7 @@ func (obj *BaseRes) Init() error {
if obj.kind == "" { if obj.kind == "" {
return fmt.Errorf("Resource did not set 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 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 svc = fmt.Sprintf("%s.service", obj.Name) // systemd name
var send = false // send event? var send = false // send event?
var exit = false var exit = false
var dirty = false
var invalid = false // does the svc exist or not? var invalid = false // does the svc exist or not?
var previous bool // previous invalid value var previous bool // previous invalid value
set := conn.NewSubscriptionSet() // no error should be returned 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 if previous != invalid { // if invalid changed, send signal
send = true send = true
dirty = true obj.StateOK(false) // dirty
} }
if invalid { if invalid {
@@ -173,7 +172,7 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
return nil // exit return nil // exit
} }
if event.GetActivity() { if event.GetActivity() {
dirty = true obj.StateOK(false) // dirty
} }
case <-cuid.ConvergedTimer(): case <-cuid.ConvergedTimer():
@@ -183,7 +182,7 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
case <-Startup(startup): case <-Startup(startup):
cuid.SetConverged(false) cuid.SetConverged(false)
send = true send = true
dirty = true obj.StateOK(false) // dirty
} }
} else { } else {
if !activeSet { if !activeSet {
@@ -216,7 +215,7 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
log.Printf("Svc[%s]->Stopped", svc) log.Printf("Svc[%s]->Stopped", svc)
} }
send = true send = true
dirty = true obj.StateOK(false) // dirty
case err := <-subErrors: case err := <-subErrors:
cuid.SetConverged(false) cuid.SetConverged(false)
@@ -228,7 +227,7 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
return nil // exit return nil // exit
} }
if event.GetActivity() { if event.GetActivity() {
dirty = true obj.StateOK(false) // dirty
} }
case <-cuid.ConvergedTimer(): case <-cuid.ConvergedTimer():
@@ -238,17 +237,13 @@ func (obj *SvcRes) Watch(processChan chan event.Event) error {
case <-Startup(startup): case <-Startup(startup):
cuid.SetConverged(false) cuid.SetConverged(false)
send = true send = true
dirty = true obj.StateOK(false) // dirty
} }
} }
if send { if send {
startup = true // startup finished startup = true // startup finished
send = false send = false
if dirty {
dirty = false
obj.isStateOK = false // something made state dirty
}
if exit, err := obj.DoSend(processChan, ""); exit || err != nil { if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK... 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 // 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. // 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) { 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
}
if !systemdUtil.IsRunningSystemd() { if !systemdUtil.IsRunningSystemd() {
return false, fmt.Errorf("Systemd is not running.") 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 var startupOK = true // XXX: DETECT AND SET
if stateOK && startupOK { if stateOK && startupOK {
obj.isStateOK = true
return true, nil // we are in the correct state 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 // XXX: also set enabled on boot
obj.isStateOK = true
return false, nil // success return false, nil // success
} }

View File

@@ -114,7 +114,6 @@ func (obj *TimerRes) Watch(processChan chan event.Event) error {
if send { if send {
startup = true // startup finished startup = true // startup finished
send = false send = false
//obj.isStateOK = false
if exit, err := obj.DoSend(processChan, "timer ticked"); exit || err != nil { if exit, err := obj.DoSend(processChan, "timer ticked"); exit || err != nil {
return err // we exit or bubble up a NACK... 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! // CheckApply method for Timer resource. Does nothing, returns happy!
func (obj *TimerRes) CheckApply(apply bool) (bool, error) { 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 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 send = false
var exit = false var exit = false
var dirty = false
for { for {
select { select {
@@ -215,37 +214,37 @@ func (obj *VirtRes) Watch(processChan chan event.Event) error {
switch event { switch event {
case libvirt.VIR_DOMAIN_EVENT_DEFINED: case libvirt.VIR_DOMAIN_EVENT_DEFINED:
if obj.Transient { if obj.Transient {
dirty = true obj.StateOK(false) // dirty
send = true send = true
} }
case libvirt.VIR_DOMAIN_EVENT_UNDEFINED: case libvirt.VIR_DOMAIN_EVENT_UNDEFINED:
if !obj.Transient { if !obj.Transient {
dirty = true obj.StateOK(false) // dirty
send = true send = true
} }
case libvirt.VIR_DOMAIN_EVENT_STARTED: case libvirt.VIR_DOMAIN_EVENT_STARTED:
fallthrough fallthrough
case libvirt.VIR_DOMAIN_EVENT_RESUMED: case libvirt.VIR_DOMAIN_EVENT_RESUMED:
if obj.State != "running" { if obj.State != "running" {
dirty = true obj.StateOK(false) // dirty
send = true send = true
} }
case libvirt.VIR_DOMAIN_EVENT_SUSPENDED: case libvirt.VIR_DOMAIN_EVENT_SUSPENDED:
if obj.State != "paused" { if obj.State != "paused" {
dirty = true obj.StateOK(false) // dirty
send = true send = true
} }
case libvirt.VIR_DOMAIN_EVENT_STOPPED: case libvirt.VIR_DOMAIN_EVENT_STOPPED:
fallthrough fallthrough
case libvirt.VIR_DOMAIN_EVENT_SHUTDOWN: case libvirt.VIR_DOMAIN_EVENT_SHUTDOWN:
if obj.State != "shutoff" { if obj.State != "shutoff" {
dirty = true obj.StateOK(false) // dirty
send = true send = true
} }
case libvirt.VIR_DOMAIN_EVENT_PMSUSPENDED: case libvirt.VIR_DOMAIN_EVENT_PMSUSPENDED:
fallthrough fallthrough
case libvirt.VIR_DOMAIN_EVENT_CRASHED: case libvirt.VIR_DOMAIN_EVENT_CRASHED:
dirty = true obj.StateOK(false) // dirty
send = true send = true
} }
@@ -266,17 +265,12 @@ func (obj *VirtRes) Watch(processChan chan event.Event) error {
case <-Startup(startup): case <-Startup(startup):
cuid.SetConverged(false) cuid.SetConverged(false)
send = true send = true
dirty = true obj.StateOK(false) // dirty
} }
if send { if send {
startup = true // startup finished startup = true // startup finished
send = false 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 { if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
return err // we exit or bubble up a NACK... 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 // 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. // input is true. It returns error info and if the state check passed or not.
func (obj *VirtRes) CheckApply(apply bool) (bool, error) { 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 var err error
obj.conn, err = obj.connect() obj.conn, err = obj.connect()
if err != nil { 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 { } else if virErr, ok := err.(libvirt.VirError); ok && virErr.Code == libvirt.VIR_ERR_NO_DOMAIN {
// domain not found // domain not found
if obj.absent { if obj.absent {
obj.isStateOK = true
return true, nil 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 return checkOK, nil // w00t
} }