resources: Add VarDir support

This gives resources a private directory where they can store state.
This commit is contained in:
James Shubin
2016-11-21 16:04:25 -05:00
parent e5a3dae332
commit 62e6a7d7fa
3 changed files with 58 additions and 9 deletions

View File

@@ -22,6 +22,7 @@ import (
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"path"
"sync" "sync"
"time" "time"
@@ -31,6 +32,7 @@ import (
"github.com/purpleidea/mgmt/pgraph" "github.com/purpleidea/mgmt/pgraph"
"github.com/purpleidea/mgmt/recwatch" "github.com/purpleidea/mgmt/recwatch"
"github.com/purpleidea/mgmt/remote" "github.com/purpleidea/mgmt/remote"
"github.com/purpleidea/mgmt/resources"
"github.com/purpleidea/mgmt/util" "github.com/purpleidea/mgmt/util"
etcdtypes "github.com/coreos/etcd/pkg/types" etcdtypes "github.com/coreos/etcd/pkg/types"
@@ -205,6 +207,10 @@ func (obj *Main) Run() error {
} }
} }
log.Printf("Main: Working prefix is: %s", prefix) 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 wg sync.WaitGroup
var G, oldGraph *pgraph.Graph var G, oldGraph *pgraph.Graph
@@ -348,6 +354,12 @@ func (obj *Main) Run() error {
continue continue
} }
// pass in the information we need
newGraph.AssociateData(&resources.Data{
Converger: converger,
Prefix: pgraphPrefix,
})
// apply the global noop parameter if requested // apply the global noop parameter if requested
if obj.Noop { if obj.Noop {
for _, m := range newGraph.GraphMetas() { for _, m := range newGraph.GraphMetas() {
@@ -383,7 +395,6 @@ func (obj *Main) Run() error {
log.Printf("Graphviz: Successfully generated graph!") log.Printf("Graphviz: Successfully generated graph!")
} }
} }
G.AssociateData(converger)
// G.Start(...) needs to be synchronous or wait, // G.Start(...) needs to be synchronous or wait,
// because if half of the nodes are started and // because if half of the nodes are started and
// some are not ready yet and the EtcdWatch // some are not ready yet and the EtcdWatch

View File

@@ -31,7 +31,6 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/purpleidea/mgmt/converger"
"github.com/purpleidea/mgmt/event" "github.com/purpleidea/mgmt/event"
"github.com/purpleidea/mgmt/global" "github.com/purpleidea/mgmt/global"
"github.com/purpleidea/mgmt/resources" "github.com/purpleidea/mgmt/resources"
@@ -1040,10 +1039,10 @@ func (g *Graph) GraphMetas() []*resources.MetaParams {
return metas return metas
} }
// AssociateData associates some data with the object in the graph in question // AssociateData associates some data with the object in the graph in question.
func (g *Graph) AssociateData(converger converger.Converger) { func (g *Graph) AssociateData(data *resources.Data) {
for v := range g.GetVerticesChan() { for k := range g.Adjacency {
v.Res.AssociateData(converger) k.Res.AssociateData(data)
} }
} }

View File

@@ -24,11 +24,15 @@ import (
"encoding/gob" "encoding/gob"
"fmt" "fmt"
"log" "log"
"os"
"path"
// TODO: should each resource be a sub-package? // TODO: should each resource be a sub-package?
"github.com/purpleidea/mgmt/converger" "github.com/purpleidea/mgmt/converger"
"github.com/purpleidea/mgmt/event" "github.com/purpleidea/mgmt/event"
"github.com/purpleidea/mgmt/global" "github.com/purpleidea/mgmt/global"
errwrap "github.com/pkg/errors"
) )
//go:generate stringer -type=ResState -output=resstate_stringer.go //go:generate stringer -type=ResState -output=resstate_stringer.go
@@ -45,6 +49,15 @@ const (
ResStatePoking 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"). // ResUID is a unique identifier for a resource, namely it's name, and the kind ("type").
type ResUID interface { type ResUID interface {
GetName() string GetName() string
@@ -112,7 +125,7 @@ type Base interface {
Kind() string Kind() string
Meta() *MetaParams Meta() *MetaParams
Events() chan event.Event Events() chan event.Event
AssociateData(converger.Converger) AssociateData(*Data)
IsWatching() bool IsWatching() bool
SetWatching(bool) SetWatching(bool)
GetState() ResState GetState() ResState
@@ -126,6 +139,7 @@ type Base interface {
SetGrouped(bool) // set grouped bool SetGrouped(bool) // set grouped bool
GetGroup() []Res // return everyone grouped inside me GetGroup() []Res // return everyone grouped inside me
SetGroup([]Res) SetGroup([]Res)
VarDir(string) (string, error)
} }
// Res is the minimum interface you need to implement to define a new resource. // 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. // AssociateData associates some data with the object in question.
func (obj *BaseRes) AssociateData(converger converger.Converger) { func (obj *BaseRes) AssociateData(data *Data) {
obj.converger = converger obj.converger = data.Converger
obj.prefix = data.Prefix
} }
// IsWatching tells us if the Watch() function is running. // IsWatching tells us if the Watch() function is running.
@@ -415,6 +430,30 @@ func (obj *BaseRes) CollectPattern(pattern string) {
// XXX: default method is empty // 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) // ResToB64 encodes a resource to a base64 encoded string (after serialization)
func ResToB64(res Res) (string, error) { func ResToB64(res Res) (string, error) {
b := bytes.Buffer{} b := bytes.Buffer{}