Skip to content

Commit 53b287e

Browse files
fetchforresourceType bpa added (#15043)
Co-authored-by: Cameron Thornton <[email protected]>
1 parent f261d71 commit 53b287e

File tree

4 files changed

+328
-1
lines changed

4 files changed

+328
-1
lines changed

mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ var handwrittenDatasources = map[string]*schema.Resource{
4343
"google_apphub_discovered_service": apphub.DataSourceApphubDiscoveredService(),
4444
"google_backup_dr_management_server": backupdr.DataSourceGoogleCloudBackupDRService(),
4545
"google_backup_dr_backup_plan_association": backupdr.DataSourceGoogleCloudBackupDRBackupPlanAssociation(),
46+
"google_backup_dr_backup_plan_associations": backupdr.DataSourceGoogleCloudBackupDRBackupPlanAssociations(),
4647
"google_backup_dr_backup_plan": backupdr.DataSourceGoogleCloudBackupDRBackupPlan(),
4748
"google_backup_dr_backup": backupdr.DataSourceGoogleCloudBackupDRBackup(),
4849
"google_backup_dr_data_source": backupdr.DataSourceGoogleCloudBackupDRDataSource(),

mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup_plan_association.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package backupdr
22

33
import (
44
"fmt"
5+
56
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
67
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
78
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
@@ -44,3 +45,110 @@ func dataSourceGoogleCloudBackupDRBackupPlanAssociationRead(d *schema.ResourceDa
4445
}
4546
return nil
4647
}
48+
49+
// Plural datasource to Fetch BackupPlanAssociations for a given resource type
50+
func DataSourceGoogleCloudBackupDRBackupPlanAssociations() *schema.Resource {
51+
return &schema.Resource{
52+
Read: dataSourceGoogleCloudBackupDRBackupPlanAssociationsRead,
53+
Schema: map[string]*schema.Schema{
54+
"location": {
55+
Type: schema.TypeString,
56+
Required: true,
57+
Description: "The location to list the backup plan associations from.",
58+
},
59+
"project": {
60+
Type: schema.TypeString,
61+
Optional: true,
62+
Computed: true,
63+
Description: "The ID of the project in which the resource belongs.",
64+
},
65+
"resource_type": {
66+
Type: schema.TypeString,
67+
Required: true,
68+
Description: `The resource type of workload on which backup plan is applied. Examples include, "compute.googleapis.com/Instance", "compute.googleapis.com/Disk".`,
69+
},
70+
71+
"associations": {
72+
Type: schema.TypeList,
73+
Computed: true,
74+
Description: "A list of the backup plan associations found.",
75+
Elem: &schema.Resource{
76+
Schema: map[string]*schema.Schema{
77+
"name": {
78+
Type: schema.TypeString,
79+
Computed: true,
80+
},
81+
"resource": {
82+
Type: schema.TypeString,
83+
Computed: true,
84+
},
85+
"backup_plan": {
86+
Type: schema.TypeString,
87+
Computed: true,
88+
},
89+
"create_time": {
90+
Type: schema.TypeString,
91+
Computed: true,
92+
},
93+
},
94+
},
95+
},
96+
},
97+
}
98+
}
99+
100+
func dataSourceGoogleCloudBackupDRBackupPlanAssociationsRead(d *schema.ResourceData, meta interface{}) error {
101+
config := meta.(*transport_tpg.Config)
102+
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
103+
if err != nil {
104+
return err
105+
}
106+
107+
project, err := tpgresource.GetProject(d, config)
108+
if err != nil {
109+
return err
110+
}
111+
112+
location := d.Get("location").(string)
113+
resourceType := d.Get("resource_type").(string)
114+
115+
url := fmt.Sprintf("%sprojects/%s/locations/%s/backupPlanAssociations:fetchForResourceType?resourceType=%s", config.BackupDRBasePath, project, location, resourceType)
116+
117+
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
118+
Config: config,
119+
Method: "GET",
120+
Project: project,
121+
RawURL: url,
122+
UserAgent: userAgent,
123+
})
124+
if err != nil {
125+
return fmt.Errorf("Error reading BackupPlanAssociations: %s", err)
126+
}
127+
128+
// Adjust "backupPlanAssociations" to match the key in the actual API response.
129+
items, ok := res["backupPlanAssociations"].([]interface{})
130+
if !ok {
131+
items = make([]interface{}, 0)
132+
}
133+
134+
// Flatten the list of items from the API response into the schema
135+
associations := make([]map[string]interface{}, 0, len(items))
136+
for _, item := range items {
137+
association := item.(map[string]interface{})
138+
flattened := map[string]interface{}{
139+
"name": association["name"],
140+
"resource": association["resource"],
141+
"backup_plan": association["backupPlan"],
142+
"create_time": association["createTime"],
143+
}
144+
associations = append(associations, flattened)
145+
}
146+
147+
if err := d.Set("associations", associations); err != nil {
148+
return fmt.Errorf("Error setting associations: %s", err)
149+
}
150+
151+
d.SetId(url)
152+
153+
return nil
154+
}

mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup_plan_association_test.go

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
package backupdr_test
22

33
import (
4+
"fmt"
5+
"strconv"
6+
"strings"
7+
"testing"
8+
49
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
10+
"github.com/hashicorp/terraform-plugin-testing/terraform"
511
"github.com/hashicorp/terraform-provider-google/google/acctest"
6-
"testing"
712
)
813

914
func TestAccDataSourceGoogleBackupDRBackupPlanAssociation_basic(t *testing.T) {
@@ -121,3 +126,168 @@ data "google_backup_dr_backup_plan_association" "bpa-test" {
121126
}
122127
`, context)
123128
}
129+
130+
func TestAccDataSourceGoogleBackupDRBackupPlanAssociations(t *testing.T) {
131+
t.Parallel()
132+
context := map[string]interface{}{
133+
"random_suffix": acctest.RandString(t, 10),
134+
"bpa_id": "tf-test-bpa-plural-" + acctest.RandString(t, 10),
135+
}
136+
137+
acctest.VcrTest(t, resource.TestCase{
138+
PreCheck: func() { acctest.AccTestPreCheck(t) },
139+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
140+
Steps: []resource.TestStep{
141+
{
142+
Config: testAccDataSourceGoogleBackupDRBackupPlanAssociations_config(context),
143+
Check: testAccCheckBackupPlanAssociationInList(
144+
"data.google_backup_dr_backup_plan_associations.bpas",
145+
"google_compute_instance.default",
146+
"google_backup_dr_backup_plan.foo1",
147+
"data.google_project.project",
148+
),
149+
},
150+
},
151+
})
152+
}
153+
154+
func testAccCheckBackupPlanAssociationInList(dataSourceName, instanceName, backupPlanName, projectDsName string) resource.TestCheckFunc {
155+
return func(s *terraform.State) error {
156+
ds, ok := s.RootModule().Resources[dataSourceName]
157+
if !ok {
158+
return fmt.Errorf("data source not found: %s", dataSourceName)
159+
}
160+
161+
instance, ok := s.RootModule().Resources[instanceName]
162+
if !ok {
163+
return fmt.Errorf("instance resource not found: %s", instanceName)
164+
}
165+
166+
backupPlan, ok := s.RootModule().Resources[backupPlanName]
167+
if !ok {
168+
return fmt.Errorf("backup plan resource not found: %s", backupPlanName)
169+
}
170+
backupPlanNameFromState := backupPlan.Primary.Attributes["name"]
171+
172+
project, ok := s.RootModule().Resources[projectDsName]
173+
if !ok {
174+
return fmt.Errorf("project data source not found: %s", projectDsName)
175+
}
176+
projectID := project.Primary.Attributes["project_id"]
177+
projectNumber := project.Primary.Attributes["number"]
178+
179+
fmt.Printf("\n--- Performing Direct Association Check ---\n")
180+
181+
// 1. Reconstruct the 'resource' string using the project NUMBER and instance ID
182+
// to match the format returned by the BackupDR API.
183+
instanceID := instance.Primary.Attributes["instance_id"]
184+
zone := instance.Primary.Attributes["zone"]
185+
expectedResource := fmt.Sprintf("projects/%s/zones/%s/instances/%s", projectNumber, zone, instanceID)
186+
fmt.Printf("Expected Resource (constructed): %s\n", expectedResource)
187+
188+
// 2. Normalize the backup plan name to also use the project NUMBER.
189+
expectedBackupPlan := strings.Replace(backupPlanNameFromState, "projects/"+projectID, "projects/"+projectNumber, 1)
190+
fmt.Printf("Expected Backup Plan (normalized): %s\n", expectedBackupPlan)
191+
192+
associationsCount, _ := strconv.Atoi(ds.Primary.Attributes["associations.#"])
193+
fmt.Printf("Total associations found by data source: %d\n", associationsCount)
194+
195+
for i := 0; i < associationsCount; i++ {
196+
resourceAttr := ds.Primary.Attributes[fmt.Sprintf("associations.%d.resource", i)]
197+
backupPlanAttr := ds.Primary.Attributes[fmt.Sprintf("associations.%d.backup_plan", i)]
198+
199+
fmt.Printf("Found Association #%d: Resource='%s', BackupPlan='%s'\n", i, resourceAttr, backupPlanAttr)
200+
201+
if resourceAttr == expectedResource && backupPlanAttr == expectedBackupPlan {
202+
fmt.Println("--- Match found! Test successful. ---")
203+
return nil
204+
}
205+
}
206+
207+
fmt.Println("--- No match found after checking all associations. ---")
208+
return fmt.Errorf("no matching backup plan association found in data source '%s' for resource '%s'", dataSourceName, expectedResource)
209+
}
210+
}
211+
212+
func testAccDataSourceGoogleBackupDRBackupPlanAssociations_config(context map[string]interface{}) string {
213+
return acctest.Nprintf(`
214+
data "google_project" "project" {}
215+
216+
resource "google_service_account" "default" {
217+
account_id = "tf-test-my-custom1-%{random_suffix}"
218+
display_name = "Custom SA for VM Instance"
219+
}
220+
221+
resource "google_compute_instance" "default" {
222+
name = "tf-test-compute-instance1-%{random_suffix}"
223+
machine_type = "n2-standard-2"
224+
zone = "us-central1-a"
225+
tags = ["foo", "bar"]
226+
boot_disk {
227+
initialize_params {
228+
image = "debian-cloud/debian-11"
229+
}
230+
}
231+
network_interface {
232+
network = "default"
233+
}
234+
service_account {
235+
email = google_service_account.default.email
236+
scopes = ["cloud-platform"]
237+
}
238+
}
239+
240+
resource "google_backup_dr_backup_vault" "my-backup-vault" {
241+
location = "us-central1"
242+
backup_vault_id = "tf-test-bv1-%{random_suffix}"
243+
description = "This is a backup vault for list datasource test."
244+
backup_minimum_enforced_retention_duration = "100000s"
245+
labels = {
246+
foo = "bar1"
247+
bar = "baz1"
248+
}
249+
annotations = {
250+
annotations1 = "bar1"
251+
annotations2 = "baz1"
252+
}
253+
force_update = "true"
254+
force_delete = "true"
255+
allow_missing = "true"
256+
}
257+
258+
resource "google_backup_dr_backup_plan" "foo1" {
259+
location = "us-central1"
260+
backup_plan_id = "tf-test-bp-test1-%{random_suffix}"
261+
resource_type = "compute.googleapis.com/Instance"
262+
backup_vault = google_backup_dr_backup_vault.my-backup-vault.name
263+
264+
backup_rules {
265+
rule_id = "rule-1"
266+
backup_retention_days = 2
267+
standard_schedule {
268+
recurrence_type = "HOURLY"
269+
hourly_frequency = 6
270+
time_zone = "UTC"
271+
backup_window {
272+
start_hour_of_day = 12
273+
end_hour_of_day = 18
274+
}
275+
}
276+
}
277+
}
278+
279+
resource "google_backup_dr_backup_plan_association" "bpa" {
280+
location = "us-central1"
281+
backup_plan_association_id = "%{bpa_id}"
282+
resource = google_compute_instance.default.id
283+
resource_type = "compute.googleapis.com/Instance"
284+
backup_plan = google_backup_dr_backup_plan.foo1.name
285+
}
286+
287+
data "google_backup_dr_backup_plan_associations" "bpas" {
288+
location = "us-central1"
289+
resource_type = "compute.googleapis.com/Instance"
290+
depends_on = [google_backup_dr_backup_plan_association.bpa]
291+
}
292+
`, context)
293+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
subcategory: "Backup and DR Service"
3+
description: |-
4+
Get information about a list of Backup and DR BackupPlanAssociations for a specific resource type .
5+
---
6+
7+
# google_backup_dr_backup_plan_associations
8+
9+
Provides a list of Backup and DR BackupPlanAssociations for a specific resource type.
10+
11+
~> **Warning:** This datasource is in beta, and should be used with the terraform-provider-google-beta provider.
12+
See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta datasources.
13+
14+
## Example Usage
15+
16+
```hcl
17+
data "google_backup_dr_backup_plan_associations" "compute_instance_associations" {
18+
location = "us-central1"
19+
resource_type = "compute.googleapis.com/Instance"
20+
}
21+
22+
## Argument Reference
23+
24+
The following arguments are supported:
25+
26+
* `location` - (Required)The location where the Backup Plan Association resources reside.
27+
* `resource_type` - (Required) The resource type of the workload. For example, sqladmin.googleapis.com/Instance or compute.googleapis.com/Instance.
28+
29+
- - -
30+
31+
* `project` - (Optional) The project in which the resource belongs. If it
32+
is not provided, the provider project is used.
33+
34+
## Attributes Reference
35+
36+
In addition to the arguments listed above, the following computed attributes are exported:
37+
38+
* `project` - The ID of the project in which the resource belongs.
39+
* `associations` - A list of the backup plan associations found.
40+
41+
Each entry in the `associations` list contains the following fields:
42+
43+
* `name` - The full name of the backup plan association resource.
44+
* `resource` - The resource to which the backup plan is applied.
45+
* `backup_plan` - The backup plan to which the resource is attached.
46+
* `create_time` - The time when the association was created.
47+
48+
See [google_backup_dr_backup_plan_associations](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/backup_dr_backup_plan_associations) resource for details of the available attributes.

0 commit comments

Comments
 (0)