Skip to content

Commit f1e67ae

Browse files
fetchforresourceType bpa added (#15043) (#24304)
[upstream:53b287e6f06ce9beec9d6bfeee285a61348e34ac] Signed-off-by: Modular Magician <[email protected]>
1 parent 718cb85 commit f1e67ae

File tree

5 files changed

+345
-1
lines changed

5 files changed

+345
-1
lines changed

.changelog/15043.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
backupdr: added new RPC fetch for resource type for backup plan association in `data_source_backup_dr_backup_plan_association.go` . This rpc will allow users to fetch all the backup plan associations for a particular resource type like compute.googleapis.com/Instance , sqladmin.googleapis.com/Instance etc
3+
```

google/provider/provider_mmv1_resources.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ var handwrittenDatasources = map[string]*schema.Resource{
199199
"google_apphub_discovered_service": apphub.DataSourceApphubDiscoveredService(),
200200
"google_backup_dr_management_server": backupdr.DataSourceGoogleCloudBackupDRService(),
201201
"google_backup_dr_backup_plan_association": backupdr.DataSourceGoogleCloudBackupDRBackupPlanAssociation(),
202+
"google_backup_dr_backup_plan_associations": backupdr.DataSourceGoogleCloudBackupDRBackupPlanAssociations(),
202203
"google_backup_dr_backup_plan": backupdr.DataSourceGoogleCloudBackupDRBackupPlan(),
203204
"google_backup_dr_backup": backupdr.DataSourceGoogleCloudBackupDRBackup(),
204205
"google_backup_dr_data_source": backupdr.DataSourceGoogleCloudBackupDRDataSource(),

google/services/backupdr/data_source_backup_dr_backup_plan_association.go

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

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

google/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
@@ -17,9 +17,14 @@
1717
package backupdr_test
1818

1919
import (
20+
"fmt"
21+
"strconv"
22+
"strings"
23+
"testing"
24+
2025
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
26+
"github.com/hashicorp/terraform-plugin-testing/terraform"
2127
"github.com/hashicorp/terraform-provider-google/google/acctest"
22-
"testing"
2328
)
2429

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