Rename type to resource (res) and service to svc

Naming the resources "type" was a stupid mistake, and is a huge source
of confusion when also talking about real types. Fix this before it gets
out of hand.
This commit is contained in:
James Shubin
2016-02-21 15:45:05 -05:00
parent d20b529508
commit 3a85384377
37 changed files with 446 additions and 446 deletions

View File

@@ -3,7 +3,7 @@ If you're looking for something to do, look here!
Let us know if you're working on one of the items. Let us know if you're working on one of the items.
## Package resource ## Package resource
- [ ] base type [bug](https://github.com/purpleidea/mgmt/issues/11) - [ ] base resource [bug](https://github.com/purpleidea/mgmt/issues/11)
- [ ] dnf blocker [bug](https://github.com/hughsie/PackageKit/issues/110) - [ ] dnf blocker [bug](https://github.com/hughsie/PackageKit/issues/110)
- [ ] install signal blocker [bug](https://github.com/hughsie/PackageKit/issues/109) - [ ] install signal blocker [bug](https://github.com/hughsie/PackageKit/issues/109)

View File

@@ -25,13 +25,13 @@ import (
"strings" "strings"
) )
type collectorTypeConfig struct { type collectorResConfig struct {
Type string `yaml:"type"` Res string `yaml:"res"`
Pattern string `yaml:"pattern"` // XXX: Not Implemented Pattern string `yaml:"pattern"` // XXX: Not Implemented
} }
type vertexConfig struct { type vertexConfig struct {
Type string `yaml:"type"` Res string `yaml:"res"`
Name string `yaml:"name"` Name string `yaml:"name"`
} }
@@ -42,16 +42,16 @@ type edgeConfig struct {
} }
type GraphConfig struct { type GraphConfig struct {
Graph string `yaml:"graph"` Graph string `yaml:"graph"`
Types struct { Resources struct {
Noop []NoopType `yaml:"noop"` Noop []NoopRes `yaml:"noop"`
File []FileType `yaml:"file"` File []FileRes `yaml:"file"`
Service []ServiceType `yaml:"service"` Svc []SvcRes `yaml:"svc"`
Exec []ExecType `yaml:"exec"` Exec []ExecRes `yaml:"exec"`
} `yaml:"types"` } `yaml:"resources"`
Collector []collectorTypeConfig `yaml:"collect"` Collector []collectorResConfig `yaml:"collect"`
Edges []edgeConfig `yaml:"edges"` Edges []edgeConfig `yaml:"edges"`
Comment string `yaml:"comment"` Comment string `yaml:"comment"`
} }
func (c *GraphConfig) Parse(data []byte) error { func (c *GraphConfig) Parse(data []byte) error {
@@ -95,13 +95,13 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
var NoopMap = make(map[string]*Vertex) var NoopMap = make(map[string]*Vertex)
var FileMap = make(map[string]*Vertex) var FileMap = make(map[string]*Vertex)
var ServiceMap = make(map[string]*Vertex) var SvcMap = make(map[string]*Vertex)
var ExecMap = make(map[string]*Vertex) var ExecMap = make(map[string]*Vertex)
var lookup = make(map[string]map[string]*Vertex) var lookup = make(map[string]map[string]*Vertex)
lookup["noop"] = NoopMap lookup["noop"] = NoopMap
lookup["file"] = FileMap lookup["file"] = FileMap
lookup["service"] = ServiceMap lookup["svc"] = SvcMap
lookup["exec"] = ExecMap lookup["exec"] = ExecMap
//log.Printf("%+v", config) // debug //log.Printf("%+v", config) // debug
@@ -110,8 +110,8 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
var keep []*Vertex // list of vertex which are the same in new graph var keep []*Vertex // list of vertex which are the same in new graph
for _, t := range config.Types.Noop { for _, t := range config.Resources.Noop {
obj := NewNoopType(t.Name) obj := NewNoopRes(t.Name)
v := g.GetVertexMatch(obj) v := g.GetVertexMatch(obj)
if v == nil { // no match found if v == nil { // no match found
v = NewVertex(obj) v = NewVertex(obj)
@@ -121,7 +121,7 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
keep = append(keep, v) // append keep = append(keep, v) // append
} }
for _, t := range config.Types.File { for _, t := range config.Resources.File {
// XXX: should we export based on a @@ prefix, or a metaparam // XXX: should we export based on a @@ prefix, or a metaparam
// like exported => true || exported => (host pattern)||(other pattern?) // like exported => true || exported => (host pattern)||(other pattern?)
if strings.HasPrefix(t.Name, "@@") { // exported resource if strings.HasPrefix(t.Name, "@@") { // exported resource
@@ -132,7 +132,7 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
continue continue
} }
} else { } else {
obj := NewFileType(t.Name, t.Path, t.Dirname, t.Basename, t.Content, t.State) obj := NewFileRes(t.Name, t.Path, t.Dirname, t.Basename, t.Content, t.State)
v := g.GetVertexMatch(obj) v := g.GetVertexMatch(obj)
if v == nil { // no match found if v == nil { // no match found
v = NewVertex(obj) v = NewVertex(obj)
@@ -143,19 +143,19 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
} }
} }
for _, t := range config.Types.Service { for _, t := range config.Resources.Svc {
obj := NewServiceType(t.Name, t.State, t.Startup) obj := NewSvcRes(t.Name, t.State, t.Startup)
v := g.GetVertexMatch(obj) v := g.GetVertexMatch(obj)
if v == nil { // no match found if v == nil { // no match found
v = NewVertex(obj) v = NewVertex(obj)
g.AddVertex(v) // call standalone in case not part of an edge g.AddVertex(v) // call standalone in case not part of an edge
} }
ServiceMap[obj.Name] = v // used for constructing edges SvcMap[obj.Name] = v // used for constructing edges
keep = append(keep, v) // append keep = append(keep, v) // append
} }
for _, t := range config.Types.Exec { for _, t := range config.Resources.Exec {
obj := NewExecType(t.Name, t.Cmd, t.Shell, t.Timeout, t.WatchCmd, t.WatchShell, t.IfCmd, t.IfShell, t.PollInt, t.State) obj := NewExecRes(t.Name, t.Cmd, t.Shell, t.Timeout, t.WatchCmd, t.WatchShell, t.IfCmd, t.IfShell, t.PollInt, t.State)
v := g.GetVertexMatch(obj) v := g.GetVertexMatch(obj)
if v == nil { // no match found if v == nil { // no match found
v = NewVertex(obj) v = NewVertex(obj)
@@ -171,11 +171,11 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
nodes, ok := etcdO.EtcdGet() nodes, ok := etcdO.EtcdGet()
if ok { if ok {
for _, t := range config.Collector { for _, t := range config.Collector {
// XXX: use t.Type and optionally t.Pattern to collect from etcd storage // XXX: use t.Res and optionally t.Pattern to collect from etcd storage
log.Printf("Collect: %v; Pattern: %v", t.Type, t.Pattern) log.Printf("Collect: %v; Pattern: %v", t.Res, t.Pattern)
for _, x := range etcdO.EtcdGetProcess(nodes, "file") { for _, x := range etcdO.EtcdGetProcess(nodes, "file") {
var obj *FileType var obj *FileRes
if B64ToObj(x, &obj) != true { if B64ToObj(x, &obj) != true {
log.Printf("Collect: File: %v not collected!", x) log.Printf("Collect: File: %v not collected!", x)
continue continue
@@ -205,25 +205,25 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
for _, v := range g.GetVertices() { for _, v := range g.GetVertices() {
if !HasVertex(v, keep) { if !HasVertex(v, keep) {
// wait for exit before starting new graph! // wait for exit before starting new graph!
v.Type.SendEvent(eventExit, true, false) v.Res.SendEvent(eventExit, true, false)
g.DeleteVertex(v) g.DeleteVertex(v)
} }
} }
for _, e := range config.Edges { for _, e := range config.Edges {
if _, ok := lookup[e.From.Type]; !ok { if _, ok := lookup[e.From.Res]; !ok {
return false return false
} }
if _, ok := lookup[e.To.Type]; !ok { if _, ok := lookup[e.To.Res]; !ok {
return false return false
} }
if _, ok := lookup[e.From.Type][e.From.Name]; !ok { if _, ok := lookup[e.From.Res][e.From.Name]; !ok {
return false return false
} }
if _, ok := lookup[e.To.Type][e.To.Name]; !ok { if _, ok := lookup[e.To.Res][e.To.Name]; !ok {
return false return false
} }
g.AddEdge(lookup[e.From.Type][e.From.Name], lookup[e.To.Type][e.To.Name], NewEdge(e.Name)) g.AddEdge(lookup[e.From.Res][e.From.Name], lookup[e.To.Res][e.To.Name], NewEdge(e.Name))
} }
return true return true
} }

View File

@@ -27,7 +27,7 @@ import (
"syscall" "syscall"
) )
// XXX: it would be great if we could reuse code between this and the file type // XXX: it would be great if we could reuse code between this and the file resource
// XXX: patch this to submit it as part of go-fsnotify if they're interested... // XXX: patch this to submit it as part of go-fsnotify if they're interested...
func ConfigWatch(file string) chan bool { func ConfigWatch(file string) chan bool {
ch := make(chan bool) ch := make(chan bool)

30
etcd.go
View File

@@ -191,8 +191,8 @@ func (etcdO *EtcdWObject) EtcdWatch() chan etcdMsg {
} }
} }
// FIXME: we get events on key/type/value changes for // FIXME: we get events on key/res/value changes for
// each type directory... ignore the non final ones... // each res directory... ignore the non final ones...
// IOW, ignore everything except for the value or some // IOW, ignore everything except for the value or some
// field which gets set last... this could be the max count field thing... // field which gets set last... this could be the max count field thing...
@@ -207,7 +207,7 @@ func (etcdO *EtcdWObject) EtcdWatch() chan etcdMsg {
} }
// helper function to store our data in etcd // helper function to store our data in etcd
func (etcdO *EtcdWObject) EtcdPut(hostname, key, typ string, obj interface{}) bool { func (etcdO *EtcdWObject) EtcdPut(hostname, key, res string, obj interface{}) bool {
kapi := etcdO.GetKAPI() kapi := etcdO.GetKAPI()
output, ok := ObjToB64(obj) output, ok := ObjToB64(obj)
if !ok { if !ok {
@@ -215,11 +215,11 @@ func (etcdO *EtcdWObject) EtcdPut(hostname, key, typ string, obj interface{}) bo
return false return false
} }
path := fmt.Sprintf("/exported/%s/types/%s/type", hostname, key) path := fmt.Sprintf("/exported/%s/resources/%s/res", hostname, key)
_, err := kapi.Set(etcd_context.Background(), path, typ, nil) _, err := kapi.Set(etcd_context.Background(), path, res, nil)
// XXX validate... // XXX validate...
path = fmt.Sprintf("/exported/%s/types/%s/value", hostname, key) path = fmt.Sprintf("/exported/%s/resources/%s/value", hostname, key)
resp, err := kapi.Set(etcd_context.Background(), path, output, nil) resp, err := kapi.Set(etcd_context.Background(), path, output, nil)
if err != nil { if err != nil {
if cerr, ok := err.(*etcd.ClusterError); ok { if cerr, ok := err.(*etcd.ClusterError); ok {
@@ -240,7 +240,7 @@ func (etcdO *EtcdWObject) EtcdPut(hostname, key, typ string, obj interface{}) bo
// lookup /exported/ node hierarchy // lookup /exported/ node hierarchy
func (etcdO *EtcdWObject) EtcdGet() (etcd.Nodes, bool) { func (etcdO *EtcdWObject) EtcdGet() (etcd.Nodes, bool) {
kapi := etcdO.GetKAPI() kapi := etcdO.GetKAPI()
// key structure is /exported/<hostname>/types/... // key structure is /exported/<hostname>/resources/...
resp, err := kapi.Get(etcd_context.Background(), "/exported/", &etcd.GetOptions{Recursive: true}) resp, err := kapi.Get(etcd_context.Background(), "/exported/", &etcd.GetOptions{Recursive: true})
if err != nil { if err != nil {
return nil, false // not found return nil, false // not found
@@ -248,8 +248,8 @@ func (etcdO *EtcdWObject) EtcdGet() (etcd.Nodes, bool) {
return resp.Node.Nodes, true return resp.Node.Nodes, true
} }
func (etcdO *EtcdWObject) EtcdGetProcess(nodes etcd.Nodes, typ string) []string { func (etcdO *EtcdWObject) EtcdGetProcess(nodes etcd.Nodes, res string) []string {
//path := fmt.Sprintf("/exported/%s/types/", h) //path := fmt.Sprintf("/exported/%s/resources/", h)
top := "/exported/" top := "/exported/"
log.Printf("Etcd: Get: %+v", nodes) // Get().Nodes.Nodes log.Printf("Etcd: Get: %+v", nodes) // Get().Nodes.Nodes
var output []string var output []string
@@ -261,20 +261,20 @@ func (etcdO *EtcdWObject) EtcdGetProcess(nodes etcd.Nodes, typ string) []string
host := x.Key[len(top):] host := x.Key[len(top):]
//log.Printf("Get().Nodes[%v]: %+v ==> %+v", -1, host, x.Nodes) //log.Printf("Get().Nodes[%v]: %+v ==> %+v", -1, host, x.Nodes)
//log.Printf("Get().Nodes[%v]: %+v ==> %+v", i, x.Key, x.Nodes) //log.Printf("Get().Nodes[%v]: %+v ==> %+v", i, x.Key, x.Nodes)
types, ok := EtcdGetChildNodeByKey(x, "types") resources, ok := EtcdGetChildNodeByKey(x, "resources")
if !ok { if !ok {
continue continue
} }
for _, y := range types.Nodes { // loop through types for _, y := range resources.Nodes { // loop through resources
//key := y.Key # UUID? //key := y.Key # UUID?
//log.Printf("Get(%v): TYPE[%v]", host, y.Key) //log.Printf("Get(%v): RES[%v]", host, y.Key)
t, ok := EtcdGetChildNodeByKey(y, "type") t, ok := EtcdGetChildNodeByKey(y, "res")
if !ok { if !ok {
continue continue
} }
if typ != "" && typ != t.Value { if res != "" && res != t.Value {
continue continue
} // filter based on type } // filter based on res
v, ok := EtcdGetChildNodeByKey(y, "value") // B64ToObj this v, ok := EtcdGetChildNodeByKey(y, "value") // B64ToObj this
if !ok { if !ok {

View File

@@ -1,7 +1,7 @@
--- ---
graph: mygraph graph: mygraph
comment: hello world example comment: hello world example
types: resources:
noop: noop:
- name: noop1 - name: noop1
file: file:
@@ -13,8 +13,8 @@ types:
edges: edges:
- name: e1 - name: e1
from: from:
type: noop res: noop
name: noop1 name: noop1
to: to:
type: file res: file
name: file1 name: file1

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
noop: noop:
- name: noop1 - name: noop1
file: file:
@@ -27,15 +27,15 @@ types:
edges: edges:
- name: e1 - name: e1
from: from:
type: file res: file
name: file1 name: file1
to: to:
type: file res: file
name: file2 name: file2
- name: e2 - name: e2
from: from:
type: file res: file
name: file2 name: file2
to: to:
type: file res: file
name: file3 name: file3

View File

@@ -1,7 +1,7 @@
--- ---
graph: mygraph graph: mygraph
comment: simple exec fan in to fan out example to demonstrate optimization comment: simple exec fan in to fan out example to demonstrate optimization
types: resources:
exec: exec:
- name: exec1 - name: exec1
cmd: sleep 10s cmd: sleep 10s
@@ -86,43 +86,43 @@ types:
edges: edges:
- name: e1 - name: e1
from: from:
type: exec res: exec
name: exec1 name: exec1
to: to:
type: exec res: exec
name: exec4 name: exec4
- name: e2 - name: e2
from: from:
type: exec res: exec
name: exec2 name: exec2
to: to:
type: exec res: exec
name: exec4 name: exec4
- name: e3 - name: e3
from: from:
type: exec res: exec
name: exec3 name: exec3
to: to:
type: exec res: exec
name: exec4 name: exec4
- name: e4 - name: e4
from: from:
type: exec res: exec
name: exec4 name: exec4
to: to:
type: exec res: exec
name: exec5 name: exec5
- name: e5 - name: e5
from: from:
type: exec res: exec
name: exec4 name: exec4
to: to:
type: exec res: exec
name: exec6 name: exec6
- name: e6 - name: e6
from: from:
type: exec res: exec
name: exec4 name: exec4
to: to:
type: exec res: exec
name: exec7 name: exec7

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
file: file:
- name: file1 - name: file1
path: "/tmp/mgmt/f1" path: "/tmp/mgmt/f1"
@@ -15,8 +15,8 @@ types:
edges: edges:
- name: e1 - name: e1
from: from:
type: file res: file
name: file1 name: file1
to: to:
type: file res: file
name: file2 name: file2

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
file: file:
- name: file2 - name: file2
path: "/tmp/mgmt/f2" path: "/tmp/mgmt/f2"
@@ -15,8 +15,8 @@ types:
edges: edges:
- name: e2 - name: e2
from: from:
type: file res: file
name: file2 name: file2
to: to:
type: file res: file
name: file3 name: file3

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
noop: noop:
- name: noop1 - name: noop1
file: file:
@@ -9,22 +9,22 @@ types:
content: | content: |
i am f1 i am f1
state: exists state: exists
service: svc:
- name: purpleidea - name: purpleidea
state: running state: running
startup: enabled startup: enabled
edges: edges:
- name: e1 - name: e1
from: from:
type: noop res: noop
name: noop1 name: noop1
to: to:
type: file res: file
name: file1 name: file1
- name: e2 - name: e2
from: from:
type: file res: file
name: file1 name: file1
to: to:
type: service res: svc
name: purpleidea name: purpleidea

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
file: file:
- name: file1a - name: file1a
path: "/tmp/mgmtA/f1a" path: "/tmp/mgmtA/f1a"
@@ -23,6 +23,6 @@ types:
i am f4, exported from host A i am f4, exported from host A
state: exists state: exists
collect: collect:
- type: file - res: file
pattern: "/tmp/mgmtA/" pattern: "/tmp/mgmtA/"
edges: [] edges: []

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
file: file:
- name: file1b - name: file1b
path: "/tmp/mgmtB/f1b" path: "/tmp/mgmtB/f1b"
@@ -23,6 +23,6 @@ types:
i am f4, exported from host B i am f4, exported from host B
state: exists state: exists
collect: collect:
- type: file - res: file
pattern: "/tmp/mgmtB/" pattern: "/tmp/mgmtB/"
edges: [] edges: []

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
file: file:
- name: file1c - name: file1c
path: "/tmp/mgmtC/f1c" path: "/tmp/mgmtC/f1c"
@@ -23,6 +23,6 @@ types:
i am f4, exported from host C i am f4, exported from host C
state: exists state: exists
collect: collect:
- type: file - res: file
pattern: "/tmp/mgmtC/" pattern: "/tmp/mgmtC/"
edges: [] edges: []

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
file: file:
- name: file1 - name: file1
path: "/tmp/mgmt/f1" path: "/tmp/mgmt/f1"
@@ -13,6 +13,6 @@ types:
i am f3, exported from host A i am f3, exported from host A
state: exists state: exists
collect: collect:
- type: file - res: file
pattern: '' pattern: ''
edges: edges:

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
file: file:
- name: file1 - name: file1
path: "/tmp/mgmt/f1" path: "/tmp/mgmt/f1"
@@ -8,6 +8,6 @@ types:
i am f1 i am f1
state: exists state: exists
collect: collect:
- type: file - res: file
pattern: '' pattern: ''
edges: edges:

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
noop: noop:
- name: noop1 - name: noop1
edges: edges:

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
noop: noop:
- name: noop1 - name: noop1
exec: exec:

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
exec: exec:
- name: exec1 - name: exec1
cmd: sleep 10s cmd: sleep 10s
@@ -45,15 +45,15 @@ types:
edges: edges:
- name: e1 - name: e1
from: from:
type: exec res: exec
name: exec1 name: exec1
to: to:
type: exec res: exec
name: exec2 name: exec2
- name: e2 - name: e2
from: from:
type: exec res: exec
name: exec2 name: exec2
to: to:
type: exec res: exec
name: exec3 name: exec3

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
exec: exec:
- name: exec1 - name: exec1
cmd: sleep 10s cmd: sleep 10s
@@ -25,8 +25,8 @@ types:
edges: edges:
- name: e1 - name: e1
from: from:
type: exec res: exec
name: exec1 name: exec1
to: to:
type: exec res: exec
name: exec2 name: exec2

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
exec: exec:
- name: exec1 - name: exec1
cmd: sleep 10s cmd: sleep 10s
@@ -25,8 +25,8 @@ types:
edges: edges:
- name: e1 - name: e1
from: from:
type: exec res: exec
name: exec1 name: exec1
to: to:
type: exec res: exec
name: exec2 name: exec2

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
exec: exec:
- name: exec1 - name: exec1
cmd: echo hello from exec1 cmd: echo hello from exec1
@@ -25,8 +25,8 @@ types:
edges: edges:
- name: e1 - name: e1
from: from:
type: exec res: exec
name: exec1 name: exec1
to: to:
type: exec res: exec
name: exec2 name: exec2

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
exec: exec:
- name: exec1 - name: exec1
cmd: echo hello from exec1 cmd: echo hello from exec1

View File

@@ -1,7 +1,7 @@
--- ---
graph: mygraph graph: mygraph
comment: simple exec fan in example to demonstrate optimization comment: simple exec fan in example to demonstrate optimization
types: resources:
exec: exec:
- name: exec1 - name: exec1
cmd: sleep 10s cmd: sleep 10s
@@ -56,22 +56,22 @@ types:
edges: edges:
- name: e1 - name: e1
from: from:
type: exec res: exec
name: exec1 name: exec1
to: to:
type: exec res: exec
name: exec5 name: exec5
- name: e2 - name: e2
from: from:
type: exec res: exec
name: exec2 name: exec2
to: to:
type: exec res: exec
name: exec5 name: exec5
- name: e3 - name: e3
from: from:
type: exec res: exec
name: exec3 name: exec3
to: to:
type: exec res: exec
name: exec5 name: exec5

78
exec.go
View File

@@ -25,8 +25,8 @@ import (
"strings" "strings"
) )
type ExecType struct { type ExecRes struct {
BaseType `yaml:",inline"` BaseRes `yaml:",inline"`
State string `yaml:"state"` // state: exists/present?, absent, (undefined?) State string `yaml:"state"` // state: exists/present?, absent, (undefined?)
Cmd string `yaml:"cmd"` // the command to run Cmd string `yaml:"cmd"` // the command to run
Shell string `yaml:"shell"` // the (optional) shell to use to run the cmd Shell string `yaml:"shell"` // the (optional) shell to use to run the cmd
@@ -38,10 +38,10 @@ type ExecType struct {
PollInt int `yaml:"pollint"` // the poll interval for the ifcmd PollInt int `yaml:"pollint"` // the poll interval for the ifcmd
} }
func NewExecType(name, cmd, shell string, timeout int, watchcmd, watchshell, ifcmd, ifshell string, pollint int, state string) *ExecType { func NewExecRes(name, cmd, shell string, timeout int, watchcmd, watchshell, ifcmd, ifshell string, pollint int, state string) *ExecRes {
// FIXME if path = nil, path = name ... // FIXME if path = nil, path = name ...
return &ExecType{ return &ExecRes{
BaseType: BaseType{ BaseRes: BaseRes{
Name: name, Name: name,
events: make(chan Event), events: make(chan Event),
vertex: nil, vertex: nil,
@@ -58,13 +58,13 @@ func NewExecType(name, cmd, shell string, timeout int, watchcmd, watchshell, ifc
} }
} }
func (obj *ExecType) GetType() string { func (obj *ExecRes) GetRes() string {
return "Exec" return "Exec"
} }
// validate if the params passed in are valid data // validate if the params passed in are valid data
// FIXME: where should this get called ? // FIXME: where should this get called ?
func (obj *ExecType) Validate() bool { func (obj *ExecRes) Validate() bool {
if obj.Cmd == "" { // this is the only thing that is really required if obj.Cmd == "" { // this is the only thing that is really required
return false return false
} }
@@ -78,7 +78,7 @@ func (obj *ExecType) Validate() bool {
} }
// wraps the scanner output in a channel // wraps the scanner output in a channel
func (obj *ExecType) BufioChanScanner(scanner *bufio.Scanner) (chan string, chan error) { func (obj *ExecRes) BufioChanScanner(scanner *bufio.Scanner) (chan string, chan error) {
ch, errch := make(chan string), make(chan error) ch, errch := make(chan string), make(chan error)
go func() { go func() {
for scanner.Scan() { for scanner.Scan() {
@@ -96,7 +96,7 @@ func (obj *ExecType) BufioChanScanner(scanner *bufio.Scanner) (chan string, chan
} }
// Exec watcher // Exec watcher
func (obj *ExecType) Watch() { func (obj *ExecRes) Watch() {
if obj.IsWatching() { if obj.IsWatching() {
return return
} }
@@ -128,7 +128,7 @@ func (obj *ExecType) Watch() {
cmdReader, err := cmd.StdoutPipe() cmdReader, err := cmd.StdoutPipe()
if err != nil { if err != nil {
log.Printf("%v[%v]: Error creating StdoutPipe for Cmd: %v", obj.GetType(), obj.GetName(), err) log.Printf("%v[%v]: Error creating StdoutPipe for Cmd: %v", obj.GetRes(), obj.GetName(), err)
log.Fatal(err) // XXX: how should we handle errors? log.Fatal(err) // XXX: how should we handle errors?
} }
scanner := bufio.NewScanner(cmdReader) scanner := bufio.NewScanner(cmdReader)
@@ -140,7 +140,7 @@ func (obj *ExecType) Watch() {
cmd.Process.Kill() // TODO: is this necessary? cmd.Process.Kill() // TODO: is this necessary?
}() }()
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
log.Printf("%v[%v]: Error starting Cmd: %v", obj.GetType(), obj.GetName(), err) log.Printf("%v[%v]: Error starting Cmd: %v", obj.GetRes(), obj.GetName(), err)
log.Fatal(err) // XXX: how should we handle errors? log.Fatal(err) // XXX: how should we handle errors?
} }
@@ -148,36 +148,36 @@ func (obj *ExecType) Watch() {
} }
for { for {
obj.SetState(typeWatching) // reset obj.SetState(resStateWatching) // reset
select { select {
case text := <-bufioch: case text := <-bufioch:
obj.SetConvergedState(typeConvergedNil) obj.SetConvergedState(resConvergedNil)
// each time we get a line of output, we loop! // each time we get a line of output, we loop!
log.Printf("%v[%v]: Watch output: %s", obj.GetType(), obj.GetName(), text) log.Printf("%v[%v]: Watch output: %s", obj.GetRes(), obj.GetName(), text)
if text != "" { if text != "" {
send = true send = true
} }
case err := <-errch: case err := <-errch:
obj.SetConvergedState(typeConvergedNil) // XXX ? obj.SetConvergedState(resConvergedNil) // XXX ?
if err == nil { // EOF if err == nil { // EOF
// FIXME: add an "if watch command ends/crashes" // FIXME: add an "if watch command ends/crashes"
// restart or generate error option // restart or generate error option
log.Printf("%v[%v]: Reached EOF", obj.GetType(), obj.GetName()) log.Printf("%v[%v]: Reached EOF", obj.GetRes(), obj.GetName())
return return
} }
log.Printf("%v[%v]: Error reading input?: %v", obj.GetType(), obj.GetName(), err) log.Printf("%v[%v]: Error reading input?: %v", obj.GetRes(), obj.GetName(), err)
log.Fatal(err) log.Fatal(err)
// XXX: how should we handle errors? // XXX: how should we handle errors?
case event := <-obj.events: case event := <-obj.events:
obj.SetConvergedState(typeConvergedNil) obj.SetConvergedState(resConvergedNil)
if exit, send = obj.ReadEvent(&event); exit { if exit, send = obj.ReadEvent(&event); exit {
return // exit return // exit
} }
case _ = <-TimeAfterOrBlock(obj.ctimeout): case _ = <-TimeAfterOrBlock(obj.ctimeout):
obj.SetConvergedState(typeConvergedTimeout) obj.SetConvergedState(resConvergedTimeout)
obj.converged <- true obj.converged <- true
continue continue
} }
@@ -193,7 +193,7 @@ func (obj *ExecType) Watch() {
} }
// TODO: expand the IfCmd to be a list of commands // TODO: expand the IfCmd to be a list of commands
func (obj *ExecType) StateOK() bool { func (obj *ExecRes) StateOK() bool {
// 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 b := obj.isStateOK; obj.WatchCmd != "" && obj.IfCmd == "" { if b := obj.isStateOK; obj.WatchCmd != "" && obj.IfCmd == "" {
@@ -241,8 +241,8 @@ func (obj *ExecType) StateOK() bool {
} }
} }
func (obj *ExecType) Apply() bool { func (obj *ExecRes) Apply() bool {
log.Printf("%v[%v]: Apply", obj.GetType(), obj.GetName()) log.Printf("%v[%v]: Apply", obj.GetRes(), obj.GetName())
var cmdName string var cmdName string
var cmdArgs []string var cmdArgs []string
if obj.Shell == "" { if obj.Shell == "" {
@@ -264,7 +264,7 @@ func (obj *ExecType) Apply() bool {
cmd.Stdout = &out cmd.Stdout = &out
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
log.Printf("%v[%v]: Error starting Cmd: %v", obj.GetType(), obj.GetName(), err) log.Printf("%v[%v]: Error starting Cmd: %v", obj.GetRes(), obj.GetName(), err)
return false return false
} }
@@ -278,12 +278,12 @@ func (obj *ExecType) Apply() bool {
select { select {
case err := <-done: case err := <-done:
if err != nil { if err != nil {
log.Printf("%v[%v]: Error waiting for Cmd: %v", obj.GetType(), obj.GetName(), err) log.Printf("%v[%v]: Error waiting for Cmd: %v", obj.GetRes(), obj.GetName(), err)
return false return false
} }
case <-TimeAfterOrBlock(timeout): case <-TimeAfterOrBlock(timeout):
log.Printf("%v[%v]: Timeout waiting for Cmd", obj.GetType(), obj.GetName()) log.Printf("%v[%v]: Timeout waiting for Cmd", obj.GetRes(), obj.GetName())
//cmd.Process.Kill() // TODO: is this necessary? //cmd.Process.Kill() // TODO: is this necessary?
return false return false
} }
@@ -301,35 +301,35 @@ func (obj *ExecType) Apply() bool {
return true return true
} }
func (obj *ExecType) Compare(typ Type) bool { func (obj *ExecRes) Compare(res Res) bool {
switch typ.(type) { switch res.(type) {
case *ExecType: case *ExecRes:
typ := typ.(*ExecType) res := res.(*ExecRes)
if obj.Name != typ.Name { if obj.Name != res.Name {
return false return false
} }
if obj.Cmd != typ.Cmd { if obj.Cmd != res.Cmd {
return false return false
} }
if obj.Shell != typ.Shell { if obj.Shell != res.Shell {
return false return false
} }
if obj.Timeout != typ.Timeout { if obj.Timeout != res.Timeout {
return false return false
} }
if obj.WatchCmd != typ.WatchCmd { if obj.WatchCmd != res.WatchCmd {
return false return false
} }
if obj.WatchShell != typ.WatchShell { if obj.WatchShell != res.WatchShell {
return false return false
} }
if obj.IfCmd != typ.IfCmd { if obj.IfCmd != res.IfCmd {
return false return false
} }
if obj.PollInt != typ.PollInt { if obj.PollInt != res.PollInt {
return false return false
} }
if obj.State != typ.State { if obj.State != res.State {
return false return false
} }
default: default:

68
file.go
View File

@@ -31,8 +31,8 @@ import (
"syscall" "syscall"
) )
type FileType struct { type FileRes struct {
BaseType `yaml:",inline"` BaseRes `yaml:",inline"`
Path string `yaml:"path"` // path variable (should default to name) Path string `yaml:"path"` // path variable (should default to name)
Dirname string `yaml:"dirname"` Dirname string `yaml:"dirname"`
Basename string `yaml:"basename"` Basename string `yaml:"basename"`
@@ -41,10 +41,10 @@ type FileType struct {
sha256sum string sha256sum string
} }
func NewFileType(name, path, dirname, basename, content, state string) *FileType { func NewFileRes(name, path, dirname, basename, content, state string) *FileRes {
// FIXME if path = nil, path = name ... // FIXME if path = nil, path = name ...
return &FileType{ return &FileRes{
BaseType: BaseType{ BaseRes: BaseRes{
Name: name, Name: name,
events: make(chan Event), events: make(chan Event),
vertex: nil, vertex: nil,
@@ -58,12 +58,12 @@ func NewFileType(name, path, dirname, basename, content, state string) *FileType
} }
} }
func (obj *FileType) GetType() string { func (obj *FileRes) GetRes() string {
return "File" return "File"
} }
// validate if the params passed in are valid data // validate if the params passed in are valid data
func (obj *FileType) Validate() bool { func (obj *FileRes) Validate() bool {
if obj.Dirname != "" { if obj.Dirname != "" {
// must end with / // must end with /
if obj.Dirname[len(obj.Dirname)-1:] != "/" { if obj.Dirname[len(obj.Dirname)-1:] != "/" {
@@ -79,7 +79,7 @@ func (obj *FileType) Validate() bool {
return true return true
} }
func (obj *FileType) GetPath() string { func (obj *FileRes) GetPath() string {
d := Dirname(obj.Path) d := Dirname(obj.Path)
b := Basename(obj.Path) b := Basename(obj.Path)
if !obj.Validate() || (obj.Dirname == "" && obj.Basename == "") { if !obj.Validate() || (obj.Dirname == "" && obj.Basename == "") {
@@ -96,7 +96,7 @@ func (obj *FileType) GetPath() string {
// File watcher for files and directories // File watcher for files and directories
// Modify with caution, probably important to write some test cases first! // Modify with caution, probably important to write some test cases first!
// obj.GetPath(): file or directory // obj.GetPath(): file or directory
func (obj *FileType) Watch() { func (obj *FileRes) Watch() {
if obj.IsWatching() { if obj.IsWatching() {
return return
} }
@@ -152,13 +152,13 @@ func (obj *FileType) Watch() {
continue continue
} }
obj.SetState(typeWatching) // reset obj.SetState(resStateWatching) // reset
select { select {
case event := <-watcher.Events: case event := <-watcher.Events:
if DEBUG { if DEBUG {
log.Printf("File[%v]: Watch(%v), Event(%v): %v", obj.GetName(), current, event.Name, event.Op) log.Printf("File[%v]: Watch(%v), Event(%v): %v", obj.GetName(), current, event.Name, event.Op)
} }
obj.SetConvergedState(typeConvergedNil) // XXX: technically i can detect if the event is erroneous or not first obj.SetConvergedState(resConvergedNil) // XXX: technically i can detect if the event is erroneous or not first
// the deeper you go, the bigger the deltaDepth is... // the deeper you go, the bigger the deltaDepth is...
// this is the difference between what we're watching, // this is the difference between what we're watching,
// and the event... doesn't mean we can't watch deeper // and the event... doesn't mean we can't watch deeper
@@ -228,20 +228,20 @@ func (obj *FileType) Watch() {
} }
case err := <-watcher.Errors: case err := <-watcher.Errors:
obj.SetConvergedState(typeConvergedNil) // XXX ? obj.SetConvergedState(resConvergedNil) // XXX ?
log.Println("error:", err) log.Println("error:", err)
log.Fatal(err) log.Fatal(err)
//obj.events <- fmt.Sprintf("file: %v", "error") // XXX: how should we handle errors? //obj.events <- fmt.Sprintf("file: %v", "error") // XXX: how should we handle errors?
case event := <-obj.events: case event := <-obj.events:
obj.SetConvergedState(typeConvergedNil) obj.SetConvergedState(resConvergedNil)
if exit, send = obj.ReadEvent(&event); exit { if exit, send = obj.ReadEvent(&event); exit {
return // exit return // exit
} }
//dirty = false // these events don't invalidate state //dirty = false // these events don't invalidate state
case _ = <-TimeAfterOrBlock(obj.ctimeout): case _ = <-TimeAfterOrBlock(obj.ctimeout):
obj.SetConvergedState(typeConvergedTimeout) obj.SetConvergedState(resConvergedTimeout)
obj.converged <- true obj.converged <- true
continue continue
} }
@@ -259,7 +259,7 @@ func (obj *FileType) Watch() {
} }
} }
func (obj *FileType) HashSHA256fromContent() string { func (obj *FileRes) HashSHA256fromContent() string {
if obj.sha256sum != "" { // return if already computed if obj.sha256sum != "" { // return if already computed
return obj.sha256sum return obj.sha256sum
} }
@@ -271,7 +271,7 @@ func (obj *FileType) HashSHA256fromContent() string {
} }
// FIXME: add the obj.CleanState() calls all over the true returns! // FIXME: add the obj.CleanState() calls all over the true returns!
func (obj *FileType) StateOK() bool { func (obj *FileRes) StateOK() bool {
if obj.isStateOK { // cache the state if obj.isStateOK { // cache the state
return true return true
} }
@@ -295,9 +295,9 @@ func (obj *FileType) StateOK() bool {
} }
} }
func (obj *FileType) StateOKFile() bool { func (obj *FileRes) StateOKFile() bool {
if PathIsDir(obj.GetPath()) { if PathIsDir(obj.GetPath()) {
log.Fatal("This should only be called on a File type.") log.Fatal("This should only be called on a File resource.")
} }
// run a diff, and return true if needs changing // run a diff, and return true if needs changing
@@ -326,9 +326,9 @@ func (obj *FileType) StateOKFile() bool {
return false return false
} }
func (obj *FileType) StateOKDir() bool { func (obj *FileRes) StateOKDir() bool {
if !PathIsDir(obj.GetPath()) { if !PathIsDir(obj.GetPath()) {
log.Fatal("This should only be called on a Dir type.") log.Fatal("This should only be called on a Dir resource.")
} }
// XXX: not implemented // XXX: not implemented
@@ -336,8 +336,8 @@ func (obj *FileType) StateOKDir() bool {
return false return false
} }
func (obj *FileType) Apply() bool { func (obj *FileRes) Apply() bool {
log.Printf("%v[%v]: Apply", obj.GetType(), obj.GetName()) log.Printf("%v[%v]: Apply", obj.GetRes(), obj.GetName())
if PathIsDir(obj.GetPath()) { if PathIsDir(obj.GetPath()) {
return obj.ApplyDir() return obj.ApplyDir()
@@ -346,10 +346,10 @@ func (obj *FileType) Apply() bool {
} }
} }
func (obj *FileType) ApplyFile() bool { func (obj *FileRes) ApplyFile() bool {
if PathIsDir(obj.GetPath()) { if PathIsDir(obj.GetPath()) {
log.Fatal("This should only be called on a File type.") log.Fatal("This should only be called on a File resource.")
} }
if obj.State == "absent" { if obj.State == "absent" {
@@ -378,9 +378,9 @@ func (obj *FileType) ApplyFile() bool {
return true return true
} }
func (obj *FileType) ApplyDir() bool { func (obj *FileRes) ApplyDir() bool {
if !PathIsDir(obj.GetPath()) { if !PathIsDir(obj.GetPath()) {
log.Fatal("This should only be called on a Dir type.") log.Fatal("This should only be called on a Dir resource.")
} }
// XXX: not implemented // XXX: not implemented
@@ -388,20 +388,20 @@ func (obj *FileType) ApplyDir() bool {
return true return true
} }
func (obj *FileType) Compare(typ Type) bool { func (obj *FileRes) Compare(res Res) bool {
switch typ.(type) { switch res.(type) {
case *FileType: case *FileRes:
typ := typ.(*FileType) res := res.(*FileRes)
if obj.Name != typ.Name { if obj.Name != res.Name {
return false return false
} }
if obj.GetPath() != typ.Path { if obj.GetPath() != res.Path {
return false return false
} }
if obj.Content != typ.Content { if obj.Content != res.Content {
return false return false
} }
if obj.State != typ.State { if obj.State != res.State {
return false return false
} }
default: default:

View File

@@ -177,7 +177,7 @@ func run(c *cli.Context) {
continue continue
} }
for v := range G.GetVerticesChan() { for v := range G.GetVerticesChan() {
if v.Type.GetConvergedState() != typeConvergedTimeout { if v.Res.GetConvergedState() != resConvergedTimeout {
continue ConvergedLoop continue ConvergedLoop
} }
} }

View File

@@ -152,7 +152,7 @@ func TestMiscT6(t *testing.T) {
type foo struct { type foo struct {
Name string `yaml:"name"` Name string `yaml:"name"`
Type string `yaml:"type"` Res string `yaml:"res"`
Value int `yaml:"value"` Value int `yaml:"value"`
} }
@@ -175,7 +175,7 @@ func TestMiscT7(t *testing.T) {
type Foo struct { type Foo struct {
Name string `yaml:"name"` Name string `yaml:"name"`
Type string `yaml:"type"` Res string `yaml:"res"`
Value int `yaml:"value"` Value int `yaml:"value"`
} }

View File

@@ -57,7 +57,7 @@ type Graph struct {
type Vertex struct { type Vertex struct {
graph *Graph // store a pointer to the graph it's on graph *Graph // store a pointer to the graph it's on
Type // anonymous field Res // anonymous field
data map[string]string // XXX: currently unused i think, remove? data map[string]string // XXX: currently unused i think, remove?
} }
@@ -73,9 +73,9 @@ func NewGraph(name string) *Graph {
} }
} }
func NewVertex(t Type) *Vertex { func NewVertex(r Res) *Vertex {
return &Vertex{ return &Vertex{
Type: t, Res: r,
data: make(map[string]string), data: make(map[string]string),
} }
} }
@@ -111,10 +111,10 @@ func (g *Graph) SetState(state graphState) graphState {
return prev return prev
} }
// store a pointer in the type to it's parent vertex // store a pointer in the resource to it's parent vertex
func (g *Graph) SetVertex() { func (g *Graph) SetVertex() {
for v := range g.GetVerticesChan() { for v := range g.GetVerticesChan() {
v.Type.SetVertex(v) v.Res.SetVertex(v)
} }
} }
@@ -160,7 +160,7 @@ func (g *Graph) GetVertex(name string) chan *Vertex {
return ch return ch
} }
func (g *Graph) GetVertexMatch(obj Type) *Vertex { func (g *Graph) GetVertexMatch(obj Res) *Vertex {
for k := range g.Adjacency { for k := range g.Adjacency {
if k.Compare(obj) { // XXX test if k.Compare(obj) { // XXX test
return k return k
@@ -241,7 +241,7 @@ func (g *Graph) Graphviz() (out string) {
//out += "\tnode [shape=box];\n" //out += "\tnode [shape=box];\n"
str := "" str := ""
for i := range g.Adjacency { // reverse paths for i := range g.Adjacency { // reverse paths
out += fmt.Sprintf("\t%v [label=\"%v[%v]\"];\n", i.GetName(), i.GetType(), i.GetName()) out += fmt.Sprintf("\t%v [label=\"%v[%v]\"];\n", i.GetName(), i.GetRes(), i.GetName())
for j := range g.Adjacency[i] { for j := range g.Adjacency[i] {
k := g.Adjacency[i][j] k := g.Adjacency[i][j]
// use str for clearer output ordering // use str for clearer output ordering
@@ -549,14 +549,14 @@ func (g *Graph) Start(wg *sync.WaitGroup, first bool) { // start or continue
indegree := g.InDegree() // compute all of the indegree's indegree := g.InDegree() // compute all of the indegree's
for _, v := range Reverse(t) { for _, v := range Reverse(t) {
if !v.Type.IsWatching() { // if Watch() is not running... if !v.Res.IsWatching() { // if Watch() is not running...
wg.Add(1) wg.Add(1)
// must pass in value to avoid races... // must pass in value to avoid races...
// see: https://ttboj.wordpress.com/2015/07/27/golang-parallelism-issues-causing-too-many-open-files-error/ // see: https://ttboj.wordpress.com/2015/07/27/golang-parallelism-issues-causing-too-many-open-files-error/
go func(vv *Vertex) { go func(vv *Vertex) {
defer wg.Done() defer wg.Done()
vv.Type.Watch() vv.Res.Watch()
log.Printf("%v[%v]: Exited", vv.GetType(), vv.GetName()) log.Printf("%v[%v]: Exited", vv.GetRes(), vv.GetName())
}(v) }(v)
} }
@@ -574,10 +574,10 @@ func (g *Graph) Start(wg *sync.WaitGroup, first bool) { // start or continue
// and not just selectively the subset with no indegree. // and not just selectively the subset with no indegree.
if (!first) || indegree[v] == 0 { if (!first) || indegree[v] == 0 {
// ensure state is started before continuing on to next vertex // ensure state is started before continuing on to next vertex
for !v.Type.SendEvent(eventStart, true, false) { for !v.Res.SendEvent(eventStart, true, false) {
if DEBUG { if DEBUG {
// if SendEvent fails, we aren't up yet // if SendEvent fails, we aren't up yet
log.Printf("%v[%v]: Retrying SendEvent(Start)", v.GetType(), v.GetName()) log.Printf("%v[%v]: Retrying SendEvent(Start)", v.GetRes(), v.GetName())
// sleep here briefly or otherwise cause // sleep here briefly or otherwise cause
// a different goroutine to be scheduled // a different goroutine to be scheduled
time.Sleep(1 * time.Millisecond) time.Sleep(1 * time.Millisecond)
@@ -590,7 +590,7 @@ func (g *Graph) Start(wg *sync.WaitGroup, first bool) { // start or continue
func (g *Graph) Pause() { func (g *Graph) Pause() {
t, _ := g.TopologicalSort() t, _ := g.TopologicalSort()
for _, v := range t { // squeeze out the events... for _, v := range t { // squeeze out the events...
v.Type.SendEvent(eventPause, true, false) v.Res.SendEvent(eventPause, true, false)
} }
} }
@@ -602,13 +602,13 @@ func (g *Graph) Exit() {
// when we hit the 'default' in the select statement! // when we hit the 'default' in the select statement!
// XXX: we can do this to quiesce, but it's not necessary now // XXX: we can do this to quiesce, but it's not necessary now
v.Type.SendEvent(eventExit, true, false) v.Res.SendEvent(eventExit, true, false)
} }
} }
func (g *Graph) SetConvergedCallback(ctimeout int, converged chan bool) { func (g *Graph) SetConvergedCallback(ctimeout int, converged chan bool) {
for v := range g.GetVerticesChan() { for v := range g.GetVerticesChan() {
v.Type.SetConvegedCallback(ctimeout, converged) v.Res.SetConvergedCallback(ctimeout, converged)
} }
} }

View File

@@ -36,8 +36,8 @@ func TestPgraphT1(t *testing.T) {
t.Errorf("Should have 0 edges instead of: %d.", i) t.Errorf("Should have 0 edges instead of: %d.", i)
} }
v1 := NewVertex(NewNoopType("v1")) v1 := NewVertex(NewNoopRes("v1"))
v2 := NewVertex(NewNoopType("v2")) v2 := NewVertex(NewNoopRes("v2"))
e1 := NewEdge("e1") e1 := NewEdge("e1")
G.AddEdge(v1, v2, e1) G.AddEdge(v1, v2, e1)
@@ -53,12 +53,12 @@ func TestPgraphT1(t *testing.T) {
func TestPgraphT2(t *testing.T) { func TestPgraphT2(t *testing.T) {
G := NewGraph("g2") G := NewGraph("g2")
v1 := NewVertex(NewNoopType("v1")) v1 := NewVertex(NewNoopRes("v1"))
v2 := NewVertex(NewNoopType("v2")) v2 := NewVertex(NewNoopRes("v2"))
v3 := NewVertex(NewNoopType("v3")) v3 := NewVertex(NewNoopRes("v3"))
v4 := NewVertex(NewNoopType("v4")) v4 := NewVertex(NewNoopRes("v4"))
v5 := NewVertex(NewNoopType("v5")) v5 := NewVertex(NewNoopRes("v5"))
v6 := NewVertex(NewNoopType("v6")) v6 := NewVertex(NewNoopRes("v6"))
e1 := NewEdge("e1") e1 := NewEdge("e1")
e2 := NewEdge("e2") e2 := NewEdge("e2")
e3 := NewEdge("e3") e3 := NewEdge("e3")
@@ -80,12 +80,12 @@ func TestPgraphT2(t *testing.T) {
func TestPgraphT3(t *testing.T) { func TestPgraphT3(t *testing.T) {
G := NewGraph("g3") G := NewGraph("g3")
v1 := NewVertex(NewNoopType("v1")) v1 := NewVertex(NewNoopRes("v1"))
v2 := NewVertex(NewNoopType("v2")) v2 := NewVertex(NewNoopRes("v2"))
v3 := NewVertex(NewNoopType("v3")) v3 := NewVertex(NewNoopRes("v3"))
v4 := NewVertex(NewNoopType("v4")) v4 := NewVertex(NewNoopRes("v4"))
v5 := NewVertex(NewNoopType("v5")) v5 := NewVertex(NewNoopRes("v5"))
v6 := NewVertex(NewNoopType("v6")) v6 := NewVertex(NewNoopRes("v6"))
e1 := NewEdge("e1") e1 := NewEdge("e1")
e2 := NewEdge("e2") e2 := NewEdge("e2")
e3 := NewEdge("e3") e3 := NewEdge("e3")
@@ -121,9 +121,9 @@ func TestPgraphT3(t *testing.T) {
func TestPgraphT4(t *testing.T) { func TestPgraphT4(t *testing.T) {
G := NewGraph("g4") G := NewGraph("g4")
v1 := NewVertex(NewNoopType("v1")) v1 := NewVertex(NewNoopRes("v1"))
v2 := NewVertex(NewNoopType("v2")) v2 := NewVertex(NewNoopRes("v2"))
v3 := NewVertex(NewNoopType("v3")) v3 := NewVertex(NewNoopRes("v3"))
e1 := NewEdge("e1") e1 := NewEdge("e1")
e2 := NewEdge("e2") e2 := NewEdge("e2")
e3 := NewEdge("e3") e3 := NewEdge("e3")
@@ -143,12 +143,12 @@ func TestPgraphT4(t *testing.T) {
func TestPgraphT5(t *testing.T) { func TestPgraphT5(t *testing.T) {
G := NewGraph("g5") G := NewGraph("g5")
v1 := NewVertex(NewNoopType("v1")) v1 := NewVertex(NewNoopRes("v1"))
v2 := NewVertex(NewNoopType("v2")) v2 := NewVertex(NewNoopRes("v2"))
v3 := NewVertex(NewNoopType("v3")) v3 := NewVertex(NewNoopRes("v3"))
v4 := NewVertex(NewNoopType("v4")) v4 := NewVertex(NewNoopRes("v4"))
v5 := NewVertex(NewNoopType("v5")) v5 := NewVertex(NewNoopRes("v5"))
v6 := NewVertex(NewNoopType("v6")) v6 := NewVertex(NewNoopRes("v6"))
e1 := NewEdge("e1") e1 := NewEdge("e1")
e2 := NewEdge("e2") e2 := NewEdge("e2")
e3 := NewEdge("e3") e3 := NewEdge("e3")
@@ -172,12 +172,12 @@ func TestPgraphT5(t *testing.T) {
func TestPgraphT6(t *testing.T) { func TestPgraphT6(t *testing.T) {
G := NewGraph("g6") G := NewGraph("g6")
v1 := NewVertex(NewNoopType("v1")) v1 := NewVertex(NewNoopRes("v1"))
v2 := NewVertex(NewNoopType("v2")) v2 := NewVertex(NewNoopRes("v2"))
v3 := NewVertex(NewNoopType("v3")) v3 := NewVertex(NewNoopRes("v3"))
v4 := NewVertex(NewNoopType("v4")) v4 := NewVertex(NewNoopRes("v4"))
v5 := NewVertex(NewNoopType("v5")) v5 := NewVertex(NewNoopRes("v5"))
v6 := NewVertex(NewNoopType("v6")) v6 := NewVertex(NewNoopRes("v6"))
e1 := NewEdge("e1") e1 := NewEdge("e1")
e2 := NewEdge("e2") e2 := NewEdge("e2")
e3 := NewEdge("e3") e3 := NewEdge("e3")
@@ -210,9 +210,9 @@ func TestPgraphT6(t *testing.T) {
func TestPgraphT7(t *testing.T) { func TestPgraphT7(t *testing.T) {
G := NewGraph("g7") G := NewGraph("g7")
v1 := NewVertex(NewNoopType("v1")) v1 := NewVertex(NewNoopRes("v1"))
v2 := NewVertex(NewNoopType("v2")) v2 := NewVertex(NewNoopRes("v2"))
v3 := NewVertex(NewNoopType("v3")) v3 := NewVertex(NewNoopRes("v3"))
e1 := NewEdge("e1") e1 := NewEdge("e1")
e2 := NewEdge("e2") e2 := NewEdge("e2")
e3 := NewEdge("e3") e3 := NewEdge("e3")
@@ -251,28 +251,28 @@ func TestPgraphT7(t *testing.T) {
func TestPgraphT8(t *testing.T) { func TestPgraphT8(t *testing.T) {
v1 := NewVertex(NewNoopType("v1")) v1 := NewVertex(NewNoopRes("v1"))
v2 := NewVertex(NewNoopType("v2")) v2 := NewVertex(NewNoopRes("v2"))
v3 := NewVertex(NewNoopType("v3")) v3 := NewVertex(NewNoopRes("v3"))
if HasVertex(v1, []*Vertex{v1, v2, v3}) != true { if HasVertex(v1, []*Vertex{v1, v2, v3}) != true {
t.Errorf("Should be true instead of false.") t.Errorf("Should be true instead of false.")
} }
v4 := NewVertex(NewNoopType("v4")) v4 := NewVertex(NewNoopRes("v4"))
v5 := NewVertex(NewNoopType("v5")) v5 := NewVertex(NewNoopRes("v5"))
v6 := NewVertex(NewNoopType("v6")) v6 := NewVertex(NewNoopRes("v6"))
if HasVertex(v4, []*Vertex{v5, v6}) != false { if HasVertex(v4, []*Vertex{v5, v6}) != false {
t.Errorf("Should be false instead of true.") t.Errorf("Should be false instead of true.")
} }
v7 := NewVertex(NewNoopType("v7")) v7 := NewVertex(NewNoopRes("v7"))
v8 := NewVertex(NewNoopType("v8")) v8 := NewVertex(NewNoopRes("v8"))
v9 := NewVertex(NewNoopType("v9")) v9 := NewVertex(NewNoopRes("v9"))
if HasVertex(v8, []*Vertex{v7, v8, v9}) != true { if HasVertex(v8, []*Vertex{v7, v8, v9}) != true {
t.Errorf("Should be true instead of false.") t.Errorf("Should be true instead of false.")
} }
v1b := NewVertex(NewNoopType("v1")) // same value, different objects v1b := NewVertex(NewNoopRes("v1")) // same value, different objects
if HasVertex(v1b, []*Vertex{v1, v2, v3}) != false { if HasVertex(v1b, []*Vertex{v1, v2, v3}) != false {
t.Errorf("Should be false instead of true.") t.Errorf("Should be false instead of true.")
} }
@@ -281,12 +281,12 @@ func TestPgraphT8(t *testing.T) {
func TestPgraphT9(t *testing.T) { func TestPgraphT9(t *testing.T) {
G := NewGraph("g9") G := NewGraph("g9")
v1 := NewVertex(NewNoopType("v1")) v1 := NewVertex(NewNoopRes("v1"))
v2 := NewVertex(NewNoopType("v2")) v2 := NewVertex(NewNoopRes("v2"))
v3 := NewVertex(NewNoopType("v3")) v3 := NewVertex(NewNoopRes("v3"))
v4 := NewVertex(NewNoopType("v4")) v4 := NewVertex(NewNoopRes("v4"))
v5 := NewVertex(NewNoopType("v5")) v5 := NewVertex(NewNoopRes("v5"))
v6 := NewVertex(NewNoopType("v6")) v6 := NewVertex(NewNoopRes("v6"))
e1 := NewEdge("e1") e1 := NewEdge("e1")
e2 := NewEdge("e2") e2 := NewEdge("e2")
e3 := NewEdge("e3") e3 := NewEdge("e3")
@@ -348,7 +348,7 @@ func TestPgraphT9(t *testing.T) {
t.Errorf("Topological sort failed, status: %v.", ok) t.Errorf("Topological sort failed, status: %v.", ok)
str := "Found:" str := "Found:"
for _, v := range s { for _, v := range s {
str += " " + v.Type.GetName() str += " " + v.Res.GetName()
} }
t.Errorf(str) t.Errorf(str)
} }
@@ -357,12 +357,12 @@ func TestPgraphT9(t *testing.T) {
func TestPgraphT10(t *testing.T) { func TestPgraphT10(t *testing.T) {
G := NewGraph("g10") G := NewGraph("g10")
v1 := NewVertex(NewNoopType("v1")) v1 := NewVertex(NewNoopRes("v1"))
v2 := NewVertex(NewNoopType("v2")) v2 := NewVertex(NewNoopRes("v2"))
v3 := NewVertex(NewNoopType("v3")) v3 := NewVertex(NewNoopRes("v3"))
v4 := NewVertex(NewNoopType("v4")) v4 := NewVertex(NewNoopRes("v4"))
v5 := NewVertex(NewNoopType("v5")) v5 := NewVertex(NewNoopRes("v5"))
v6 := NewVertex(NewNoopType("v6")) v6 := NewVertex(NewNoopRes("v6"))
e1 := NewEdge("e1") e1 := NewEdge("e1")
e2 := NewEdge("e2") e2 := NewEdge("e2")
e3 := NewEdge("e3") e3 := NewEdge("e3")
@@ -382,12 +382,12 @@ func TestPgraphT10(t *testing.T) {
} }
func TestPgraphT11(t *testing.T) { func TestPgraphT11(t *testing.T) {
v1 := NewVertex(NewNoopType("v1")) v1 := NewVertex(NewNoopRes("v1"))
v2 := NewVertex(NewNoopType("v2")) v2 := NewVertex(NewNoopRes("v2"))
v3 := NewVertex(NewNoopType("v3")) v3 := NewVertex(NewNoopRes("v3"))
v4 := NewVertex(NewNoopType("v4")) v4 := NewVertex(NewNoopRes("v4"))
v5 := NewVertex(NewNoopType("v5")) v5 := NewVertex(NewNoopRes("v5"))
v6 := NewVertex(NewNoopType("v6")) v6 := NewVertex(NewNoopRes("v6"))
if rev := Reverse([]*Vertex{}); !reflect.DeepEqual(rev, []*Vertex{}) { if rev := Reverse([]*Vertex{}); !reflect.DeepEqual(rev, []*Vertex{}) {
t.Errorf("Reverse of vertex slice failed.") t.Errorf("Reverse of vertex slice failed.")

View File

@@ -22,43 +22,43 @@ import (
"time" "time"
) )
//go:generate stringer -type=typeState -output=typestate_stringer.go //go:generate stringer -type=resState -output=resstate_stringer.go
type typeState int type resState int
const ( const (
typeNil typeState = iota resStateNil resState = iota
typeWatching resStateWatching
typeEvent // an event has happened, but we haven't poked yet resStateEvent // an event has happened, but we haven't poked yet
typeApplying resStateCheckApply
typePoking resStatePoking
) )
//go:generate stringer -type=typeConvergedState -output=typeconvergedstate_stringer.go //go:generate stringer -type=resConvergedState -output=resconvergedstate_stringer.go
type typeConvergedState int type resConvergedState int
const ( const (
typeConvergedNil typeConvergedState = iota resConvergedNil resConvergedState = iota
//typeConverged //resConverged
typeConvergedTimeout resConvergedTimeout
) )
type Type interface { type Res interface {
Init() Init()
GetName() string // can't be named "Name()" because of struct field GetName() string // can't be named "Name()" because of struct field
GetType() string GetRes() string
Watch() Watch()
StateOK() bool // TODO: can we rename this to something better? StateOK() bool // TODO: can we rename this to something better?
Apply() bool Apply() bool
SetVertex(*Vertex) SetVertex(*Vertex)
SetConvegedCallback(ctimeout int, converged chan bool) SetConvergedCallback(ctimeout int, converged chan bool)
Compare(Type) bool Compare(Res) bool
SendEvent(eventName, bool, bool) bool SendEvent(eventName, bool, bool) bool
IsWatching() bool IsWatching() bool
SetWatching(bool) SetWatching(bool)
GetConvergedState() typeConvergedState GetConvergedState() resConvergedState
SetConvergedState(typeConvergedState) SetConvergedState(resConvergedState)
GetState() typeState GetState() resState
SetState(typeState) SetState(resState)
GetTimestamp() int64 GetTimestamp() int64
UpdateTimestamp() int64 UpdateTimestamp() int64
OKTimestamp() bool OKTimestamp() bool
@@ -66,28 +66,28 @@ type Type interface {
BackPoke() BackPoke()
} }
type BaseType struct { type BaseRes struct {
Name string `yaml:"name"` Name string `yaml:"name"`
timestamp int64 // last updated timestamp ? timestamp int64 // last updated timestamp ?
events chan Event events chan Event
vertex *Vertex vertex *Vertex
state typeState state resState
convergedState typeConvergedState convergedState resConvergedState
watching bool // is Watch() loop running ? watching bool // is Watch() loop running ?
ctimeout int // converged timeout ctimeout int // converged timeout
converged chan bool converged chan bool
isStateOK bool // whether the state is okay based on events or not isStateOK bool // whether the state is okay based on events or not
} }
type NoopType struct { type NoopRes struct {
BaseType `yaml:",inline"` BaseRes `yaml:",inline"`
Comment string `yaml:"comment"` // extra field for example purposes Comment string `yaml:"comment"` // extra field for example purposes
} }
func NewNoopType(name string) *NoopType { func NewNoopRes(name string) *NoopRes {
// FIXME: we could get rid of this New constructor and use raw object creation with a required Init() // FIXME: we could get rid of this New constructor and use raw object creation with a required Init()
return &NoopType{ return &NoopRes{
BaseType: BaseType{ BaseRes: BaseRes{
Name: name, Name: name,
events: make(chan Event), // unbuffered chan size to avoid stale events events: make(chan Event), // unbuffered chan size to avoid stale events
vertex: nil, vertex: nil,
@@ -97,74 +97,74 @@ func NewNoopType(name string) *NoopType {
} }
// initialize structures like channels if created without New constructor // initialize structures like channels if created without New constructor
func (obj *BaseType) Init() { func (obj *BaseRes) Init() {
obj.events = make(chan Event) obj.events = make(chan Event)
} }
// this method gets used by all the types, if we have one of (obj NoopType) it would get overridden in that case! // this method gets used by all the types, if we have one of (obj NoopRes) it would get overridden in that case!
func (obj *BaseType) GetName() string { func (obj *BaseRes) GetName() string {
return obj.Name return obj.Name
} }
func (obj *BaseType) GetType() string { func (obj *BaseRes) GetRes() string {
return "Base" return "Base"
} }
func (obj *BaseType) GetVertex() *Vertex { func (obj *BaseRes) GetVertex() *Vertex {
return obj.vertex return obj.vertex
} }
func (obj *BaseType) SetVertex(v *Vertex) { func (obj *BaseRes) SetVertex(v *Vertex) {
obj.vertex = v obj.vertex = v
} }
func (obj *BaseType) SetConvegedCallback(ctimeout int, converged chan bool) { func (obj *BaseRes) SetConvergedCallback(ctimeout int, converged chan bool) {
obj.ctimeout = ctimeout obj.ctimeout = ctimeout
obj.converged = converged obj.converged = converged
} }
// is the Watch() function running? // is the Watch() function running?
func (obj *BaseType) IsWatching() bool { func (obj *BaseRes) IsWatching() bool {
return obj.watching return obj.watching
} }
// store status of if the Watch() function is running // store status of if the Watch() function is running
func (obj *BaseType) SetWatching(b bool) { func (obj *BaseRes) SetWatching(b bool) {
obj.watching = b obj.watching = b
} }
func (obj *BaseType) GetConvergedState() typeConvergedState { func (obj *BaseRes) GetConvergedState() resConvergedState {
return obj.convergedState return obj.convergedState
} }
func (obj *BaseType) SetConvergedState(state typeConvergedState) { func (obj *BaseRes) SetConvergedState(state resConvergedState) {
obj.convergedState = state obj.convergedState = state
} }
func (obj *BaseType) GetState() typeState { func (obj *BaseRes) GetState() resState {
return obj.state return obj.state
} }
func (obj *BaseType) SetState(state typeState) { func (obj *BaseRes) SetState(state resState) {
if DEBUG { if DEBUG {
log.Printf("%v[%v]: State: %v -> %v", obj.GetType(), obj.GetName(), obj.GetState(), state) log.Printf("%v[%v]: State: %v -> %v", obj.GetRes(), obj.GetName(), obj.GetState(), state)
} }
obj.state = state obj.state = state
} }
// GetTimestamp returns the timestamp of a vertex // GetTimestamp returns the timestamp of a vertex
func (obj *BaseType) GetTimestamp() int64 { func (obj *BaseRes) GetTimestamp() int64 {
return obj.timestamp return obj.timestamp
} }
// UpdateTimestamp updates the timestamp on a vertex and returns the new value // UpdateTimestamp updates the timestamp on a vertex and returns the new value
func (obj *BaseType) UpdateTimestamp() int64 { func (obj *BaseRes) UpdateTimestamp() int64 {
obj.timestamp = time.Now().UnixNano() // update obj.timestamp = time.Now().UnixNano() // update
return obj.timestamp return obj.timestamp
} }
// can this element run right now? // can this element run right now?
func (obj *BaseType) OKTimestamp() bool { func (obj *BaseRes) OKTimestamp() bool {
v := obj.GetVertex() v := obj.GetVertex()
g := v.GetGraph() g := v.GetGraph()
// these are all the vertices pointing TO v, eg: ??? -> v // these are all the vertices pointing TO v, eg: ??? -> v
@@ -173,9 +173,9 @@ func (obj *BaseType) OKTimestamp() bool {
// then we can't run right now... // then we can't run right now...
// if they're equal (eg: on init of 0) then we also can't run // if they're equal (eg: on init of 0) then we also can't run
// b/c we should let our pre-req's go first... // b/c we should let our pre-req's go first...
x, y := obj.GetTimestamp(), n.Type.GetTimestamp() x, y := obj.GetTimestamp(), n.Res.GetTimestamp()
if DEBUG { if DEBUG {
log.Printf("%v[%v]: OKTimestamp: (%v) >= %v[%v](%v): !%v", obj.GetType(), obj.GetName(), x, n.GetType(), n.GetName(), y, x >= y) log.Printf("%v[%v]: OKTimestamp: (%v) >= %v[%v](%v): !%v", obj.GetRes(), obj.GetName(), x, n.GetRes(), n.GetName(), y, x >= y)
} }
if x >= y { if x >= y {
return false return false
@@ -186,55 +186,55 @@ func (obj *BaseType) OKTimestamp() bool {
// notify nodes after me in the dependency graph that they need refreshing... // notify nodes after me in the dependency graph that they need refreshing...
// NOTE: this assumes that this can never fail or need to be rescheduled // NOTE: this assumes that this can never fail or need to be rescheduled
func (obj *BaseType) Poke(activity bool) { func (obj *BaseRes) Poke(activity bool) {
v := obj.GetVertex() v := obj.GetVertex()
g := v.GetGraph() g := v.GetGraph()
// these are all the vertices pointing AWAY FROM v, eg: v -> ??? // these are all the vertices pointing AWAY FROM v, eg: v -> ???
for _, n := range g.OutgoingGraphEdges(v) { for _, n := range g.OutgoingGraphEdges(v) {
// XXX: if we're in state event and haven't been cancelled by // XXX: if we're in state event and haven't been cancelled by
// apply, then we can cancel a poke to a child, right? XXX // apply, then we can cancel a poke to a child, right? XXX
// XXX: if n.Type.GetState() != typeEvent { // is this correct? // XXX: if n.Res.GetState() != resStateEvent { // is this correct?
if true { // XXX if true { // XXX
if DEBUG { if DEBUG {
log.Printf("%v[%v]: Poke: %v[%v]", v.GetType(), v.GetName(), n.GetType(), n.GetName()) log.Printf("%v[%v]: Poke: %v[%v]", v.GetRes(), v.GetName(), n.GetRes(), n.GetName())
} }
n.SendEvent(eventPoke, false, activity) // XXX: can this be switched to sync? n.SendEvent(eventPoke, false, activity) // XXX: can this be switched to sync?
} else { } else {
if DEBUG { if DEBUG {
log.Printf("%v[%v]: Poke: %v[%v]: Skipped!", v.GetType(), v.GetName(), n.GetType(), n.GetName()) log.Printf("%v[%v]: Poke: %v[%v]: Skipped!", v.GetRes(), v.GetName(), n.GetRes(), n.GetName())
} }
} }
} }
} }
// poke the pre-requisites that are stale and need to run before I can run... // poke the pre-requisites that are stale and need to run before I can run...
func (obj *BaseType) BackPoke() { func (obj *BaseRes) BackPoke() {
v := obj.GetVertex() v := obj.GetVertex()
g := v.GetGraph() g := v.GetGraph()
// these are all the vertices pointing TO v, eg: ??? -> v // these are all the vertices pointing TO v, eg: ??? -> v
for _, n := range g.IncomingGraphEdges(v) { for _, n := range g.IncomingGraphEdges(v) {
x, y, s := obj.GetTimestamp(), n.Type.GetTimestamp(), n.Type.GetState() x, y, s := obj.GetTimestamp(), n.Res.GetTimestamp(), n.Res.GetState()
// if the parent timestamp needs poking AND it's not in state // if the parent timestamp needs poking AND it's not in state
// typeEvent, then poke it. If the parent is in typeEvent it // resStateEvent, then poke it. If the parent is in resStateEvent it
// means that an event is pending, so we'll be expecting a poke // means that an event is pending, so we'll be expecting a poke
// back soon, so we can safely discard the extra parent poke... // back soon, so we can safely discard the extra parent poke...
// TODO: implement a stateLT (less than) to tell if something // TODO: implement a stateLT (less than) to tell if something
// happens earlier in the state cycle and that doesn't wrap nil // happens earlier in the state cycle and that doesn't wrap nil
if x >= y && (s != typeEvent && s != typeApplying) { if x >= y && (s != resStateEvent && s != resStateCheckApply) {
if DEBUG { if DEBUG {
log.Printf("%v[%v]: BackPoke: %v[%v]", v.GetType(), v.GetName(), n.GetType(), n.GetName()) log.Printf("%v[%v]: BackPoke: %v[%v]", v.GetRes(), v.GetName(), n.GetRes(), n.GetName())
} }
n.SendEvent(eventBackPoke, false, false) // XXX: can this be switched to sync? n.SendEvent(eventBackPoke, false, false) // XXX: can this be switched to sync?
} else { } else {
if DEBUG { if DEBUG {
log.Printf("%v[%v]: BackPoke: %v[%v]: Skipped!", v.GetType(), v.GetName(), n.GetType(), n.GetName()) log.Printf("%v[%v]: BackPoke: %v[%v]: Skipped!", v.GetRes(), v.GetName(), n.GetRes(), n.GetName())
} }
} }
} }
} }
// push an event into the message queue for a particular type vertex // push an event into the message queue for a particular vertex
func (obj *BaseType) SendEvent(event eventName, sync bool, activity bool) bool { func (obj *BaseRes) SendEvent(event eventName, sync bool, activity bool) bool {
// TODO: isn't this race-y ? // TODO: isn't this race-y ?
if !obj.IsWatching() { // element has already exited if !obj.IsWatching() { // element has already exited
return false // if we don't return, we'll block on the send return false // if we don't return, we'll block on the send
@@ -257,7 +257,7 @@ func (obj *BaseType) SendEvent(event eventName, sync bool, activity bool) bool {
// process events when a select gets one, this handles the pause code too! // process events when a select gets one, this handles the pause code too!
// the return values specify if we should exit and poke respectively // the return values specify if we should exit and poke respectively
func (obj *BaseType) ReadEvent(event *Event) (exit, poke bool) { func (obj *BaseRes) ReadEvent(event *Event) (exit, poke bool) {
event.ACK() event.ACK()
switch event.Name { switch event.Name {
case eventStart: case eventStart:
@@ -283,7 +283,7 @@ func (obj *BaseType) ReadEvent(event *Event) (exit, poke bool) {
return false, false // don't poke on unpause! return false, false // don't poke on unpause!
} else { } else {
// if we get a poke event here, it's a bug! // if we get a poke event here, it's a bug!
log.Fatalf("%v[%v]: Unknown event: %v, while paused!", obj.GetType(), obj.GetName(), e) log.Fatalf("%v[%v]: Unknown event: %v, while paused!", obj.GetRes(), obj.GetName(), e)
} }
} }
@@ -295,17 +295,17 @@ func (obj *BaseType) ReadEvent(event *Event) (exit, poke bool) {
// useful for using as: return CleanState() in the StateOK functions when there // useful for using as: return CleanState() in the StateOK functions when there
// are multiple `true` return exits // are multiple `true` return exits
func (obj *BaseType) CleanState() bool { func (obj *BaseRes) CleanState() bool {
obj.isStateOK = true obj.isStateOK = true
return true return true
} }
// XXX: rename this function // XXX: rename this function
func Process(obj Type) { func Process(obj Res) {
if DEBUG { if DEBUG {
log.Printf("%v[%v]: Process()", obj.GetType(), obj.GetName()) log.Printf("%v[%v]: Process()", obj.GetRes(), obj.GetName())
} }
obj.SetState(typeEvent) obj.SetState(resStateEvent)
var ok = true var ok = true
var apply = false // did we run an apply? var apply = false // did we run an apply?
// is it okay to run dependency wise right now? // is it okay to run dependency wise right now?
@@ -313,15 +313,15 @@ func Process(obj Type) {
// us back and we will run if needed then! // us back and we will run if needed then!
if obj.OKTimestamp() { if obj.OKTimestamp() {
if DEBUG { if DEBUG {
log.Printf("%v[%v]: OKTimestamp(%v)", obj.GetType(), obj.GetName(), obj.GetTimestamp()) log.Printf("%v[%v]: OKTimestamp(%v)", obj.GetRes(), obj.GetName(), obj.GetTimestamp())
} }
if !obj.StateOK() { // TODO: can we rename this to something better? if !obj.StateOK() { // TODO: can we rename this to something better?
if DEBUG { if DEBUG {
log.Printf("%v[%v]: !StateOK()", obj.GetType(), obj.GetName()) log.Printf("%v[%v]: !StateOK()", obj.GetRes(), obj.GetName())
} }
// throw an error if apply fails... // throw an error if apply fails...
// if this fails, don't UpdateTimestamp() // if this fails, don't UpdateTimestamp()
obj.SetState(typeApplying) obj.SetState(resStateCheckApply)
if !obj.Apply() { // check for error if !obj.Apply() { // check for error
ok = false ok = false
} else { } else {
@@ -332,8 +332,8 @@ func Process(obj Type) {
if ok { if ok {
// update this timestamp *before* we poke or the poked // update this timestamp *before* we poke or the poked
// nodes might fail due to having a too old timestamp! // nodes might fail due to having a too old timestamp!
obj.UpdateTimestamp() // this was touched... obj.UpdateTimestamp() // this was touched...
obj.SetState(typePoking) // can't cancel parent poke obj.SetState(resStatePoking) // can't cancel parent poke
obj.Poke(apply) obj.Poke(apply)
} }
// poke at our pre-req's instead since they need to refresh/run... // poke at our pre-req's instead since they need to refresh/run...
@@ -343,11 +343,11 @@ func Process(obj Type) {
} }
} }
func (obj *NoopType) GetType() string { func (obj *NoopRes) GetRes() string {
return "Noop" return "Noop"
} }
func (obj *NoopType) Watch() { func (obj *NoopRes) Watch() {
if obj.IsWatching() { if obj.IsWatching() {
return return
} }
@@ -358,17 +358,17 @@ func (obj *NoopType) Watch() {
var send = false // send event? var send = false // send event?
var exit = false var exit = false
for { for {
obj.SetState(typeWatching) // reset obj.SetState(resStateWatching) // reset
select { select {
case event := <-obj.events: case event := <-obj.events:
obj.SetConvergedState(typeConvergedNil) obj.SetConvergedState(resConvergedNil)
// we avoid sending events on unpause // we avoid sending events on unpause
if exit, send = obj.ReadEvent(&event); exit { if exit, send = obj.ReadEvent(&event); exit {
return // exit return // exit
} }
case _ = <-TimeAfterOrBlock(obj.ctimeout): case _ = <-TimeAfterOrBlock(obj.ctimeout):
obj.SetConvergedState(typeConvergedTimeout) obj.SetConvergedState(resConvergedTimeout)
obj.converged <- true obj.converged <- true
continue continue
} }
@@ -383,21 +383,21 @@ func (obj *NoopType) Watch() {
} }
} }
func (obj *NoopType) StateOK() bool { func (obj *NoopRes) StateOK() bool {
return true // never needs updating return true // never needs updating
} }
func (obj *NoopType) Apply() bool { func (obj *NoopRes) Apply() bool {
log.Printf("%v[%v]: Apply", obj.GetType(), obj.GetName()) log.Printf("%v[%v]: Apply", obj.GetRes(), obj.GetName())
return true return true
} }
func (obj *NoopType) Compare(typ Type) bool { func (obj *NoopRes) Compare(res Res) bool {
switch typ.(type) { switch res.(type) {
// we can only compare NoopType to others of the same type // we can only compare NoopRes to others of the same resource
case *NoopType: case *NoopRes:
typ := typ.(*NoopType) res := res.(*NoopRes)
if obj.Name != typ.Name { if obj.Name != res.Name {
return false return false
} }
default: default:

View File

@@ -27,15 +27,15 @@ import (
"log" "log"
) )
type ServiceType struct { type SvcRes struct {
BaseType `yaml:",inline"` BaseRes `yaml:",inline"`
State string `yaml:"state"` // state: running, stopped State string `yaml:"state"` // state: running, stopped
Startup string `yaml:"startup"` // enabled, disabled, undefined Startup string `yaml:"startup"` // enabled, disabled, undefined
} }
func NewServiceType(name, state, startup string) *ServiceType { func NewSvcRes(name, state, startup string) *SvcRes {
return &ServiceType{ return &SvcRes{
BaseType: BaseType{ BaseRes: BaseRes{
Name: name, Name: name,
events: make(chan Event), events: make(chan Event),
vertex: nil, vertex: nil,
@@ -45,19 +45,19 @@ func NewServiceType(name, state, startup string) *ServiceType {
} }
} }
func (obj *ServiceType) GetType() string { func (obj *SvcRes) GetRes() string {
return "Service" return "Svc"
} }
// Service watcher // Service watcher
func (obj *ServiceType) Watch() { func (obj *SvcRes) Watch() {
if obj.IsWatching() { if obj.IsWatching() {
return return
} }
obj.SetWatching(true) obj.SetWatching(true)
defer obj.SetWatching(false) defer obj.SetWatching(false)
// obj.Name: service name // obj.Name: svc name
//vertex := obj.GetVertex() // stored with SetVertex //vertex := obj.GetVertex() // stored with SetVertex
if !util.IsRunningSystemd() { if !util.IsRunningSystemd() {
log.Fatal("Systemd is not running.") log.Fatal("Systemd is not running.")
@@ -80,11 +80,11 @@ func (obj *ServiceType) Watch() {
buschan := make(chan *dbus.Signal, 10) buschan := make(chan *dbus.Signal, 10)
bus.Signal(buschan) bus.Signal(buschan)
var service = fmt.Sprintf("%v.service", obj.Name) // systemd name var svc = fmt.Sprintf("%v.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 dirty = false
var invalid = false // does the service 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
subChannel, subErrors := set.Subscribe() subChannel, subErrors := set.Subscribe()
@@ -97,8 +97,8 @@ func (obj *ServiceType) Watch() {
previous = invalid previous = invalid
invalid = false invalid = false
// firstly, does service even exist or not? // firstly, does svc even exist or not?
loadstate, err := conn.GetUnitProperty(service, "LoadState") loadstate, err := conn.GetUnitProperty(svc, "LoadState")
if err != nil { if err != nil {
log.Printf("Failed to get property: %v", err) log.Printf("Failed to get property: %v", err)
invalid = true invalid = true
@@ -107,7 +107,7 @@ func (obj *ServiceType) Watch() {
if !invalid { if !invalid {
var notFound = (loadstate.Value == dbus.MakeVariant("not-found")) var notFound = (loadstate.Value == dbus.MakeVariant("not-found"))
if notFound { // XXX: in the loop we'll handle changes better... if notFound { // XXX: in the loop we'll handle changes better...
log.Printf("Failed to find service: %v", service) log.Printf("Failed to find svc: %v", svc)
invalid = true // XXX ? invalid = true // XXX ?
} }
} }
@@ -118,21 +118,21 @@ func (obj *ServiceType) Watch() {
} }
if invalid { if invalid {
log.Printf("Waiting for: %v", service) // waiting for service to appear... log.Printf("Waiting for: %v", svc) // waiting for svc to appear...
if activeSet { if activeSet {
activeSet = false activeSet = false
set.Remove(service) // no return value should ever occur set.Remove(svc) // no return value should ever occur
} }
obj.SetState(typeWatching) // reset obj.SetState(resStateWatching) // reset
select { select {
case _ = <-buschan: // XXX wait for new units event to unstick case _ = <-buschan: // XXX wait for new units event to unstick
obj.SetConvergedState(typeConvergedNil) obj.SetConvergedState(resConvergedNil)
// loop so that we can see the changed invalid signal // loop so that we can see the changed invalid signal
log.Printf("Service[%v]->DaemonReload()", service) log.Printf("Svc[%v]->DaemonReload()", svc)
case event := <-obj.events: case event := <-obj.events:
obj.SetConvergedState(typeConvergedNil) obj.SetConvergedState(resConvergedNil)
if exit, send = obj.ReadEvent(&event); exit { if exit, send = obj.ReadEvent(&event); exit {
return // exit return // exit
} }
@@ -141,47 +141,47 @@ func (obj *ServiceType) Watch() {
} }
case _ = <-TimeAfterOrBlock(obj.ctimeout): case _ = <-TimeAfterOrBlock(obj.ctimeout):
obj.SetConvergedState(typeConvergedTimeout) obj.SetConvergedState(resConvergedTimeout)
obj.converged <- true obj.converged <- true
continue continue
} }
} else { } else {
if !activeSet { if !activeSet {
activeSet = true activeSet = true
set.Add(service) // no return value should ever occur set.Add(svc) // no return value should ever occur
} }
log.Printf("Watching: %v", service) // attempting to watch... log.Printf("Watching: %v", svc) // attempting to watch...
obj.SetState(typeWatching) // reset obj.SetState(resStateWatching) // reset
select { select {
case event := <-subChannel: case event := <-subChannel:
log.Printf("Service event: %+v", event) log.Printf("Svc event: %+v", event)
// NOTE: the value returned is a map for some reason... // NOTE: the value returned is a map for some reason...
if event[service] != nil { if event[svc] != nil {
// event[service].ActiveState is not nil // event[svc].ActiveState is not nil
if event[service].ActiveState == "active" { if event[svc].ActiveState == "active" {
log.Printf("Service[%v]->Started()", service) log.Printf("Svc[%v]->Started()", svc)
} else if event[service].ActiveState == "inactive" { } else if event[svc].ActiveState == "inactive" {
log.Printf("Service[%v]->Stopped!()", service) log.Printf("Svc[%v]->Stopped!()", svc)
} else { } else {
log.Fatal("Unknown service state: ", event[service].ActiveState) log.Fatal("Unknown svc state: ", event[svc].ActiveState)
} }
} else { } else {
// service stopped (and ActiveState is nil...) // svc stopped (and ActiveState is nil...)
log.Printf("Service[%v]->Stopped", service) log.Printf("Svc[%v]->Stopped", svc)
} }
send = true send = true
dirty = true dirty = true
case err := <-subErrors: case err := <-subErrors:
obj.SetConvergedState(typeConvergedNil) // XXX ? obj.SetConvergedState(resConvergedNil) // XXX ?
log.Println("error:", err) log.Println("error:", err)
log.Fatal(err) log.Fatal(err)
//vertex.events <- fmt.Sprintf("service: %v", "error") // XXX: how should we handle errors? //vertex.events <- fmt.Sprintf("svc: %v", "error") // XXX: how should we handle errors?
case event := <-obj.events: case event := <-obj.events:
obj.SetConvergedState(typeConvergedNil) obj.SetConvergedState(resConvergedNil)
if exit, send = obj.ReadEvent(&event); exit { if exit, send = obj.ReadEvent(&event); exit {
return // exit return // exit
} }
@@ -203,7 +203,7 @@ func (obj *ServiceType) Watch() {
} }
} }
func (obj *ServiceType) StateOK() bool { func (obj *SvcRes) StateOK() bool {
if obj.isStateOK { // cache the state if obj.isStateOK { // cache the state
return true return true
} }
@@ -218,9 +218,9 @@ func (obj *ServiceType) StateOK() bool {
} }
defer conn.Close() defer conn.Close()
var service = fmt.Sprintf("%v.service", obj.Name) // systemd name var svc = fmt.Sprintf("%v.service", obj.Name) // systemd name
loadstate, err := conn.GetUnitProperty(service, "LoadState") loadstate, err := conn.GetUnitProperty(svc, "LoadState")
if err != nil { if err != nil {
log.Printf("Failed to get load state: %v", err) log.Printf("Failed to get load state: %v", err)
return false return false
@@ -229,14 +229,14 @@ func (obj *ServiceType) StateOK() bool {
// NOTE: we have to compare variants with other variants, they are really strings... // NOTE: we have to compare variants with other variants, they are really strings...
var notFound = (loadstate.Value == dbus.MakeVariant("not-found")) var notFound = (loadstate.Value == dbus.MakeVariant("not-found"))
if notFound { if notFound {
log.Printf("Failed to find service: %v", service) log.Printf("Failed to find svc: %v", svc)
return false return false
} }
// XXX: check service "enabled at boot" or not status... // XXX: check svc "enabled at boot" or not status...
//conn.GetUnitProperties(service) //conn.GetUnitProperties(svc)
activestate, err := conn.GetUnitProperty(service, "ActiveState") activestate, err := conn.GetUnitProperty(svc, "ActiveState")
if err != nil { if err != nil {
log.Fatal("Failed to get active state: ", err) log.Fatal("Failed to get active state: ", err)
} }
@@ -258,8 +258,8 @@ func (obj *ServiceType) StateOK() bool {
return true // all is good, no state change needed return true // all is good, no state change needed
} }
func (obj *ServiceType) Apply() bool { func (obj *SvcRes) Apply() bool {
log.Printf("%v[%v]: Apply", obj.GetType(), obj.GetName()) log.Printf("%v[%v]: Apply", obj.GetRes(), obj.GetName())
if !util.IsRunningSystemd() { if !util.IsRunningSystemd() {
log.Fatal("Systemd is not running.") log.Fatal("Systemd is not running.")
@@ -271,8 +271,8 @@ func (obj *ServiceType) Apply() bool {
} }
defer conn.Close() defer conn.Close()
var service = fmt.Sprintf("%v.service", obj.Name) // systemd name var svc = fmt.Sprintf("%v.service", obj.Name) // systemd name
var files = []string{service} // the service represented in a list var files = []string{svc} // the svc represented in a list
if obj.Startup == "enabled" { if obj.Startup == "enabled" {
_, _, err = conn.EnableUnitFiles(files, false, true) _, _, err = conn.EnableUnitFiles(files, false, true)
@@ -289,13 +289,13 @@ func (obj *ServiceType) Apply() bool {
result := make(chan string, 1) // catch result information result := make(chan string, 1) // catch result information
if obj.State == "running" { if obj.State == "running" {
_, err := conn.StartUnit(service, "fail", result) _, err := conn.StartUnit(svc, "fail", result)
if err != nil { if err != nil {
log.Fatal("Failed to start unit: ", err) log.Fatal("Failed to start unit: ", err)
return false return false
} }
} else if obj.State == "stopped" { } else if obj.State == "stopped" {
_, err = conn.StopUnit(service, "fail", result) _, err = conn.StopUnit(svc, "fail", result)
if err != nil { if err != nil {
log.Fatal("Failed to stop unit: ", err) log.Fatal("Failed to stop unit: ", err)
return false return false
@@ -319,17 +319,17 @@ func (obj *ServiceType) Apply() bool {
return true return true
} }
func (obj *ServiceType) Compare(typ Type) bool { func (obj *SvcRes) Compare(res Res) bool {
switch typ.(type) { switch res.(type) {
case *ServiceType: case *SvcRes:
typ := typ.(*ServiceType) res := res.(*SvcRes)
if obj.Name != typ.Name { if obj.Name != res.Name {
return false return false
} }
if obj.State != typ.State { if obj.State != res.State {
return false return false
} }
if obj.Startup != typ.Startup { if obj.Startup != res.Startup {
return false return false
} }
default: default:

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
noop: noop:
- name: noop1 - name: noop1
file: file:
@@ -27,15 +27,15 @@ types:
edges: edges:
- name: e1 - name: e1
from: from:
type: file res: file
name: file1 name: file1
to: to:
type: file res: file
name: file2 name: file2
- name: e2 - name: e2
from: from:
type: file res: file
name: file2 name: file2
to: to:
type: file res: file
name: file3 name: file3

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
file: file:
- name: file1a - name: file1a
path: "/tmp/mgmt/mgmtA/f1a" path: "/tmp/mgmt/mgmtA/f1a"
@@ -23,6 +23,6 @@ types:
i am f4, exported from host A i am f4, exported from host A
state: exists state: exists
collect: collect:
- type: file - res: file
pattern: "/tmp/mgmt/mgmtA/" pattern: "/tmp/mgmt/mgmtA/"
edges: [] edges: []

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
file: file:
- name: file1b - name: file1b
path: "/tmp/mgmt/mgmtB/f1b" path: "/tmp/mgmt/mgmtB/f1b"
@@ -23,6 +23,6 @@ types:
i am f4, exported from host B i am f4, exported from host B
state: exists state: exists
collect: collect:
- type: file - res: file
pattern: "/tmp/mgmt/mgmtB/" pattern: "/tmp/mgmt/mgmtB/"
edges: [] edges: []

View File

@@ -1,6 +1,6 @@
--- ---
graph: mygraph graph: mygraph
types: resources:
file: file:
- name: file1c - name: file1c
path: "/tmp/mgmt/mgmtC/f1c" path: "/tmp/mgmt/mgmtC/f1c"
@@ -23,6 +23,6 @@ types:
i am f4, exported from host C i am f4, exported from host C
state: exists state: exists
collect: collect:
- type: file - res: file
pattern: "/tmp/mgmt/mgmtC/" pattern: "/tmp/mgmt/mgmtC/"
edges: [] edges: []

View File

@@ -1,7 +1,7 @@
--- ---
graph: mygraph graph: mygraph
comment: simple exec fan in example to demonstrate optimization) comment: simple exec fan in example to demonstrate optimization)
types: resources:
exec: exec:
- name: exec1 - name: exec1
cmd: sleep 10s cmd: sleep 10s
@@ -56,22 +56,22 @@ types:
edges: edges:
- name: e1 - name: e1
from: from:
type: exec res: exec
name: exec1 name: exec1
to: to:
type: exec res: exec
name: exec5 name: exec5
- name: e2 - name: e2
from: from:
type: exec res: exec
name: exec2 name: exec2
to: to:
type: exec res: exec
name: exec5 name: exec5
- name: e3 - name: e3
from: from:
type: exec res: exec
name: exec3 name: exec3
to: to:
type: exec res: exec
name: exec5 name: exec5

View File

@@ -1,7 +1,7 @@
--- ---
graph: mygraph graph: mygraph
comment: simple exec fan in to fan out example to demonstrate optimization comment: simple exec fan in to fan out example to demonstrate optimization
types: resources:
exec: exec:
- name: exec1 - name: exec1
cmd: sleep 10s cmd: sleep 10s
@@ -86,43 +86,43 @@ types:
edges: edges:
- name: e1 - name: e1
from: from:
type: exec res: exec
name: exec1 name: exec1
to: to:
type: exec res: exec
name: exec4 name: exec4
- name: e2 - name: e2
from: from:
type: exec res: exec
name: exec2 name: exec2
to: to:
type: exec res: exec
name: exec4 name: exec4
- name: e3 - name: e3
from: from:
type: exec res: exec
name: exec3 name: exec3
to: to:
type: exec res: exec
name: exec4 name: exec4
- name: e4 - name: e4
from: from:
type: exec res: exec
name: exec4 name: exec4
to: to:
type: exec res: exec
name: exec5 name: exec5
- name: e5 - name: e5
from: from:
type: exec res: exec
name: exec4 name: exec4
to: to:
type: exec res: exec
name: exec6 name: exec6
- name: e6 - name: e6
from: from:
type: exec res: exec
name: exec4 name: exec4
to: to:
type: exec res: exec
name: exec7 name: exec7