terraform/builtin/providers/consul/resource_consul_keys.go

300 lines
7.0 KiB
Go
Raw Normal View History

2014-07-26 21:14:41 +02:00
package consul
import (
"bytes"
2014-07-26 21:14:41 +02:00
"fmt"
"log"
"strconv"
"github.com/armon/consul-api"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"
2014-07-26 21:14:41 +02:00
)
func resourceConsulKeys() *schema.Resource {
return &schema.Resource{
Create: resourceConsulKeysCreate,
Update: resourceConsulKeysCreate,
Read: resourceConsulKeysRead,
Delete: resourceConsulKeysDelete,
Schema: map[string]*schema.Schema{
"datacenter": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"token": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"keys": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"path": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"value": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"default": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"delete": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
},
},
},
Set: resourceConsulKeysHash,
},
"var": &schema.Schema{
Type: schema.TypeMap,
Computed: true,
},
2014-07-26 21:14:41 +02:00
},
}
}
func resourceConsulKeysHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["path"].(string)))
return hashcode.String(buf.String())
}
2014-07-26 21:14:41 +02:00
func resourceConsulKeysCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*consulapi.Client)
kv := client.KV()
2014-07-26 21:14:41 +02:00
// Resolve the datacenter first, all the other keys are dependent
// on this.
var dc string
if v := d.Get("datacenter"); v != nil {
dc = v.(string)
log.Printf("[DEBUG] Consul datacenter: %s", dc)
} else {
log.Printf("[DEBUG] Resolving Consul datacenter...")
2014-07-26 21:14:41 +02:00
var err error
dc, err = get_dc(client)
2014-07-26 21:14:41 +02:00
if err != nil {
return err
2014-07-26 21:14:41 +02:00
}
}
var token string
if v := d.Get("token"); v != nil {
token = v.(string)
}
2014-07-26 21:14:41 +02:00
// Setup the operations using the datacenter
qOpts := consulapi.QueryOptions{Datacenter: dc, Token: token}
wOpts := consulapi.WriteOptions{Datacenter: dc, Token: token}
// Store the computed vars
vars := make(map[string]string)
// Extract the keys
keys := d.Get("keys").(*schema.Set).List()
for _, raw := range keys {
2014-07-26 21:32:34 +02:00
key, path, sub, err := parse_key(raw)
if err != nil {
return err
2014-07-26 21:14:41 +02:00
}
2014-07-27 02:21:48 +02:00
if valueRaw, ok := sub["value"]; ok {
2014-07-26 21:14:41 +02:00
value, ok := valueRaw.(string)
if !ok {
return fmt.Errorf("Failed to get value for key '%s'", key)
2014-07-26 21:14:41 +02:00
}
log.Printf("[DEBUG] Setting key '%s' to '%v' in %s", path, value, dc)
pair := consulapi.KVPair{Key: path, Value: []byte(value)}
if _, err := kv.Put(&pair, &wOpts); err != nil {
return fmt.Errorf("Failed to set Consul key '%s': %v", path, err)
2014-07-26 21:14:41 +02:00
}
vars[key] = value
sub["value"] = value
2014-07-26 21:32:34 +02:00
2014-07-26 21:14:41 +02:00
} else {
log.Printf("[DEBUG] Getting key '%s' in %s", path, dc)
pair, _, err := kv.Get(path, &qOpts)
if err != nil {
return fmt.Errorf("Failed to get Consul key '%s': %v", path, err)
2014-07-26 21:14:41 +02:00
}
value := attribute_value(sub, key, pair)
vars[key] = value
sub["value"] = value
2014-07-26 21:14:41 +02:00
}
}
// Update the resource
d.SetId("consul")
d.Set("datacenter", dc)
d.Set("keys", keys)
d.Set("var", vars)
return nil
2014-07-26 21:14:41 +02:00
}
func resourceConsulKeysRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*consulapi.Client)
2014-07-26 21:14:41 +02:00
kv := client.KV()
// Get the DC, error if not available.
var dc string
if v := d.Get("datacenter"); v != nil {
dc = v.(string)
log.Printf("[DEBUG] Consul datacenter: %s", dc)
} else {
return fmt.Errorf("Missing datacenter configuration")
2014-07-26 21:14:41 +02:00
}
var token string
if v := d.Get("token"); v != nil {
token = v.(string)
}
2014-07-26 21:14:41 +02:00
// Setup the operations using the datacenter
qOpts := consulapi.QueryOptions{Datacenter: dc, Token: token}
// Store the computed vars
vars := make(map[string]string)
// Extract the keys
keys := d.Get("keys").(*schema.Set).List()
2014-07-26 21:14:41 +02:00
for _, raw := range keys {
key, path, sub, err := parse_key(raw)
2014-07-26 21:32:34 +02:00
if err != nil {
return err
2014-07-26 21:14:41 +02:00
}
log.Printf("[DEBUG] Refreshing value of key '%s' in %s", path, dc)
pair, _, err := kv.Get(path, &qOpts)
2014-07-26 21:32:34 +02:00
if err != nil {
return fmt.Errorf("Failed to get value for path '%s' from Consul: %v", path, err)
2014-07-26 21:14:41 +02:00
}
value := attribute_value(sub, key, pair)
vars[key] = value
sub["value"] = value
2014-07-26 21:14:41 +02:00
}
// Update the resource
d.Set("keys", keys)
d.Set("var", vars)
return nil
2014-07-26 21:14:41 +02:00
}
func resourceConsulKeysDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*consulapi.Client)
2014-07-26 21:14:41 +02:00
kv := client.KV()
// Get the DC, error if not available.
var dc string
if v := d.Get("datacenter"); v != nil {
dc = v.(string)
log.Printf("[DEBUG] Consul datacenter: %s", dc)
} else {
return fmt.Errorf("Missing datacenter configuration")
2014-07-26 21:14:41 +02:00
}
var token string
if v := d.Get("token"); v != nil {
token = v.(string)
}
2014-07-26 21:14:41 +02:00
// Setup the operations using the datacenter
wOpts := consulapi.WriteOptions{Datacenter: dc, Token: token}
// Extract the keys
keys := d.Get("keys").(*schema.Set).List()
for _, raw := range keys {
_, path, sub, err := parse_key(raw)
2014-07-26 21:32:34 +02:00
if err != nil {
return err
2014-07-26 21:14:41 +02:00
}
// Ignore if the key is non-managed
shouldDelete, ok := sub["delete"].(bool)
if !ok || !shouldDelete {
continue
2014-07-26 21:14:41 +02:00
}
log.Printf("[DEBUG] Deleting key '%s' in %s", path, dc)
if _, err := kv.Delete(path, &wOpts); err != nil {
return fmt.Errorf("Failed to delete Consul key '%s': %v", path, err)
2014-07-26 21:14:41 +02:00
}
2014-07-26 21:32:34 +02:00
}
// Clear the ID
d.SetId("")
return nil
2014-07-26 21:32:34 +02:00
}
2014-07-26 21:14:41 +02:00
2014-07-26 21:32:34 +02:00
// parse_key is used to parse a key into a name, path, config or error
func parse_key(raw interface{}) (string, string, map[string]interface{}, error) {
sub, ok := raw.(map[string]interface{})
if !ok {
return "", "", nil, fmt.Errorf("Failed to unroll: %#v", raw)
}
key, ok := sub["name"].(string)
if !ok {
return "", "", nil, fmt.Errorf("Failed to expand key '%#v'", sub)
}
path, ok := sub["path"].(string)
if !ok {
return "", "", nil, fmt.Errorf("Failed to get path for key '%s'", key)
}
return key, path, sub, nil
}
// attribute_value determines the value for a key, potentially
// using a default value if provided.
2014-07-26 21:32:34 +02:00
func attribute_value(sub map[string]interface{}, key string, pair *consulapi.KVPair) string {
// Use the value if given
if pair != nil {
return string(pair.Value)
}
// Use a default if given
if raw, ok := sub["default"]; ok {
switch def := raw.(type) {
case string:
return def
case bool:
return strconv.FormatBool(def)
2014-07-26 21:14:41 +02:00
}
}
2014-07-26 21:32:34 +02:00
// No value
return ""
2014-07-26 21:14:41 +02:00
}
// get_dc is used to get the datacenter of the local agent
func get_dc(client *consulapi.Client) (string, error) {
info, err := client.Agent().Self()
if err != nil {
return "", fmt.Errorf("Failed to get datacenter from Consul agent: %v", err)
}
dc := info["Config"]["Datacenter"].(string)
return dc, nil
}