// Graph returns a current Graph. func (obj *MyGAPI) Graph() (*pgraph.Graph, error) { if !obj.initialized { return nil, fmt.Errorf("libmgmt: MyGAPI is not initialized") } g := pgraph.NewGraph(obj.Name) var vertex *pgraph.Vertex for i := uint(0); i < obj.Count; i++ { n, err := resources.NewNoopRes(fmt.Sprintf("noop%d", i)) if err != nil { return nil, fmt.Errorf("Can't create resource: %v", err) } v := pgraph.NewVertex(n) g.AddVertex(v) if i > 0 { g.AddEdge(vertex, v, pgraph.NewEdge(fmt.Sprintf("e%d", i))) } vertex = v // save } //g, err := config.NewGraphFromConfig(obj.data.Hostname, obj.data.World, obj.data.Noop) return g, nil }
// NewGraphFromConfig transforms a GraphConfig struct into a new graph. // FIXME: remove any possibly left over, now obsolete graph diff code from here! func (c *GraphConfig) NewGraphFromConfig(hostname string, world gapi.World, noop bool) (*pgraph.Graph, error) { // hostname is the uuid for the host var graph *pgraph.Graph // new graph to return graph = pgraph.NewGraph("Graph") // give graph a default name var lookup = make(map[string]map[string]*pgraph.Vertex) //log.Printf("%+v", config) // debug // TODO: if defined (somehow)... graph.SetName(c.Graph) // set graph name var keep []*pgraph.Vertex // list of vertex which are the same in new graph var resourceList []resources.Res // list of resources to export // use reflection to avoid duplicating code... better options welcome! value := reflect.Indirect(reflect.ValueOf(c.Resources)) vtype := value.Type() for i := 0; i < vtype.NumField(); i++ { // number of fields in struct name := vtype.Field(i).Name // string of field name field := value.FieldByName(name) iface := field.Interface() // interface type of value slice := reflect.ValueOf(iface) // XXX: should we just drop these everywhere and have the kind strings be all lowercase? kind := util.FirstToUpper(name) if Debug { log.Printf("Config: Processing: %v...", kind) } for j := 0; j < slice.Len(); j++ { // loop through resources of same kind x := slice.Index(j).Interface() res, ok := x.(resources.Res) // convert to Res type if !ok { return nil, fmt.Errorf("Config: Error: Can't convert: %v of type: %T to Res.", x, x) } //if noop { // now done in mgmtmain // res.Meta().Noop = noop //} if _, exists := lookup[kind]; !exists { lookup[kind] = make(map[string]*pgraph.Vertex) } // XXX: should we export based on a @@ prefix, or a metaparam // like exported => true || exported => (host pattern)||(other pattern?) if !strings.HasPrefix(res.GetName(), "@@") { // not exported resource v := graph.GetVertexMatch(res) if v == nil { // no match found res.Init() v = pgraph.NewVertex(res) graph.AddVertex(v) // call standalone in case not part of an edge } lookup[kind][res.GetName()] = v // used for constructing edges keep = append(keep, v) // append } else if !noop { // do not export any resources if noop // store for addition to backend storage... res.SetName(res.GetName()[2:]) //slice off @@ res.SetKind(kind) // cheap init resourceList = append(resourceList, res) } } } // store in backend (usually etcd) if err := world.ResExport(resourceList); err != nil { return nil, fmt.Errorf("Config: Could not export resources: %v", err) } // lookup from backend (usually etcd) var hostnameFilter []string // empty to get from everyone kindFilter := []string{} for _, t := range c.Collector { // XXX: should we just drop these everywhere and have the kind strings be all lowercase? kind := util.FirstToUpper(t.Kind) kindFilter = append(kindFilter, kind) } // do all the graph look ups in one single step, so that if the backend // database changes, we don't have a partial state of affairs... if len(kindFilter) > 0 { // if kindFilter is empty, don't need to do lookups! var err error resourceList, err = world.ResCollect(hostnameFilter, kindFilter) if err != nil { return nil, fmt.Errorf("Config: Could not collect resources: %v", err) } } for _, res := range resourceList { matched := false // see if we find a collect pattern that matches for _, t := range c.Collector { // XXX: should we just drop these everywhere and have the kind strings be all lowercase? kind := util.FirstToUpper(t.Kind) // use t.Kind and optionally t.Pattern to collect from storage log.Printf("Collect: %v; Pattern: %v", kind, t.Pattern) // XXX: expand to more complex pattern matching here... if res.Kind() != kind { continue } if matched { // we've already matched this resource, should we match again? log.Printf("Config: Warning: Matching %v[%v] again!", kind, res.GetName()) } matched = true // collect resources but add the noop metaparam //if noop { // now done in mgmtmain // res.Meta().Noop = noop //} if t.Pattern != "" { // XXX: simplistic for now res.CollectPattern(t.Pattern) // res.Dirname = t.Pattern } log.Printf("Collect: %v[%v]: collected!", kind, res.GetName()) // XXX: similar to other resource add code: if _, exists := lookup[kind]; !exists { lookup[kind] = make(map[string]*pgraph.Vertex) } v := graph.GetVertexMatch(res) if v == nil { // no match found res.Init() // initialize go channels or things won't work!!! v = pgraph.NewVertex(res) graph.AddVertex(v) // call standalone in case not part of an edge } lookup[kind][res.GetName()] = v // used for constructing edges keep = append(keep, v) // append //break // let's see if another resource even matches } } for _, e := range c.Edges { if _, ok := lookup[util.FirstToUpper(e.From.Kind)]; !ok { return nil, fmt.Errorf("Can't find 'from' resource!") } if _, ok := lookup[util.FirstToUpper(e.To.Kind)]; !ok { return nil, fmt.Errorf("Can't find 'to' resource!") } if _, ok := lookup[util.FirstToUpper(e.From.Kind)][e.From.Name]; !ok { return nil, fmt.Errorf("Can't find 'from' name!") } if _, ok := lookup[util.FirstToUpper(e.To.Kind)][e.To.Name]; !ok { return nil, fmt.Errorf("Can't find 'to' name!") } graph.AddEdge(lookup[util.FirstToUpper(e.From.Kind)][e.From.Name], lookup[util.FirstToUpper(e.To.Kind)][e.To.Name], pgraph.NewEdge(e.Name)) } return graph, nil }
// Graph returns a current Graph. func (obj *MyGAPI) Graph() (*pgraph.Graph, error) { if !obj.initialized { return nil, fmt.Errorf("libmgmt: MyGAPI is not initialized") } g := pgraph.NewGraph(obj.Name) content := "Delete me to trigger a notification!\n" f0 := &resources.FileRes{ BaseRes: resources.BaseRes{ Name: "README", }, Path: "/tmp/mgmt/README", Content: &content, State: "present", } v0 := pgraph.NewVertex(f0) g.AddVertex(v0) p1 := &resources.PasswordRes{ BaseRes: resources.BaseRes{ Name: "password1", }, Length: 8, // generated string will have this many characters Saved: true, // this causes passwords to be stored in plain text! } v1 := pgraph.NewVertex(p1) g.AddVertex(v1) f1 := &resources.FileRes{ BaseRes: resources.BaseRes{ Name: "file1", // send->recv! Recv: map[string]*resources.Send{ "Content": &resources.Send{Res: p1, Key: "Password"}, }, }, Path: "/tmp/mgmt/secret", //Content: p1.Password, // won't work State: "present", } v2 := pgraph.NewVertex(f1) g.AddVertex(v2) n1 := &resources.NoopRes{ BaseRes: resources.BaseRes{ Name: "noop1", }, } v3 := pgraph.NewVertex(n1) g.AddVertex(v3) e0 := pgraph.NewEdge("e0") e0.Notify = true // send a notification from v0 to v1 g.AddEdge(v0, v1, e0) g.AddEdge(v1, v2, pgraph.NewEdge("e1")) e2 := pgraph.NewEdge("e2") e2.Notify = true // send a notification from v2 to v3 g.AddEdge(v2, v3, e2) //g, err := config.NewGraphFromConfig(obj.data.Hostname, obj.data.World, obj.data.Noop) return g, nil }