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
}
diff --git a/build.gradle b/build.gradle
index 5103b76..fcc000e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -26,28 +26,30 @@
// Deployment target config file (yaml format); this can be overwritten from the command line
// using the -PdeployConfig=<file-path> syntax.
deployConfig = project.hasProperty('deployConfig') ? project.getProperty('deployConfig') : './config/default.yml'
+
+ dockerPath = project.hasProperty('dockerPath') ? project.getProperty('dockerPath') : '$dockerPath'
}
task buildBootstrapImage(type: Exec) {
- commandLine '/usr/bin/docker', 'build', '-t', 'cord-maas-bootstrap', './bootstrap'
+ commandLine "$dockerPath/docker", 'build', '-t', 'cord-maas-bootstrap', './bootstrap'
}
task tagBootstrapImage(type: Exec) {
dependsOn buildBootstrapImage
- commandLine '/usr/bin/docker', 'tag', 'cord-maas-bootstrap', "$targetReg/cord-maas-bootstrap:$targetTag"
+ commandLine "$dockerPath/docker", 'tag', 'cord-maas-bootstrap', "$targetReg/cord-maas-bootstrap:$targetTag"
}
task publishBootstrapImage(type: Exec) {
dependsOn tagBootstrapImage
- commandLine '/usr/bin/docker', 'push', "$targetReg/cord-maas-bootstrap:$targetTag"
+ commandLine "$dockerPath/docker", 'push', "$targetReg/cord-maas-bootstrap:$targetTag"
}
task buildAutomationImage(type: Exec) {
- commandLine '/usr/bin/docker', 'build', '-t', "cord-maas-automation", "-f", "./automation/Dockerfile", "./automation"
+ commandLine "$dockerPath/docker", 'build', '-t', "cord-maas-automation", "-f", "./automation/Dockerfile", "./automation"
}
task buildAutomationImageAnsible(type: Exec) {
- commandLine '/usr/bin/docker', 'build', '-t', "cord-maas-automation:ansible", "-f", "./automation/Dockerfile.ansible", "./automation"
+ commandLine "$dockerPath/docker", 'build', '-t', "cord-maas-automation:ansible", "-f", "./automation/Dockerfile.ansible", "./automation"
}
task buildAutomationImages {
@@ -57,12 +59,12 @@
task tagAutomationImage(type: Exec) {
dependsOn buildAutomationImage
- commandLine '/usr/bin/docker', 'tag', 'cord-maas-automation', "$targetReg/cord-maas-automation:$targetTag"
+ commandLine "$dockerPath/docker", 'tag', 'cord-maas-automation', "$targetReg/cord-maas-automation:$targetTag"
}
task tagAutomationImageAnsible(type: Exec) {
dependsOn buildAutomationImageAnsible
- commandLine '/usr/bin/docker', 'tag', 'cord-maas-automation:ansible', "$targetReg/cord-maas-automation:$targetTag-ansible"
+ commandLine "$dockerPath/docker", 'tag', 'cord-maas-automation:ansible', "$targetReg/cord-maas-automation:$targetTag-ansible"
}
task tagAutomationImages {
@@ -72,12 +74,12 @@
task publishAutomationImage(type: Exec) {
dependsOn tagAutomationImage
- commandLine '/usr/bin/docker', 'push', "$targetReg/cord-maas-automation:$targetTag"
+ commandLine "$dockerPath/docker", 'push', "$targetReg/cord-maas-automation:$targetTag"
}
task publishAutomationImageAnsible(type: Exec) {
dependsOn tagAutomationImageAnsible
- commandLine '/usr/bin/docker', 'push', "$targetReg/cord-maas-automation:$targetTag-ansible"
+ commandLine "$dockerPath/docker", 'push', "$targetReg/cord-maas-automation:$targetTag-ansible"
}
task publishAutomationImages {
@@ -86,17 +88,17 @@
}
task buildHarvesterImage(type: Exec) {
- commandLine '/usr/bin/docker', 'build', '-t', "cord-maas-dhcp-harvester", "./harvester"
+ commandLine "$dockerPath/docker", 'build', '-t', "cord-maas-dhcp-harvester", "./harvester"
}
task tagHarvesterImage(type: Exec) {
dependsOn buildHarvesterImage
- commandLine '/usr/bin/docker', 'tag', 'cord-maas-dhcp-harvester', "$targetReg/cord-maas-dhcp-harvester:$targetTag"
+ commandLine "$dockerPath/docker", 'tag', 'cord-maas-dhcp-harvester', "$targetReg/cord-maas-dhcp-harvester:$targetTag"
}
task publishHarvesterImage(type: Exec) {
dependsOn tagHarvesterImage
- commandLine '/usr/bin/docker', 'push', "$targetReg/cord-maas-dhcp-harvester:$targetTag"
+ commandLine "$dockerPath/docker", 'push', "$targetReg/cord-maas-dhcp-harvester:$targetTag"
}
// ~~~~~~~~~~~~~~~~~~~ Global tasks ~~~~~~~~~~~~~~~~~~~~~~~
@@ -105,8 +107,8 @@
task fetch(type: Exec) {
// this is where we fetch upstream artifacts that we do not need internet for the build phase"
// Placeholdr example:
- commandLine "/usr/bin/docker", "pull", "golang:alpine"
- commandLine "/usr/bin/docker", "pull", "python:2.7-alpine"
+ commandLine "$dockerPath/docker", "pull", "golang:alpine"
+ commandLine "$dockerPath/docker", "pull", "python:2.7-alpine"
}
// To be used to generate all needed binaries that need to be present on the target
@@ -192,5 +194,4 @@
def skipTags = [].p(config.seedServer.skipTags)
args = args.p(skipTags.asParam("skip-tags", ",")).p(extraVars.asParam("extra-vars", " ")) << "head-node.yml"
- println args
}