github.com/ezbercih/terraform@v0.1.1-0.20140729011846-3c33865e0839/builtin/providers/consul/resource_consul_keys.go (about)

     1  package consul
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  
     8  	"github.com/armon/consul-api"
     9  	"github.com/hashicorp/terraform/flatmap"
    10  	"github.com/hashicorp/terraform/helper/config"
    11  	"github.com/hashicorp/terraform/helper/diff"
    12  	"github.com/hashicorp/terraform/terraform"
    13  )
    14  
    15  func resource_consul_keys_validation() *config.Validator {
    16  	return &config.Validator{
    17  		Required: []string{
    18  			"key.*.name",
    19  			"key.*.path",
    20  		},
    21  		Optional: []string{
    22  			"datacenter",
    23  			"key.*.value",
    24  			"key.*.default",
    25  			"key.*.delete",
    26  		},
    27  	}
    28  }
    29  func resource_consul_keys_update(
    30  	s *terraform.ResourceState,
    31  	d *terraform.ResourceDiff,
    32  	meta interface{}) (*terraform.ResourceState, error) {
    33  	return resource_consul_keys_create(s, d, meta)
    34  }
    35  
    36  func resource_consul_keys_create(
    37  	s *terraform.ResourceState,
    38  	d *terraform.ResourceDiff,
    39  	meta interface{}) (*terraform.ResourceState, error) {
    40  	p := meta.(*ResourceProvider)
    41  
    42  	// Merge the diff into the state so that we have all the attributes
    43  	// properly.
    44  	rs := s.MergeDiff(d)
    45  	rs.ID = "consul"
    46  
    47  	// Check if the datacenter should be computed
    48  	dc := rs.Attributes["datacenter"]
    49  	if aDiff, ok := d.Attributes["datacenter"]; ok && aDiff.NewComputed {
    50  		var err error
    51  		dc, err = get_dc(p.client)
    52  		if err != nil {
    53  			return rs, fmt.Errorf("Failed to get agent datacenter: %v", err)
    54  		}
    55  		rs.Attributes["datacenter"] = dc
    56  	}
    57  
    58  	// Get the keys
    59  	keys, ok := flatmap.Expand(rs.Attributes, "key").([]interface{})
    60  	if !ok {
    61  		return rs, fmt.Errorf("Failed to unroll keys")
    62  	}
    63  
    64  	kv := p.client.KV()
    65  	qOpts := consulapi.QueryOptions{Datacenter: dc}
    66  	wOpts := consulapi.WriteOptions{Datacenter: dc}
    67  	for idx, raw := range keys {
    68  		key, path, sub, err := parse_key(raw)
    69  		if err != nil {
    70  			return rs, err
    71  		}
    72  
    73  		if valueRaw, ok := sub["value"]; ok {
    74  			value, ok := valueRaw.(string)
    75  			if !ok {
    76  				return rs, fmt.Errorf("Failed to get value for key '%s'", key)
    77  			}
    78  
    79  			log.Printf("[DEBUG] Setting key '%s' to '%v' in %s", path, value, dc)
    80  			pair := consulapi.KVPair{Key: path, Value: []byte(value)}
    81  			if _, err := kv.Put(&pair, &wOpts); err != nil {
    82  				return rs, fmt.Errorf("Failed to set Consul key '%s': %v", path, err)
    83  			}
    84  			rs.Attributes[fmt.Sprintf("var.%s", key)] = value
    85  			rs.Attributes[fmt.Sprintf("key.%d.value", idx)] = value
    86  
    87  		} else {
    88  			log.Printf("[DEBUG] Getting key '%s' in %s", path, dc)
    89  			pair, _, err := kv.Get(path, &qOpts)
    90  			if err != nil {
    91  				return rs, fmt.Errorf("Failed to get Consul key '%s': %v", path, err)
    92  			}
    93  			rs.Attributes[fmt.Sprintf("var.%s", key)] = attribute_value(sub, key, pair)
    94  		}
    95  	}
    96  	return rs, nil
    97  }
    98  
    99  func resource_consul_keys_destroy(
   100  	s *terraform.ResourceState,
   101  	meta interface{}) error {
   102  	p := meta.(*ResourceProvider)
   103  	client := p.client
   104  	kv := client.KV()
   105  
   106  	// Get the keys
   107  	keys, ok := flatmap.Expand(s.Attributes, "key").([]interface{})
   108  	if !ok {
   109  		return fmt.Errorf("Failed to unroll keys")
   110  	}
   111  
   112  	dc := s.Attributes["datacenter"]
   113  	wOpts := consulapi.WriteOptions{Datacenter: dc}
   114  	for _, raw := range keys {
   115  		_, path, sub, err := parse_key(raw)
   116  		if err != nil {
   117  			return err
   118  		}
   119  
   120  		// Ignore if the key is non-managed
   121  		shouldDelete, ok := sub["delete"].(bool)
   122  		if !ok || !shouldDelete {
   123  			continue
   124  		}
   125  
   126  		log.Printf("[DEBUG] Deleting key '%s' in %s", path, dc)
   127  		if _, err := kv.Delete(path, &wOpts); err != nil {
   128  			return fmt.Errorf("Failed to delete Consul key '%s': %v", path, err)
   129  		}
   130  	}
   131  	return nil
   132  }
   133  
   134  func resource_consul_keys_diff(
   135  	s *terraform.ResourceState,
   136  	c *terraform.ResourceConfig,
   137  	meta interface{}) (*terraform.ResourceDiff, error) {
   138  
   139  	// Determine the list of computed variables
   140  	var computed []string
   141  	keys, ok := flatmap.Expand(flatmap.Flatten(c.Config), "key").([]interface{})
   142  	if !ok {
   143  		goto AFTER
   144  	}
   145  	for _, sub := range keys {
   146  		key, _, _, err := parse_key(sub)
   147  		if err != nil {
   148  			continue
   149  		}
   150  		computed = append(computed, "var."+key)
   151  	}
   152  
   153  AFTER:
   154  	b := &diff.ResourceBuilder{
   155  		Attrs: map[string]diff.AttrType{
   156  			"datacenter": diff.AttrTypeCreate,
   157  			"key":        diff.AttrTypeUpdate,
   158  		},
   159  		ComputedAttrsUpdate: computed,
   160  	}
   161  	return b.Diff(s, c)
   162  }
   163  
   164  func resource_consul_keys_refresh(
   165  	s *terraform.ResourceState,
   166  	meta interface{}) (*terraform.ResourceState, error) {
   167  	p := meta.(*ResourceProvider)
   168  	client := p.client
   169  	kv := client.KV()
   170  
   171  	// Get the list of keys
   172  	keys, ok := flatmap.Expand(s.Attributes, "key").([]interface{})
   173  	if !ok {
   174  		return s, fmt.Errorf("Failed to unroll keys")
   175  	}
   176  
   177  	// Update each key
   178  	dc := s.Attributes["datacenter"]
   179  	opts := consulapi.QueryOptions{Datacenter: dc}
   180  	for idx, raw := range keys {
   181  		key, path, sub, err := parse_key(raw)
   182  		if err != nil {
   183  			return s, err
   184  		}
   185  
   186  		log.Printf("[DEBUG] Refreshing value of key '%s' in %s", path, dc)
   187  		pair, _, err := kv.Get(path, &opts)
   188  		if err != nil {
   189  			return s, fmt.Errorf("Failed to get value for path '%s' from Consul: %v", path, err)
   190  		}
   191  
   192  		setVal := attribute_value(sub, key, pair)
   193  		s.Attributes[fmt.Sprintf("var.%s", key)] = setVal
   194  		if _, ok := sub["value"]; ok {
   195  			s.Attributes[fmt.Sprintf("key.%d.value", idx)] = setVal
   196  		}
   197  	}
   198  	return s, nil
   199  }
   200  
   201  // parse_key is used to parse a key into a name, path, config or error
   202  func parse_key(raw interface{}) (string, string, map[string]interface{}, error) {
   203  	sub, ok := raw.(map[string]interface{})
   204  	if !ok {
   205  		return "", "", nil, fmt.Errorf("Failed to unroll: %#v", raw)
   206  	}
   207  
   208  	key, ok := sub["name"].(string)
   209  	if !ok {
   210  		return "", "", nil, fmt.Errorf("Failed to expand key '%#v'", sub)
   211  	}
   212  
   213  	path, ok := sub["path"].(string)
   214  	if !ok {
   215  		return "", "", nil, fmt.Errorf("Failed to get path for key '%s'", key)
   216  	}
   217  	return key, path, sub, nil
   218  }
   219  
   220  // attribute_value determienes the value for a key
   221  func attribute_value(sub map[string]interface{}, key string, pair *consulapi.KVPair) string {
   222  	// Use the value if given
   223  	if pair != nil {
   224  		return string(pair.Value)
   225  	}
   226  
   227  	// Use a default if given
   228  	if raw, ok := sub["default"]; ok {
   229  		switch def := raw.(type) {
   230  		case string:
   231  			return def
   232  		case bool:
   233  			return strconv.FormatBool(def)
   234  		}
   235  	}
   236  
   237  	// No value
   238  	return ""
   239  }
   240  
   241  // get_dc is used to get the datacenter of the local agent
   242  func get_dc(client *consulapi.Client) (string, error) {
   243  	info, err := client.Agent().Self()
   244  	if err != nil {
   245  		return "", fmt.Errorf("Failed to get datacenter from Consul agent: %v", err)
   246  	}
   247  	dc := info["Config"]["Datacenter"].(string)
   248  	return dc, nil
   249  }