1+ terraform {
2+ required_providers {
3+ http = {
4+ source = " hashicorp/http"
5+ version = " ~> 3.4"
6+ }
7+ # ADDED: Provider for the null_resource used for polling
8+ null = {
9+ source = " hashicorp/null"
10+ version = " ~> 3.2"
11+ }
12+ }
13+ }
14+
15+ variable "trigger_dr_restore" {
16+ type = bool
17+ description = " Set to true to trigger the DR restore API call."
18+ default = false
19+ }
20+
21+ variable "gcp_access_token" {
22+ type = string
23+ description = " A valid GCP access token."
24+ default = " " # Provide a default to avoid errors when trigger_dr_restore is false
25+ }
26+
27+ variable "consumer_project_id" {
28+ type = string
29+ description = " Consumer project ID"
30+ default = " kavishgupta-consumer-18"
31+ }
32+
33+ variable "location" {
34+ type = string
35+ description = " GCP region for the BackupDR service"
36+ default = " asia-northeast1"
37+ }
38+
39+ variable "target_zone" {
40+ type = string
41+ description = " Target zone for the restored instance"
42+ default = " asia-northeast1-c"
43+ }
44+
45+ variable "restored_vm_name" {
46+ type = string
47+ description = " Name for the restored VM"
48+ default = " instance-11-restrd"
49+ }
50+
51+ variable "backup_vault" {
52+ type = string
53+ default = " bv1"
54+ }
55+
56+ variable "data_source" {
57+ type = string
58+ default = " ds1"
59+ }
60+
61+ variable "backup_id" {
62+ type = string
63+ default = " b1"
64+ }
65+
66+ variable "restore_network" {
67+ type = string
68+ default = " projects/kavishgupta-consumer-18/global/networks/test-restore"
69+ }
70+
71+ variable "restore_subnetwork" {
72+ type = string
73+ default = " projects/kavishgupta-consumer-18/regions/asia-northeast1/subnetworks/test-subnet"
74+ }
75+
76+ variable "service_account_email" {
77+ type = string
78+ default = " <REDACTED_EMAIL>"
79+ }
80+
81+ locals {
82+ api_endpoint = " https://backupdr.googleapis.com" # Base endpoint without version
83+ restore_url = " ${ local . api_endpoint } /v1/projects/${ var . consumer_project_id } /locations/${ var . location } /backupVaults/${ var . backup_vault } /dataSources/${ var . data_source } /backups/${ var . backup_id } :restore"
84+
85+ request_body = jsonencode ({
86+ compute_instance_target_environment = {
87+ project = " nkuravi-cons-1"
88+ zone = var.target_zone
89+ }
90+ compute_instance_restore_properties = {
91+ name = var.restored_vm_name
92+ network_interfaces = [
93+ {
94+ network = var.restore_network
95+ subnetwork = var.restore_subnetwork
96+ }
97+ ]
98+ service_accounts = [
99+ {
100+ email = var.service_account_email
101+ }
102+ ]
103+ }
104+ })
105+ }
106+
107+ # Step 1: Trigger the initial restore operation
108+ data "http" "gcbdr_restore" {
109+ count = var. trigger_dr_restore ? 1 : 0
110+
111+ url = local. restore_url
112+ method = " POST"
113+
114+ request_headers = {
115+ " Authorization" = " Bearer ${ var . gcp_access_token } "
116+ " Content-Type" = " application/json"
117+ " X-Goog-User-Project" = var.consumer_project_id
118+ }
119+
120+ request_body = local. request_body
121+ }
122+
123+ # --------------------------------------------------------------------------
124+ # --- APPENDED SCRIPT TO POLL THE OPERATION ---
125+ # --------------------------------------------------------------------------
126+
127+ # Step 2: Poll the operation until it is 'done' using a local-exec provisioner
128+ # Step 2: Poll the operation until it is 'done' using a local-exec provisioner
129+ resource "null_resource" "poll_restore_operation" {
130+ count = var. trigger_dr_restore ? 1 : 0
131+
132+ # This trigger ensures the provisioner runs only when a new operation is created
133+ triggers = {
134+ operation_body = data.http.gcbdr_restore[0 ].response_body
135+ }
136+
137+ provisioner "local-exec" {
138+ interpreter = [" /bin/bash" , " -c" ]
139+
140+ command = <<- EOT
141+ set -e
142+ OPERATION_NAME=$(echo '${ self . triggers . operation_body } ' | jq -r '.name')
143+ if [ -z "$OPERATION_NAME" ] || [ "$OPERATION_NAME" == "null" ]; then
144+ echo "Error: Could not parse operation name from response."
145+ echo '${ self . triggers . operation_body } '
146+ exit 1
147+ fi
148+
149+ OPERATION_URL="https://backupdr.googleapis.com/v1/$OPERATION_NAME"
150+ echo "Polling operation at: $OPERATION_URL"
151+
152+ for i in {1..40}; do
153+ RESPONSE=$$(curl --fail -s -H "Authorization: Bearer '${ var . gcp_access_token } '" "$${OPERATION_URL}")
154+ DONE_STATUS=$$(echo "$${RESPONSE}" | jq -r '.done')
155+ echo "Attempt $$i: Polling... Operation done status is '$${DONE_STATUS}'."
156+
157+ if [ "$${DONE_STATUS}" == "true" ]; then
158+ echo "Operation has completed."
159+ if echo "$${RESPONSE}" | jq -e '.error' > /dev/null; then
160+ echo "Final Status: FAILED"
161+ echo "$${RESPONSE}" | jq '.error'
162+ exit 1
163+ else
164+ echo "Final Status: SUCCESS"
165+ echo "$${RESPONSE}" > operation_result.json
166+ exit 0
167+ fi
168+ fi
169+ sleep 15
170+ done
171+
172+ echo "Error: Operation polling timed out after 10 minutes."
173+ exit 1
174+ EOT
175+ }
176+ }
177+ # Step 3 (Optional but recommended): Read the result from the file created by the poller
178+ data "local_file" "operation_result" {
179+ count = var. trigger_dr_restore ? 1 : 0
180+
181+ filename = " ${ path . module } /operation_result.json"
182+
183+ # Ensures this data source reads the file only after the polling script has finished
184+ depends_on = [null_resource. poll_restore_operation ]
185+ }
186+
187+ # --- UPDATED AND NEW OUTPUTS ---
188+
189+ output "final_operation_details" {
190+ description = " The full JSON body of the completed operation after polling."
191+ value = jsondecode (data. local_file . operation_result [0 ]. content )
192+ sensitive = true
193+ }
0 commit comments