Mega patch

This is still a dirty prototype, so please excuse the mess. Please
excuse the fact that this is a mega patch. Once things settle down this
won't happen any more.

Some of the changes squashed into here include:
* Merge vertex loop with type loop
(The file watcher seems to cache events anyways)
* Improve pgraph library
* Add indegree, outdegree, and topological sort with tests
* Add reverse function for vertex list
* Tons of additional cleanup!

Amazingly, on my first successful compile, this seemed to run!

A special thanks to Ira Cooper who helped me talk through some of the
algorithmic decisions and for his help in finding better ones!
This commit is contained in:
James Shubin
2015-12-10 03:34:51 -05:00
parent 0ea6f30ef2
commit 6b4fa21074
20 changed files with 1411 additions and 363 deletions

133
config.go
View File

@@ -18,27 +18,19 @@
package main
import (
//etcd_context "github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
etcd "github.com/coreos/etcd/client"
"errors"
"gopkg.in/yaml.v2"
"io/ioutil"
"log"
"strings"
)
type noopTypeConfig struct {
Name string `yaml:"name"`
}
type fileTypeConfig struct {
Name string `yaml:"name"`
Path string `yaml:"path"`
Content string `yaml:"content"`
State string `yaml:"state"`
}
type serviceTypeConfig struct {
Name string `yaml:"name"`
State string `yaml:"state"`
Startup string `yaml:"startup"`
type collectorTypeConfig struct {
Type string `yaml:"type"`
Pattern string `yaml:"pattern"` // XXX: Not Implemented
}
type vertexConfig struct {
@@ -55,12 +47,13 @@ type edgeConfig struct {
type graphConfig struct {
Graph string `yaml:"graph"`
Types struct {
Noop []noopTypeConfig `yaml:"noop"`
File []fileTypeConfig `yaml:"file"`
Service []serviceTypeConfig `yaml:"service"`
Noop []NoopType `yaml:"noop"`
File []FileType `yaml:"file"`
Service []ServiceType `yaml:"service"`
} `yaml:"types"`
Edges []edgeConfig `yaml:"edges"`
Comment string `yaml:"comment"`
Collector []collectorTypeConfig `yaml:"collect"`
Edges []edgeConfig `yaml:"edges"`
Comment string `yaml:"comment"`
}
func (c *graphConfig) Parse(data []byte) error {
@@ -73,7 +66,7 @@ func (c *graphConfig) Parse(data []byte) error {
return nil
}
func GraphFromConfig(filename string) *Graph {
func UpdateGraphFromConfig(filename, hostname string, g *Graph, kapi etcd.KeysAPI) bool {
var NoopMap map[string]*Vertex = make(map[string]*Vertex)
var FileMap map[string]*Vertex = make(map[string]*Vertex)
@@ -87,40 +80,108 @@ func GraphFromConfig(filename string) *Graph {
data, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatal(err)
return false
}
var config graphConfig
if err := config.Parse(data); err != nil {
log.Fatal(err)
return false
}
//fmt.Printf("%+v\n", config) // debug
//fmt.Printf("%+v\n", config) // debug
g := NewGraph(config.Graph)
g.SetName(config.Graph) // set graph name
var keep []*Vertex // list of vertex which are the same in new graph
for _, t := range config.Types.Noop {
NoopMap[t.Name] = NewVertex(t.Name, "noop")
// FIXME: duplicate of name stored twice... where should it go?
NoopMap[t.Name].Associate(NewNoopType(t.Name))
g.AddVertex(NoopMap[t.Name]) // call standalone in case not part of an edge
obj := NewNoopType(t.Name)
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
}
NoopMap[obj.Name] = v // used for constructing edges
keep = append(keep, v) // append
}
for _, t := range config.Types.File {
FileMap[t.Name] = NewVertex(t.Name, "file")
// FIXME: duplicate of name stored twice... where should it go?
FileMap[t.Name].Associate(NewFileType(t.Name, t.Path, t.Content, t.State))
g.AddVertex(FileMap[t.Name]) // call standalone in case not part of an edge
// 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
// add to etcd storage...
t.Name = t.Name[2:] //slice off @@
if !EtcdPut(kapi, hostname, t.Name, "file", t) {
log.Printf("Problem exporting file resource %v.", t.Name)
continue
}
} else {
obj := NewFileType(t.Name, t.Path, t.Content, t.State)
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
}
FileMap[obj.Name] = v // used for constructing edges
keep = append(keep, v) // append
}
}
for _, t := range config.Types.Service {
ServiceMap[t.Name] = NewVertex(t.Name, "service")
// FIXME: duplicate of name stored twice... where should it go?
ServiceMap[t.Name].Associate(NewServiceType(t.Name, t.State, t.Startup))
g.AddVertex(ServiceMap[t.Name]) // call standalone in case not part of an edge
obj := NewServiceType(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
keep = append(keep, v) // append
}
// lookup from etcd graph
// do all the graph look ups in one single step, so that if the etcd
// database changes, we don't have a partial state of affairs...
nodes, ok := EtcdGet(kapi)
if ok {
for _, t := range config.Collector {
// XXX: use t.Type and optionally t.Pattern to collect from etcd storage
log.Printf("Collect: %v(%v)", t.Type, t.Pattern)
for _, x := range EtcdGetProcess(nodes, "file") {
var obj *FileType
if B64ToObj(x, &obj) != true {
log.Printf("File: %v error!", x)
continue
}
log.Printf("File: %v found!", obj.GetName())
// XXX: similar to file add code:
v := g.GetVertexMatch(obj)
if v == nil { // no match found
obj.Init() // initialize go channels or things won't work!!!
v = NewVertex(obj)
g.AddVertex(v) // call standalone in case not part of an edge
}
FileMap[obj.GetName()] = v // used for constructing edges
keep = append(keep, v) // append
}
}
}
// get rid of any vertices we shouldn't "keep" (that aren't in new graph)
for _, v := range g.GetVertices() {
if !HasVertex(v, keep) {
// wait for exit before starting new graph!
v.Type.SendEvent(eventExit, true)
g.DeleteVertex(v)
}
}
for _, e := range config.Edges {
g.AddEdge(lookup[e.From.Type][e.From.Name], lookup[e.To.Type][e.To.Name], NewEdge(e.Name))
}
return g
return true
}