Skip to content

Commit 42fadcc

Browse files
authored
Add RestoreWorkload resource with custom create and delete (#16080)
1 parent 3168a24 commit 42fadcc

9 files changed

+2471
-0
lines changed

mmv1/products/backupdr/RestoreWorkload.yaml

Lines changed: 798 additions & 0 deletions
Large diffs are not rendered by default.

mmv1/templates/terraform/custom_create/backup_dr_restore_workload.go.tmpl

Lines changed: 1005 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
project, err := tpgresource.GetProject(d, config)
2+
if err != nil {
3+
return fmt.Errorf("Error fetching project for RestoreWorkload: %s", err)
4+
}
5+
billingProject := project
6+
7+
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
8+
billingProject = bp
9+
}
10+
11+
deleteInstance := true
12+
if v, ok := d.GetOkExists("delete_restored_instance"); ok {
13+
deleteInstance = v.(bool)
14+
}
15+
16+
// If the caller asked us to keep the restored resource, exit immediately and only clear state.
17+
if !deleteInstance {
18+
log.Printf("[DEBUG] Skipping deletion of restored resource (deleteRestoredInstance=%v)", deleteInstance)
19+
d.SetId("")
20+
return nil
21+
}
22+
23+
// If deleteRestoredInstance is true, delete the actual restored resource from GCP
24+
if deleteInstance {
25+
// Get the gcp_resourcename from target_resource
26+
var resourceId string
27+
if v, ok := d.GetOk("target_resource"); ok {
28+
targetResourceList := v.([]interface{})
29+
if len(targetResourceList) > 0 {
30+
targetResourceMap := targetResourceList[0].(map[string]interface{})
31+
if gcpResourceList, ok := targetResourceMap["gcp_resource"].([]interface{}); ok && len(gcpResourceList) > 0 {
32+
gcpResourceMap := gcpResourceList[0].(map[string]interface{})
33+
if gcpResourceName, ok := gcpResourceMap["gcp_resourcename"].(string); ok {
34+
resourceId = gcpResourceName
35+
}
36+
}
37+
}
38+
}
39+
40+
if resourceId != "" {
41+
log.Printf("[DEBUG] Deleting restored resource: %s", resourceId)
42+
43+
// Parse the resource ID to determine the resource type
44+
// For compute instances: projects/PROJECT/zones/ZONE/instances/INSTANCE_NAME
45+
if strings.Contains(resourceId, "/instances/") {
46+
// This is a Compute Engine instance - delete it
47+
deleteUrl := fmt.Sprintf("https://compute.googleapis.com/compute/v1/%s", resourceId)
48+
49+
opRes, deleteErr := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
50+
Config: config,
51+
Method: "DELETE",
52+
Project: billingProject,
53+
RawURL: deleteUrl,
54+
UserAgent: userAgent,
55+
Timeout: d.Timeout(schema.TimeoutDelete),
56+
Headers: make(http.Header),
57+
})
58+
59+
if deleteErr != nil {
60+
log.Printf("[WARN] Error deleting restored instance %s: %v", resourceId, deleteErr)
61+
} else if opRes != nil {
62+
// Wait for the compute LRO to finish by polling the operation
63+
if opName, ok := opRes["name"].(string); ok && opName != "" {
64+
// Simple polling loop
65+
timeout := d.Timeout(schema.TimeoutDelete)
66+
pollStart := time.Now()
67+
for {
68+
if time.Since(pollStart) > timeout {
69+
log.Printf("[WARN] Timeout waiting for delete operation %s", opName)
70+
break
71+
}
72+
73+
// Get operation status
74+
opUrl := fmt.Sprintf("https://compute.googleapis.com/compute/v1/projects/%s/global/operations/%s", billingProject, opName)
75+
pollRes, pollErr := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
76+
Config: config,
77+
Method: "GET",
78+
Project: billingProject,
79+
RawURL: opUrl,
80+
UserAgent: userAgent,
81+
Timeout: timeout,
82+
Headers: make(http.Header),
83+
})
84+
85+
if pollErr != nil {
86+
log.Printf("[WARN] Error polling operation status: %v", pollErr)
87+
break
88+
}
89+
90+
if status, ok := pollRes["status"].(string); ok && status == "DONE" {
91+
log.Printf("[DEBUG] Delete operation %s completed", opName)
92+
break
93+
}
94+
95+
time.Sleep(time.Second)
96+
}
97+
}
98+
}
99+
} else if strings.Contains(resourceId, "/disks/") {
100+
// This is a Compute Engine disk - delete it
101+
deleteUrl := fmt.Sprintf("https://compute.googleapis.com/compute/v1/%s", resourceId)
102+
103+
deleteOpRes, deleteErr := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
104+
Config: config,
105+
Method: "DELETE",
106+
Project: billingProject,
107+
RawURL: deleteUrl,
108+
UserAgent: userAgent,
109+
Timeout: d.Timeout(schema.TimeoutDelete),
110+
Headers: make(http.Header),
111+
})
112+
113+
if deleteErr != nil {
114+
log.Printf("[WARN] Error deleting restored disk %s: %v", resourceId, deleteErr)
115+
} else if deleteOpRes != nil {
116+
// Wait for the compute LRO to finish by polling the operation
117+
if opName, ok := deleteOpRes["name"].(string); ok && opName != "" {
118+
// Simple polling loop
119+
timeout := d.Timeout(schema.TimeoutDelete)
120+
pollStart := time.Now()
121+
for {
122+
if time.Since(pollStart) > timeout {
123+
log.Printf("[WARN] Timeout waiting for delete operation %s", opName)
124+
break
125+
}
126+
127+
// Get operation status
128+
opUrl := fmt.Sprintf("https://compute.googleapis.com/compute/v1/projects/%s/global/operations/%s", billingProject, opName)
129+
pollRes, pollErr := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
130+
Config: config,
131+
Method: "GET",
132+
Project: billingProject,
133+
RawURL: opUrl,
134+
UserAgent: userAgent,
135+
Timeout: timeout,
136+
Headers: make(http.Header),
137+
})
138+
139+
if pollErr != nil {
140+
log.Printf("[WARN] Error polling operation status: %v", pollErr)
141+
break
142+
}
143+
144+
if status, ok := pollRes["status"].(string); ok && status == "DONE" {
145+
log.Printf("[DEBUG] Delete operation %s completed", opName)
146+
break
147+
}
148+
149+
time.Sleep(time.Second)
150+
}
151+
}
152+
}
153+
}
154+
} else {
155+
log.Printf("[DEBUG] No resource ID found in target_resource, skipping deletion")
156+
}
157+
}
158+
159+
// Always remove from Terraform state
160+
d.SetId("")
161+
162+
log.Printf("[DEBUG] Finished deleting RestoreWorkload")
163+
164+
return nil
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
resource "google_backup_dr_restore_workload" "{{$.PrimaryResourceId}}" {
2+
location = "us-central1"
3+
backup_vault_id = "{{index $.Vars "backup_vault_id"}}"
4+
data_source_id = "{{index $.Vars "data_source_id"}}"
5+
backup_id = "{{index $.Vars "backup_id"}}"
6+
7+
name = "{{index $.Vars "backup_name"}}"
8+
9+
compute_instance_target_environment {
10+
project = "{{index $.TestEnvVars "project"}}"
11+
zone = "us-central1-a"
12+
}
13+
14+
compute_instance_restore_properties {
15+
name = "{{index $.Vars "instance_name"}}"
16+
machine_type = "e2-medium"
17+
}
18+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
resource "google_backup_dr_restore_workload" "{{$.PrimaryResourceId}}" {
2+
location = "us-central1"
3+
backup_vault_id = "{{index $.Vars "backup_vault_id"}}"
4+
data_source_id = "{{index $.Vars "data_source_id"}}"
5+
backup_id = "{{index $.Vars "backup_id"}}"
6+
7+
name = "{{index $.Vars "backup_name"}}"
8+
9+
compute_instance_target_environment {
10+
project = "{{index $.TestEnvVars "project"}}"
11+
zone = "us-central1-a"
12+
}
13+
14+
compute_instance_restore_properties {
15+
name = "{{index $.Vars "instance_name"}}"
16+
machine_type = "e2-medium"
17+
description = "Restored compute instance with advanced configuration"
18+
19+
can_ip_forward = true
20+
deletion_protection = false
21+
22+
labels = {
23+
environment = "production"
24+
restored = "true"
25+
team = "infrastructure"
26+
}
27+
28+
tags {
29+
items = ["web", "https-server", "restored"]
30+
}
31+
32+
network_interfaces {
33+
network = "default"
34+
subnetwork = "projects/{{index $.TestEnvVars "project"}}/regions/us-central1/subnetworks/default"
35+
36+
access_configs {
37+
name = "External NAT"
38+
network_tier = "PREMIUM"
39+
}
40+
}
41+
42+
scheduling {
43+
automatic_restart = true
44+
on_host_maintenance = "MIGRATE"
45+
preemptible = false
46+
provisioning_model = "STANDARD"
47+
}
48+
49+
service_accounts {
50+
email = "default"
51+
scopes = [
52+
"https://www.googleapis.com/auth/cloud-platform",
53+
"https://www.googleapis.com/auth/compute"
54+
]
55+
}
56+
57+
shielded_instance_config {
58+
enable_secure_boot = true
59+
enable_vtpm = true
60+
enable_integrity_monitoring = true
61+
}
62+
63+
advanced_machine_features {
64+
enable_nested_virtualization = false
65+
threads_per_core = 1
66+
}
67+
68+
metadata {
69+
items {
70+
key = "startup-script"
71+
value = "#!/bin/bash\necho 'Instance restored' > /tmp/restored.txt"
72+
}
73+
items {
74+
key = "enable-oslogin"
75+
value = "TRUE"
76+
}
77+
}
78+
}
79+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
resource "google_backup_dr_restore_workload" "{{$.PrimaryResourceId}}" {
2+
location = "us-central1"
3+
backup_vault_id = "{{index $.Vars "backup_vault_id"}}"
4+
data_source_id = "{{index $.Vars "data_source_id"}}"
5+
backup_id = "{{index $.Vars "backup_id"}}"
6+
7+
name = "{{index $.Vars "backup_name"}}"
8+
9+
disk_target_environment {
10+
project = "{{index $.TestEnvVars "project"}}"
11+
zone = "us-central1-a"
12+
}
13+
14+
disk_restore_properties {
15+
name = "{{index $.Vars "disk_name"}}"
16+
size_gb = 100
17+
type = "pd-standard"
18+
19+
description = "Restored persistent disk from backup"
20+
21+
labels = {
22+
environment = "production"
23+
restored = "true"
24+
}
25+
}
26+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
resource "google_backup_dr_restore_workload" "{{$.PrimaryResourceId}}" {
2+
location = "us-central1"
3+
backup_vault_id = "{{index $.Vars "backup_vault_id"}}"
4+
data_source_id = "{{index $.Vars "data_source_id"}}"
5+
backup_id = "{{index $.Vars "backup_id"}}"
6+
7+
name = "{{index $.Vars "backup_name"}}"
8+
9+
region_disk_target_environment {
10+
project = "{{index $.TestEnvVars "project"}}"
11+
region = "us-central1"
12+
replica_zones = [
13+
"us-central1-a",
14+
"us-central1-b"
15+
]
16+
}
17+
18+
disk_restore_properties {
19+
name = "{{index $.Vars "disk_name"}}"
20+
size_gb = 200
21+
type = "pd-balanced"
22+
23+
description = "Restored regional persistent disk"
24+
25+
labels = {
26+
type = "regional"
27+
environment = "production"
28+
}
29+
30+
provisioned_iops = 3000
31+
provisioned_throughput = 140
32+
}
33+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
resource "google_backup_dr_restore_workload" "{{$.PrimaryResourceId}}" {
2+
location = "us-central1"
3+
backup_vault_id = "{{index $.Vars "backup_vault_id"}}"
4+
data_source_id = "{{index $.Vars "data_source_id"}}"
5+
backup_id = "{{index $.Vars "backup_id"}}"
6+
7+
name = "{{index $.Vars "backup_name"}}"
8+
9+
# Set to false to keep the restored resource in GCP after terraform destroy
10+
delete_restored_instance = false
11+
12+
disk_target_environment {
13+
project = "{{index $.TestEnvVars "project"}}"
14+
zone = "us-central1-a"
15+
}
16+
17+
disk_restore_properties {
18+
name = "{{index $.Vars "disk_name"}}"
19+
size_gb = 50
20+
type = "pd-standard"
21+
}
22+
}

0 commit comments

Comments
 (0)