本文整理汇总了Golang中github.com/hashicorp/hil.InterfaceToVariable函数的典型用法代码示例。如果您正苦于以下问题:Golang InterfaceToVariable函数的具体用法?Golang InterfaceToVariable怎么用?Golang InterfaceToVariable使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了InterfaceToVariable函数的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Golang代码示例。
示例1: valueUserVar
func (i *Interpolater) valueUserVar(
scope *InterpolationScope,
n string,
v *config.UserVariable,
result map[string]ast.Variable) error {
i.VariableValuesLock.Lock()
defer i.VariableValuesLock.Unlock()
val, ok := i.VariableValues[v.Name]
if ok {
varValue, err := hil.InterfaceToVariable(val)
if err != nil {
return fmt.Errorf("cannot convert %s value %q to an ast.Variable for interpolation: %s",
v.Name, val, err)
}
result[n] = varValue
return nil
}
if _, ok := result[n]; !ok && i.Operation == walkValidate {
result[n] = unknownVariable()
return nil
}
// Look up if we have any variables with this prefix because
// those are map overrides. Include those.
for k, val := range i.VariableValues {
if strings.HasPrefix(k, v.Name+".") {
keyComponents := strings.Split(k, ".")
overrideKey := keyComponents[len(keyComponents)-1]
mapInterface, ok := result["var."+v.Name]
if !ok {
return fmt.Errorf("override for non-existent variable: %s", v.Name)
}
mapVariable := mapInterface.Value.(map[string]ast.Variable)
varValue, err := hil.InterfaceToVariable(val)
if err != nil {
return fmt.Errorf("cannot convert %s value %q to an ast.Variable for interpolation: %s",
v.Name, val, err)
}
mapVariable[overrideKey] = varValue
}
}
return nil
}
示例2: interpolateComplexTypeAttribute
func (i *Interpolater) interpolateComplexTypeAttribute(
resourceID string,
attributes map[string]string) (ast.Variable, error) {
attr := attributes[resourceID+".#"]
log.Printf("[DEBUG] Interpolating computed complex type attribute %s (%s)",
resourceID, attr)
// In Terraform's internal dotted representation of list-like attributes, the
// ".#" count field is marked as unknown to indicate "this whole list is
// unknown". We must honor that meaning here so computed references can be
// treated properly during the plan phase.
if attr == config.UnknownVariableValue {
return unknownVariable(), nil
}
// At this stage we don't know whether the item is a list or a map, so we
// examine the keys to see whether they are all numeric.
var numericKeys []string
var allKeys []string
numberedListKey := regexp.MustCompile("^" + resourceID + "\\.[0-9]+$")
otherListKey := regexp.MustCompile("^" + resourceID + "\\.([^#]+)$")
for id, _ := range attributes {
if numberedListKey.MatchString(id) {
numericKeys = append(numericKeys, id)
}
if submatches := otherListKey.FindAllStringSubmatch(id, -1); len(submatches) > 0 {
allKeys = append(allKeys, submatches[0][1])
}
}
if len(numericKeys) == len(allKeys) {
// This is a list
var members []string
for _, key := range numericKeys {
members = append(members, attributes[key])
}
sort.Strings(members)
return hil.InterfaceToVariable(members)
} else {
// This is a map
members := make(map[string]interface{})
for _, key := range allKeys {
members[key] = attributes[resourceID+"."+key]
}
return hil.InterfaceToVariable(members)
}
}
示例3: interpolationFuncValues
// interpolationFuncValues implements the "values" function that yields a list of
// keys of map types within a Terraform configuration.
func interpolationFuncValues(vs map[string]ast.Variable) ast.Function {
return ast.Function{
ArgTypes: []ast.Type{ast.TypeMap},
ReturnType: ast.TypeList,
Callback: func(args []interface{}) (interface{}, error) {
mapVar := args[0].(map[string]ast.Variable)
keys := make([]string, 0)
for k, _ := range mapVar {
keys = append(keys, k)
}
sort.Strings(keys)
values := make([]string, len(keys))
for index, key := range keys {
if value, ok := mapVar[key].Value.(string); ok {
values[index] = value
} else {
return "", fmt.Errorf("values(): %q has element with bad type %s",
key, mapVar[key].Type)
}
}
variable, err := hil.InterfaceToVariable(values)
if err != nil {
return nil, err
}
return variable.Value, nil
},
}
}
示例4: Values
// Values returns the values for all the variables in the given map.
func (i *Interpolater) Values(
scope *InterpolationScope,
vars map[string]config.InterpolatedVariable) (map[string]ast.Variable, error) {
if scope == nil {
scope = &InterpolationScope{}
}
result := make(map[string]ast.Variable, len(vars))
// Copy the default variables
if i.Module != nil && scope != nil {
mod := i.Module
if len(scope.Path) > 1 {
mod = i.Module.Child(scope.Path[1:])
}
for _, v := range mod.Config().Variables {
// Set default variables
if v.Default == nil {
continue
}
n := fmt.Sprintf("var.%s", v.Name)
variable, err := hil.InterfaceToVariable(v.Default)
if err != nil {
return nil, fmt.Errorf("invalid default map value for %s: %v", v.Name, v.Default)
}
result[n] = variable
}
}
for n, rawV := range vars {
var err error
switch v := rawV.(type) {
case *config.CountVariable:
err = i.valueCountVar(scope, n, v, result)
case *config.ModuleVariable:
err = i.valueModuleVar(scope, n, v, result)
case *config.PathVariable:
err = i.valuePathVar(scope, n, v, result)
case *config.ResourceVariable:
err = i.valueResourceVar(scope, n, v, result)
case *config.SelfVariable:
err = i.valueSelfVar(scope, n, v, result)
case *config.SimpleVariable:
err = i.valueSimpleVar(scope, n, v, result)
case *config.UserVariable:
err = i.valueUserVar(scope, n, v, result)
default:
err = fmt.Errorf("%s: unknown variable type: %T", n, rawV)
}
if err != nil {
return nil, err
}
}
return result, nil
}
示例5: valueModuleVar
func (i *Interpolater) valueModuleVar(
scope *InterpolationScope,
n string,
v *config.ModuleVariable,
result map[string]ast.Variable) error {
// Build the path to the child module we want
path := make([]string, len(scope.Path), len(scope.Path)+1)
copy(path, scope.Path)
path = append(path, v.Name)
// Grab the lock so that if other interpolations are running or
// state is being modified, we'll be safe.
i.StateLock.RLock()
defer i.StateLock.RUnlock()
// Get the module where we're looking for the value
mod := i.State.ModuleByPath(path)
if mod == nil {
// If the module doesn't exist, then we can return an empty string.
// This happens usually only in Refresh() when we haven't populated
// a state. During validation, we semantically verify that all
// modules reference other modules, and graph ordering should
// ensure that the module is in the state, so if we reach this
// point otherwise it really is a panic.
result[n] = unknownVariable()
// During apply this is always an error
if i.Operation == walkApply {
return fmt.Errorf(
"Couldn't find module %q for var: %s",
v.Name, v.FullKey())
}
} else {
// Get the value from the outputs
if outputState, ok := mod.Outputs[v.Field]; ok {
output, err := hil.InterfaceToVariable(outputState.Value)
if err != nil {
return err
}
result[n] = output
} else {
// Same reasons as the comment above.
result[n] = unknownVariable()
// During apply this is always an error
if i.Operation == walkApply {
return fmt.Errorf(
"Couldn't find output %q for module var: %s",
v.Field, v.FullKey())
}
}
}
return nil
}
示例6: interpolateComplexTypeAttribute
func (i *Interpolater) interpolateComplexTypeAttribute(
resourceID string,
attributes map[string]string) (ast.Variable, error) {
// We can now distinguish between lists and maps in state by the count field:
// - lists (and by extension, sets) use the traditional .# notation
// - maps use the newer .% notation
// Consequently here we can decide how to deal with the keys appropriately
// based on whether the type is a map of list.
if lengthAttr, isList := attributes[resourceID+".#"]; isList {
log.Printf("[DEBUG] Interpolating computed list element attribute %s (%s)",
resourceID, lengthAttr)
// In Terraform's internal dotted representation of list-like attributes, the
// ".#" count field is marked as unknown to indicate "this whole list is
// unknown". We must honor that meaning here so computed references can be
// treated properly during the plan phase.
if lengthAttr == config.UnknownVariableValue {
return unknownVariable(), nil
}
expanded := flatmap.Expand(attributes, resourceID)
return hil.InterfaceToVariable(expanded)
}
if lengthAttr, isMap := attributes[resourceID+".%"]; isMap {
log.Printf("[DEBUG] Interpolating computed map element attribute %s (%s)",
resourceID, lengthAttr)
// In Terraform's internal dotted representation of map attributes, the
// ".%" count field is marked as unknown to indicate "this whole list is
// unknown". We must honor that meaning here so computed references can be
// treated properly during the plan phase.
if lengthAttr == config.UnknownVariableValue {
return unknownVariable(), nil
}
expanded := flatmap.Expand(attributes, resourceID)
return hil.InterfaceToVariable(expanded)
}
return ast.Variable{}, fmt.Errorf("No complex type %s found", resourceID)
}
示例7: interpolationFuncMap
// interpolationFuncMap creates a map from the parameters passed
// to it.
func interpolationFuncMap() ast.Function {
return ast.Function{
ArgTypes: []ast.Type{},
ReturnType: ast.TypeMap,
Variadic: true,
VariadicType: ast.TypeAny,
Callback: func(args []interface{}) (interface{}, error) {
outputMap := make(map[string]ast.Variable)
if len(args)%2 != 0 {
return nil, fmt.Errorf("requires an even number of arguments, got %d", len(args))
}
var firstType *ast.Type
for i := 0; i < len(args); i += 2 {
key, ok := args[i].(string)
if !ok {
return nil, fmt.Errorf("argument %d represents a key, so it must be a string", i+1)
}
val := args[i+1]
variable, err := hil.InterfaceToVariable(val)
if err != nil {
return nil, err
}
// Enforce map type homogeneity
if firstType == nil {
firstType = &variable.Type
} else if variable.Type != *firstType {
return nil, fmt.Errorf("all map values must have the same type, got %s then %s", firstType.Printable(), variable.Type.Printable())
}
// Check for duplicate keys
if _, ok := outputMap[key]; ok {
return nil, fmt.Errorf("argument %d is a duplicate key: %q", i+1, key)
}
outputMap[key] = variable
}
return outputMap, nil
},
}
}
示例8: interfaceToVariableSwallowError
func interfaceToVariableSwallowError(input interface{}) ast.Variable {
variable, _ := hil.InterfaceToVariable(input)
return variable
}
示例9: TestResourceConfigGetRaw
func TestResourceConfigGetRaw(t *testing.T) {
cases := []struct {
Config map[string]interface{}
Vars map[string]interface{}
Key string
Value interface{}
}{
// Referencing a list-of-maps variable doesn't work from GetRaw.
// The ConfigFieldReader currently catches this case and looks up the
// variable in the config.
{
Vars: map[string]interface{}{
"maplist": []interface{}{
map[string]interface{}{
"key": "a",
},
map[string]interface{}{
"key": "b",
},
},
},
Config: map[string]interface{}{
"maplist": "${var.maplist}",
},
Key: "maplist.0",
Value: nil,
},
// Reference a map-of-lists variable.
// The ConfigFieldReader currently catches this case and looks up the
// variable in the config.
{
Vars: map[string]interface{}{
"listmap": map[string]interface{}{
"key1": []interface{}{"a", "b"},
"key2": []interface{}{"c", "d"},
},
},
Config: map[string]interface{}{
"listmap": "${var.listmap}",
},
Key: "listmap.key1",
Value: nil,
},
}
for i, tc := range cases {
var rawC *config.RawConfig
if tc.Config != nil {
var err error
rawC, err = config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
}
if tc.Vars != nil {
vs := make(map[string]ast.Variable)
for k, v := range tc.Vars {
hilVar, err := hil.InterfaceToVariable(v)
if err != nil {
t.Fatalf("%#v to var: %s", v, err)
}
vs["var."+k] = hilVar
}
if err := rawC.Interpolate(vs); err != nil {
t.Fatalf("err: %s", err)
}
}
rc := NewResourceConfig(rawC)
rc.interpolateForce()
// Test getting a key
t.Run(fmt.Sprintf("get-%d", i), func(t *testing.T) {
v, ok := rc.GetRaw(tc.Key)
if ok && v == nil {
t.Fatal("(nil, true) returned from GetRaw")
}
if !reflect.DeepEqual(v, tc.Value) {
t.Fatalf("%d bad: %#v", i, v)
}
})
}
}
示例10: interpolateComplexTypeAttribute
func (i *Interpolater) interpolateComplexTypeAttribute(
resourceID string,
attributes map[string]string) (ast.Variable, error) {
// We can now distinguish between lists and maps in state by the count field:
// - lists (and by extension, sets) use the traditional .# notation
// - maps use the newer .% notation
// Consequently here we can decide how to deal with the keys appropriately
// based on whether the type is a map of list.
if lengthAttr, isList := attributes[resourceID+".#"]; isList {
log.Printf("[DEBUG] Interpolating computed list element attribute %s (%s)",
resourceID, lengthAttr)
// In Terraform's internal dotted representation of list-like attributes, the
// ".#" count field is marked as unknown to indicate "this whole list is
// unknown". We must honor that meaning here so computed references can be
// treated properly during the plan phase.
if lengthAttr == config.UnknownVariableValue {
return unknownVariable(), nil
}
keys := make([]string, 0)
listElementKey := regexp.MustCompile("^" + resourceID + "\\.[0-9]+$")
for id, _ := range attributes {
if listElementKey.MatchString(id) {
keys = append(keys, id)
}
}
sort.Strings(keys)
var members []string
for _, key := range keys {
members = append(members, attributes[key])
}
return hil.InterfaceToVariable(members)
}
if lengthAttr, isMap := attributes[resourceID+".%"]; isMap {
log.Printf("[DEBUG] Interpolating computed map element attribute %s (%s)",
resourceID, lengthAttr)
// In Terraform's internal dotted representation of map attributes, the
// ".%" count field is marked as unknown to indicate "this whole list is
// unknown". We must honor that meaning here so computed references can be
// treated properly during the plan phase.
if lengthAttr == config.UnknownVariableValue {
return unknownVariable(), nil
}
resourceFlatMap := make(map[string]string)
mapElementKey := regexp.MustCompile("^" + resourceID + "\\.([^%]+)$")
for id, val := range attributes {
if mapElementKey.MatchString(id) {
resourceFlatMap[id] = val
}
}
expanded := flatmap.Expand(resourceFlatMap, resourceID)
return hil.InterfaceToVariable(expanded)
}
return ast.Variable{}, fmt.Errorf("No complex type %s found", resourceID)
}
示例11: computeResourceMultiVariable
//.........这里部分代码省略.........
// Get the information about this resource variable, and verify
// that it exists and such.
module, cr, err := i.resourceVariableInfo(scope, v)
if err != nil {
return nil, err
}
// Get the count so we know how many to iterate over
count, err := cr.Count()
if err != nil {
return nil, fmt.Errorf(
"Error reading %s count: %s",
v.ResourceId(),
err)
}
// If we have no module in the state yet or count, return empty
if module == nil || len(module.Resources) == 0 || count == 0 {
return &ast.Variable{Type: ast.TypeList, Value: []ast.Variable{}}, nil
}
var values []string
for j := 0; j < count; j++ {
id := fmt.Sprintf("%s.%d", v.ResourceId(), j)
// If we're dealing with only a single resource, then the
// ID doesn't have a trailing index.
if count == 1 {
id = v.ResourceId()
}
r, ok := module.Resources[id]
if !ok {
continue
}
if r.Primary == nil {
continue
}
if singleAttr, ok := r.Primary.Attributes[v.Field]; ok {
if singleAttr == config.UnknownVariableValue {
return &unknownVariable, nil
}
values = append(values, singleAttr)
continue
}
// computed list attribute
_, ok = r.Primary.Attributes[v.Field+".#"]
if !ok {
continue
}
multiAttr, err := i.interpolateComplexTypeAttribute(v.Field, r.Primary.Attributes)
if err != nil {
return nil, err
}
if multiAttr == unknownVariable {
return &ast.Variable{Type: ast.TypeString, Value: ""}, nil
}
for _, element := range multiAttr.Value.([]ast.Variable) {
strVal := element.Value.(string)
if strVal == config.UnknownVariableValue {
return &unknownVariable, nil
}
values = append(values, strVal)
}
}
if len(values) == 0 {
// If the operation is refresh, it isn't an error for a value to
// be unknown. Instead, we return that the value is computed so
// that the graph can continue to refresh other nodes. It doesn't
// matter because the config isn't interpolated anyways.
//
// For a Destroy, we're also fine with computed values, since our goal is
// only to get destroy nodes for existing resources.
//
// For an input walk, computed values are okay to return because we're only
// looking for missing variables to prompt the user for.
if i.Operation == walkRefresh || i.Operation == walkPlanDestroy || i.Operation == walkDestroy || i.Operation == walkInput {
return &unknownVariable, nil
}
return nil, fmt.Errorf(
"Resource '%s' does not have attribute '%s' "+
"for variable '%s'",
v.ResourceId(),
v.Field,
v.FullKey())
}
variable, err := hil.InterfaceToVariable(values)
return &variable, err
}
示例12: TestResourceConfigIsComputed
//.........这里部分代码省略.........
},
Vars: map[string]interface{}{
"foo": []string{
"a",
"b",
},
},
Key: "foo",
Result: false,
},
/*
{
Name: "set count with computed elements",
Config: map[string]interface{}{
"foo": "${var.foo}",
},
Vars: map[string]interface{}{
"foo": []string{
"a",
unknownValue(),
},
},
Key: "foo.#",
Result: true,
},
*/
{
Name: "set count with computed elements",
Config: map[string]interface{}{
"foo": []interface{}{"${var.foo}"},
},
Vars: map[string]interface{}{
"foo": []string{
"a",
unknownValue(),
},
},
Key: "foo.#",
Result: true,
},
{
Name: "nested set with computed elements",
Config: map[string]interface{}{
"route": []map[string]interface{}{
map[string]interface{}{
"index": "1",
"gateway": []interface{}{"${var.foo}"},
},
},
},
Vars: map[string]interface{}{
"foo": unknownValue(),
},
Key: "route.0.gateway",
Result: true,
},
}
for i, tc := range cases {
t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
var rawC *config.RawConfig
if tc.Config != nil {
var err error
rawC, err = config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
}
if tc.Vars != nil {
vs := make(map[string]ast.Variable)
for k, v := range tc.Vars {
hilVar, err := hil.InterfaceToVariable(v)
if err != nil {
t.Fatalf("%#v to var: %s", v, err)
}
vs["var."+k] = hilVar
}
if err := rawC.Interpolate(vs); err != nil {
t.Fatalf("err: %s", err)
}
}
rc := NewResourceConfig(rawC)
rc.interpolateForce()
t.Logf("Config: %#v", rc)
actual := rc.IsComputed(tc.Key)
if actual != tc.Result {
t.Fatalf("bad: %#v", actual)
}
})
}
}
示例13: computeResourceMultiVariable
//.........这里部分代码省略.........
// Get the information about this resource variable, and verify
// that it exists and such.
module, cr, err := i.resourceVariableInfo(scope, v)
if err != nil {
return nil, err
}
// Get the keys for all the resources that are created for this resource
countMax, err := i.resourceCountMax(module, cr, v)
if err != nil {
return nil, err
}
// If count is zero, we return an empty list
if countMax == 0 {
return &ast.Variable{Type: ast.TypeList, Value: []ast.Variable{}}, nil
}
// If we have no module in the state yet or count, return unknown
if module == nil || len(module.Resources) == 0 {
return &unknownVariable, nil
}
var values []interface{}
for idx := 0; idx < countMax; idx++ {
id := fmt.Sprintf("%s.%d", v.ResourceId(), idx)
// ID doesn't have a trailing index. We try both here, but if a value
// without a trailing index is found we prefer that. This choice
// is for legacy reasons: older versions of TF preferred it.
if id == v.ResourceId()+".0" {
potential := v.ResourceId()
if _, ok := module.Resources[potential]; ok {
id = potential
}
}
r, ok := module.Resources[id]
if !ok {
continue
}
if r.Primary == nil {
continue
}
if singleAttr, ok := r.Primary.Attributes[v.Field]; ok {
if singleAttr == config.UnknownVariableValue {
return &unknownVariable, nil
}
values = append(values, singleAttr)
continue
}
// computed list or map attribute
_, isList := r.Primary.Attributes[v.Field+".#"]
_, isMap := r.Primary.Attributes[v.Field+".%"]
if !(isList || isMap) {
continue
}
multiAttr, err := i.interpolateComplexTypeAttribute(v.Field, r.Primary.Attributes)
if err != nil {
return nil, err
}
if multiAttr == unknownVariable {
return &unknownVariable, nil
}
values = append(values, multiAttr)
}
if len(values) == 0 {
// If the operation is refresh, it isn't an error for a value to
// be unknown. Instead, we return that the value is computed so
// that the graph can continue to refresh other nodes. It doesn't
// matter because the config isn't interpolated anyways.
//
// For a Destroy, we're also fine with computed values, since our goal is
// only to get destroy nodes for existing resources.
//
// For an input walk, computed values are okay to return because we're only
// looking for missing variables to prompt the user for.
if i.Operation == walkRefresh || i.Operation == walkPlanDestroy || i.Operation == walkDestroy || i.Operation == walkInput {
return &unknownVariable, nil
}
return nil, fmt.Errorf(
"Resource '%s' does not have attribute '%s' "+
"for variable '%s'",
v.ResourceId(),
v.Field,
v.FullKey())
}
variable, err := hil.InterfaceToVariable(values)
return &variable, err
}
示例14: TestResourceConfigGet
//.........这里部分代码省略.........
},
},
},
},
Key: "mapname.0.listkey.0.key",
Value: 3,
},
// FIXME: this is ambiguous, and matches the nested map
// leaving here to catch this behaviour if it changes.
{
Config: map[string]interface{}{
"mapname": []map[string]interface{}{
map[string]interface{}{
"key.name": 1,
"key.name.0": 2,
"key": map[string]interface{}{"name": 3},
},
},
},
Key: "mapname.0.key.name",
Value: 3,
},
/*
// TODO: can't access this nested list at all.
// FIXME: key with name matching substring of nested list can panic
{
Config: map[string]interface{}{
"mapname": []map[string]interface{}{
map[string]interface{}{
"key.name": []map[string]interface{}{
{"subkey": 1},
},
"key": 3,
},
},
},
Key: "mapname.0.key.name.0.subkey",
Value: 3,
},
*/
}
for i, tc := range cases {
var rawC *config.RawConfig
if tc.Config != nil {
var err error
rawC, err = config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
}
if tc.Vars != nil {
vs := make(map[string]ast.Variable)
for k, v := range tc.Vars {
hilVar, err := hil.InterfaceToVariable(v)
if err != nil {
t.Fatalf("%#v to var: %s", v, err)
}
vs["var."+k] = hilVar
}
if err := rawC.Interpolate(vs); err != nil {
t.Fatalf("err: %s", err)
}
}
rc := NewResourceConfig(rawC)
rc.interpolateForce()
// Test getting a key
t.Run(fmt.Sprintf("get-%d", i), func(t *testing.T) {
v, _ := rc.Get(tc.Key)
if !reflect.DeepEqual(v, tc.Value) {
t.Fatalf("%d bad: %#v", i, v)
}
})
// If we have vars, we don't test copying
if len(tc.Vars) > 0 {
continue
}
// Test copying and equality
t.Run(fmt.Sprintf("copy-and-equal-%d", i), func(t *testing.T) {
copy := rc.DeepCopy()
if !reflect.DeepEqual(copy, rc) {
t.Fatalf("bad:\n\n%#v\n\n%#v", copy, rc)
}
if !copy.Equal(rc) {
t.Fatalf("copy != rc:\n\n%#v\n\n%#v", copy, rc)
}
if !rc.Equal(copy) {
t.Fatalf("rc != copy:\n\n%#v\n\n%#v", copy, rc)
}
})
}
}
示例15: computeResourceVariable
func (i *Interpolater) computeResourceVariable(
scope *InterpolationScope,
v *config.ResourceVariable) (*ast.Variable, error) {
id := v.ResourceId()
if v.Multi {
id = fmt.Sprintf("%s.%d", id, v.Index)
}
i.StateLock.RLock()
defer i.StateLock.RUnlock()
unknownVariable := unknownVariable()
// These variables must be declared early because of the use of GOTO
var isList bool
var isMap bool
// Get the information about this resource variable, and verify
// that it exists and such.
module, cr, err := i.resourceVariableInfo(scope, v)
if err != nil {
return nil, err
}
// If we're requesting "count" its a special variable that we grab
// directly from the config itself.
if v.Field == "count" {
var count int
if cr != nil {
count, err = cr.Count()
} else {
count, err = i.resourceCountMax(module, cr, v)
}
if err != nil {
return nil, fmt.Errorf(
"Error reading %s count: %s",
v.ResourceId(),
err)
}
return &ast.Variable{Type: ast.TypeInt, Value: count}, nil
}
// Get the resource out from the state. We know the state exists
// at this point and if there is a state, we expect there to be a
// resource with the given name.
var r *ResourceState
if module != nil && len(module.Resources) > 0 {
var ok bool
r, ok = module.Resources[id]
if !ok && v.Multi && v.Index == 0 {
r, ok = module.Resources[v.ResourceId()]
}
if !ok {
r = nil
}
}
if r == nil || r.Primary == nil {
if i.Operation == walkApply || i.Operation == walkPlan {
return nil, fmt.Errorf(
"Resource '%s' not found for variable '%s'",
v.ResourceId(),
v.FullKey())
}
// If we have no module in the state yet or count, return empty.
// NOTE(@mitchellh): I actually don't know why this is here. During
// a refactor I kept this here to maintain the same behavior, but
// I'm not sure why its here.
if module == nil || len(module.Resources) == 0 {
return nil, nil
}
goto MISSING
}
if attr, ok := r.Primary.Attributes[v.Field]; ok {
v, err := hil.InterfaceToVariable(attr)
return &v, err
}
// computed list or map attribute
_, isList = r.Primary.Attributes[v.Field+".#"]
_, isMap = r.Primary.Attributes[v.Field+".%"]
if isList || isMap {
variable, err := i.interpolateComplexTypeAttribute(v.Field, r.Primary.Attributes)
return &variable, err
}
// At apply time, we can't do the "maybe has it" check below
// that we need for plans since parent elements might be computed.
// Therefore, it is an error and we're missing the key.
//
// TODO: test by creating a state and configuration that is referencing
// a non-existent variable "foo.bar" where the state only has "foo"
// and verify plan works, but apply doesn't.
if i.Operation == walkApply || i.Operation == walkDestroy {
goto MISSING
}
//.........这里部分代码省略.........