github.com/jpreese/tflint@v0.19.2-0.20200908152133-b01686250fb6/tflint/terraform.go (about) 1 package tflint 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "log" 8 "os" 9 "path/filepath" 10 "strings" 11 12 hcl "github.com/hashicorp/hcl/v2" 13 "github.com/hashicorp/hcl/v2/hclsyntax" 14 "github.com/hashicorp/terraform/configs" 15 "github.com/hashicorp/terraform/terraform" 16 "github.com/zclconf/go-cty/cty" 17 ) 18 19 var defaultValuesFile = "terraform.tfvars" 20 21 // ParseTFVariables parses the passed Terraform variable CLI arguments, and returns terraform.InputValues 22 func ParseTFVariables(vars []string, declVars map[string]*configs.Variable) (terraform.InputValues, error) { 23 variables := make(terraform.InputValues) 24 for _, raw := range vars { 25 idx := strings.Index(raw, "=") 26 if idx == -1 { 27 return variables, fmt.Errorf("`%s` is invalid. Variables must be `key=value` format", raw) 28 } 29 name := raw[:idx] 30 rawVal := raw[idx+1:] 31 32 var mode configs.VariableParsingMode 33 declVar, declared := declVars[name] 34 if declared { 35 mode = declVar.ParsingMode 36 } else { 37 mode = configs.VariableParseLiteral 38 } 39 40 val, diags := mode.Parse(name, rawVal) 41 if diags.HasErrors() { 42 return variables, diags 43 } 44 45 variables[name] = &terraform.InputValue{ 46 Value: val, 47 SourceType: terraform.ValueFromCLIArg, 48 } 49 } 50 51 return variables, nil 52 } 53 54 // ParseExpression is a wrapper for a function that parses JSON and HCL expressions 55 func ParseExpression(src []byte, filename string, start hcl.Pos) (hcl.Expression, hcl.Diagnostics) { 56 if strings.HasSuffix(filename, ".tf") { 57 return hclsyntax.ParseExpression(src, filename, start) 58 } 59 60 if strings.HasSuffix(filename, ".tf.json") { 61 return nil, hcl.Diagnostics{ 62 &hcl.Diagnostic{ 63 Severity: hcl.DiagError, 64 Summary: "JSON configuration syntax is not supported", 65 Subject: &hcl.Range{Filename: filename, Start: start, End: start}, 66 }, 67 } 68 } 69 70 panic(fmt.Sprintf("Unexpected file: %s", filename)) 71 } 72 73 // HCLBodyRange attempts to find a range of the passed body 74 func HCLBodyRange(body hcl.Body, defRange hcl.Range) hcl.Range { 75 if strings.HasSuffix(defRange.Filename, ".tf") { 76 var bodyRange hcl.Range 77 78 // Estimate the range of the body from the range of all attributes and blocks. 79 hclBody := body.(*hclsyntax.Body) 80 for _, attr := range hclBody.Attributes { 81 if bodyRange.Empty() { 82 bodyRange = attr.Range() 83 } else { 84 bodyRange = hcl.RangeOver(bodyRange, attr.Range()) 85 } 86 } 87 for _, block := range hclBody.Blocks { 88 if bodyRange.Empty() { 89 bodyRange = block.Range() 90 } else { 91 bodyRange = hcl.RangeOver(bodyRange, block.Range()) 92 } 93 } 94 return bodyRange 95 } 96 97 if strings.HasSuffix(defRange.Filename, ".tf.json") { 98 // HACK: In JSON syntax, DefRange corresponds to open brace and MissingItemRange corresponds to close brace. 99 return hcl.RangeOver(defRange, body.MissingItemRange()) 100 } 101 102 panic(fmt.Sprintf("Unexpected file: %s", defRange.Filename)) 103 } 104 105 func getTFDataDir() string { 106 dir := os.Getenv("TF_DATA_DIR") 107 if dir != "" { 108 log.Printf("[INFO] TF_DATA_DIR environment variable found: %s", dir) 109 } else { 110 dir = ".terraform" 111 } 112 113 return dir 114 } 115 116 func getTFModuleDir() string { 117 return filepath.Join(getTFDataDir(), "modules") 118 } 119 120 func getTFModuleManifestPath() string { 121 return filepath.Join(getTFModuleDir(), "modules.json") 122 } 123 124 func getTFWorkspace() string { 125 if envVar := os.Getenv("TF_WORKSPACE"); envVar != "" { 126 log.Printf("[INFO] TF_WORKSPACE environment variable found: %s", envVar) 127 return envVar 128 } 129 130 envData, _ := ioutil.ReadFile(filepath.Join(getTFDataDir(), "environment")) 131 current := string(bytes.TrimSpace(envData)) 132 if current != "" { 133 log.Printf("[INFO] environment file found: %s", current) 134 } else { 135 current = "default" 136 } 137 138 return current 139 } 140 141 func getTFEnvVariables() terraform.InputValues { 142 envVariables := make(terraform.InputValues) 143 for _, e := range os.Environ() { 144 idx := strings.Index(e, "=") 145 envKey := e[:idx] 146 envVal := e[idx+1:] 147 148 if strings.HasPrefix(envKey, "TF_VAR_") { 149 log.Printf("[INFO] TF_VAR_* environment variable found: key=%s", envKey) 150 varName := strings.Replace(envKey, "TF_VAR_", "", 1) 151 152 envVariables[varName] = &terraform.InputValue{ 153 Value: cty.StringVal(envVal), 154 SourceType: terraform.ValueFromEnvVar, 155 } 156 } 157 } 158 159 return envVariables 160 }