Skip to content

Commit 3e249a4

Browse files
committed
provider/consul: Port to helper.Schema framework
1 parent c6a165f commit 3e249a4

6 files changed

Lines changed: 200 additions & 229 deletions

File tree

builtin/bins/provider-consul/main.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@ package main
33
import (
44
"github.com/hashicorp/terraform/builtin/providers/consul"
55
"github.com/hashicorp/terraform/plugin"
6-
"github.com/hashicorp/terraform/terraform"
76
)
87

98
func main() {
109
plugin.Serve(&plugin.ServeOpts{
11-
ProviderFunc: func() terraform.ResourceProvider {
12-
return new(consul.ResourceProvider)
13-
},
10+
ProviderFunc: consul.Provider,
1411
})
1512
}

builtin/providers/consul/resource_consul_keys.go

Lines changed: 160 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,201 +1,233 @@
11
package consul
22

33
import (
4+
"bytes"
45
"fmt"
56
"log"
67
"strconv"
78

89
"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"
10+
"github.com/hashicorp/terraform/helper/hashcode"
11+
"github.com/hashicorp/terraform/helper/schema"
1312
)
1413

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",
14+
func resourceConsulKeys() *schema.Resource {
15+
return &schema.Resource{
16+
Create: resourceConsulKeysCreate,
17+
Update: resourceConsulKeysCreate,
18+
Read: resourceConsulKeysRead,
19+
Delete: resourceConsulKeysDelete,
20+
21+
Schema: map[string]*schema.Schema{
22+
"datacenter": &schema.Schema{
23+
Type: schema.TypeString,
24+
Optional: true,
25+
Computed: true,
26+
ForceNew: true,
27+
},
28+
29+
"keys": &schema.Schema{
30+
Type: schema.TypeSet,
31+
Optional: true,
32+
Elem: &schema.Resource{
33+
Schema: map[string]*schema.Schema{
34+
"name": &schema.Schema{
35+
Type: schema.TypeString,
36+
Required: true,
37+
},
38+
39+
"path": &schema.Schema{
40+
Type: schema.TypeString,
41+
Required: true,
42+
},
43+
44+
"value": &schema.Schema{
45+
Type: schema.TypeString,
46+
Optional: true,
47+
Computed: true,
48+
},
49+
50+
"default": &schema.Schema{
51+
Type: schema.TypeString,
52+
Optional: true,
53+
},
54+
55+
"delete": &schema.Schema{
56+
Type: schema.TypeBool,
57+
Optional: true,
58+
},
59+
},
60+
},
61+
Set: resourceConsulKeysHash,
62+
},
63+
64+
"var": &schema.Schema{
65+
Type: schema.TypeMap,
66+
Computed: true,
67+
},
2668
},
2769
}
2870
}
29-
func resource_consul_keys_update(
30-
s *terraform.InstanceState,
31-
d *terraform.InstanceDiff,
32-
meta interface{}) (*terraform.InstanceState, error) {
33-
return resource_consul_keys_create(s, d, meta)
34-
}
3571

36-
func resource_consul_keys_create(
37-
s *terraform.InstanceState,
38-
d *terraform.InstanceDiff,
39-
meta interface{}) (*terraform.InstanceState, error) {
40-
p := meta.(*ResourceProvider)
72+
func resourceConsulKeysHash(v interface{}) int {
73+
var buf bytes.Buffer
74+
m := v.(map[string]interface{})
75+
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
76+
buf.WriteString(fmt.Sprintf("%s-", m["path"].(string)))
77+
return hashcode.String(buf.String())
78+
}
4179

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"
80+
func resourceConsulKeysCreate(d *schema.ResourceData, meta interface{}) error {
81+
client := meta.(*consulapi.Client)
82+
kv := client.KV()
4683

47-
// Check if the datacenter should be computed
48-
dc := rs.Attributes["datacenter"]
49-
if aDiff, ok := d.Attributes["datacenter"]; ok && aDiff.NewComputed {
84+
// Resolve the datacenter first, all the other keys are dependent
85+
// on this.
86+
var dc string
87+
if v := d.Get("datacenter"); v != nil {
88+
dc = v.(string)
89+
log.Printf("[DEBUG] Consul datacenter: %s", dc)
90+
} else {
91+
log.Printf("[DEBUG] Resolving Consul datacenter...")
5092
var err error
51-
dc, err = get_dc(p.client)
93+
dc, err = get_dc(client)
5294
if err != nil {
53-
return rs, fmt.Errorf("Failed to get agent datacenter: %v", err)
95+
return err
5496
}
55-
rs.Attributes["datacenter"] = dc
5697
}
5798

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()
99+
// Setup the operations using the datacenter
65100
qOpts := consulapi.QueryOptions{Datacenter: dc}
66101
wOpts := consulapi.WriteOptions{Datacenter: dc}
67-
for idx, raw := range keys {
102+
103+
// Store the computed vars
104+
vars := make(map[string]string)
105+
106+
// Extract the keys
107+
keys := d.Get("keys").(*schema.Set).List()
108+
for _, raw := range keys {
68109
key, path, sub, err := parse_key(raw)
69110
if err != nil {
70-
return rs, err
111+
return err
71112
}
72113

73114
if valueRaw, ok := sub["value"]; ok {
74115
value, ok := valueRaw.(string)
75116
if !ok {
76-
return rs, fmt.Errorf("Failed to get value for key '%s'", key)
117+
return fmt.Errorf("Failed to get value for key '%s'", key)
77118
}
78119

79120
log.Printf("[DEBUG] Setting key '%s' to '%v' in %s", path, value, dc)
80121
pair := consulapi.KVPair{Key: path, Value: []byte(value)}
81122
if _, err := kv.Put(&pair, &wOpts); err != nil {
82-
return rs, fmt.Errorf("Failed to set Consul key '%s': %v", path, err)
123+
return fmt.Errorf("Failed to set Consul key '%s': %v", path, err)
83124
}
84-
rs.Attributes[fmt.Sprintf("var.%s", key)] = value
85-
rs.Attributes[fmt.Sprintf("key.%d.value", idx)] = value
125+
vars[key] = value
126+
sub["value"] = value
86127

87128
} else {
88129
log.Printf("[DEBUG] Getting key '%s' in %s", path, dc)
89130
pair, _, err := kv.Get(path, &qOpts)
90131
if err != nil {
91-
return rs, fmt.Errorf("Failed to get Consul key '%s': %v", path, err)
132+
return fmt.Errorf("Failed to get Consul key '%s': %v", path, err)
92133
}
93-
rs.Attributes[fmt.Sprintf("var.%s", key)] = attribute_value(sub, key, pair)
134+
value := attribute_value(sub, key, pair)
135+
vars[key] = value
136+
sub["value"] = value
94137
}
95138
}
96-
return rs, nil
139+
140+
// Update the resource
141+
d.SetId("consul")
142+
d.Set("datacenter", dc)
143+
d.Set("keys", keys)
144+
d.Set("var", vars)
145+
return nil
97146
}
98147

99-
func resource_consul_keys_destroy(
100-
s *terraform.InstanceState,
101-
meta interface{}) error {
102-
p := meta.(*ResourceProvider)
103-
client := p.client
148+
func resourceConsulKeysRead(d *schema.ResourceData, meta interface{}) error {
149+
client := meta.(*consulapi.Client)
104150
kv := client.KV()
105151

106-
// Get the keys
107-
keys, ok := flatmap.Expand(s.Attributes, "key").([]interface{})
108-
if !ok {
109-
return fmt.Errorf("Failed to unroll keys")
152+
// Get the DC, error if not available.
153+
var dc string
154+
if v := d.Get("datacenter"); v != nil {
155+
dc = v.(string)
156+
log.Printf("[DEBUG] Consul datacenter: %s", dc)
157+
} else {
158+
return fmt.Errorf("Missing datacenter configuration")
110159
}
111160

112-
dc := s.Attributes["datacenter"]
113-
wOpts := consulapi.WriteOptions{Datacenter: dc}
161+
// Setup the operations using the datacenter
162+
qOpts := consulapi.QueryOptions{Datacenter: dc}
163+
164+
// Store the computed vars
165+
vars := make(map[string]string)
166+
167+
// Extract the keys
168+
keys := d.Get("keys").(*schema.Set).List()
114169
for _, raw := range keys {
115-
_, path, sub, err := parse_key(raw)
170+
key, path, sub, err := parse_key(raw)
116171
if err != nil {
117172
return err
118173
}
119174

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.InstanceState,
136-
c *terraform.ResourceConfig,
137-
meta interface{}) (*terraform.InstanceDiff, 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)
175+
log.Printf("[DEBUG] Refreshing value of key '%s' in %s", path, dc)
176+
pair, _, err := kv.Get(path, &qOpts)
147177
if err != nil {
148-
continue
178+
return fmt.Errorf("Failed to get value for path '%s' from Consul: %v", path, err)
149179
}
150-
computed = append(computed, "var."+key)
151-
}
152180

153-
AFTER:
154-
b := &diff.ResourceBuilder{
155-
Attrs: map[string]diff.AttrType{
156-
"datacenter": diff.AttrTypeCreate,
157-
"key": diff.AttrTypeUpdate,
158-
},
159-
ComputedAttrsUpdate: computed,
181+
value := attribute_value(sub, key, pair)
182+
vars[key] = value
183+
sub["value"] = value
160184
}
161-
return b.Diff(s, c)
185+
186+
// Update the resource
187+
d.Set("keys", keys)
188+
d.Set("var", vars)
189+
return nil
162190
}
163191

164-
func resource_consul_keys_refresh(
165-
s *terraform.InstanceState,
166-
meta interface{}) (*terraform.InstanceState, error) {
167-
p := meta.(*ResourceProvider)
168-
client := p.client
192+
func resourceConsulKeysDelete(d *schema.ResourceData, meta interface{}) error {
193+
client := meta.(*consulapi.Client)
169194
kv := client.KV()
170195

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")
196+
// Get the DC, error if not available.
197+
var dc string
198+
if v := d.Get("datacenter"); v != nil {
199+
dc = v.(string)
200+
log.Printf("[DEBUG] Consul datacenter: %s", dc)
201+
} else {
202+
return fmt.Errorf("Missing datacenter configuration")
175203
}
176204

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)
205+
// Setup the operations using the datacenter
206+
wOpts := consulapi.WriteOptions{Datacenter: dc}
207+
208+
// Extract the keys
209+
keys := d.Get("keys").(*schema.Set).List()
210+
for _, raw := range keys {
211+
_, path, sub, err := parse_key(raw)
182212
if err != nil {
183-
return s, err
213+
return err
184214
}
185215

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)
216+
// Ignore if the key is non-managed
217+
shouldDelete, ok := sub["delete"].(bool)
218+
if !ok || !shouldDelete {
219+
continue
190220
}
191221

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
222+
log.Printf("[DEBUG] Deleting key '%s' in %s", path, dc)
223+
if _, err := kv.Delete(path, &wOpts); err != nil {
224+
return fmt.Errorf("Failed to delete Consul key '%s': %v", path, err)
196225
}
197226
}
198-
return s, nil
227+
228+
// Clear the ID
229+
d.SetId("")
230+
return nil
199231
}
200232

201233
// parse_key is used to parse a key into a name, path, config or error
@@ -217,7 +249,8 @@ func parse_key(raw interface{}) (string, string, map[string]interface{}, error)
217249
return key, path, sub, nil
218250
}
219251

220-
// attribute_value determienes the value for a key
252+
// attribute_value determines the value for a key, potentially
253+
// using a default value if provided.
221254
func attribute_value(sub map[string]interface{}, key string, pair *consulapi.KVPair) string {
222255
// Use the value if given
223256
if pair != nil {

0 commit comments

Comments
 (0)