github.com/anfernee/terraform@v0.6.16-0.20160430000239-06e5085a92f2/terraform/eval_variable.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/hashicorp/errwrap" 8 "github.com/hashicorp/terraform/config" 9 "github.com/hashicorp/terraform/config/module" 10 "github.com/mitchellh/mapstructure" 11 ) 12 13 // EvalTypeCheckVariable is an EvalNode which ensures that the variable 14 // values which are assigned as inputs to a module (including the root) 15 // match the types which are either declared for the variables explicitly 16 // or inferred from the default values. 17 // 18 // In order to achieve this three things are required: 19 // - a map of the proposed variable values 20 // - the configuration tree of the module in which the variable is 21 // declared 22 // - the path to the module (so we know which part of the tree to 23 // compare the values against). 24 // 25 // Currently since the type system is simple, we currently do not make 26 // use of the values since it is only valid to pass string values. The 27 // structure is in place for extension of the type system, however. 28 type EvalTypeCheckVariable struct { 29 Variables map[string]string 30 ModulePath []string 31 ModuleTree *module.Tree 32 } 33 34 func (n *EvalTypeCheckVariable) Eval(ctx EvalContext) (interface{}, error) { 35 currentTree := n.ModuleTree 36 for _, pathComponent := range n.ModulePath[1:] { 37 currentTree = currentTree.Children()[pathComponent] 38 } 39 targetConfig := currentTree.Config() 40 41 prototypes := make(map[string]config.VariableType) 42 for _, variable := range targetConfig.Variables { 43 prototypes[variable.Name] = variable.Type() 44 } 45 46 for name, declaredType := range prototypes { 47 // This is only necessary when we _actually_ check. It is left as a reminder 48 // that at the current time we are dealing with a type system consisting only 49 // of strings and maps - where the only valid inter-module variable type is 50 // string. 51 _, ok := n.Variables[name] 52 if !ok { 53 // This means the default value should be used as no overriding value 54 // has been set. Therefore we should continue as no check is necessary. 55 continue 56 } 57 58 switch declaredType { 59 case config.VariableTypeString: 60 // This will need actual verification once we aren't dealing with 61 // a map[string]string but this is sufficient for now. 62 continue 63 default: 64 // Only display a module if we are not in the root module 65 modulePathDescription := fmt.Sprintf(" in module %s", strings.Join(n.ModulePath[1:], ".")) 66 if len(n.ModulePath) == 1 { 67 modulePathDescription = "" 68 } 69 // This will need the actual type substituting when we have more than 70 // just strings and maps. 71 return nil, fmt.Errorf("variable %s%s should be type %s, got type string", 72 name, modulePathDescription, declaredType.Printable()) 73 } 74 } 75 76 return nil, nil 77 } 78 79 // EvalSetVariables is an EvalNode implementation that sets the variables 80 // explicitly for interpolation later. 81 type EvalSetVariables struct { 82 Module *string 83 Variables map[string]string 84 } 85 86 // TODO: test 87 func (n *EvalSetVariables) Eval(ctx EvalContext) (interface{}, error) { 88 ctx.SetVariables(*n.Module, n.Variables) 89 return nil, nil 90 } 91 92 // EvalVariableBlock is an EvalNode implementation that evaluates the 93 // given configuration, and uses the final values as a way to set the 94 // mapping. 95 type EvalVariableBlock struct { 96 Config **ResourceConfig 97 Variables map[string]string 98 } 99 100 // TODO: test 101 func (n *EvalVariableBlock) Eval(ctx EvalContext) (interface{}, error) { 102 // Clear out the existing mapping 103 for k, _ := range n.Variables { 104 delete(n.Variables, k) 105 } 106 107 // Get our configuration 108 rc := *n.Config 109 for k, v := range rc.Config { 110 var vStr string 111 if err := mapstructure.WeakDecode(v, &vStr); err != nil { 112 return nil, errwrap.Wrapf(fmt.Sprintf( 113 "%s: error reading value: {{err}}", k), err) 114 } 115 116 n.Variables[k] = vStr 117 } 118 for k, _ := range rc.Raw { 119 if _, ok := n.Variables[k]; !ok { 120 n.Variables[k] = config.UnknownVariableValue 121 } 122 } 123 124 return nil, nil 125 }