mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-01 11:47:07 -06:00
c6d0333dc0
Fixes #12183 The fix is in flatmap for this but the entire issue is a bit more complex. Given a schema with a computed set, if you reference it like this: lookup(attr[0], "field") And "attr" contains a computed set within it, it would panic even though "field" is available. There were a couple avenues I could've taken to fix this: 1.) Any complex value containing any unknown value at any point is entirely unknown. 2.) Only the specific part of the complex value is unknown. I took route 2 so that the above works without any computed (since "name" is not computed but something else is). This may actually have an effect on other parts of Terraform configs, however those similar configs would've simply crashed previously so it shouldn't break any pre-existing configs.
122 lines
2.4 KiB
Go
122 lines
2.4 KiB
Go
package flatmap
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/hil"
|
|
)
|
|
|
|
// Expand takes a map and a key (prefix) and expands that value into
|
|
// a more complex structure. This is the reverse of the Flatten operation.
|
|
func Expand(m map[string]string, key string) interface{} {
|
|
// If the key is exactly a key in the map, just return it
|
|
if v, ok := m[key]; ok {
|
|
if v == "true" {
|
|
return true
|
|
} else if v == "false" {
|
|
return false
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
// Check if the key is an array, and if so, expand the array
|
|
if v, ok := m[key+".#"]; ok {
|
|
// If the count of the key is unknown, then just put the unknown
|
|
// value in the value itself. This will be detected by Terraform
|
|
// core later.
|
|
if v == hil.UnknownValue {
|
|
return v
|
|
}
|
|
|
|
return expandArray(m, key)
|
|
}
|
|
|
|
// Check if this is a prefix in the map
|
|
prefix := key + "."
|
|
for k, _ := range m {
|
|
if strings.HasPrefix(k, prefix) {
|
|
return expandMap(m, prefix)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func expandArray(m map[string]string, prefix string) []interface{} {
|
|
num, err := strconv.ParseInt(m[prefix+".#"], 0, 0)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// The Schema "Set" type stores its values in an array format, but using
|
|
// numeric hash values instead of ordinal keys. Take the set of keys
|
|
// regardless of value, and expand them in numeric order.
|
|
// See GH-11042 for more details.
|
|
keySet := map[int]bool{}
|
|
for k := range m {
|
|
if !strings.HasPrefix(k, prefix+".") {
|
|
continue
|
|
}
|
|
|
|
key := k[len(prefix)+1:]
|
|
idx := strings.Index(key, ".")
|
|
if idx != -1 {
|
|
key = key[:idx]
|
|
}
|
|
|
|
// skip the count value
|
|
if key == "#" {
|
|
continue
|
|
}
|
|
|
|
k, err := strconv.Atoi(key)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
keySet[int(k)] = true
|
|
}
|
|
|
|
keysList := make([]int, 0, num)
|
|
for key := range keySet {
|
|
keysList = append(keysList, key)
|
|
}
|
|
sort.Ints(keysList)
|
|
|
|
result := make([]interface{}, num)
|
|
for i, key := range keysList {
|
|
result[i] = Expand(m, fmt.Sprintf("%s.%d", prefix, key))
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func expandMap(m map[string]string, prefix string) map[string]interface{} {
|
|
result := make(map[string]interface{})
|
|
for k, _ := range m {
|
|
if !strings.HasPrefix(k, prefix) {
|
|
continue
|
|
}
|
|
|
|
key := k[len(prefix):]
|
|
idx := strings.Index(key, ".")
|
|
if idx != -1 {
|
|
key = key[:idx]
|
|
}
|
|
if _, ok := result[key]; ok {
|
|
continue
|
|
}
|
|
|
|
// skip the map count value
|
|
if key == "%" {
|
|
continue
|
|
}
|
|
result[key] = Expand(m, k[:len(prefix)+len(key)])
|
|
}
|
|
|
|
return result
|
|
}
|