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:
2
TODO.md
2
TODO.md
@@ -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.
|
||||
|
||||
## 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)
|
||||
- [ ] install signal blocker [bug](https://github.com/hughsie/PackageKit/issues/109)
|
||||
|
||||
|
||||
60
config.go
60
config.go
@@ -25,13 +25,13 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type collectorTypeConfig struct {
|
||||
Type string `yaml:"type"`
|
||||
type collectorResConfig struct {
|
||||
Res string `yaml:"res"`
|
||||
Pattern string `yaml:"pattern"` // XXX: Not Implemented
|
||||
}
|
||||
|
||||
type vertexConfig struct {
|
||||
Type string `yaml:"type"`
|
||||
Res string `yaml:"res"`
|
||||
Name string `yaml:"name"`
|
||||
}
|
||||
|
||||
@@ -43,13 +43,13 @@ type edgeConfig struct {
|
||||
|
||||
type GraphConfig struct {
|
||||
Graph string `yaml:"graph"`
|
||||
Types struct {
|
||||
Noop []NoopType `yaml:"noop"`
|
||||
File []FileType `yaml:"file"`
|
||||
Service []ServiceType `yaml:"service"`
|
||||
Exec []ExecType `yaml:"exec"`
|
||||
} `yaml:"types"`
|
||||
Collector []collectorTypeConfig `yaml:"collect"`
|
||||
Resources struct {
|
||||
Noop []NoopRes `yaml:"noop"`
|
||||
File []FileRes `yaml:"file"`
|
||||
Svc []SvcRes `yaml:"svc"`
|
||||
Exec []ExecRes `yaml:"exec"`
|
||||
} `yaml:"resources"`
|
||||
Collector []collectorResConfig `yaml:"collect"`
|
||||
Edges []edgeConfig `yaml:"edges"`
|
||||
Comment string `yaml:"comment"`
|
||||
}
|
||||
@@ -95,13 +95,13 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
|
||||
|
||||
var NoopMap = 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 lookup = make(map[string]map[string]*Vertex)
|
||||
lookup["noop"] = NoopMap
|
||||
lookup["file"] = FileMap
|
||||
lookup["service"] = ServiceMap
|
||||
lookup["svc"] = SvcMap
|
||||
lookup["exec"] = ExecMap
|
||||
|
||||
//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
|
||||
|
||||
for _, t := range config.Types.Noop {
|
||||
obj := NewNoopType(t.Name)
|
||||
for _, t := range config.Resources.Noop {
|
||||
obj := NewNoopRes(t.Name)
|
||||
v := g.GetVertexMatch(obj)
|
||||
if v == nil { // no match found
|
||||
v = NewVertex(obj)
|
||||
@@ -121,7 +121,7 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
|
||||
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
|
||||
// like exported => true || exported => (host pattern)||(other pattern?)
|
||||
if strings.HasPrefix(t.Name, "@@") { // exported resource
|
||||
@@ -132,7 +132,7 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
|
||||
continue
|
||||
}
|
||||
} 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)
|
||||
if v == nil { // no match found
|
||||
v = NewVertex(obj)
|
||||
@@ -143,19 +143,19 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
|
||||
}
|
||||
}
|
||||
|
||||
for _, t := range config.Types.Service {
|
||||
obj := NewServiceType(t.Name, t.State, t.Startup)
|
||||
for _, t := range config.Resources.Svc {
|
||||
obj := NewSvcRes(t.Name, t.State, t.Startup)
|
||||
v := g.GetVertexMatch(obj)
|
||||
if v == nil { // no match found
|
||||
v = NewVertex(obj)
|
||||
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
|
||||
}
|
||||
|
||||
for _, t := range config.Types.Exec {
|
||||
obj := NewExecType(t.Name, t.Cmd, t.Shell, t.Timeout, t.WatchCmd, t.WatchShell, t.IfCmd, t.IfShell, t.PollInt, t.State)
|
||||
for _, t := range config.Resources.Exec {
|
||||
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)
|
||||
if v == nil { // no match found
|
||||
v = NewVertex(obj)
|
||||
@@ -171,11 +171,11 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
|
||||
nodes, ok := etcdO.EtcdGet()
|
||||
if ok {
|
||||
for _, t := range config.Collector {
|
||||
// XXX: use t.Type and optionally t.Pattern to collect from etcd storage
|
||||
log.Printf("Collect: %v; Pattern: %v", t.Type, t.Pattern)
|
||||
// XXX: use t.Res and optionally t.Pattern to collect from etcd storage
|
||||
log.Printf("Collect: %v; Pattern: %v", t.Res, t.Pattern)
|
||||
|
||||
for _, x := range etcdO.EtcdGetProcess(nodes, "file") {
|
||||
var obj *FileType
|
||||
var obj *FileRes
|
||||
if B64ToObj(x, &obj) != true {
|
||||
log.Printf("Collect: File: %v not collected!", x)
|
||||
continue
|
||||
@@ -205,25 +205,25 @@ func UpdateGraphFromConfig(config *GraphConfig, hostname string, g *Graph, etcdO
|
||||
for _, v := range g.GetVertices() {
|
||||
if !HasVertex(v, keep) {
|
||||
// wait for exit before starting new graph!
|
||||
v.Type.SendEvent(eventExit, true, false)
|
||||
v.Res.SendEvent(eventExit, true, false)
|
||||
g.DeleteVertex(v)
|
||||
}
|
||||
}
|
||||
|
||||
for _, e := range config.Edges {
|
||||
if _, ok := lookup[e.From.Type]; !ok {
|
||||
if _, ok := lookup[e.From.Res]; !ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := lookup[e.To.Type]; !ok {
|
||||
if _, ok := lookup[e.To.Res]; !ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := lookup[e.From.Type][e.From.Name]; !ok {
|
||||
if _, ok := lookup[e.From.Res][e.From.Name]; !ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := lookup[e.To.Type][e.To.Name]; !ok {
|
||||
if _, ok := lookup[e.To.Res][e.To.Name]; !ok {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
"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...
|
||||
func ConfigWatch(file string) chan bool {
|
||||
ch := make(chan bool)
|
||||
|
||||
30
etcd.go
30
etcd.go
@@ -191,8 +191,8 @@ func (etcdO *EtcdWObject) EtcdWatch() chan etcdMsg {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: we get events on key/type/value changes for
|
||||
// each type directory... ignore the non final ones...
|
||||
// FIXME: we get events on key/res/value changes for
|
||||
// each res directory... ignore the non final ones...
|
||||
// IOW, ignore everything except for the value or some
|
||||
// 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
|
||||
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()
|
||||
output, ok := ObjToB64(obj)
|
||||
if !ok {
|
||||
@@ -215,11 +215,11 @@ func (etcdO *EtcdWObject) EtcdPut(hostname, key, typ string, obj interface{}) bo
|
||||
return false
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("/exported/%s/types/%s/type", hostname, key)
|
||||
_, err := kapi.Set(etcd_context.Background(), path, typ, nil)
|
||||
path := fmt.Sprintf("/exported/%s/resources/%s/res", hostname, key)
|
||||
_, err := kapi.Set(etcd_context.Background(), path, res, nil)
|
||||
// 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)
|
||||
if err != nil {
|
||||
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
|
||||
func (etcdO *EtcdWObject) EtcdGet() (etcd.Nodes, bool) {
|
||||
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})
|
||||
if err != nil {
|
||||
return nil, false // not found
|
||||
@@ -248,8 +248,8 @@ func (etcdO *EtcdWObject) EtcdGet() (etcd.Nodes, bool) {
|
||||
return resp.Node.Nodes, true
|
||||
}
|
||||
|
||||
func (etcdO *EtcdWObject) EtcdGetProcess(nodes etcd.Nodes, typ string) []string {
|
||||
//path := fmt.Sprintf("/exported/%s/types/", h)
|
||||
func (etcdO *EtcdWObject) EtcdGetProcess(nodes etcd.Nodes, res string) []string {
|
||||
//path := fmt.Sprintf("/exported/%s/resources/", h)
|
||||
top := "/exported/"
|
||||
log.Printf("Etcd: Get: %+v", nodes) // Get().Nodes.Nodes
|
||||
var output []string
|
||||
@@ -261,20 +261,20 @@ func (etcdO *EtcdWObject) EtcdGetProcess(nodes etcd.Nodes, typ string) []string
|
||||
host := x.Key[len(top):]
|
||||
//log.Printf("Get().Nodes[%v]: %+v ==> %+v", -1, host, 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 {
|
||||
continue
|
||||
}
|
||||
for _, y := range types.Nodes { // loop through types
|
||||
for _, y := range resources.Nodes { // loop through resources
|
||||
//key := y.Key # UUID?
|
||||
//log.Printf("Get(%v): TYPE[%v]", host, y.Key)
|
||||
t, ok := EtcdGetChildNodeByKey(y, "type")
|
||||
//log.Printf("Get(%v): RES[%v]", host, y.Key)
|
||||
t, ok := EtcdGetChildNodeByKey(y, "res")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if typ != "" && typ != t.Value {
|
||||
if res != "" && res != t.Value {
|
||||
continue
|
||||
} // filter based on type
|
||||
} // filter based on res
|
||||
|
||||
v, ok := EtcdGetChildNodeByKey(y, "value") // B64ToObj this
|
||||
if !ok {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
graph: mygraph
|
||||
comment: hello world example
|
||||
types:
|
||||
resources:
|
||||
noop:
|
||||
- name: noop1
|
||||
file:
|
||||
@@ -13,8 +13,8 @@ types:
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: noop
|
||||
res: noop
|
||||
name: noop1
|
||||
to:
|
||||
type: file
|
||||
res: file
|
||||
name: file1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
noop:
|
||||
- name: noop1
|
||||
file:
|
||||
@@ -27,15 +27,15 @@ types:
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: file
|
||||
res: file
|
||||
name: file1
|
||||
to:
|
||||
type: file
|
||||
res: file
|
||||
name: file2
|
||||
- name: e2
|
||||
from:
|
||||
type: file
|
||||
res: file
|
||||
name: file2
|
||||
to:
|
||||
type: file
|
||||
res: file
|
||||
name: file3
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
graph: mygraph
|
||||
comment: simple exec fan in to fan out example to demonstrate optimization
|
||||
types:
|
||||
resources:
|
||||
exec:
|
||||
- name: exec1
|
||||
cmd: sleep 10s
|
||||
@@ -86,43 +86,43 @@ types:
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec1
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec4
|
||||
- name: e2
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec2
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec4
|
||||
- name: e3
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec3
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec4
|
||||
- name: e4
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec4
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec5
|
||||
- name: e5
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec4
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec6
|
||||
- name: e6
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec4
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec7
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
file:
|
||||
- name: file1
|
||||
path: "/tmp/mgmt/f1"
|
||||
@@ -15,8 +15,8 @@ types:
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: file
|
||||
res: file
|
||||
name: file1
|
||||
to:
|
||||
type: file
|
||||
res: file
|
||||
name: file2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
file:
|
||||
- name: file2
|
||||
path: "/tmp/mgmt/f2"
|
||||
@@ -15,8 +15,8 @@ types:
|
||||
edges:
|
||||
- name: e2
|
||||
from:
|
||||
type: file
|
||||
res: file
|
||||
name: file2
|
||||
to:
|
||||
type: file
|
||||
res: file
|
||||
name: file3
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
noop:
|
||||
- name: noop1
|
||||
file:
|
||||
@@ -9,22 +9,22 @@ types:
|
||||
content: |
|
||||
i am f1
|
||||
state: exists
|
||||
service:
|
||||
svc:
|
||||
- name: purpleidea
|
||||
state: running
|
||||
startup: enabled
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: noop
|
||||
res: noop
|
||||
name: noop1
|
||||
to:
|
||||
type: file
|
||||
res: file
|
||||
name: file1
|
||||
- name: e2
|
||||
from:
|
||||
type: file
|
||||
res: file
|
||||
name: file1
|
||||
to:
|
||||
type: service
|
||||
res: svc
|
||||
name: purpleidea
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
file:
|
||||
- name: file1a
|
||||
path: "/tmp/mgmtA/f1a"
|
||||
@@ -23,6 +23,6 @@ types:
|
||||
i am f4, exported from host A
|
||||
state: exists
|
||||
collect:
|
||||
- type: file
|
||||
- res: file
|
||||
pattern: "/tmp/mgmtA/"
|
||||
edges: []
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
file:
|
||||
- name: file1b
|
||||
path: "/tmp/mgmtB/f1b"
|
||||
@@ -23,6 +23,6 @@ types:
|
||||
i am f4, exported from host B
|
||||
state: exists
|
||||
collect:
|
||||
- type: file
|
||||
- res: file
|
||||
pattern: "/tmp/mgmtB/"
|
||||
edges: []
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
file:
|
||||
- name: file1c
|
||||
path: "/tmp/mgmtC/f1c"
|
||||
@@ -23,6 +23,6 @@ types:
|
||||
i am f4, exported from host C
|
||||
state: exists
|
||||
collect:
|
||||
- type: file
|
||||
- res: file
|
||||
pattern: "/tmp/mgmtC/"
|
||||
edges: []
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
file:
|
||||
- name: file1
|
||||
path: "/tmp/mgmt/f1"
|
||||
@@ -13,6 +13,6 @@ types:
|
||||
i am f3, exported from host A
|
||||
state: exists
|
||||
collect:
|
||||
- type: file
|
||||
- res: file
|
||||
pattern: ''
|
||||
edges:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
file:
|
||||
- name: file1
|
||||
path: "/tmp/mgmt/f1"
|
||||
@@ -8,6 +8,6 @@ types:
|
||||
i am f1
|
||||
state: exists
|
||||
collect:
|
||||
- type: file
|
||||
- res: file
|
||||
pattern: ''
|
||||
edges:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
noop:
|
||||
- name: noop1
|
||||
edges:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
noop:
|
||||
- name: noop1
|
||||
exec:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
exec:
|
||||
- name: exec1
|
||||
cmd: sleep 10s
|
||||
@@ -45,15 +45,15 @@ types:
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec1
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec2
|
||||
- name: e2
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec2
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec3
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
exec:
|
||||
- name: exec1
|
||||
cmd: sleep 10s
|
||||
@@ -25,8 +25,8 @@ types:
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec1
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
exec:
|
||||
- name: exec1
|
||||
cmd: sleep 10s
|
||||
@@ -25,8 +25,8 @@ types:
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec1
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
exec:
|
||||
- name: exec1
|
||||
cmd: echo hello from exec1
|
||||
@@ -25,8 +25,8 @@ types:
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec1
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
exec:
|
||||
- name: exec1
|
||||
cmd: echo hello from exec1
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
graph: mygraph
|
||||
comment: simple exec fan in example to demonstrate optimization
|
||||
types:
|
||||
resources:
|
||||
exec:
|
||||
- name: exec1
|
||||
cmd: sleep 10s
|
||||
@@ -56,22 +56,22 @@ types:
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec1
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec5
|
||||
- name: e2
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec2
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec5
|
||||
- name: e3
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec3
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec5
|
||||
|
||||
76
exec.go
76
exec.go
@@ -25,8 +25,8 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ExecType struct {
|
||||
BaseType `yaml:",inline"`
|
||||
type ExecRes struct {
|
||||
BaseRes `yaml:",inline"`
|
||||
State string `yaml:"state"` // state: exists/present?, absent, (undefined?)
|
||||
Cmd string `yaml:"cmd"` // the command to run
|
||||
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
|
||||
}
|
||||
|
||||
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 ...
|
||||
return &ExecType{
|
||||
BaseType: BaseType{
|
||||
return &ExecRes{
|
||||
BaseRes: BaseRes{
|
||||
Name: name,
|
||||
events: make(chan Event),
|
||||
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"
|
||||
}
|
||||
|
||||
// validate if the params passed in are valid data
|
||||
// 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
|
||||
return false
|
||||
}
|
||||
@@ -78,7 +78,7 @@ func (obj *ExecType) Validate() bool {
|
||||
}
|
||||
|
||||
// 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)
|
||||
go func() {
|
||||
for scanner.Scan() {
|
||||
@@ -96,7 +96,7 @@ func (obj *ExecType) BufioChanScanner(scanner *bufio.Scanner) (chan string, chan
|
||||
}
|
||||
|
||||
// Exec watcher
|
||||
func (obj *ExecType) Watch() {
|
||||
func (obj *ExecRes) Watch() {
|
||||
if obj.IsWatching() {
|
||||
return
|
||||
}
|
||||
@@ -128,7 +128,7 @@ func (obj *ExecType) Watch() {
|
||||
|
||||
cmdReader, err := cmd.StdoutPipe()
|
||||
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?
|
||||
}
|
||||
scanner := bufio.NewScanner(cmdReader)
|
||||
@@ -140,7 +140,7 @@ func (obj *ExecType) Watch() {
|
||||
cmd.Process.Kill() // TODO: is this necessary?
|
||||
}()
|
||||
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?
|
||||
}
|
||||
|
||||
@@ -148,36 +148,36 @@ func (obj *ExecType) Watch() {
|
||||
}
|
||||
|
||||
for {
|
||||
obj.SetState(typeWatching) // reset
|
||||
obj.SetState(resStateWatching) // reset
|
||||
select {
|
||||
case text := <-bufioch:
|
||||
obj.SetConvergedState(typeConvergedNil)
|
||||
obj.SetConvergedState(resConvergedNil)
|
||||
// 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 != "" {
|
||||
send = true
|
||||
}
|
||||
|
||||
case err := <-errch:
|
||||
obj.SetConvergedState(typeConvergedNil) // XXX ?
|
||||
obj.SetConvergedState(resConvergedNil) // XXX ?
|
||||
if err == nil { // EOF
|
||||
// FIXME: add an "if watch command ends/crashes"
|
||||
// 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
|
||||
}
|
||||
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)
|
||||
// XXX: how should we handle errors?
|
||||
|
||||
case event := <-obj.events:
|
||||
obj.SetConvergedState(typeConvergedNil)
|
||||
obj.SetConvergedState(resConvergedNil)
|
||||
if exit, send = obj.ReadEvent(&event); exit {
|
||||
return // exit
|
||||
}
|
||||
|
||||
case _ = <-TimeAfterOrBlock(obj.ctimeout):
|
||||
obj.SetConvergedState(typeConvergedTimeout)
|
||||
obj.SetConvergedState(resConvergedTimeout)
|
||||
obj.converged <- true
|
||||
continue
|
||||
}
|
||||
@@ -193,7 +193,7 @@ func (obj *ExecType) Watch() {
|
||||
}
|
||||
|
||||
// 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 b := obj.isStateOK; obj.WatchCmd != "" && obj.IfCmd == "" {
|
||||
@@ -241,8 +241,8 @@ func (obj *ExecType) StateOK() bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *ExecType) Apply() bool {
|
||||
log.Printf("%v[%v]: Apply", obj.GetType(), obj.GetName())
|
||||
func (obj *ExecRes) Apply() bool {
|
||||
log.Printf("%v[%v]: Apply", obj.GetRes(), obj.GetName())
|
||||
var cmdName string
|
||||
var cmdArgs []string
|
||||
if obj.Shell == "" {
|
||||
@@ -264,7 +264,7 @@ func (obj *ExecType) Apply() bool {
|
||||
cmd.Stdout = &out
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -278,12 +278,12 @@ func (obj *ExecType) Apply() bool {
|
||||
select {
|
||||
case err := <-done:
|
||||
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
|
||||
}
|
||||
|
||||
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?
|
||||
return false
|
||||
}
|
||||
@@ -301,35 +301,35 @@ func (obj *ExecType) Apply() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (obj *ExecType) Compare(typ Type) bool {
|
||||
switch typ.(type) {
|
||||
case *ExecType:
|
||||
typ := typ.(*ExecType)
|
||||
if obj.Name != typ.Name {
|
||||
func (obj *ExecRes) Compare(res Res) bool {
|
||||
switch res.(type) {
|
||||
case *ExecRes:
|
||||
res := res.(*ExecRes)
|
||||
if obj.Name != res.Name {
|
||||
return false
|
||||
}
|
||||
if obj.Cmd != typ.Cmd {
|
||||
if obj.Cmd != res.Cmd {
|
||||
return false
|
||||
}
|
||||
if obj.Shell != typ.Shell {
|
||||
if obj.Shell != res.Shell {
|
||||
return false
|
||||
}
|
||||
if obj.Timeout != typ.Timeout {
|
||||
if obj.Timeout != res.Timeout {
|
||||
return false
|
||||
}
|
||||
if obj.WatchCmd != typ.WatchCmd {
|
||||
if obj.WatchCmd != res.WatchCmd {
|
||||
return false
|
||||
}
|
||||
if obj.WatchShell != typ.WatchShell {
|
||||
if obj.WatchShell != res.WatchShell {
|
||||
return false
|
||||
}
|
||||
if obj.IfCmd != typ.IfCmd {
|
||||
if obj.IfCmd != res.IfCmd {
|
||||
return false
|
||||
}
|
||||
if obj.PollInt != typ.PollInt {
|
||||
if obj.PollInt != res.PollInt {
|
||||
return false
|
||||
}
|
||||
if obj.State != typ.State {
|
||||
if obj.State != res.State {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
|
||||
68
file.go
68
file.go
@@ -31,8 +31,8 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type FileType struct {
|
||||
BaseType `yaml:",inline"`
|
||||
type FileRes struct {
|
||||
BaseRes `yaml:",inline"`
|
||||
Path string `yaml:"path"` // path variable (should default to name)
|
||||
Dirname string `yaml:"dirname"`
|
||||
Basename string `yaml:"basename"`
|
||||
@@ -41,10 +41,10 @@ type FileType struct {
|
||||
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 ...
|
||||
return &FileType{
|
||||
BaseType: BaseType{
|
||||
return &FileRes{
|
||||
BaseRes: BaseRes{
|
||||
Name: name,
|
||||
events: make(chan Event),
|
||||
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"
|
||||
}
|
||||
|
||||
// validate if the params passed in are valid data
|
||||
func (obj *FileType) Validate() bool {
|
||||
func (obj *FileRes) Validate() bool {
|
||||
if obj.Dirname != "" {
|
||||
// must end with /
|
||||
if obj.Dirname[len(obj.Dirname)-1:] != "/" {
|
||||
@@ -79,7 +79,7 @@ func (obj *FileType) Validate() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (obj *FileType) GetPath() string {
|
||||
func (obj *FileRes) GetPath() string {
|
||||
d := Dirname(obj.Path)
|
||||
b := Basename(obj.Path)
|
||||
if !obj.Validate() || (obj.Dirname == "" && obj.Basename == "") {
|
||||
@@ -96,7 +96,7 @@ func (obj *FileType) GetPath() string {
|
||||
// File watcher for files and directories
|
||||
// Modify with caution, probably important to write some test cases first!
|
||||
// obj.GetPath(): file or directory
|
||||
func (obj *FileType) Watch() {
|
||||
func (obj *FileRes) Watch() {
|
||||
if obj.IsWatching() {
|
||||
return
|
||||
}
|
||||
@@ -152,13 +152,13 @@ func (obj *FileType) Watch() {
|
||||
continue
|
||||
}
|
||||
|
||||
obj.SetState(typeWatching) // reset
|
||||
obj.SetState(resStateWatching) // reset
|
||||
select {
|
||||
case event := <-watcher.Events:
|
||||
if DEBUG {
|
||||
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...
|
||||
// this is the difference between what we're watching,
|
||||
// and the event... doesn't mean we can't watch deeper
|
||||
@@ -228,20 +228,20 @@ func (obj *FileType) Watch() {
|
||||
}
|
||||
|
||||
case err := <-watcher.Errors:
|
||||
obj.SetConvergedState(typeConvergedNil) // XXX ?
|
||||
obj.SetConvergedState(resConvergedNil) // XXX ?
|
||||
log.Println("error:", err)
|
||||
log.Fatal(err)
|
||||
//obj.events <- fmt.Sprintf("file: %v", "error") // XXX: how should we handle errors?
|
||||
|
||||
case event := <-obj.events:
|
||||
obj.SetConvergedState(typeConvergedNil)
|
||||
obj.SetConvergedState(resConvergedNil)
|
||||
if exit, send = obj.ReadEvent(&event); exit {
|
||||
return // exit
|
||||
}
|
||||
//dirty = false // these events don't invalidate state
|
||||
|
||||
case _ = <-TimeAfterOrBlock(obj.ctimeout):
|
||||
obj.SetConvergedState(typeConvergedTimeout)
|
||||
obj.SetConvergedState(resConvergedTimeout)
|
||||
obj.converged <- true
|
||||
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
|
||||
return obj.sha256sum
|
||||
}
|
||||
@@ -271,7 +271,7 @@ func (obj *FileType) HashSHA256fromContent() string {
|
||||
}
|
||||
|
||||
// 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
|
||||
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()) {
|
||||
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
|
||||
@@ -326,9 +326,9 @@ func (obj *FileType) StateOKFile() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (obj *FileType) StateOKDir() bool {
|
||||
func (obj *FileRes) StateOKDir() bool {
|
||||
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
|
||||
@@ -336,8 +336,8 @@ func (obj *FileType) StateOKDir() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (obj *FileType) Apply() bool {
|
||||
log.Printf("%v[%v]: Apply", obj.GetType(), obj.GetName())
|
||||
func (obj *FileRes) Apply() bool {
|
||||
log.Printf("%v[%v]: Apply", obj.GetRes(), obj.GetName())
|
||||
|
||||
if PathIsDir(obj.GetPath()) {
|
||||
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()) {
|
||||
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" {
|
||||
@@ -378,9 +378,9 @@ func (obj *FileType) ApplyFile() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (obj *FileType) ApplyDir() bool {
|
||||
func (obj *FileRes) ApplyDir() bool {
|
||||
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
|
||||
@@ -388,20 +388,20 @@ func (obj *FileType) ApplyDir() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (obj *FileType) Compare(typ Type) bool {
|
||||
switch typ.(type) {
|
||||
case *FileType:
|
||||
typ := typ.(*FileType)
|
||||
if obj.Name != typ.Name {
|
||||
func (obj *FileRes) Compare(res Res) bool {
|
||||
switch res.(type) {
|
||||
case *FileRes:
|
||||
res := res.(*FileRes)
|
||||
if obj.Name != res.Name {
|
||||
return false
|
||||
}
|
||||
if obj.GetPath() != typ.Path {
|
||||
if obj.GetPath() != res.Path {
|
||||
return false
|
||||
}
|
||||
if obj.Content != typ.Content {
|
||||
if obj.Content != res.Content {
|
||||
return false
|
||||
}
|
||||
if obj.State != typ.State {
|
||||
if obj.State != res.State {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
|
||||
2
main.go
2
main.go
@@ -177,7 +177,7 @@ func run(c *cli.Context) {
|
||||
continue
|
||||
}
|
||||
for v := range G.GetVerticesChan() {
|
||||
if v.Type.GetConvergedState() != typeConvergedTimeout {
|
||||
if v.Res.GetConvergedState() != resConvergedTimeout {
|
||||
continue ConvergedLoop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ func TestMiscT6(t *testing.T) {
|
||||
|
||||
type foo struct {
|
||||
Name string `yaml:"name"`
|
||||
Type string `yaml:"type"`
|
||||
Res string `yaml:"res"`
|
||||
Value int `yaml:"value"`
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ func TestMiscT7(t *testing.T) {
|
||||
|
||||
type Foo struct {
|
||||
Name string `yaml:"name"`
|
||||
Type string `yaml:"type"`
|
||||
Res string `yaml:"res"`
|
||||
Value int `yaml:"value"`
|
||||
}
|
||||
|
||||
|
||||
30
pgraph.go
30
pgraph.go
@@ -57,7 +57,7 @@ type Graph struct {
|
||||
|
||||
type Vertex struct {
|
||||
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?
|
||||
}
|
||||
|
||||
@@ -73,9 +73,9 @@ func NewGraph(name string) *Graph {
|
||||
}
|
||||
}
|
||||
|
||||
func NewVertex(t Type) *Vertex {
|
||||
func NewVertex(r Res) *Vertex {
|
||||
return &Vertex{
|
||||
Type: t,
|
||||
Res: r,
|
||||
data: make(map[string]string),
|
||||
}
|
||||
}
|
||||
@@ -111,10 +111,10 @@ func (g *Graph) SetState(state graphState) graphState {
|
||||
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() {
|
||||
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
|
||||
}
|
||||
|
||||
func (g *Graph) GetVertexMatch(obj Type) *Vertex {
|
||||
func (g *Graph) GetVertexMatch(obj Res) *Vertex {
|
||||
for k := range g.Adjacency {
|
||||
if k.Compare(obj) { // XXX test
|
||||
return k
|
||||
@@ -241,7 +241,7 @@ func (g *Graph) Graphviz() (out string) {
|
||||
//out += "\tnode [shape=box];\n"
|
||||
str := ""
|
||||
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] {
|
||||
k := g.Adjacency[i][j]
|
||||
// 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
|
||||
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)
|
||||
// must pass in value to avoid races...
|
||||
// see: https://ttboj.wordpress.com/2015/07/27/golang-parallelism-issues-causing-too-many-open-files-error/
|
||||
go func(vv *Vertex) {
|
||||
defer wg.Done()
|
||||
vv.Type.Watch()
|
||||
log.Printf("%v[%v]: Exited", vv.GetType(), vv.GetName())
|
||||
vv.Res.Watch()
|
||||
log.Printf("%v[%v]: Exited", vv.GetRes(), vv.GetName())
|
||||
}(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.
|
||||
if (!first) || indegree[v] == 0 {
|
||||
// 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 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
|
||||
// a different goroutine to be scheduled
|
||||
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() {
|
||||
t, _ := g.TopologicalSort()
|
||||
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!
|
||||
// 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) {
|
||||
for v := range g.GetVerticesChan() {
|
||||
v.Type.SetConvegedCallback(ctimeout, converged)
|
||||
v.Res.SetConvergedCallback(ctimeout, converged)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
122
pgraph_test.go
122
pgraph_test.go
@@ -36,8 +36,8 @@ func TestPgraphT1(t *testing.T) {
|
||||
t.Errorf("Should have 0 edges instead of: %d.", i)
|
||||
}
|
||||
|
||||
v1 := NewVertex(NewNoopType("v1"))
|
||||
v2 := NewVertex(NewNoopType("v2"))
|
||||
v1 := NewVertex(NewNoopRes("v1"))
|
||||
v2 := NewVertex(NewNoopRes("v2"))
|
||||
e1 := NewEdge("e1")
|
||||
G.AddEdge(v1, v2, e1)
|
||||
|
||||
@@ -53,12 +53,12 @@ func TestPgraphT1(t *testing.T) {
|
||||
func TestPgraphT2(t *testing.T) {
|
||||
|
||||
G := NewGraph("g2")
|
||||
v1 := NewVertex(NewNoopType("v1"))
|
||||
v2 := NewVertex(NewNoopType("v2"))
|
||||
v3 := NewVertex(NewNoopType("v3"))
|
||||
v4 := NewVertex(NewNoopType("v4"))
|
||||
v5 := NewVertex(NewNoopType("v5"))
|
||||
v6 := NewVertex(NewNoopType("v6"))
|
||||
v1 := NewVertex(NewNoopRes("v1"))
|
||||
v2 := NewVertex(NewNoopRes("v2"))
|
||||
v3 := NewVertex(NewNoopRes("v3"))
|
||||
v4 := NewVertex(NewNoopRes("v4"))
|
||||
v5 := NewVertex(NewNoopRes("v5"))
|
||||
v6 := NewVertex(NewNoopRes("v6"))
|
||||
e1 := NewEdge("e1")
|
||||
e2 := NewEdge("e2")
|
||||
e3 := NewEdge("e3")
|
||||
@@ -80,12 +80,12 @@ func TestPgraphT2(t *testing.T) {
|
||||
func TestPgraphT3(t *testing.T) {
|
||||
|
||||
G := NewGraph("g3")
|
||||
v1 := NewVertex(NewNoopType("v1"))
|
||||
v2 := NewVertex(NewNoopType("v2"))
|
||||
v3 := NewVertex(NewNoopType("v3"))
|
||||
v4 := NewVertex(NewNoopType("v4"))
|
||||
v5 := NewVertex(NewNoopType("v5"))
|
||||
v6 := NewVertex(NewNoopType("v6"))
|
||||
v1 := NewVertex(NewNoopRes("v1"))
|
||||
v2 := NewVertex(NewNoopRes("v2"))
|
||||
v3 := NewVertex(NewNoopRes("v3"))
|
||||
v4 := NewVertex(NewNoopRes("v4"))
|
||||
v5 := NewVertex(NewNoopRes("v5"))
|
||||
v6 := NewVertex(NewNoopRes("v6"))
|
||||
e1 := NewEdge("e1")
|
||||
e2 := NewEdge("e2")
|
||||
e3 := NewEdge("e3")
|
||||
@@ -121,9 +121,9 @@ func TestPgraphT3(t *testing.T) {
|
||||
func TestPgraphT4(t *testing.T) {
|
||||
|
||||
G := NewGraph("g4")
|
||||
v1 := NewVertex(NewNoopType("v1"))
|
||||
v2 := NewVertex(NewNoopType("v2"))
|
||||
v3 := NewVertex(NewNoopType("v3"))
|
||||
v1 := NewVertex(NewNoopRes("v1"))
|
||||
v2 := NewVertex(NewNoopRes("v2"))
|
||||
v3 := NewVertex(NewNoopRes("v3"))
|
||||
e1 := NewEdge("e1")
|
||||
e2 := NewEdge("e2")
|
||||
e3 := NewEdge("e3")
|
||||
@@ -143,12 +143,12 @@ func TestPgraphT4(t *testing.T) {
|
||||
|
||||
func TestPgraphT5(t *testing.T) {
|
||||
G := NewGraph("g5")
|
||||
v1 := NewVertex(NewNoopType("v1"))
|
||||
v2 := NewVertex(NewNoopType("v2"))
|
||||
v3 := NewVertex(NewNoopType("v3"))
|
||||
v4 := NewVertex(NewNoopType("v4"))
|
||||
v5 := NewVertex(NewNoopType("v5"))
|
||||
v6 := NewVertex(NewNoopType("v6"))
|
||||
v1 := NewVertex(NewNoopRes("v1"))
|
||||
v2 := NewVertex(NewNoopRes("v2"))
|
||||
v3 := NewVertex(NewNoopRes("v3"))
|
||||
v4 := NewVertex(NewNoopRes("v4"))
|
||||
v5 := NewVertex(NewNoopRes("v5"))
|
||||
v6 := NewVertex(NewNoopRes("v6"))
|
||||
e1 := NewEdge("e1")
|
||||
e2 := NewEdge("e2")
|
||||
e3 := NewEdge("e3")
|
||||
@@ -172,12 +172,12 @@ func TestPgraphT5(t *testing.T) {
|
||||
|
||||
func TestPgraphT6(t *testing.T) {
|
||||
G := NewGraph("g6")
|
||||
v1 := NewVertex(NewNoopType("v1"))
|
||||
v2 := NewVertex(NewNoopType("v2"))
|
||||
v3 := NewVertex(NewNoopType("v3"))
|
||||
v4 := NewVertex(NewNoopType("v4"))
|
||||
v5 := NewVertex(NewNoopType("v5"))
|
||||
v6 := NewVertex(NewNoopType("v6"))
|
||||
v1 := NewVertex(NewNoopRes("v1"))
|
||||
v2 := NewVertex(NewNoopRes("v2"))
|
||||
v3 := NewVertex(NewNoopRes("v3"))
|
||||
v4 := NewVertex(NewNoopRes("v4"))
|
||||
v5 := NewVertex(NewNoopRes("v5"))
|
||||
v6 := NewVertex(NewNoopRes("v6"))
|
||||
e1 := NewEdge("e1")
|
||||
e2 := NewEdge("e2")
|
||||
e3 := NewEdge("e3")
|
||||
@@ -210,9 +210,9 @@ func TestPgraphT6(t *testing.T) {
|
||||
func TestPgraphT7(t *testing.T) {
|
||||
|
||||
G := NewGraph("g7")
|
||||
v1 := NewVertex(NewNoopType("v1"))
|
||||
v2 := NewVertex(NewNoopType("v2"))
|
||||
v3 := NewVertex(NewNoopType("v3"))
|
||||
v1 := NewVertex(NewNoopRes("v1"))
|
||||
v2 := NewVertex(NewNoopRes("v2"))
|
||||
v3 := NewVertex(NewNoopRes("v3"))
|
||||
e1 := NewEdge("e1")
|
||||
e2 := NewEdge("e2")
|
||||
e3 := NewEdge("e3")
|
||||
@@ -251,28 +251,28 @@ func TestPgraphT7(t *testing.T) {
|
||||
|
||||
func TestPgraphT8(t *testing.T) {
|
||||
|
||||
v1 := NewVertex(NewNoopType("v1"))
|
||||
v2 := NewVertex(NewNoopType("v2"))
|
||||
v3 := NewVertex(NewNoopType("v3"))
|
||||
v1 := NewVertex(NewNoopRes("v1"))
|
||||
v2 := NewVertex(NewNoopRes("v2"))
|
||||
v3 := NewVertex(NewNoopRes("v3"))
|
||||
if HasVertex(v1, []*Vertex{v1, v2, v3}) != true {
|
||||
t.Errorf("Should be true instead of false.")
|
||||
}
|
||||
|
||||
v4 := NewVertex(NewNoopType("v4"))
|
||||
v5 := NewVertex(NewNoopType("v5"))
|
||||
v6 := NewVertex(NewNoopType("v6"))
|
||||
v4 := NewVertex(NewNoopRes("v4"))
|
||||
v5 := NewVertex(NewNoopRes("v5"))
|
||||
v6 := NewVertex(NewNoopRes("v6"))
|
||||
if HasVertex(v4, []*Vertex{v5, v6}) != false {
|
||||
t.Errorf("Should be false instead of true.")
|
||||
}
|
||||
|
||||
v7 := NewVertex(NewNoopType("v7"))
|
||||
v8 := NewVertex(NewNoopType("v8"))
|
||||
v9 := NewVertex(NewNoopType("v9"))
|
||||
v7 := NewVertex(NewNoopRes("v7"))
|
||||
v8 := NewVertex(NewNoopRes("v8"))
|
||||
v9 := NewVertex(NewNoopRes("v9"))
|
||||
if HasVertex(v8, []*Vertex{v7, v8, v9}) != true {
|
||||
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 {
|
||||
t.Errorf("Should be false instead of true.")
|
||||
}
|
||||
@@ -281,12 +281,12 @@ func TestPgraphT8(t *testing.T) {
|
||||
func TestPgraphT9(t *testing.T) {
|
||||
|
||||
G := NewGraph("g9")
|
||||
v1 := NewVertex(NewNoopType("v1"))
|
||||
v2 := NewVertex(NewNoopType("v2"))
|
||||
v3 := NewVertex(NewNoopType("v3"))
|
||||
v4 := NewVertex(NewNoopType("v4"))
|
||||
v5 := NewVertex(NewNoopType("v5"))
|
||||
v6 := NewVertex(NewNoopType("v6"))
|
||||
v1 := NewVertex(NewNoopRes("v1"))
|
||||
v2 := NewVertex(NewNoopRes("v2"))
|
||||
v3 := NewVertex(NewNoopRes("v3"))
|
||||
v4 := NewVertex(NewNoopRes("v4"))
|
||||
v5 := NewVertex(NewNoopRes("v5"))
|
||||
v6 := NewVertex(NewNoopRes("v6"))
|
||||
e1 := NewEdge("e1")
|
||||
e2 := NewEdge("e2")
|
||||
e3 := NewEdge("e3")
|
||||
@@ -348,7 +348,7 @@ func TestPgraphT9(t *testing.T) {
|
||||
t.Errorf("Topological sort failed, status: %v.", ok)
|
||||
str := "Found:"
|
||||
for _, v := range s {
|
||||
str += " " + v.Type.GetName()
|
||||
str += " " + v.Res.GetName()
|
||||
}
|
||||
t.Errorf(str)
|
||||
}
|
||||
@@ -357,12 +357,12 @@ func TestPgraphT9(t *testing.T) {
|
||||
func TestPgraphT10(t *testing.T) {
|
||||
|
||||
G := NewGraph("g10")
|
||||
v1 := NewVertex(NewNoopType("v1"))
|
||||
v2 := NewVertex(NewNoopType("v2"))
|
||||
v3 := NewVertex(NewNoopType("v3"))
|
||||
v4 := NewVertex(NewNoopType("v4"))
|
||||
v5 := NewVertex(NewNoopType("v5"))
|
||||
v6 := NewVertex(NewNoopType("v6"))
|
||||
v1 := NewVertex(NewNoopRes("v1"))
|
||||
v2 := NewVertex(NewNoopRes("v2"))
|
||||
v3 := NewVertex(NewNoopRes("v3"))
|
||||
v4 := NewVertex(NewNoopRes("v4"))
|
||||
v5 := NewVertex(NewNoopRes("v5"))
|
||||
v6 := NewVertex(NewNoopRes("v6"))
|
||||
e1 := NewEdge("e1")
|
||||
e2 := NewEdge("e2")
|
||||
e3 := NewEdge("e3")
|
||||
@@ -382,12 +382,12 @@ func TestPgraphT10(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPgraphT11(t *testing.T) {
|
||||
v1 := NewVertex(NewNoopType("v1"))
|
||||
v2 := NewVertex(NewNoopType("v2"))
|
||||
v3 := NewVertex(NewNoopType("v3"))
|
||||
v4 := NewVertex(NewNoopType("v4"))
|
||||
v5 := NewVertex(NewNoopType("v5"))
|
||||
v6 := NewVertex(NewNoopType("v6"))
|
||||
v1 := NewVertex(NewNoopRes("v1"))
|
||||
v2 := NewVertex(NewNoopRes("v2"))
|
||||
v3 := NewVertex(NewNoopRes("v3"))
|
||||
v4 := NewVertex(NewNoopRes("v4"))
|
||||
v5 := NewVertex(NewNoopRes("v5"))
|
||||
v6 := NewVertex(NewNoopRes("v6"))
|
||||
|
||||
if rev := Reverse([]*Vertex{}); !reflect.DeepEqual(rev, []*Vertex{}) {
|
||||
t.Errorf("Reverse of vertex slice failed.")
|
||||
|
||||
@@ -22,43 +22,43 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
//go:generate stringer -type=typeState -output=typestate_stringer.go
|
||||
type typeState int
|
||||
//go:generate stringer -type=resState -output=resstate_stringer.go
|
||||
type resState int
|
||||
|
||||
const (
|
||||
typeNil typeState = iota
|
||||
typeWatching
|
||||
typeEvent // an event has happened, but we haven't poked yet
|
||||
typeApplying
|
||||
typePoking
|
||||
resStateNil resState = iota
|
||||
resStateWatching
|
||||
resStateEvent // an event has happened, but we haven't poked yet
|
||||
resStateCheckApply
|
||||
resStatePoking
|
||||
)
|
||||
|
||||
//go:generate stringer -type=typeConvergedState -output=typeconvergedstate_stringer.go
|
||||
type typeConvergedState int
|
||||
//go:generate stringer -type=resConvergedState -output=resconvergedstate_stringer.go
|
||||
type resConvergedState int
|
||||
|
||||
const (
|
||||
typeConvergedNil typeConvergedState = iota
|
||||
//typeConverged
|
||||
typeConvergedTimeout
|
||||
resConvergedNil resConvergedState = iota
|
||||
//resConverged
|
||||
resConvergedTimeout
|
||||
)
|
||||
|
||||
type Type interface {
|
||||
type Res interface {
|
||||
Init()
|
||||
GetName() string // can't be named "Name()" because of struct field
|
||||
GetType() string
|
||||
GetRes() string
|
||||
Watch()
|
||||
StateOK() bool // TODO: can we rename this to something better?
|
||||
Apply() bool
|
||||
SetVertex(*Vertex)
|
||||
SetConvegedCallback(ctimeout int, converged chan bool)
|
||||
Compare(Type) bool
|
||||
SetConvergedCallback(ctimeout int, converged chan bool)
|
||||
Compare(Res) bool
|
||||
SendEvent(eventName, bool, bool) bool
|
||||
IsWatching() bool
|
||||
SetWatching(bool)
|
||||
GetConvergedState() typeConvergedState
|
||||
SetConvergedState(typeConvergedState)
|
||||
GetState() typeState
|
||||
SetState(typeState)
|
||||
GetConvergedState() resConvergedState
|
||||
SetConvergedState(resConvergedState)
|
||||
GetState() resState
|
||||
SetState(resState)
|
||||
GetTimestamp() int64
|
||||
UpdateTimestamp() int64
|
||||
OKTimestamp() bool
|
||||
@@ -66,28 +66,28 @@ type Type interface {
|
||||
BackPoke()
|
||||
}
|
||||
|
||||
type BaseType struct {
|
||||
type BaseRes struct {
|
||||
Name string `yaml:"name"`
|
||||
timestamp int64 // last updated timestamp ?
|
||||
events chan Event
|
||||
vertex *Vertex
|
||||
state typeState
|
||||
convergedState typeConvergedState
|
||||
state resState
|
||||
convergedState resConvergedState
|
||||
watching bool // is Watch() loop running ?
|
||||
ctimeout int // converged timeout
|
||||
converged chan bool
|
||||
isStateOK bool // whether the state is okay based on events or not
|
||||
}
|
||||
|
||||
type NoopType struct {
|
||||
BaseType `yaml:",inline"`
|
||||
type NoopRes struct {
|
||||
BaseRes `yaml:",inline"`
|
||||
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()
|
||||
return &NoopType{
|
||||
BaseType: BaseType{
|
||||
return &NoopRes{
|
||||
BaseRes: BaseRes{
|
||||
Name: name,
|
||||
events: make(chan Event), // unbuffered chan size to avoid stale events
|
||||
vertex: nil,
|
||||
@@ -97,74 +97,74 @@ func NewNoopType(name string) *NoopType {
|
||||
}
|
||||
|
||||
// initialize structures like channels if created without New constructor
|
||||
func (obj *BaseType) Init() {
|
||||
func (obj *BaseRes) Init() {
|
||||
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!
|
||||
func (obj *BaseType) GetName() string {
|
||||
// this method gets used by all the types, if we have one of (obj NoopRes) it would get overridden in that case!
|
||||
func (obj *BaseRes) GetName() string {
|
||||
return obj.Name
|
||||
}
|
||||
|
||||
func (obj *BaseType) GetType() string {
|
||||
func (obj *BaseRes) GetRes() string {
|
||||
return "Base"
|
||||
}
|
||||
|
||||
func (obj *BaseType) GetVertex() *Vertex {
|
||||
func (obj *BaseRes) GetVertex() *Vertex {
|
||||
return obj.vertex
|
||||
}
|
||||
|
||||
func (obj *BaseType) SetVertex(v *Vertex) {
|
||||
func (obj *BaseRes) SetVertex(v *Vertex) {
|
||||
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.converged = converged
|
||||
}
|
||||
|
||||
// is the Watch() function running?
|
||||
func (obj *BaseType) IsWatching() bool {
|
||||
func (obj *BaseRes) IsWatching() bool {
|
||||
return obj.watching
|
||||
}
|
||||
|
||||
// store status of if the Watch() function is running
|
||||
func (obj *BaseType) SetWatching(b bool) {
|
||||
func (obj *BaseRes) SetWatching(b bool) {
|
||||
obj.watching = b
|
||||
}
|
||||
|
||||
func (obj *BaseType) GetConvergedState() typeConvergedState {
|
||||
func (obj *BaseRes) GetConvergedState() resConvergedState {
|
||||
return obj.convergedState
|
||||
}
|
||||
|
||||
func (obj *BaseType) SetConvergedState(state typeConvergedState) {
|
||||
func (obj *BaseRes) SetConvergedState(state resConvergedState) {
|
||||
obj.convergedState = state
|
||||
}
|
||||
|
||||
func (obj *BaseType) GetState() typeState {
|
||||
func (obj *BaseRes) GetState() resState {
|
||||
return obj.state
|
||||
}
|
||||
|
||||
func (obj *BaseType) SetState(state typeState) {
|
||||
func (obj *BaseRes) SetState(state resState) {
|
||||
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
|
||||
}
|
||||
|
||||
// GetTimestamp returns the timestamp of a vertex
|
||||
func (obj *BaseType) GetTimestamp() int64 {
|
||||
func (obj *BaseRes) GetTimestamp() int64 {
|
||||
return obj.timestamp
|
||||
}
|
||||
|
||||
// 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
|
||||
return obj.timestamp
|
||||
}
|
||||
|
||||
// can this element run right now?
|
||||
func (obj *BaseType) OKTimestamp() bool {
|
||||
func (obj *BaseRes) OKTimestamp() bool {
|
||||
v := obj.GetVertex()
|
||||
g := v.GetGraph()
|
||||
// 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...
|
||||
// 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...
|
||||
x, y := obj.GetTimestamp(), n.Type.GetTimestamp()
|
||||
x, y := obj.GetTimestamp(), n.Res.GetTimestamp()
|
||||
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 {
|
||||
return false
|
||||
@@ -186,55 +186,55 @@ func (obj *BaseType) OKTimestamp() bool {
|
||||
|
||||
// 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
|
||||
func (obj *BaseType) Poke(activity bool) {
|
||||
func (obj *BaseRes) Poke(activity bool) {
|
||||
v := obj.GetVertex()
|
||||
g := v.GetGraph()
|
||||
// these are all the vertices pointing AWAY FROM v, eg: v -> ???
|
||||
for _, n := range g.OutgoingGraphEdges(v) {
|
||||
// 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
|
||||
// XXX: if n.Type.GetState() != typeEvent { // is this correct?
|
||||
// XXX: if n.Res.GetState() != resStateEvent { // is this correct?
|
||||
if true { // XXX
|
||||
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?
|
||||
} else {
|
||||
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...
|
||||
func (obj *BaseType) BackPoke() {
|
||||
func (obj *BaseRes) BackPoke() {
|
||||
v := obj.GetVertex()
|
||||
g := v.GetGraph()
|
||||
// these are all the vertices pointing TO v, eg: ??? -> 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
|
||||
// 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
|
||||
// back soon, so we can safely discard the extra parent poke...
|
||||
// TODO: implement a stateLT (less than) to tell if something
|
||||
// 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 {
|
||||
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?
|
||||
} else {
|
||||
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
|
||||
func (obj *BaseType) SendEvent(event eventName, sync bool, activity bool) bool {
|
||||
// push an event into the message queue for a particular vertex
|
||||
func (obj *BaseRes) SendEvent(event eventName, sync bool, activity bool) bool {
|
||||
// TODO: isn't this race-y ?
|
||||
if !obj.IsWatching() { // element has already exited
|
||||
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!
|
||||
// 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()
|
||||
switch event.Name {
|
||||
case eventStart:
|
||||
@@ -283,7 +283,7 @@ func (obj *BaseType) ReadEvent(event *Event) (exit, poke bool) {
|
||||
return false, false // don't poke on unpause!
|
||||
} else {
|
||||
// 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
|
||||
// are multiple `true` return exits
|
||||
func (obj *BaseType) CleanState() bool {
|
||||
func (obj *BaseRes) CleanState() bool {
|
||||
obj.isStateOK = true
|
||||
return true
|
||||
}
|
||||
|
||||
// XXX: rename this function
|
||||
func Process(obj Type) {
|
||||
func Process(obj Res) {
|
||||
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 apply = false // did we run an apply?
|
||||
// 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!
|
||||
if obj.OKTimestamp() {
|
||||
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 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...
|
||||
// if this fails, don't UpdateTimestamp()
|
||||
obj.SetState(typeApplying)
|
||||
obj.SetState(resStateCheckApply)
|
||||
if !obj.Apply() { // check for error
|
||||
ok = false
|
||||
} else {
|
||||
@@ -333,7 +333,7 @@ func Process(obj Type) {
|
||||
// update this timestamp *before* we poke or the poked
|
||||
// nodes might fail due to having a too old timestamp!
|
||||
obj.UpdateTimestamp() // this was touched...
|
||||
obj.SetState(typePoking) // can't cancel parent poke
|
||||
obj.SetState(resStatePoking) // can't cancel parent poke
|
||||
obj.Poke(apply)
|
||||
}
|
||||
// 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"
|
||||
}
|
||||
|
||||
func (obj *NoopType) Watch() {
|
||||
func (obj *NoopRes) Watch() {
|
||||
if obj.IsWatching() {
|
||||
return
|
||||
}
|
||||
@@ -358,17 +358,17 @@ func (obj *NoopType) Watch() {
|
||||
var send = false // send event?
|
||||
var exit = false
|
||||
for {
|
||||
obj.SetState(typeWatching) // reset
|
||||
obj.SetState(resStateWatching) // reset
|
||||
select {
|
||||
case event := <-obj.events:
|
||||
obj.SetConvergedState(typeConvergedNil)
|
||||
obj.SetConvergedState(resConvergedNil)
|
||||
// we avoid sending events on unpause
|
||||
if exit, send = obj.ReadEvent(&event); exit {
|
||||
return // exit
|
||||
}
|
||||
|
||||
case _ = <-TimeAfterOrBlock(obj.ctimeout):
|
||||
obj.SetConvergedState(typeConvergedTimeout)
|
||||
obj.SetConvergedState(resConvergedTimeout)
|
||||
obj.converged <- true
|
||||
continue
|
||||
}
|
||||
@@ -383,21 +383,21 @@ func (obj *NoopType) Watch() {
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *NoopType) StateOK() bool {
|
||||
func (obj *NoopRes) StateOK() bool {
|
||||
return true // never needs updating
|
||||
}
|
||||
|
||||
func (obj *NoopType) Apply() bool {
|
||||
log.Printf("%v[%v]: Apply", obj.GetType(), obj.GetName())
|
||||
func (obj *NoopRes) Apply() bool {
|
||||
log.Printf("%v[%v]: Apply", obj.GetRes(), obj.GetName())
|
||||
return true
|
||||
}
|
||||
|
||||
func (obj *NoopType) Compare(typ Type) bool {
|
||||
switch typ.(type) {
|
||||
// we can only compare NoopType to others of the same type
|
||||
case *NoopType:
|
||||
typ := typ.(*NoopType)
|
||||
if obj.Name != typ.Name {
|
||||
func (obj *NoopRes) Compare(res Res) bool {
|
||||
switch res.(type) {
|
||||
// we can only compare NoopRes to others of the same resource
|
||||
case *NoopRes:
|
||||
res := res.(*NoopRes)
|
||||
if obj.Name != res.Name {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
@@ -27,15 +27,15 @@ import (
|
||||
"log"
|
||||
)
|
||||
|
||||
type ServiceType struct {
|
||||
BaseType `yaml:",inline"`
|
||||
type SvcRes struct {
|
||||
BaseRes `yaml:",inline"`
|
||||
State string `yaml:"state"` // state: running, stopped
|
||||
Startup string `yaml:"startup"` // enabled, disabled, undefined
|
||||
}
|
||||
|
||||
func NewServiceType(name, state, startup string) *ServiceType {
|
||||
return &ServiceType{
|
||||
BaseType: BaseType{
|
||||
func NewSvcRes(name, state, startup string) *SvcRes {
|
||||
return &SvcRes{
|
||||
BaseRes: BaseRes{
|
||||
Name: name,
|
||||
events: make(chan Event),
|
||||
vertex: nil,
|
||||
@@ -45,19 +45,19 @@ func NewServiceType(name, state, startup string) *ServiceType {
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *ServiceType) GetType() string {
|
||||
return "Service"
|
||||
func (obj *SvcRes) GetRes() string {
|
||||
return "Svc"
|
||||
}
|
||||
|
||||
// Service watcher
|
||||
func (obj *ServiceType) Watch() {
|
||||
func (obj *SvcRes) Watch() {
|
||||
if obj.IsWatching() {
|
||||
return
|
||||
}
|
||||
obj.SetWatching(true)
|
||||
defer obj.SetWatching(false)
|
||||
|
||||
// obj.Name: service name
|
||||
// obj.Name: svc name
|
||||
//vertex := obj.GetVertex() // stored with SetVertex
|
||||
if !util.IsRunningSystemd() {
|
||||
log.Fatal("Systemd is not running.")
|
||||
@@ -80,11 +80,11 @@ func (obj *ServiceType) Watch() {
|
||||
buschan := make(chan *dbus.Signal, 10)
|
||||
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 exit = 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
|
||||
set := conn.NewSubscriptionSet() // no error should be returned
|
||||
subChannel, subErrors := set.Subscribe()
|
||||
@@ -97,8 +97,8 @@ func (obj *ServiceType) Watch() {
|
||||
previous = invalid
|
||||
invalid = false
|
||||
|
||||
// firstly, does service even exist or not?
|
||||
loadstate, err := conn.GetUnitProperty(service, "LoadState")
|
||||
// firstly, does svc even exist or not?
|
||||
loadstate, err := conn.GetUnitProperty(svc, "LoadState")
|
||||
if err != nil {
|
||||
log.Printf("Failed to get property: %v", err)
|
||||
invalid = true
|
||||
@@ -107,7 +107,7 @@ func (obj *ServiceType) Watch() {
|
||||
if !invalid {
|
||||
var notFound = (loadstate.Value == dbus.MakeVariant("not-found"))
|
||||
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 ?
|
||||
}
|
||||
}
|
||||
@@ -118,21 +118,21 @@ func (obj *ServiceType) Watch() {
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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
|
||||
log.Printf("Service[%v]->DaemonReload()", service)
|
||||
log.Printf("Svc[%v]->DaemonReload()", svc)
|
||||
|
||||
case event := <-obj.events:
|
||||
obj.SetConvergedState(typeConvergedNil)
|
||||
obj.SetConvergedState(resConvergedNil)
|
||||
if exit, send = obj.ReadEvent(&event); exit {
|
||||
return // exit
|
||||
}
|
||||
@@ -141,47 +141,47 @@ func (obj *ServiceType) Watch() {
|
||||
}
|
||||
|
||||
case _ = <-TimeAfterOrBlock(obj.ctimeout):
|
||||
obj.SetConvergedState(typeConvergedTimeout)
|
||||
obj.SetConvergedState(resConvergedTimeout)
|
||||
obj.converged <- true
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if !activeSet {
|
||||
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...
|
||||
obj.SetState(typeWatching) // reset
|
||||
log.Printf("Watching: %v", svc) // attempting to watch...
|
||||
obj.SetState(resStateWatching) // reset
|
||||
select {
|
||||
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...
|
||||
if event[service] != nil {
|
||||
// event[service].ActiveState is not nil
|
||||
if event[service].ActiveState == "active" {
|
||||
log.Printf("Service[%v]->Started()", service)
|
||||
} else if event[service].ActiveState == "inactive" {
|
||||
log.Printf("Service[%v]->Stopped!()", service)
|
||||
if event[svc] != nil {
|
||||
// event[svc].ActiveState is not nil
|
||||
if event[svc].ActiveState == "active" {
|
||||
log.Printf("Svc[%v]->Started()", svc)
|
||||
} else if event[svc].ActiveState == "inactive" {
|
||||
log.Printf("Svc[%v]->Stopped!()", svc)
|
||||
} else {
|
||||
log.Fatal("Unknown service state: ", event[service].ActiveState)
|
||||
log.Fatal("Unknown svc state: ", event[svc].ActiveState)
|
||||
}
|
||||
} else {
|
||||
// service stopped (and ActiveState is nil...)
|
||||
log.Printf("Service[%v]->Stopped", service)
|
||||
// svc stopped (and ActiveState is nil...)
|
||||
log.Printf("Svc[%v]->Stopped", svc)
|
||||
}
|
||||
send = true
|
||||
dirty = true
|
||||
|
||||
case err := <-subErrors:
|
||||
obj.SetConvergedState(typeConvergedNil) // XXX ?
|
||||
obj.SetConvergedState(resConvergedNil) // XXX ?
|
||||
log.Println("error:", 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:
|
||||
obj.SetConvergedState(typeConvergedNil)
|
||||
obj.SetConvergedState(resConvergedNil)
|
||||
if exit, send = obj.ReadEvent(&event); 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
|
||||
return true
|
||||
}
|
||||
@@ -218,9 +218,9 @@ func (obj *ServiceType) StateOK() bool {
|
||||
}
|
||||
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 {
|
||||
log.Printf("Failed to get load state: %v", err)
|
||||
return false
|
||||
@@ -229,14 +229,14 @@ func (obj *ServiceType) StateOK() bool {
|
||||
// NOTE: we have to compare variants with other variants, they are really strings...
|
||||
var notFound = (loadstate.Value == dbus.MakeVariant("not-found"))
|
||||
if notFound {
|
||||
log.Printf("Failed to find service: %v", service)
|
||||
log.Printf("Failed to find svc: %v", svc)
|
||||
return false
|
||||
}
|
||||
|
||||
// XXX: check service "enabled at boot" or not status...
|
||||
// XXX: check svc "enabled at boot" or not status...
|
||||
|
||||
//conn.GetUnitProperties(service)
|
||||
activestate, err := conn.GetUnitProperty(service, "ActiveState")
|
||||
//conn.GetUnitProperties(svc)
|
||||
activestate, err := conn.GetUnitProperty(svc, "ActiveState")
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func (obj *ServiceType) Apply() bool {
|
||||
log.Printf("%v[%v]: Apply", obj.GetType(), obj.GetName())
|
||||
func (obj *SvcRes) Apply() bool {
|
||||
log.Printf("%v[%v]: Apply", obj.GetRes(), obj.GetName())
|
||||
|
||||
if !util.IsRunningSystemd() {
|
||||
log.Fatal("Systemd is not running.")
|
||||
@@ -271,8 +271,8 @@ func (obj *ServiceType) Apply() bool {
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
var service = fmt.Sprintf("%v.service", obj.Name) // systemd name
|
||||
var files = []string{service} // the service represented in a list
|
||||
var svc = fmt.Sprintf("%v.service", obj.Name) // systemd name
|
||||
var files = []string{svc} // the svc represented in a list
|
||||
if obj.Startup == "enabled" {
|
||||
_, _, err = conn.EnableUnitFiles(files, false, true)
|
||||
|
||||
@@ -289,13 +289,13 @@ func (obj *ServiceType) Apply() bool {
|
||||
result := make(chan string, 1) // catch result information
|
||||
|
||||
if obj.State == "running" {
|
||||
_, err := conn.StartUnit(service, "fail", result)
|
||||
_, err := conn.StartUnit(svc, "fail", result)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to start unit: ", err)
|
||||
return false
|
||||
}
|
||||
} else if obj.State == "stopped" {
|
||||
_, err = conn.StopUnit(service, "fail", result)
|
||||
_, err = conn.StopUnit(svc, "fail", result)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to stop unit: ", err)
|
||||
return false
|
||||
@@ -319,17 +319,17 @@ func (obj *ServiceType) Apply() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (obj *ServiceType) Compare(typ Type) bool {
|
||||
switch typ.(type) {
|
||||
case *ServiceType:
|
||||
typ := typ.(*ServiceType)
|
||||
if obj.Name != typ.Name {
|
||||
func (obj *SvcRes) Compare(res Res) bool {
|
||||
switch res.(type) {
|
||||
case *SvcRes:
|
||||
res := res.(*SvcRes)
|
||||
if obj.Name != res.Name {
|
||||
return false
|
||||
}
|
||||
if obj.State != typ.State {
|
||||
if obj.State != res.State {
|
||||
return false
|
||||
}
|
||||
if obj.Startup != typ.Startup {
|
||||
if obj.Startup != res.Startup {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
noop:
|
||||
- name: noop1
|
||||
file:
|
||||
@@ -27,15 +27,15 @@ types:
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: file
|
||||
res: file
|
||||
name: file1
|
||||
to:
|
||||
type: file
|
||||
res: file
|
||||
name: file2
|
||||
- name: e2
|
||||
from:
|
||||
type: file
|
||||
res: file
|
||||
name: file2
|
||||
to:
|
||||
type: file
|
||||
res: file
|
||||
name: file3
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
file:
|
||||
- name: file1a
|
||||
path: "/tmp/mgmt/mgmtA/f1a"
|
||||
@@ -23,6 +23,6 @@ types:
|
||||
i am f4, exported from host A
|
||||
state: exists
|
||||
collect:
|
||||
- type: file
|
||||
- res: file
|
||||
pattern: "/tmp/mgmt/mgmtA/"
|
||||
edges: []
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
file:
|
||||
- name: file1b
|
||||
path: "/tmp/mgmt/mgmtB/f1b"
|
||||
@@ -23,6 +23,6 @@ types:
|
||||
i am f4, exported from host B
|
||||
state: exists
|
||||
collect:
|
||||
- type: file
|
||||
- res: file
|
||||
pattern: "/tmp/mgmt/mgmtB/"
|
||||
edges: []
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
graph: mygraph
|
||||
types:
|
||||
resources:
|
||||
file:
|
||||
- name: file1c
|
||||
path: "/tmp/mgmt/mgmtC/f1c"
|
||||
@@ -23,6 +23,6 @@ types:
|
||||
i am f4, exported from host C
|
||||
state: exists
|
||||
collect:
|
||||
- type: file
|
||||
- res: file
|
||||
pattern: "/tmp/mgmt/mgmtC/"
|
||||
edges: []
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
graph: mygraph
|
||||
comment: simple exec fan in example to demonstrate optimization)
|
||||
types:
|
||||
resources:
|
||||
exec:
|
||||
- name: exec1
|
||||
cmd: sleep 10s
|
||||
@@ -56,22 +56,22 @@ types:
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec1
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec5
|
||||
- name: e2
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec2
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec5
|
||||
- name: e3
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec3
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec5
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
graph: mygraph
|
||||
comment: simple exec fan in to fan out example to demonstrate optimization
|
||||
types:
|
||||
resources:
|
||||
exec:
|
||||
- name: exec1
|
||||
cmd: sleep 10s
|
||||
@@ -86,43 +86,43 @@ types:
|
||||
edges:
|
||||
- name: e1
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec1
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec4
|
||||
- name: e2
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec2
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec4
|
||||
- name: e3
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec3
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec4
|
||||
- name: e4
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec4
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec5
|
||||
- name: e5
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec4
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec6
|
||||
- name: e6
|
||||
from:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec4
|
||||
to:
|
||||
type: exec
|
||||
res: exec
|
||||
name: exec7
|
||||
|
||||
Reference in New Issue
Block a user