Merge pull request #480 from hashicorp/f-fix-consul

Consul param should be "key"
This commit is contained in:
Mitchell Hashimoto 2014-10-20 15:35:31 -07:00
commit 8f166458d2
7 changed files with 185 additions and 68 deletions

View File

@ -31,7 +31,7 @@ func resourceConsulKeys() *schema.Resource {
Optional: true, Optional: true,
}, },
"keys": &schema.Schema{ "key": &schema.Schema{
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
@ -60,6 +60,7 @@ func resourceConsulKeys() *schema.Resource {
"delete": &schema.Schema{ "delete": &schema.Schema{
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Default: false,
}, },
}, },
}, },
@ -113,19 +114,15 @@ func resourceConsulKeysCreate(d *schema.ResourceData, meta interface{}) error {
vars := make(map[string]string) vars := make(map[string]string)
// Extract the keys // Extract the keys
keys := d.Get("keys").(*schema.Set).List() keys := d.Get("key").(*schema.Set).List()
for _, raw := range keys { for _, raw := range keys {
key, path, sub, err := parse_key(raw) key, path, sub, err := parse_key(raw)
if err != nil { if err != nil {
return err return err
} }
if valueRaw, ok := sub["value"]; ok { value := sub["value"].(string)
value, ok := valueRaw.(string) if value != "" {
if !ok {
return fmt.Errorf("Failed to get value for key '%s'", key)
}
log.Printf("[DEBUG] Setting key '%s' to '%v' in %s", path, value, dc) log.Printf("[DEBUG] Setting key '%s' to '%v' in %s", path, value, dc)
pair := consulapi.KVPair{Key: path, Value: []byte(value)} pair := consulapi.KVPair{Key: path, Value: []byte(value)}
if _, err := kv.Put(&pair, &wOpts); err != nil { if _, err := kv.Put(&pair, &wOpts); err != nil {
@ -142,14 +139,13 @@ func resourceConsulKeysCreate(d *schema.ResourceData, meta interface{}) error {
} }
value := attribute_value(sub, key, pair) value := attribute_value(sub, key, pair)
vars[key] = value vars[key] = value
sub["value"] = value
} }
} }
// Update the resource // Update the resource
d.SetId("consul") d.SetId("consul")
d.Set("datacenter", dc) d.Set("datacenter", dc)
d.Set("keys", keys) d.Set("key", keys)
d.Set("var", vars) d.Set("var", vars)
return nil return nil
} }
@ -178,7 +174,7 @@ func resourceConsulKeysRead(d *schema.ResourceData, meta interface{}) error {
vars := make(map[string]string) vars := make(map[string]string)
// Extract the keys // Extract the keys
keys := d.Get("keys").(*schema.Set).List() keys := d.Get("key").(*schema.Set).List()
for _, raw := range keys { for _, raw := range keys {
key, path, sub, err := parse_key(raw) key, path, sub, err := parse_key(raw)
if err != nil { if err != nil {
@ -197,7 +193,7 @@ func resourceConsulKeysRead(d *schema.ResourceData, meta interface{}) error {
} }
// Update the resource // Update the resource
d.Set("keys", keys) d.Set("key", keys)
d.Set("var", vars) d.Set("var", vars)
return nil return nil
} }
@ -223,7 +219,7 @@ func resourceConsulKeysDelete(d *schema.ResourceData, meta interface{}) error {
wOpts := consulapi.WriteOptions{Datacenter: dc, Token: token} wOpts := consulapi.WriteOptions{Datacenter: dc, Token: token}
// Extract the keys // Extract the keys
keys := d.Get("keys").(*schema.Set).List() keys := d.Get("key").(*schema.Set).List()
for _, raw := range keys { for _, raw := range keys {
_, path, sub, err := parse_key(raw) _, path, sub, err := parse_key(raw)
if err != nil { if err != nil {

View File

@ -30,7 +30,7 @@ func TestAccConsulKeys(t *testing.T) {
func testAccCheckConsulKeysDestroy(s *terraform.State) error { func testAccCheckConsulKeysDestroy(s *terraform.State) error {
kv := testAccProvider.Meta().(*consulapi.Client).KV() kv := testAccProvider.Meta().(*consulapi.Client).KV()
opts := &consulapi.QueryOptions{Datacenter: "nyc1"} opts := &consulapi.QueryOptions{Datacenter: "nyc3"}
pair, _, err := kv.Get("test/set", opts) pair, _, err := kv.Get("test/set", opts)
if err != nil { if err != nil {
return err return err
@ -44,7 +44,7 @@ func testAccCheckConsulKeysDestroy(s *terraform.State) error {
func testAccCheckConsulKeysExists() resource.TestCheckFunc { func testAccCheckConsulKeysExists() resource.TestCheckFunc {
return func(s *terraform.State) error { return func(s *terraform.State) error {
kv := testAccProvider.Meta().(*consulapi.Client).KV() kv := testAccProvider.Meta().(*consulapi.Client).KV()
opts := &consulapi.QueryOptions{Datacenter: "nyc1"} opts := &consulapi.QueryOptions{Datacenter: "nyc3"}
pair, _, err := kv.Get("test/set", opts) pair, _, err := kv.Get("test/set", opts)
if err != nil { if err != nil {
return err return err
@ -78,7 +78,7 @@ func testAccCheckConsulKeysValue(n, attr, val string) resource.TestCheckFunc {
const testAccConsulKeysConfig = ` const testAccConsulKeysConfig = `
resource "consul_keys" "app" { resource "consul_keys" "app" {
datacenter = "nyc1" datacenter = "nyc3"
key { key {
name = "time" name = "time"
path = "global/time" path = "global/time"

View File

@ -3,6 +3,7 @@ package consul
import ( import (
"testing" "testing"
"github.com/armon/consul-api"
"github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
@ -16,6 +17,13 @@ func init() {
testAccProviders = map[string]terraform.ResourceProvider{ testAccProviders = map[string]terraform.ResourceProvider{
"consul": testAccProvider, "consul": testAccProvider,
} }
// Use the demo address for the acceptance tests
testAccProvider.ConfigureFunc = func(d *schema.ResourceData) (interface{}, error) {
conf := consulapi.DefaultConfig()
conf.Address = "demo.consul.io:80"
return consulapi.NewClient(conf)
}
} }
func TestResourceProvider(t *testing.T) { func TestResourceProvider(t *testing.T) {
@ -33,7 +41,7 @@ func TestResourceProvider_Configure(t *testing.T) {
raw := map[string]interface{}{ raw := map[string]interface{}{
"address": "demo.consul.io:80", "address": "demo.consul.io:80",
"datacenter": "nyc1", "datacenter": "nyc3",
} }
rawConfig, err := config.NewRawConfig(raw) rawConfig, err := config.NewRawConfig(raw)

View File

@ -43,10 +43,11 @@ type getSource byte
const ( const (
getSourceState getSource = 1 << iota getSourceState getSource = 1 << iota
getSourceConfig getSourceConfig
getSourceDiff
getSourceSet getSourceSet
getSourceExact getSourceExact // Only get from the _exact_ level
getSourceMax = getSourceSet getSourceDiff // Apply the diff on top our level
getSourceLevelMask getSource = getSourceState | getSourceConfig | getSourceSet
getSourceMax getSource = getSourceSet
) )
// getResult is the internal structure that is generated when a Get // getResult is the internal structure that is generated when a Get
@ -82,7 +83,7 @@ func (d *ResourceData) Get(key string) interface{} {
// set and the new value is. This is common, for example, for boolean // set and the new value is. This is common, for example, for boolean
// fields which have a zero value of false. // fields which have a zero value of false.
func (d *ResourceData) GetChange(key string) (interface{}, interface{}) { func (d *ResourceData) GetChange(key string) (interface{}, interface{}) {
o, n := d.getChange(key, getSourceConfig, getSourceDiff) o, n := d.getChange(key, getSourceConfig, getSourceConfig|getSourceDiff)
return o.Value, n.Value return o.Value, n.Value
} }
@ -93,7 +94,7 @@ func (d *ResourceData) GetChange(key string) (interface{}, interface{}) {
// The first result will not necessarilly be nil if the value doesn't exist. // The first result will not necessarilly be nil if the value doesn't exist.
// The second result should be checked to determine this information. // The second result should be checked to determine this information.
func (d *ResourceData) GetOk(key string) (interface{}, bool) { func (d *ResourceData) GetOk(key string) (interface{}, bool) {
r := d.getRaw(key, getSourceSet) r := d.getRaw(key, getSourceSet|getSourceDiff)
return r.Value, r.Exists return r.Value, r.Exists
} }
@ -289,12 +290,21 @@ func (d *ResourceData) getSet(
// entire set must come from set, diff, state, etc. So we go backwards // entire set must come from set, diff, state, etc. So we go backwards
// and once we get a result, we take it. Or, we never get a result. // and once we get a result, we take it. Or, we never get a result.
var raw getResult var raw getResult
for listSource := source; listSource > 0; listSource >>= 1 { sourceLevel := source & getSourceLevelMask
if source&getSourceExact != 0 && listSource != source { sourceFlags := source & ^getSourceLevelMask
for listSource := sourceLevel; listSource > 0; listSource >>= 1 {
// If we're already asking for an exact source and it doesn't
// match, then leave since the original source was the match.
if sourceFlags&getSourceExact != 0 && listSource != sourceLevel {
break break
} }
raw = d.getList(k, nil, schema, listSource|getSourceExact) // The source we get from is the level we're on, plus the flags
// we had, plus the exact flag.
getSource := listSource
getSource |= sourceFlags
getSource |= getSourceExact
raw = d.getList(k, nil, schema, getSource)
if raw.Exists { if raw.Exists {
break break
} }
@ -384,11 +394,13 @@ func (d *ResourceData) getMap(
resultSet := false resultSet := false
prefix := k + "." prefix := k + "."
exact := source&getSourceExact != 0 flags := source & ^getSourceLevelMask
source &^= getSourceExact level := source & getSourceLevelMask
exact := flags&getSourceExact != 0
diff := flags&getSourceDiff != 0
if !exact || source == getSourceState { if !exact || level == getSourceState {
if d.state != nil && source >= getSourceState { if d.state != nil && level >= getSourceState {
for k, _ := range d.state.Attributes { for k, _ := range d.state.Attributes {
if !strings.HasPrefix(k, prefix) { if !strings.HasPrefix(k, prefix) {
continue continue
@ -401,7 +413,7 @@ func (d *ResourceData) getMap(
} }
} }
if d.config != nil && source == getSourceConfig { if d.config != nil && level == getSourceConfig {
// For config, we always set the result to exactly what was requested // For config, we always set the result to exactly what was requested
if mraw, ok := d.config.Get(k); ok { if mraw, ok := d.config.Get(k); ok {
result = make(map[string]interface{}) result = make(map[string]interface{})
@ -433,27 +445,25 @@ func (d *ResourceData) getMap(
} }
} }
if !exact || source == getSourceDiff { if d.diff != nil && diff {
if d.diff != nil && source >= getSourceDiff { for k, v := range d.diff.Attributes {
for k, v := range d.diff.Attributes { if !strings.HasPrefix(k, prefix) {
if !strings.HasPrefix(k, prefix) { continue
continue }
} resultSet = true
resultSet = true
single := k[len(prefix):] single := k[len(prefix):]
if v.NewRemoved { if v.NewRemoved {
delete(result, single) delete(result, single)
} else { } else {
result[single] = d.getPrimitive(k, nil, elemSchema, source).Value result[single] = d.getPrimitive(k, nil, elemSchema, source).Value
}
} }
} }
} }
if !exact || source == getSourceSet { if !exact || level == getSourceSet {
if d.setMap != nil && source >= getSourceSet { if d.setMap != nil && level >= getSourceSet {
cleared := false cleared := false
for k, _ := range d.setMap { for k, _ := range d.setMap {
if !strings.HasPrefix(k, prefix) { if !strings.HasPrefix(k, prefix) {
@ -577,8 +587,10 @@ func (d *ResourceData) getPrimitive(
var result string var result string
var resultProcessed interface{} var resultProcessed interface{}
var resultComputed, resultSet bool var resultComputed, resultSet bool
exact := source&getSourceExact != 0 flags := source & ^getSourceLevelMask
source &^= getSourceExact source = source & getSourceLevelMask
exact := flags&getSourceExact != 0
diff := flags&getSourceDiff != 0
if !exact || source == getSourceState { if !exact || source == getSourceState {
if d.state != nil && source >= getSourceState { if d.state != nil && source >= getSourceState {
@ -604,28 +616,26 @@ func (d *ResourceData) getPrimitive(
resultComputed = d.config.IsComputed(k) resultComputed = d.config.IsComputed(k)
} }
if !exact || source == getSourceDiff { if d.diff != nil && diff {
if d.diff != nil && source >= getSourceDiff { attrD, ok := d.diff.Attributes[k]
attrD, ok := d.diff.Attributes[k] if ok {
if ok { if !attrD.NewComputed {
if !attrD.NewComputed { result = attrD.New
result = attrD.New if attrD.NewExtra != nil {
if attrD.NewExtra != nil { // If NewExtra != nil, then we have processed data as the New,
// If NewExtra != nil, then we have processed data as the New, // so we store that but decode the unprocessed data into result
// so we store that but decode the unprocessed data into result resultProcessed = result
resultProcessed = result
err := mapstructure.WeakDecode(attrD.NewExtra, &result) err := mapstructure.WeakDecode(attrD.NewExtra, &result)
if err != nil { if err != nil {
panic(err) panic(err)
}
} }
resultSet = true
} else {
result = ""
resultSet = false
} }
resultSet = true
} else {
result = ""
resultSet = false
} }
} }
} }
@ -1101,14 +1111,14 @@ func (d *ResourceData) stateSingle(
func (d *ResourceData) stateSource(prefix string) getSource { func (d *ResourceData) stateSource(prefix string) getSource {
// If we're not doing a partial apply, then get the set level // If we're not doing a partial apply, then get the set level
if !d.partial { if !d.partial {
return getSourceSet return getSourceSet | getSourceDiff
} }
// Otherwise, only return getSourceSet if its in the partial map. // Otherwise, only return getSourceSet if its in the partial map.
// Otherwise we use state level only. // Otherwise we use state level only.
for k, _ := range d.partialMap { for k, _ := range d.partialMap {
if strings.HasPrefix(prefix, k) { if strings.HasPrefix(prefix, k) {
return getSourceSet return getSourceSet | getSourceDiff
} }
} }

View File

@ -527,6 +527,58 @@ func TestResourceDataGet(t *testing.T) {
Value: []interface{}{80}, Value: []interface{}{80},
}, },
{
Schema: map[string]*Schema{
"data": &Schema{
Type: TypeSet,
Optional: true,
Elem: &Resource{
Schema: map[string]*Schema{
"index": &Schema{
Type: TypeInt,
Required: true,
},
"value": &Schema{
Type: TypeString,
Required: true,
},
},
},
Set: func(a interface{}) int {
m := a.(map[string]interface{})
return m["index"].(int)
},
},
},
State: &terraform.InstanceState{
Attributes: map[string]string{
"data.#": "1",
"data.0.index": "10",
"data.0.value": "50",
},
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"data.0.value": &terraform.ResourceAttrDiff{
Old: "50",
New: "80",
},
},
},
Key: "data",
Value: []interface{}{
map[string]interface{}{
"index": 10,
"value": "80",
},
},
},
} }
for i, tc := range cases { for i, tc := range cases {

View File

@ -580,6 +580,11 @@ func (m schemaMap) diffMap(
return fmt.Errorf("%s: %s", k, err) return fmt.Errorf("%s: %s", k, err)
} }
// If the new map is nil and we're computed, then ignore it.
if n == nil && schema.Computed {
return nil
}
// Now we compare, preferring values from the config map // Now we compare, preferring values from the config map
for k, v := range configMap { for k, v := range configMap {
old := stateMap[k] old := stateMap[k]

View File

@ -342,6 +342,31 @@ func TestSchemaMap_Diff(t *testing.T) {
Err: false, Err: false,
}, },
/*
* Bool
*/
{
Schema: map[string]*Schema{
"delete": &Schema{
Type: TypeBool,
Optional: true,
Default: false,
},
},
State: &terraform.InstanceState{
Attributes: map[string]string{
"delete": "false",
},
},
Config: nil,
Diff: nil,
Err: false,
},
/* /*
* List decode * List decode
*/ */
@ -1166,6 +1191,27 @@ func TestSchemaMap_Diff(t *testing.T) {
Err: false, Err: false,
}, },
{
Schema: map[string]*Schema{
"vars": &Schema{
Type: TypeMap,
Computed: true,
},
},
State: &terraform.InstanceState{
Attributes: map[string]string{
"vars.foo": "bar",
},
},
Config: nil,
Diff: nil,
Err: false,
},
{ {
Schema: map[string]*Schema{ Schema: map[string]*Schema{
"config_vars": &Schema{ "config_vars": &Schema{