Setting the file. One moment.
Validate Terraform · Azure Validate · microsoft/azure-skills · Skills Docs
ContentsBack to the top of the page 28.8
Errors · azd
references/recipes/terraform/scripts/validate-terraform.sh
references/recipes/terraform/scripts/ validate-terraform.sh
Shell · 185 lines · 7 KB
15 #
16 # Arguments:
17 # infra-dir Path to the Terraform infra directory (default: ./infra).
18 # subscription-id Optional subscription to select before checks.
19 #
20 # Examples:
21 # ./validate-terraform.sh # Validate ./infra
22 # ./validate-terraform.sh ./infra # Validate an explicit directory
23 # ./validate-terraform.sh ./infra 00000000-0000-0000-0000-000000000000
24 #
25 # Exit code: 0 when every non-skipped step passes, 1 when any step fails.
26
27 set -uo pipefail
28
29 INFRA_DIR = " ${1 :- . / infra } "
30 SUBSCRIPTION_ID = " ${2 :- } "
31
32 # --- result tracking ---------------------------------------------------------
33 STEP_NAMES = ()
34 STEP_STATUS = () # PASS | FAIL | SKIP
35 STEP_ERRORS = () # captured error text (empty unless FAIL)
36
37 record () {
38 # record <name> <status> [error-text]
39 # Results are collected here and rendered once in the summary at the end.
40 STEP_NAMES += ( " $1 " )
41 STEP_STATUS += ( " $2 " )
42 STEP_ERRORS += ( " ${3 :- } " )
43 }
44
45 echo "Terraform validation preflight - infra dir: $INFRA_DIR "
46 echo ""
47
48 # --- 1. Terraform installed --------------------------------------------------
49 if command -v terraform > /dev/null 2>&1 ; then
50 record "Terraform installed" "PASS"
51 else
52 record "Terraform installed" "FAIL" "terraform not found on PATH. Install: https://developer.hashicorp.com/terraform/install"
53 fi
54
55 # --- 2. Azure CLI installed --------------------------------------------------
56 if command -v az > /dev/null 2>&1 ; then
57 record "Azure CLI installed" "PASS"
58 else
59 record "Azure CLI installed" "FAIL" "az not found on PATH. Install the Azure CLI: mcp_azure_mcp_extension_cli_install(cli-type: \" az \" )"
60 fi
61
62 # --- 3. Authentication -------------------------------------------------------
63 if command -v az > /dev/null 2>&1 ; then
64 if [ -n " $SUBSCRIPTION_ID " ]; then
65 if SUB_OUT = $( az account set --subscription " $SUBSCRIPTION_ID " 2>&1 ); then
66 record "Select subscription" "PASS"
67 else
68 record "Select subscription" "FAIL" " $SUB_OUT "
69 fi
70 fi
71 if ACCOUNT_OUT = $( az account show -o none 2>&1 ); then
72 record "Authenticated (az account show)" "PASS"
73 else
74 record "Authenticated (az account show)" "FAIL" " $ACCOUNT_OUT "
75 fi
76 else
77 record "Authenticated (az account show)" "SKIP" "Azure CLI not installed"
78 fi
79
80 # --- infra dir presence gate -------------------------------------------------
81 HAVE_TF = false
82 if command -v terraform > /dev/null 2>&1 && [ -d " $INFRA_DIR " ]; then
83 HAVE_TF = true
84 fi
85
86 run_tf () {
87 # run_tf <name> <terraform args...>
88 local name = " $1 " ; shift
89 if [ " $HAVE_TF " != true ]; then
90 record " $name " "SKIP" "terraform unavailable or infra dir ' $INFRA_DIR ' not found"
91 return
92 fi
93 # Stream output to a temp file so large output (e.g. terraform plan) is not
94 # held in memory; only read it back when the command fails.
95 local tmp
96 tmp = $( mktemp )
97 if ( cd " $INFRA_DIR " && terraform " $@ " ) > " $tmp " 2>&1 ; then
98 record " $name " "PASS"
99 else
100 record " $name " "FAIL" "$( cat " $tmp ")"
101 fi
102 rm -f " $tmp "
103 }
104
105 # --- 4. Initialize -----------------------------------------------------------
106 run_tf "terraform init" init -input=false
107
108 # --- 5. Format check ---------------------------------------------------------
109 run_tf "terraform fmt -check" fmt -check -recursive
110
111 # --- 6. Validate syntax ------------------------------------------------------
112 run_tf "terraform validate" validate
113
114 # --- 7. Plan preview ---------------------------------------------------------
115 run_tf "terraform plan" plan -input=false -out=tfplan
116
117 # --- 8. State backend --------------------------------------------------------
118 run_tf "terraform state list" state list
119
120 # --- 9. Go-style template-variable scan --------------------------------------
121 if [ -d " $INFRA_DIR " ]; then
122 TEMPLATE_HITS = $( grep -rn '{{ *\.Env\.' " $INFRA_DIR " --include= '*.tf' --include= '*.tfvars.json' 2> /dev/null || true )
123 if [ -n " $TEMPLATE_HITS " ]; then
124 record "Template-variable scan ({{ .Env.* }})" "FAIL" \
125 "Found unresolved Go-style template variables - replace {{ .Env.VAR }} with \$ {VAR} (azd envsubst format):
126 $TEMPLATE_HITS "
127 else
128 record "Template-variable scan ({{ .Env.* }})" "PASS"
129 fi
130 else
131 record "Template-variable scan ({{ .Env.* }})" "SKIP" "infra dir ' $INFRA_DIR ' not found"
132 fi
133
134 # --- 10. main.tfvars.json JSON syntax ----------------------------------------
135 TFVARS = " $INFRA_DIR /main.tfvars.json"
136 if [ -f " $TFVARS " ]; then
137 if command -v python3 > /dev/null 2>&1 ; then
138 if JSON_ERR = $( python3 -c "import json,sys; json.load(open(sys.argv[1]))" " $TFVARS " 2>&1 ); then
139 record "main.tfvars.json is valid JSON" "PASS"
140 else
141 record "main.tfvars.json is valid JSON" "FAIL" " $JSON_ERR "
142 fi
143 elif command -v jq > /dev/null 2>&1 ; then
144 if JSON_ERR = $( jq empty " $TFVARS " 2>&1 ); then
145 record "main.tfvars.json is valid JSON" "PASS"
146 else
147 record "main.tfvars.json is valid JSON" "FAIL" " $JSON_ERR "
148 fi
149 else
150 record "main.tfvars.json is valid JSON" "SKIP" "no JSON parser (python3/jq) available"
151 fi
152 else
153 record "main.tfvars.json is valid JSON" "SKIP" " $TFVARS not found"
154 fi
155
156 # --- summary -----------------------------------------------------------------
157 echo ""
158 echo "==================== SUMMARY ===================="
159 printf '%-40s %s\n' "STEP" "RESULT"
160 printf '%-40s %s\n' "----" "------"
161 FAILED = 0
162 for i in "${ ! STEP_NAMES [ @ ]}" ; do
163 printf '%-40s %s\n' "${ STEP_NAMES [ $i ]}" "${ STEP_STATUS [ $i ]}"
164 [ "${ STEP_STATUS [ $i ]}" = "FAIL" ] && FAILED = $(( FAILED + 1 ))
165 done
166 echo "================================================="
167
168 if [ " $FAILED " -gt 0 ]; then
169 echo ""
170 echo "----- FAILURE DETAILS -----"
171 for i in "${ ! STEP_NAMES [ @ ]}" ; do
172 if [ "${ STEP_STATUS [ $i ]}" = "FAIL" ]; then
173 echo ""
174 echo "### ${ STEP_NAMES [ $i ]}"
175 echo "${ STEP_ERRORS [ $i ]}"
176 fi
177 done
178 echo ""
179 echo "RESULT: $FAILED step(s) failed. See remediation guidance in README.md."
180 exit 1
181 fi
182
183 echo ""
184 echo "RESULT: All checks passed. Ready for azure-deploy."
185 exit 0