diff --git a/mgmtmain/main.go b/mgmtmain/main.go index 7c5d4479..d0b6d5f9 100644 --- a/mgmtmain/main.go +++ b/mgmtmain/main.go @@ -22,6 +22,7 @@ import ( "io/ioutil" "log" "os" + "path" "sync" "time" @@ -31,6 +32,7 @@ import ( "github.com/purpleidea/mgmt/pgraph" "github.com/purpleidea/mgmt/recwatch" "github.com/purpleidea/mgmt/remote" + "github.com/purpleidea/mgmt/resources" "github.com/purpleidea/mgmt/util" etcdtypes "github.com/coreos/etcd/pkg/types" @@ -205,6 +207,10 @@ func (obj *Main) Run() error { } } log.Printf("Main: Working prefix is: %s", prefix) + pgraphPrefix := fmt.Sprintf("%s/", path.Join(prefix, "pgraph")) // pgraph namespace + if err := os.MkdirAll(pgraphPrefix, 0770); err != nil { + return errwrap.Wrapf(err, "Can't create pgraph prefix") + } var wg sync.WaitGroup var G, oldGraph *pgraph.Graph @@ -348,6 +354,12 @@ func (obj *Main) Run() error { continue } + // pass in the information we need + newGraph.AssociateData(&resources.Data{ + Converger: converger, + Prefix: pgraphPrefix, + }) + // apply the global noop parameter if requested if obj.Noop { for _, m := range newGraph.GraphMetas() { @@ -383,7 +395,6 @@ func (obj *Main) Run() error { log.Printf("Graphviz: Successfully generated graph!") } } - G.AssociateData(converger) // G.Start(...) needs to be synchronous or wait, // because if half of the nodes are started and // some are not ready yet and the EtcdWatch diff --git a/pgraph/pgraph.go b/pgraph/pgraph.go index 5c0a1066..0d409d2c 100644 --- a/pgraph/pgraph.go +++ b/pgraph/pgraph.go @@ -31,7 +31,6 @@ import ( "syscall" "time" - "github.com/purpleidea/mgmt/converger" "github.com/purpleidea/mgmt/event" "github.com/purpleidea/mgmt/global" "github.com/purpleidea/mgmt/resources" @@ -1040,10 +1039,10 @@ func (g *Graph) GraphMetas() []*resources.MetaParams { return metas } -// AssociateData associates some data with the object in the graph in question -func (g *Graph) AssociateData(converger converger.Converger) { - for v := range g.GetVerticesChan() { - v.Res.AssociateData(converger) +// AssociateData associates some data with the object in the graph in question. +func (g *Graph) AssociateData(data *resources.Data) { + for k := range g.Adjacency { + k.Res.AssociateData(data) } } diff --git a/resources/resources.go b/resources/resources.go index 847726ef..d9445488 100644 --- a/resources/resources.go +++ b/resources/resources.go @@ -24,11 +24,15 @@ import ( "encoding/gob" "fmt" "log" + "os" + "path" // TODO: should each resource be a sub-package? "github.com/purpleidea/mgmt/converger" "github.com/purpleidea/mgmt/event" "github.com/purpleidea/mgmt/global" + + errwrap "github.com/pkg/errors" ) //go:generate stringer -type=ResState -output=resstate_stringer.go @@ -45,6 +49,15 @@ const ( ResStatePoking ) +// Data is the set of input values passed into the pgraph for the resources. +type Data struct { + //Hostname string // uuid for the host + //Noop bool + Converger converger.Converger + Prefix string // the prefix to be used for the pgraph namespace + // NOTE: we can add more fields here if needed for the resources. +} + // ResUID is a unique identifier for a resource, namely it's name, and the kind ("type"). type ResUID interface { GetName() string @@ -112,7 +125,7 @@ type Base interface { Kind() string Meta() *MetaParams Events() chan event.Event - AssociateData(converger.Converger) + AssociateData(*Data) IsWatching() bool SetWatching(bool) GetState() ResState @@ -126,6 +139,7 @@ type Base interface { SetGrouped(bool) // set grouped bool GetGroup() []Res // return everyone grouped inside me SetGroup([]Res) + VarDir(string) (string, error) } // Res is the minimum interface you need to implement to define a new resource. @@ -236,8 +250,9 @@ func (obj *BaseRes) Events() chan event.Event { } // AssociateData associates some data with the object in question. -func (obj *BaseRes) AssociateData(converger converger.Converger) { - obj.converger = converger +func (obj *BaseRes) AssociateData(data *Data) { + obj.converger = data.Converger + obj.prefix = data.Prefix } // IsWatching tells us if the Watch() function is running. @@ -415,6 +430,30 @@ func (obj *BaseRes) CollectPattern(pattern string) { // XXX: default method is empty } +// VarDir returns the path to a working directory for the resource. It will try +// and create the directory first, and return an error if this failed. +func (obj *BaseRes) VarDir(extra string) (string, error) { + // Using extra adds additional dirs onto our namespace. An empty extra + // adds no additional directories. + if obj.prefix == "" { + return "", fmt.Errorf("VarDir prefix is empty!") + } + if obj.Kind() == "" { + return "", fmt.Errorf("VarDir kind is empty!") + } + if obj.GetName() == "" { + return "", fmt.Errorf("VarDir name is empty!") + } + + // FIXME: is obj.GetName() sufficiently unique to use as a UID here? + uid := obj.GetName() + p := fmt.Sprintf("%s/", path.Join(obj.prefix, obj.Kind(), uid, extra)) + if err := os.MkdirAll(p, 0770); err != nil { + return "", errwrap.Wrapf(err, "Can't create prefix for %s[%s]", obj.Kind(), obj.GetName()) + } + return p, nil +} + // ResToB64 encodes a resource to a base64 encoded string (after serialization) func ResToB64(res Res) (string, error) { b := bytes.Buffer{}