Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
798 changes: 798 additions & 0 deletions mmv1/products/backupdr/RestoreWorkload.yaml

Large diffs are not rendered by default.

1,005 changes: 1,005 additions & 0 deletions mmv1/templates/terraform/custom_create/backup_dr_restore_workload.go.tmpl

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
project, err := tpgresource.GetProject(d, config)
if err != nil {
return fmt.Errorf("Error fetching project for RestoreWorkload: %s", err)
}
billingProject := project

if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
billingProject = bp
}

deleteInstance := true
if v, ok := d.GetOkExists("delete_restored_instance"); ok {
deleteInstance = v.(bool)
}

// If the caller asked us to keep the restored resource, exit immediately and only clear state.
if !deleteInstance {
log.Printf("[DEBUG] Skipping deletion of restored resource (deleteRestoredInstance=%v)", deleteInstance)
d.SetId("")
return nil
}

// If deleteRestoredInstance is true, delete the actual restored resource from GCP
if deleteInstance {
// Get the gcp_resourcename from target_resource
var resourceId string
if v, ok := d.GetOk("target_resource"); ok {
targetResourceList := v.([]interface{})
if len(targetResourceList) > 0 {
targetResourceMap := targetResourceList[0].(map[string]interface{})
if gcpResourceList, ok := targetResourceMap["gcp_resource"].([]interface{}); ok && len(gcpResourceList) > 0 {
gcpResourceMap := gcpResourceList[0].(map[string]interface{})
if gcpResourceName, ok := gcpResourceMap["gcp_resourcename"].(string); ok {
resourceId = gcpResourceName
}
}
}
}

if resourceId != "" {
log.Printf("[DEBUG] Deleting restored resource: %s", resourceId)

// Parse the resource ID to determine the resource type
// For compute instances: projects/PROJECT/zones/ZONE/instances/INSTANCE_NAME
if strings.Contains(resourceId, "/instances/") {
// This is a Compute Engine instance - delete it
deleteUrl := fmt.Sprintf("https://compute.googleapis.com/compute/v1/%s", resourceId)

opRes, deleteErr := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "DELETE",
Project: billingProject,
RawURL: deleteUrl,
UserAgent: userAgent,
Timeout: d.Timeout(schema.TimeoutDelete),
Headers: make(http.Header),
})

if deleteErr != nil {
log.Printf("[WARN] Error deleting restored instance %s: %v", resourceId, deleteErr)
} else if opRes != nil {
// Wait for the compute LRO to finish by polling the operation
if opName, ok := opRes["name"].(string); ok && opName != "" {
// Simple polling loop
timeout := d.Timeout(schema.TimeoutDelete)
pollStart := time.Now()
for {
if time.Since(pollStart) > timeout {
log.Printf("[WARN] Timeout waiting for delete operation %s", opName)
break
}

// Get operation status
opUrl := fmt.Sprintf("https://compute.googleapis.com/compute/v1/projects/%s/global/operations/%s", billingProject, opName)
pollRes, pollErr := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "GET",
Project: billingProject,
RawURL: opUrl,
UserAgent: userAgent,
Timeout: timeout,
Headers: make(http.Header),
})

if pollErr != nil {
log.Printf("[WARN] Error polling operation status: %v", pollErr)
break
}

if status, ok := pollRes["status"].(string); ok && status == "DONE" {
log.Printf("[DEBUG] Delete operation %s completed", opName)
break
}

time.Sleep(time.Second)
}
}
}
} else if strings.Contains(resourceId, "/disks/") {
// This is a Compute Engine disk - delete it
deleteUrl := fmt.Sprintf("https://compute.googleapis.com/compute/v1/%s", resourceId)

deleteOpRes, deleteErr := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "DELETE",
Project: billingProject,
RawURL: deleteUrl,
UserAgent: userAgent,
Timeout: d.Timeout(schema.TimeoutDelete),
Headers: make(http.Header),
})

if deleteErr != nil {
log.Printf("[WARN] Error deleting restored disk %s: %v", resourceId, deleteErr)
} else if deleteOpRes != nil {
// Wait for the compute LRO to finish by polling the operation
if opName, ok := deleteOpRes["name"].(string); ok && opName != "" {
// Simple polling loop
timeout := d.Timeout(schema.TimeoutDelete)
pollStart := time.Now()
for {
if time.Since(pollStart) > timeout {
log.Printf("[WARN] Timeout waiting for delete operation %s", opName)
break
}

// Get operation status
opUrl := fmt.Sprintf("https://compute.googleapis.com/compute/v1/projects/%s/global/operations/%s", billingProject, opName)
pollRes, pollErr := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "GET",
Project: billingProject,
RawURL: opUrl,
UserAgent: userAgent,
Timeout: timeout,
Headers: make(http.Header),
})

if pollErr != nil {
log.Printf("[WARN] Error polling operation status: %v", pollErr)
break
}

if status, ok := pollRes["status"].(string); ok && status == "DONE" {
log.Printf("[DEBUG] Delete operation %s completed", opName)
break
}

time.Sleep(time.Second)
}
}
}
}
} else {
log.Printf("[DEBUG] No resource ID found in target_resource, skipping deletion")
}
}

// Always remove from Terraform state
d.SetId("")

log.Printf("[DEBUG] Finished deleting RestoreWorkload")

return nil
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
resource "google_backup_dr_restore_workload" "{{$.PrimaryResourceId}}" {
location = "us-central1"
backup_vault_id = "{{index $.Vars "backup_vault_id"}}"
data_source_id = "{{index $.Vars "data_source_id"}}"
backup_id = "{{index $.Vars "backup_id"}}"

name = "{{index $.Vars "backup_name"}}"

compute_instance_target_environment {
project = "{{index $.TestEnvVars "project"}}"
zone = "us-central1-a"
}

compute_instance_restore_properties {
name = "{{index $.Vars "instance_name"}}"
machine_type = "e2-medium"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
resource "google_backup_dr_restore_workload" "{{$.PrimaryResourceId}}" {
location = "us-central1"
backup_vault_id = "{{index $.Vars "backup_vault_id"}}"
data_source_id = "{{index $.Vars "data_source_id"}}"
backup_id = "{{index $.Vars "backup_id"}}"

name = "{{index $.Vars "backup_name"}}"

compute_instance_target_environment {
project = "{{index $.TestEnvVars "project"}}"
zone = "us-central1-a"
}

compute_instance_restore_properties {
name = "{{index $.Vars "instance_name"}}"
machine_type = "e2-medium"
description = "Restored compute instance with advanced configuration"

can_ip_forward = true
deletion_protection = false

labels = {
environment = "production"
restored = "true"
team = "infrastructure"
}

tags {
items = ["web", "https-server", "restored"]
}

network_interfaces {
network = "default"
subnetwork = "projects/{{index $.TestEnvVars "project"}}/regions/us-central1/subnetworks/default"

access_configs {
name = "External NAT"
network_tier = "PREMIUM"
}
}

scheduling {
automatic_restart = true
on_host_maintenance = "MIGRATE"
preemptible = false
provisioning_model = "STANDARD"
}

service_accounts {
email = "default"
scopes = [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/compute"
]
}

shielded_instance_config {
enable_secure_boot = true
enable_vtpm = true
enable_integrity_monitoring = true
}

advanced_machine_features {
enable_nested_virtualization = false
threads_per_core = 1
}

metadata {
items {
key = "startup-script"
value = "#!/bin/bash\necho 'Instance restored' > /tmp/restored.txt"
}
items {
key = "enable-oslogin"
value = "TRUE"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
resource "google_backup_dr_restore_workload" "{{$.PrimaryResourceId}}" {
location = "us-central1"
backup_vault_id = "{{index $.Vars "backup_vault_id"}}"
data_source_id = "{{index $.Vars "data_source_id"}}"
backup_id = "{{index $.Vars "backup_id"}}"

name = "{{index $.Vars "backup_name"}}"

disk_target_environment {
project = "{{index $.TestEnvVars "project"}}"
zone = "us-central1-a"
}

disk_restore_properties {
name = "{{index $.Vars "disk_name"}}"
size_gb = 100
type = "pd-standard"

description = "Restored persistent disk from backup"

labels = {
environment = "production"
restored = "true"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
resource "google_backup_dr_restore_workload" "{{$.PrimaryResourceId}}" {
location = "us-central1"
backup_vault_id = "{{index $.Vars "backup_vault_id"}}"
data_source_id = "{{index $.Vars "data_source_id"}}"
backup_id = "{{index $.Vars "backup_id"}}"

name = "{{index $.Vars "backup_name"}}"

region_disk_target_environment {
project = "{{index $.TestEnvVars "project"}}"
region = "us-central1"
replica_zones = [
"us-central1-a",
"us-central1-b"
]
}

disk_restore_properties {
name = "{{index $.Vars "disk_name"}}"
size_gb = 200
type = "pd-balanced"

description = "Restored regional persistent disk"

labels = {
type = "regional"
environment = "production"
}

provisioned_iops = 3000
provisioned_throughput = 140
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
resource "google_backup_dr_restore_workload" "{{$.PrimaryResourceId}}" {
location = "us-central1"
backup_vault_id = "{{index $.Vars "backup_vault_id"}}"
data_source_id = "{{index $.Vars "data_source_id"}}"
backup_id = "{{index $.Vars "backup_id"}}"

name = "{{index $.Vars "backup_name"}}"

# Set to false to keep the restored resource in GCP after terraform destroy
delete_restored_instance = false

disk_target_environment {
project = "{{index $.TestEnvVars "project"}}"
zone = "us-central1-a"
}

disk_restore_properties {
name = "{{index $.Vars "disk_name"}}"
size_gb = 50
type = "pd-standard"
}
}
Loading
Loading