github.com/ewbankkit/terraform@v0.7.7/terraform/variables.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strings"
     7  
     8  	"github.com/hashicorp/terraform/config"
     9  	"github.com/hashicorp/terraform/config/module"
    10  )
    11  
    12  // Variables returns the fully loaded set of variables to use with
    13  // ContextOpts and NewContext, loading any additional variables from
    14  // the environment or any other sources.
    15  //
    16  // The given module tree doesn't need to be loaded.
    17  func Variables(
    18  	m *module.Tree,
    19  	override map[string]interface{}) (map[string]interface{}, error) {
    20  	result := make(map[string]interface{})
    21  
    22  	// Variables are loaded in the following sequence. Each additional step
    23  	// will override conflicting variable keys from prior steps:
    24  	//
    25  	//   * Take default values from config
    26  	//   * Take values from TF_VAR_x env vars
    27  	//   * Take values specified in the "override" param which is usually
    28  	//     from -var, -var-file, etc.
    29  	//
    30  
    31  	// First load from the config
    32  	for _, v := range m.Config().Variables {
    33  		// If the var has no default, ignore
    34  		if v.Default == nil {
    35  			continue
    36  		}
    37  
    38  		// If the type isn't a string, we use it as-is since it is a rich type
    39  		if v.Type() != config.VariableTypeString {
    40  			result[v.Name] = v.Default
    41  			continue
    42  		}
    43  
    44  		// v.Default has already been parsed as HCL but it may be an int type
    45  		switch typedDefault := v.Default.(type) {
    46  		case string:
    47  			if typedDefault == "" {
    48  				continue
    49  			}
    50  			result[v.Name] = typedDefault
    51  		case int, int64:
    52  			result[v.Name] = fmt.Sprintf("%d", typedDefault)
    53  		case float32, float64:
    54  			result[v.Name] = fmt.Sprintf("%f", typedDefault)
    55  		case bool:
    56  			result[v.Name] = fmt.Sprintf("%t", typedDefault)
    57  		default:
    58  			panic(fmt.Sprintf(
    59  				"Unknown default var type: %T\n\n"+
    60  					"THIS IS A BUG. Please report it.",
    61  				v.Default))
    62  		}
    63  	}
    64  
    65  	// Load from env vars
    66  	for _, v := range os.Environ() {
    67  		if !strings.HasPrefix(v, VarEnvPrefix) {
    68  			continue
    69  		}
    70  
    71  		// Strip off the prefix and get the value after the first "="
    72  		idx := strings.Index(v, "=")
    73  		k := v[len(VarEnvPrefix):idx]
    74  		v = v[idx+1:]
    75  
    76  		// Override the configuration-default values. Note that *not* finding the variable
    77  		// in configuration is OK, as we don't want to preclude people from having multiple
    78  		// sets of TF_VAR_whatever in their environment even if it is a little weird.
    79  		for _, schema := range m.Config().Variables {
    80  			if schema.Name != k {
    81  				continue
    82  			}
    83  
    84  			varType := schema.Type()
    85  			varVal, err := parseVariableAsHCL(k, v, varType)
    86  			if err != nil {
    87  				return nil, err
    88  			}
    89  
    90  			switch varType {
    91  			case config.VariableTypeMap:
    92  				varSetMap(result, k, varVal)
    93  			default:
    94  				result[k] = varVal
    95  			}
    96  		}
    97  	}
    98  
    99  	// Load from overrides
   100  	for k, v := range override {
   101  		for _, schema := range m.Config().Variables {
   102  			if schema.Name != k {
   103  				continue
   104  			}
   105  
   106  			switch schema.Type() {
   107  			case config.VariableTypeMap:
   108  				varSetMap(result, k, v)
   109  			default:
   110  				result[k] = v
   111  			}
   112  		}
   113  	}
   114  
   115  	return result, nil
   116  }
   117  
   118  // varSetMap sets or merges the map in "v" with the key "k" in the
   119  // "current" set of variables. This is just a private function to remove
   120  // duplicate logic in Variables
   121  func varSetMap(current map[string]interface{}, k string, v interface{}) {
   122  	existing, ok := current[k]
   123  	if !ok {
   124  		current[k] = v
   125  		return
   126  	}
   127  
   128  	existingMap, ok := existing.(map[string]interface{})
   129  	if !ok {
   130  		panic(fmt.Sprintf("%s is not a map, this is a bug in Terraform.", k))
   131  	}
   132  
   133  	switch typedV := v.(type) {
   134  	case []map[string]interface{}:
   135  		for newKey, newVal := range typedV[0] {
   136  			existingMap[newKey] = newVal
   137  		}
   138  	case map[string]interface{}:
   139  		for newKey, newVal := range typedV {
   140  			existingMap[newKey] = newVal
   141  		}
   142  	default:
   143  		panic(fmt.Sprintf("%s is not a map, this is a bug in Terraform.", k))
   144  	}
   145  }