helper/schema: empty maps, support reading objects directly
This commit is contained in:
parent
f0af1c36f5
commit
e57f3f69b1
|
@ -57,8 +57,13 @@ func addrToSchema(addr []string, schemaMap map[string]*Schema) []*Schema {
|
||||||
Type: typeObject,
|
Type: typeObject,
|
||||||
Elem: schemaMap,
|
Elem: schemaMap,
|
||||||
}
|
}
|
||||||
result := make([]*Schema, 0, len(addr))
|
|
||||||
|
|
||||||
|
// TODO: test
|
||||||
|
if len(addr) == 0 {
|
||||||
|
return []*Schema{current}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]*Schema, 0, len(addr))
|
||||||
for len(addr) > 0 {
|
for len(addr) > 0 {
|
||||||
k := addr[0]
|
k := addr[0]
|
||||||
addr = addr[1:]
|
addr = addr[1:]
|
||||||
|
|
|
@ -44,6 +44,13 @@ func (r *MapFieldReader) readMap(k string) (FieldReadResult, error) {
|
||||||
result := make(map[string]interface{})
|
result := make(map[string]interface{})
|
||||||
resultSet := false
|
resultSet := false
|
||||||
|
|
||||||
|
// If the name of the map field is directly in the map with an
|
||||||
|
// empty string, it means that the map is being deleted, so mark
|
||||||
|
// that is is set.
|
||||||
|
if v, ok := r.Map.Access(k); ok && v == "" {
|
||||||
|
resultSet = true
|
||||||
|
}
|
||||||
|
|
||||||
prefix := k + "."
|
prefix := k + "."
|
||||||
r.Map.Range(func(k, v string) bool {
|
r.Map.Range(func(k, v string) bool {
|
||||||
if strings.HasPrefix(k, prefix) {
|
if strings.HasPrefix(k, prefix) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
Elem: &Schema{Type: TypeInt},
|
Elem: &Schema{Type: TypeInt},
|
||||||
},
|
},
|
||||||
"map": &Schema{Type: TypeMap},
|
"map": &Schema{Type: TypeMap},
|
||||||
|
"mapDel": &Schema{Type: TypeMap},
|
||||||
"set": &Schema{
|
"set": &Schema{
|
||||||
Type: TypeSet,
|
Type: TypeSet,
|
||||||
Elem: &Schema{Type: TypeInt},
|
Elem: &Schema{Type: TypeInt},
|
||||||
|
@ -68,6 +69,8 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
"map.foo": "bar",
|
"map.foo": "bar",
|
||||||
"map.bar": "baz",
|
"map.bar": "baz",
|
||||||
|
|
||||||
|
"mapDel": "",
|
||||||
|
|
||||||
"set.#": "2",
|
"set.#": "2",
|
||||||
"set.10": "10",
|
"set.10": "10",
|
||||||
"set.50": "50",
|
"set.50": "50",
|
||||||
|
@ -152,6 +155,14 @@ func TestMapFieldReader(t *testing.T) {
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"mapDel": {
|
||||||
|
[]string{"mapDel"},
|
||||||
|
map[string]interface{}{},
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
"mapelem": {
|
"mapelem": {
|
||||||
[]string{"map", "foo"},
|
[]string{"map", "foo"},
|
||||||
"bar",
|
"bar",
|
||||||
|
|
|
@ -42,7 +42,10 @@ func (r *MultiLevelFieldReader) ReadFieldMerge(
|
||||||
var result FieldReadResult
|
var result FieldReadResult
|
||||||
for _, l := range r.Levels {
|
for _, l := range r.Levels {
|
||||||
if r, ok := r.Readers[l]; ok {
|
if r, ok := r.Readers[l]; ok {
|
||||||
|
println(fmt.Sprintf("GET %#v %s %#v", address, l, r))
|
||||||
out, err := r.ReadField(address)
|
out, err := r.ReadField(address)
|
||||||
|
println(fmt.Sprintf("%#v", out))
|
||||||
|
println("======================================")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FieldReadResult{}, fmt.Errorf(
|
return FieldReadResult{}, fmt.Errorf(
|
||||||
"Error reading level %s: %s", l, err)
|
"Error reading level %s: %s", l, err)
|
||||||
|
|
|
@ -105,7 +105,8 @@ func (d *ResourceData) getRaw(key string, level getSource) getResult {
|
||||||
parts = strings.Split(key, ".")
|
parts = strings.Split(key, ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.getObject("", parts, d.schema, level)
|
schema := &Schema{Type: typeObject, Elem: d.schema}
|
||||||
|
return d.get("", parts, schema, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasChange returns whether or not the given key has been changed.
|
// HasChange returns whether or not the given key has been changed.
|
||||||
|
@ -312,8 +313,9 @@ func (d *ResourceData) getChange(
|
||||||
parts2 = strings.Split(key, ".")
|
parts2 = strings.Split(key, ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
o := d.getObject("", parts, d.schema, oldLevel)
|
schema := &Schema{Type: typeObject, Elem: d.schema}
|
||||||
n := d.getObject("", parts2, d.schema, newLevel)
|
o := d.get("", parts, schema, oldLevel)
|
||||||
|
n := d.get("", parts2, schema, newLevel)
|
||||||
return o, n
|
return o, n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +342,11 @@ func (d *ResourceData) get(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the address of the key we're looking for and ask the FieldReader
|
// Build the address of the key we're looking for and ask the FieldReader
|
||||||
addr := append(strings.Split(k, "."), parts...)
|
var addr []string
|
||||||
|
if k != "" {
|
||||||
|
addr = strings.Split(k, ".")
|
||||||
|
}
|
||||||
|
addr = append(addr, parts...)
|
||||||
for i, v := range addr {
|
for i, v := range addr {
|
||||||
if v[0] == '~' {
|
if v[0] == '~' {
|
||||||
addr[i] = v[1:]
|
addr[i] = v[1:]
|
||||||
|
@ -377,511 +383,6 @@ func (d *ResourceData) get(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *ResourceData) getSet(
|
|
||||||
k string,
|
|
||||||
parts []string,
|
|
||||||
schema *Schema,
|
|
||||||
source getSource) getResult {
|
|
||||||
s := &Set{F: schema.Set}
|
|
||||||
result := getResult{Schema: schema, Value: s}
|
|
||||||
prefix := k + "."
|
|
||||||
|
|
||||||
// Get the set. For sets, the entire source must be exact: the
|
|
||||||
// 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.
|
|
||||||
var indexMap map[int]int
|
|
||||||
codes := make(map[string]int)
|
|
||||||
sourceLevel := source & getSourceLevelMask
|
|
||||||
sourceFlags := source & ^getSourceLevelMask
|
|
||||||
sourceDiff := sourceFlags&getSourceDiff != 0
|
|
||||||
for setSource := sourceLevel; setSource > 0; setSource >>= 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 && setSource != sourceLevel {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.config != nil && setSource == getSourceConfig {
|
|
||||||
raw := d.getList(k, nil, schema, setSource)
|
|
||||||
// If the entire list is computed, then the entire set is
|
|
||||||
// necessarilly computed.
|
|
||||||
if raw.Computed {
|
|
||||||
result.Computed = true
|
|
||||||
if len(parts) > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
if raw.Exists {
|
|
||||||
result.Exists = true
|
|
||||||
|
|
||||||
list := raw.Value.([]interface{})
|
|
||||||
indexMap = make(map[int]int, len(list))
|
|
||||||
|
|
||||||
// Build the set from all the items using the given hash code
|
|
||||||
for i, v := range list {
|
|
||||||
code := s.add(v)
|
|
||||||
|
|
||||||
// Check if any of the keys in this item are computed
|
|
||||||
computed := false
|
|
||||||
if len(d.config.ComputedKeys) > 0 {
|
|
||||||
prefix := fmt.Sprintf("%s.%d", k, i)
|
|
||||||
computed = d.hasComputedSubKeys(prefix, schema)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we are computed and if so negatate the hash to
|
|
||||||
// this is a approximate hash
|
|
||||||
if computed {
|
|
||||||
s.m[-code] = s.m[code]
|
|
||||||
delete(s.m, code)
|
|
||||||
code = -code
|
|
||||||
}
|
|
||||||
indexMap[code] = i
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.state != nil && setSource == getSourceState {
|
|
||||||
for k, _ := range d.state.Attributes {
|
|
||||||
if !strings.HasPrefix(k, prefix) || strings.HasPrefix(k, prefix+"#") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
parts := strings.Split(k[len(prefix):], ".")
|
|
||||||
idx := parts[0]
|
|
||||||
if _, ok := codes[idx]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
code, err := strconv.Atoi(strings.Replace(parts[0], "~", "-", -1))
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("unable to convert %s to int: %v", idx, err))
|
|
||||||
}
|
|
||||||
codes[idx] = code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.setMap != nil && setSource == getSourceSet {
|
|
||||||
for k, _ := range d.setMap {
|
|
||||||
if !strings.HasPrefix(k, prefix) || strings.HasPrefix(k, prefix+"#") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
parts := strings.Split(k[len(prefix):], ".")
|
|
||||||
idx := parts[0]
|
|
||||||
if _, ok := codes[idx]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
code, err := strconv.Atoi(strings.Replace(parts[0], "~", "-", -1))
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("unable to convert %s to int: %v", idx, err))
|
|
||||||
}
|
|
||||||
codes[idx] = code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.diff != nil && sourceDiff {
|
|
||||||
for k, _ := range d.diff.Attributes {
|
|
||||||
if !strings.HasPrefix(k, prefix) || strings.HasPrefix(k, prefix+"#") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
parts := strings.Split(k[len(prefix):], ".")
|
|
||||||
idx := parts[0]
|
|
||||||
if _, ok := codes[idx]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
code, err := strconv.Atoi(strings.Replace(parts[0], "~", "-", -1))
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("unable to convert %s to int: %v", idx, err))
|
|
||||||
}
|
|
||||||
codes[idx] = code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(codes) > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if indexMap == nil {
|
|
||||||
s.m = make(map[int]interface{})
|
|
||||||
for idx, code := range codes {
|
|
||||||
switch t := schema.Elem.(type) {
|
|
||||||
case *Resource:
|
|
||||||
// Get the entire object
|
|
||||||
m := make(map[string]interface{})
|
|
||||||
for field, _ := range t.Schema {
|
|
||||||
m[field] = d.getObject(prefix+idx, []string{field}, t.Schema, source).Value
|
|
||||||
}
|
|
||||||
s.m[code] = m
|
|
||||||
result.Exists = true
|
|
||||||
case *Schema:
|
|
||||||
// Get a single value
|
|
||||||
s.m[code] = d.get(prefix+idx, nil, t, source).Value
|
|
||||||
result.Exists = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(parts) > 0 {
|
|
||||||
// We still have parts left over meaning we're accessing an
|
|
||||||
// element of this set.
|
|
||||||
idx := parts[0]
|
|
||||||
parts = parts[1:]
|
|
||||||
|
|
||||||
// Special case if we're accessing the count of the set
|
|
||||||
if idx == "#" {
|
|
||||||
schema := &Schema{Type: TypeInt}
|
|
||||||
return d.get(prefix+"#", parts, schema, source)
|
|
||||||
}
|
|
||||||
|
|
||||||
if source&getSourceLevelMask == getSourceConfig {
|
|
||||||
i, err := strconv.Atoi(strings.Replace(idx, "~", "-", -1))
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("unable to convert %s to int: %v", idx, err))
|
|
||||||
}
|
|
||||||
if i, ok := indexMap[i]; ok {
|
|
||||||
idx = strconv.Itoa(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t := schema.Elem.(type) {
|
|
||||||
case *Resource:
|
|
||||||
return d.getObject(prefix+idx, parts, t.Schema, source)
|
|
||||||
case *Schema:
|
|
||||||
return d.get(prefix+idx, parts, t, source)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *ResourceData) getMap(
|
|
||||||
k string,
|
|
||||||
parts []string,
|
|
||||||
schema *Schema,
|
|
||||||
source getSource) getResult {
|
|
||||||
elemSchema := &Schema{Type: TypeString}
|
|
||||||
|
|
||||||
result := make(map[string]interface{})
|
|
||||||
resultSet := false
|
|
||||||
prefix := k + "."
|
|
||||||
|
|
||||||
flags := source & ^getSourceLevelMask
|
|
||||||
level := source & getSourceLevelMask
|
|
||||||
exact := flags&getSourceExact != 0
|
|
||||||
diff := flags&getSourceDiff != 0
|
|
||||||
|
|
||||||
if !exact || level == getSourceState {
|
|
||||||
if d.state != nil && level >= getSourceState {
|
|
||||||
for k, _ := range d.state.Attributes {
|
|
||||||
if !strings.HasPrefix(k, prefix) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
single := k[len(prefix):]
|
|
||||||
result[single] = d.getPrimitive(k, nil, elemSchema, source).Value
|
|
||||||
resultSet = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.config != nil && level == getSourceConfig {
|
|
||||||
// For config, we always set the result to exactly what was requested
|
|
||||||
if mraw, ok := d.config.Get(k); ok {
|
|
||||||
result = make(map[string]interface{})
|
|
||||||
switch m := mraw.(type) {
|
|
||||||
case []interface{}:
|
|
||||||
for _, innerRaw := range m {
|
|
||||||
for k, v := range innerRaw.(map[string]interface{}) {
|
|
||||||
result[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resultSet = true
|
|
||||||
case []map[string]interface{}:
|
|
||||||
for _, innerRaw := range m {
|
|
||||||
for k, v := range innerRaw {
|
|
||||||
result[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resultSet = true
|
|
||||||
case map[string]interface{}:
|
|
||||||
result = m
|
|
||||||
resultSet = true
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("unknown type: %#v", mraw))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.diff != nil && diff {
|
|
||||||
for k, v := range d.diff.Attributes {
|
|
||||||
if !strings.HasPrefix(k, prefix) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resultSet = true
|
|
||||||
|
|
||||||
single := k[len(prefix):]
|
|
||||||
|
|
||||||
if v.NewRemoved {
|
|
||||||
delete(result, single)
|
|
||||||
} else {
|
|
||||||
result[single] = d.getPrimitive(k, nil, elemSchema, source).Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exact || level == getSourceSet {
|
|
||||||
if d.setMap != nil && level >= getSourceSet {
|
|
||||||
cleared := false
|
|
||||||
if v, ok := d.setMap[k]; ok && v == "" {
|
|
||||||
// We've cleared the map
|
|
||||||
result = make(map[string]interface{})
|
|
||||||
resultSet = true
|
|
||||||
} else {
|
|
||||||
for k, _ := range d.setMap {
|
|
||||||
if !strings.HasPrefix(k, prefix) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resultSet = true
|
|
||||||
|
|
||||||
if !cleared {
|
|
||||||
// We clear the results if they are in the set map
|
|
||||||
result = make(map[string]interface{})
|
|
||||||
cleared = true
|
|
||||||
}
|
|
||||||
|
|
||||||
single := k[len(prefix):]
|
|
||||||
result[single] = d.getPrimitive(
|
|
||||||
k, nil, elemSchema, source).Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're requesting a specific element, return that
|
|
||||||
var resultValue interface{} = result
|
|
||||||
if len(parts) > 0 {
|
|
||||||
resultValue = result[parts[0]]
|
|
||||||
}
|
|
||||||
|
|
||||||
return getResult{
|
|
||||||
Value: resultValue,
|
|
||||||
Exists: resultSet,
|
|
||||||
Schema: schema,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *ResourceData) getObject(
|
|
||||||
k string,
|
|
||||||
parts []string,
|
|
||||||
schema map[string]*Schema,
|
|
||||||
source getSource) getResult {
|
|
||||||
if len(parts) > 0 {
|
|
||||||
// We're requesting a specific key in an object
|
|
||||||
key := parts[0]
|
|
||||||
parts = parts[1:]
|
|
||||||
s, ok := schema[key]
|
|
||||||
if !ok {
|
|
||||||
return getResultEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
if k != "" {
|
|
||||||
// If we're not at the root, then we need to append
|
|
||||||
// the key to get the full key path.
|
|
||||||
key = fmt.Sprintf("%s.%s", k, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return d.get(key, parts, s, source)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the entire object
|
|
||||||
result := make(map[string]interface{})
|
|
||||||
for field, _ := range schema {
|
|
||||||
result[field] = d.getObject(k, []string{field}, schema, source).Value
|
|
||||||
}
|
|
||||||
|
|
||||||
return getResult{
|
|
||||||
Value: result,
|
|
||||||
Exists: true,
|
|
||||||
Schema: &Schema{
|
|
||||||
Elem: schema,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *ResourceData) getList(
|
|
||||||
k string,
|
|
||||||
parts []string,
|
|
||||||
schema *Schema,
|
|
||||||
source getSource) getResult {
|
|
||||||
if len(parts) > 0 {
|
|
||||||
// We still have parts left over meaning we're accessing an
|
|
||||||
// element of this list.
|
|
||||||
idx := parts[0]
|
|
||||||
parts = parts[1:]
|
|
||||||
|
|
||||||
// Special case if we're accessing the count of the list
|
|
||||||
if idx == "#" {
|
|
||||||
schema := &Schema{Type: TypeInt}
|
|
||||||
return d.get(k+".#", parts, schema, source)
|
|
||||||
}
|
|
||||||
|
|
||||||
key := fmt.Sprintf("%s.%s", k, idx)
|
|
||||||
switch t := schema.Elem.(type) {
|
|
||||||
case *Resource:
|
|
||||||
return d.getObject(key, parts, t.Schema, source)
|
|
||||||
case *Schema:
|
|
||||||
return d.get(key, parts, t, source)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the entire list.
|
|
||||||
var result []interface{}
|
|
||||||
count := d.getList(k, []string{"#"}, schema, source)
|
|
||||||
if !count.Computed {
|
|
||||||
result = make([]interface{}, count.Value.(int))
|
|
||||||
for i, _ := range result {
|
|
||||||
is := strconv.FormatInt(int64(i), 10)
|
|
||||||
result[i] = d.getList(k, []string{is}, schema, source).Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getResult{
|
|
||||||
Value: result,
|
|
||||||
Computed: count.Computed,
|
|
||||||
Exists: count.Exists,
|
|
||||||
Schema: schema,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *ResourceData) getPrimitive(
|
|
||||||
k string,
|
|
||||||
parts []string,
|
|
||||||
schema *Schema,
|
|
||||||
source getSource) getResult {
|
|
||||||
var result string
|
|
||||||
var resultProcessed interface{}
|
|
||||||
var resultComputed, resultSet bool
|
|
||||||
flags := source & ^getSourceLevelMask
|
|
||||||
source = source & getSourceLevelMask
|
|
||||||
exact := flags&getSourceExact != 0
|
|
||||||
diff := flags&getSourceDiff != 0
|
|
||||||
|
|
||||||
if !exact || source == getSourceState {
|
|
||||||
if d.state != nil && source >= getSourceState {
|
|
||||||
result, resultSet = d.state.Attributes[k]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No exact check is needed here because config is always exact
|
|
||||||
if d.config != nil && source == getSourceConfig {
|
|
||||||
// For config, we always return the exact value
|
|
||||||
if v, ok := d.config.Get(k); ok {
|
|
||||||
if err := mapstructure.WeakDecode(v, &result); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resultSet = true
|
|
||||||
} else {
|
|
||||||
result = ""
|
|
||||||
resultSet = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it is computed, set that.
|
|
||||||
resultComputed = d.config.IsComputed(k)
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.diff != nil && diff {
|
|
||||||
attrD, ok := d.diff.Attributes[k]
|
|
||||||
if ok {
|
|
||||||
if !attrD.NewComputed {
|
|
||||||
result = attrD.New
|
|
||||||
if attrD.NewExtra != nil {
|
|
||||||
// If NewExtra != nil, then we have processed data as the New,
|
|
||||||
// so we store that but decode the unprocessed data into result
|
|
||||||
resultProcessed = result
|
|
||||||
|
|
||||||
err := mapstructure.WeakDecode(attrD.NewExtra, &result)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resultSet = true
|
|
||||||
} else {
|
|
||||||
result = ""
|
|
||||||
resultSet = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exact || source == getSourceSet {
|
|
||||||
if d.setMap != nil && source >= getSourceSet {
|
|
||||||
if v, ok := d.setMap[k]; ok {
|
|
||||||
result = v
|
|
||||||
resultSet = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !resultSet {
|
|
||||||
result = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultValue interface{}
|
|
||||||
switch schema.Type {
|
|
||||||
case TypeBool:
|
|
||||||
if result == "" {
|
|
||||||
resultValue = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
v, err := strconv.ParseBool(result)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resultValue = v
|
|
||||||
case TypeString:
|
|
||||||
// Use the value as-is. We just put this case here to be explicit.
|
|
||||||
resultValue = result
|
|
||||||
case TypeInt:
|
|
||||||
if result == "" {
|
|
||||||
resultValue = 0
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if resultComputed {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
v, err := strconv.ParseInt(result, 0, 0)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resultValue = int(v)
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
|
|
||||||
}
|
|
||||||
|
|
||||||
return getResult{
|
|
||||||
Value: resultValue,
|
|
||||||
ValueProcessed: resultProcessed,
|
|
||||||
Computed: resultComputed,
|
|
||||||
Exists: resultSet,
|
|
||||||
Schema: schema,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *ResourceData) set(
|
func (d *ResourceData) set(
|
||||||
k string,
|
k string,
|
||||||
parts []string,
|
parts []string,
|
||||||
|
@ -1195,7 +696,7 @@ func (d *ResourceData) stateList(
|
||||||
func (d *ResourceData) stateMap(
|
func (d *ResourceData) stateMap(
|
||||||
prefix string,
|
prefix string,
|
||||||
schema *Schema) map[string]string {
|
schema *Schema) map[string]string {
|
||||||
v := d.getMap(prefix, nil, schema, d.stateSource(prefix))
|
v := d.get(prefix, nil, schema, d.stateSource(prefix))
|
||||||
if !v.Exists {
|
if !v.Exists {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1391,7 +1391,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
Result *terraform.InstanceState
|
Result *terraform.InstanceState
|
||||||
Partial []string
|
Partial []string
|
||||||
}{
|
}{
|
||||||
// Basic primitive in diff
|
// #0 Basic primitive in diff
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"availability_zone": &Schema{
|
"availability_zone": &Schema{
|
||||||
|
@ -1421,7 +1421,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Basic primitive set override
|
// #1 Basic primitive set override
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"availability_zone": &Schema{
|
"availability_zone": &Schema{
|
||||||
|
@ -1455,6 +1455,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// #2
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"vpc": &Schema{
|
"vpc": &Schema{
|
||||||
|
@ -1478,7 +1479,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Basic primitive with StateFunc set
|
// #3 Basic primitive with StateFunc set
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"availability_zone": &Schema{
|
"availability_zone": &Schema{
|
||||||
|
@ -1508,7 +1509,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// List
|
// #4 List
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
|
@ -1547,7 +1548,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// List of resources
|
// #5 List of resources
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ingress": &Schema{
|
"ingress": &Schema{
|
||||||
|
@ -1597,7 +1598,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// List of maps
|
// #6 List of maps
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"config_vars": &Schema{
|
"config_vars": &Schema{
|
||||||
|
@ -1647,7 +1648,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// List of maps with removal in diff
|
// #7 List of maps with removal in diff
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"config_vars": &Schema{
|
"config_vars": &Schema{
|
||||||
|
@ -1687,7 +1688,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Basic state with other keys
|
// #8 Basic state with other keys
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"availability_zone": &Schema{
|
"availability_zone": &Schema{
|
||||||
|
@ -1724,7 +1725,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Sets
|
// #9 Sets
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
|
@ -1759,6 +1760,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// #10
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
|
@ -1789,6 +1791,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// #11
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
|
@ -1861,7 +1864,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
* PARTIAL STATES
|
* PARTIAL STATES
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Basic primitive
|
// #12 Basic primitive
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"availability_zone": &Schema{
|
"availability_zone": &Schema{
|
||||||
|
@ -1891,7 +1894,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// List
|
// #13 List
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
|
@ -1931,6 +1934,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// #14
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
|
@ -1965,7 +1969,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// List of resources
|
// #15 List of resources
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ingress": &Schema{
|
"ingress": &Schema{
|
||||||
|
@ -2016,7 +2020,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// List of maps
|
// #16 List of maps
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"config_vars": &Schema{
|
"config_vars": &Schema{
|
||||||
|
@ -2070,7 +2074,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Sets
|
// #17 Sets
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
|
@ -2113,6 +2117,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// #18
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
|
@ -2146,7 +2151,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Maps
|
// #19 Maps
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"tags": &Schema{
|
"tags": &Schema{
|
||||||
|
@ -2174,6 +2179,7 @@ func TestResourceDataState(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// #20
|
||||||
{
|
{
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"tags": &Schema{
|
"tags": &Schema{
|
||||||
|
|
Loading…
Reference in New Issue