示例#1
0
// 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
}
示例#2
0
// 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
}
示例#3
0
// 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
}