add support for a consul backing store for trackig provisioned state
diff --git a/automation/Godeps/Godeps.json b/automation/Godeps/Godeps.json
index c55b337..5e6d307 100644
--- a/automation/Godeps/Godeps.json
+++ b/automation/Godeps/Godeps.json
@@ -18,6 +18,11 @@
"ImportPath": "gopkg.in/mgo.v2/bson",
"Comment": "r2015.12.06-2-g03c9f3e",
"Rev": "03c9f3ee4c14c8e51ee521a6a7d0425658dd6f64"
+ },
+ {
+ "ImportPath": "github.com/hashicorp/consul",
+ "Comment": "v0.6.4-341-g22938ab",
+ "Rev": "22938ab8b3ca069e490a4897a8ec13308ac61605"
}
]
}
diff --git a/automation/tracker.go b/automation/tracker.go
index 9f38b23..e299a68 100644
--- a/automation/tracker.go
+++ b/automation/tracker.go
@@ -3,9 +3,11 @@
import (
"encoding/json"
"github.com/fzzy/radix/redis"
+ consul "github.com/hashicorp/consul/api"
"log"
"net/url"
"os"
+ "strings"
)
type ProvisionState int8
@@ -48,6 +50,46 @@
Clear(key string) error
}
+type ConsulTracker struct {
+ client *consul.Client
+ kv *consul.KV
+}
+
+func (c *ConsulTracker) Get(key string) (*TrackerRecord, error) {
+ pair, _, err := c.kv.Get(key, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ if pair == nil {
+ var record TrackerRecord
+ record.State = Unprovisioned
+ return &record, nil
+ }
+
+ var record TrackerRecord
+ err = json.Unmarshal([]byte(pair.Value), &record)
+ if err != nil {
+ return nil, err
+ }
+ return &record, nil
+}
+
+func (c *ConsulTracker) Set(key string, record *TrackerRecord) error {
+ data, err := json.Marshal(record)
+ if err != nil {
+ return err
+ }
+ pair := &consul.KVPair{Key: key, Value: data}
+ _, err = c.kv.Put(pair, nil)
+ return err
+}
+
+func (c *ConsulTracker) Clear(key string) error {
+ _, err := c.kv.Delete(key, nil)
+ return err
+}
+
// RedisTracker redis implementation of the tracker interface
type RedisTracker struct {
client *redis.Client
@@ -77,7 +119,11 @@
}
func (t *RedisTracker) Set(key string, record *TrackerRecord) error {
- reply := t.client.Cmd("set", key, true)
+ data, err := json.Marshal(record)
+ if err != nil {
+ return err
+ }
+ reply := t.client.Cmd("set", key, data)
return reply.Err
}
@@ -114,8 +160,14 @@
// depends on the environment. If a link to a redis instance is defined then this will
// be used, else an in memory version will be used.
func NewTracker() Tracker {
- // Check the environment to see if we are linked to a redis DB
- if os.Getenv("AUTODB_ENV_REDIS_VERSION") != "" {
+ driver := os.Getenv("AUTODB_DRIVER")
+ if driver == "" {
+ log.Printf("[info] No driver specified, defaulting to in memeory persistence driver")
+ driver = "MEMORY"
+ }
+
+ switch strings.ToUpper(driver) {
+ case "REDIS":
tracker := new(RedisTracker)
if spec := os.Getenv("AUTODB_PORT"); spec != "" {
port, err := url.Parse(spec)
@@ -124,14 +176,27 @@
checkError(err, "[error] unable to connect to redis database : '%s' : %s", port, err)
log.Println("[info] Using REDIS to track provisioning status of nodes")
return tracker
- } else {
- log.Fatalf("[error] looks like we are configured for REDIS, but no PORT defined in environment")
}
+ log.Fatalf("[error] No connection specified to REDIS server")
+ case "CONSUL":
+ var err error
+ config := consul.Config{
+ Address: "autodb:8500",
+ Scheme: "http",
+ }
+ tracker := new(ConsulTracker)
+ tracker.client, err = consul.NewClient(&config)
+ checkError(err, "[error] unable to connect to redis server : 'autodb:8500' : %s", err)
+ log.Println("[info] Using Consul to track provisioning status of nodes")
+ tracker.kv = tracker.client.KV()
+ return tracker
+ case "MEMORY":
+ tracker := new(MemoryTracker)
+ tracker.data = make(map[string]TrackerRecord)
+ log.Println("[info] Using memory based structures to track provisioning status of nodes")
+ return tracker
+ default:
+ log.Fatalf("[error] Unknown persistance driver specified, '%s'", driver)
}
-
- // Else fallback to an in memory tracker
- tracker := new(MemoryTracker)
- tracker.data = make(map[string]TrackerRecord)
- log.Println("[info] Using memory based structures to track provisioning status of nodes")
- return tracker
+ return nil
}