Skip to content

Commit 7d84523

Browse files
authored
Merge pull request hashicorp#277 from hashicorp/update-automation-script
update loadAndRunWorkspaces.sh
2 parents a11b056 + dcc1779 commit 7d84523

File tree

3 files changed

+36
-38
lines changed

3 files changed

+36
-38
lines changed

operations/automation-script/README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# TFE Automation Script
22
Script to automate interactions with Terraform Enterprise, including the cloning of a repository containing Terraform configuration code, creation of a workspace, tarring and uploading of the Terraform code, setting of variables, triggering a run, checking Sentinel policies, and finally doing an apply if permitted. If an apply is done, the script waits for it to finish and then downloads the apply log and the before and after state files. If an apply cannot be done, it downloads the plan log instead.
33

4+
Note that this script is only meant as an example that shows how to use the various Terraform Cloud APIs. It is not suitable for production usage since it does not support modifying workspace variables after they have already been created in a workspace.
5+
46
There is also a script to delete the workspace.
57

68
## Introduction
@@ -27,8 +29,8 @@ The script does the following steps:
2729
1. Determines the number of Sentinel policies so that it knows whether it needs to check them.
2830
1. Starts a new run.
2931
1. Enters a loop to check the run results periodically.
30-
- If $run_status is "planned", $is_confirmable is "True", and $override is "no", the script stops. In this case, no Sentinel policies existed or none of them were applicable to this workspace. The script will stop. The user should can apply the run in the Terraform Enterprise UI.
31-
- If $run_status is "planned", $is_confirmable is "True", and $override is "yes", the script will do an apply. As in the previous case, no Sentinel policies existed or none of them were applicable to this workspace.
32+
- If $run_status is "planned" or "cost_estimated", $is_confirmable is "True", and $override is "no", the script stops. In this case, no Sentinel policies existed or none of them were applicable to this workspace. The script will stop. The user should can apply the run in the Terraform Enterprise UI.
33+
- If $run_status is "planned" or "cost_estimated", $is_confirmable is "True", and $override is "yes", the script will do an apply. As in the previous case, no Sentinel policies existed or none of them were applicable to this workspace.
3234
- If $run_status is "policy_checked", it does an Apply. In this case, all Sentinel policies passed.
3335
- If $run_status is "policy_override" and $override is "yes", it overrides the failed policy checks and does an Apply. In this case, one or more Sentinel policies failed, but they were marked "advisory" or "soft-mandatory" and the script was configured to override the failure.
3436
- If $run_status is "policy_override" and $override is "no", it prints out a message indicating that some policies failed and are not being overridden.
@@ -40,18 +42,18 @@ The script does the following steps:
4042
- Other values of $run_status cause the loop to repeat after a brief sleep.
4143
1. If $save_plan was set to "true" in the above loop, the script outputs and saves the plan log.
4244
1. If any apply was done, the script goes into a second loop to wait for the apply to finish, error, or be canceled.
43-
1. If and when the apply finishes, the script downloads the apply log and the state files from before and after the apply.
45+
1. If and when the apply finishes, the script downloads the apply log and the new state file from before and after the apply.
4446

4547
In addition to the loadAndRunWorkspace.sh script, this example includes the following files:
4648

4749
1. [config/main.tf](./config/main.tf) which is a file with some Terraform code that says "Hello" to the person whose name is given and generates a random number. This is used if no git URL is provided to the script.
48-
1. [variables.csv](./variables.csv) which contains the variables that are uploaded to the workspace if no file with the same name is found in the root directory of the cloned repository. The columns are key, value, category, hcl, and sensitive with the last two corresponding to the hcl and sensitive checkboxes of TFE variables. This should be in the same directory as the script unless you include a file with the same name in your git repository.
50+
1. [variables.csv](./variables.csv) which contains the variables that are uploaded to the workspace if no file with the same name is found in the root directory of the cloned repository. The columns are key, value, category, hcl, and sensitive with the last two corresponding to the hcl and sensitive checkboxes of TFE variables. The `category` should be set to `terraform` for Terraform variables and to `env` for environment variables. The `hcl` and `sensitive` values can be set to `true` or `false`. This should be in the same directory as the script unless you include a file with the same name in your git repository.
4951
1. [deleteWorkspace.sh](./deleteWorkspace.sh): a script that can be used to delete the workspace.
5052
1. [restrict-name-variable.sentinel](./restrict-name-variable.sentinel): a Sentinel policy you can add to your TFE organization in order to see how the script can check Sentinel policies and even override soft-mandatory failures.
5153

5254
The following files are embedded inside the script:
5355

54-
1. **workspace.template.json** which is used to generate _workspace.json_ which is used when creating the workspace. If you wish to add or modify the settings that are included in the _@workspace.json_ payload, add them to _workspace.template.json_ inside the script and be sure to check the Terraform Enterprise API [syntax](https://www.terraform.io/docs/enterprise/api/workspaces.html#update-a-workspace). Update or modify `"terraform-version": "0.11.14"` within _workspace.template.json_ to set a specific workspace version of the Terraform OSS binary.
56+
1. **workspace.template.json** which is used to generate _workspace.json_ which is used when creating the workspace. If you wish to add or modify the settings that are included in the _@workspace.json_ payload, add them to _workspace.template.json_ inside the script and be sure to check the Terraform Enterprise API [syntax](https://www.terraform.io/docs/enterprise/api/workspaces.html#update-a-workspace). Update or modify `"terraform-version": "0.13.6"` within _workspace.template.json_ to set a specific workspace version of the Terraform OSS binary.
5557
1. **configversion.json** which is used to generate a new configuration version.
5658
1. **variable.template.json** which is used to generate _variable.json_ which is used when creating a variable called "name" in the workspace.
5759
1. **run.template.json** which is used to generate _run.json_ which is used when triggering a run against the workspace.

operations/automation-script/config/main.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ variable "name" {
44

55
resource "random_id" "random" {
66
keepers = {
7-
uuid = "${uuid()}"
7+
uuid = uuid()
88
}
99
byte_length = 32
1010
}
1111

1212
output "random" {
13-
value = "${random_id.random.hex}"
13+
value = random_id.random.hex
1414
}
1515

1616
output "hello_world" {

operations/automation-script/loadAndRunWorkspace.sh

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ cat > workspace.template.json <<EOF
116116
{
117117
"attributes": {
118118
"name":"placeholder",
119-
"terraform-version": "0.11.14"
119+
"terraform-version": "0.13.6"
120120
},
121121
"type":"workspaces"
122122
}
@@ -287,27 +287,40 @@ while [ $continue -ne 0 ]; do
287287
# Apply in some cases
288288
applied="false"
289289

290-
# planned means plan finished and no Sentinel policies
291-
# exist or are applicable to the workspace
292-
293290
# Run is planning - get the plan
294291
# Note that we use "True" rather than "true" because python converts the
295292
# boolean "true" in json responses to "True" and "false" to "False"
293+
294+
# planned means plan finished and no Sentinel policies
295+
# exist or are applicable to the workspace
296296
if [[ "$run_status" == "planned" ]] && [[ "$is_confirmable" == "True" ]] && [[ "$override" == "no" ]]; then
297297
continue=0
298298
echo "There are " $sentinel_policy_count "policies, but none of them are applicable to this workspace."
299299
echo "Check the run in Terraform Enterprise UI and apply there if desired."
300300
save_plan="true"
301-
# planned means plan finished and no Sentinel policies
301+
# cost_estimated means plan finished and costs were estimated
302302
# exist or are applicable to the workspace
303+
elif [[ "$run_status" == "cost_estimated" ]] && [[ "$is_confirmable" == "True" ]] && [[ "$override" == "no" ]]; then
304+
continue=0
305+
echo "There are " $sentinel_policy_count "policies, but none of them are applicable to this workspace."
306+
echo "Check the run in Terraform Enterprise UI and apply there if desired."
307+
save_plan="true"
303308
elif [[ "$run_status" == "planned" ]] && [[ "$is_confirmable" == "True" ]] && [[ "$override" == "yes" ]]; then
304-
continue=0
305-
echo "There are " $sentinel_policy_count "policies, but none of them are applicable to this workspace."
306-
echo "Since override was set to \"yes\", we are applying."
307-
# Do the apply
308-
echo "Doing Apply"
309-
apply_result=$(curl -s --header "Authorization: Bearer $TFE_TOKEN" --header "Content-Type: application/vnd.api+json" --data @apply.json https://${address}/api/v2/runs/${run_id}/actions/apply)
310-
applied="true"
309+
continue=0
310+
echo "There are " $sentinel_policy_count "policies, but none of them are applicable to this workspace."
311+
echo "Since override was set to \"yes\", we are applying."
312+
# Do the apply
313+
echo "Doing Apply"
314+
apply_result=$(curl -s --header "Authorization: Bearer $TFE_TOKEN" --header "Content-Type: application/vnd.api+json" --data @apply.json https://${address}/api/v2/runs/${run_id}/actions/apply)
315+
applied="true"
316+
elif [[ "$run_status" == "cost_estimated" ]] && [[ "$is_confirmable" == "True" ]] && [[ "$override" == "yes" ]]; then
317+
continue=0
318+
echo "There are " $sentinel_policy_count "policies, but none of them are applicable to this workspace."
319+
echo "Since override was set to \"yes\", we are applying."
320+
# Do the apply
321+
echo "Doing Apply"
322+
apply_result=$(curl -s --header "Authorization: Bearer $TFE_TOKEN" --header "Content-Type: application/vnd.api+json" --data @apply.json https://${address}/api/v2/runs/${run_id}/actions/apply)
323+
applied="true"
311324
# policy_checked means all Sentinel policies passed
312325
elif [[ "$run_status" == "policy_checked" ]]; then
313326
continue=0
@@ -428,26 +441,9 @@ if [[ "$applied" == "true" ]]; then
428441
# and output to shell and file
429442
curl -s $apply_log_url | tee ${apply_id}.log
430443

431-
# Get state version IDs from after the apply
432-
state_id_before=$(echo $check_result | python -c "import sys, json; print(json.load(sys.stdin)['data']['relationships']['state-versions']['data'][1]['id'])")
433-
echo "State ID 1:" ${state_id_before}
434-
435-
# Call API to get information about the state version including its URL
436-
state_file_before_url_result=$(curl -s --header "Authorization: Bearer $TFE_TOKEN" https://${address}/api/v2/state-versions/${state_id_before})
437-
438-
# Get state file URL from the result
439-
state_file_before_url=$(echo $state_file_before_url_result | python -c "import sys, json; print(json.load(sys.stdin)['data']['attributes']['hosted-state-download-url'])")
440-
echo "URL for state file before apply:"
441-
echo ${state_file_before_url}
442-
443-
# Retrieve state file from the URL
444-
# and output to shell and file
445-
echo "State file before the apply:"
446-
curl -s $state_file_before_url | tee ${apply_id}-before.tfstate
447-
448-
# Get state version IDs from before the apply
444+
# Get state version ID from after the apply
449445
state_id_after=$(echo $check_result | python -c "import sys, json; print(json.load(sys.stdin)['data']['relationships']['state-versions']['data'][0]['id'])")
450-
echo "State ID 0:" ${state_id_after}
446+
echo "State ID:" ${state_id_after}
451447

452448
# Call API to get information about the state version including its URL
453449
state_file_after_url_result=$(curl -s --header "Authorization: Bearer $TFE_TOKEN" https://${address}/api/v2/state-versions/${state_id_after})

0 commit comments

Comments
 (0)