Skip to content

Commit a444928

Browse files
authored
Added support for working with resource reclamations (IBM-Cloud#6396)
* Added support for resource reclamation * updated the read logic * updated test cases * updated tests
1 parent 92688a7 commit a444928

8 files changed

+823
-15
lines changed

ibm/acctest/acctest.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ var (
166166
LogsEventNotificationInstanceRegion string
167167
)
168168

169+
// Reclamation
170+
var (
171+
ReclamationId string
172+
)
173+
169174
// Secrets Manager
170175
var (
171176
SecretsManagerInstanceID string
@@ -468,6 +473,11 @@ func init() {
468473
os.Setenv("IBMCLOUD_BLUEMIX_GO_TRACE", "true")
469474
}
470475

476+
ReclamationId = os.Getenv("IBM_RECLAMATION_ID")
477+
if ReclamationId == "" {
478+
fmt.Println("[WARN] Set the environment variable IBM_RECLAMATION_ID for testing reclamation, reclamation_delete tests will fail if this is not set")
479+
}
480+
471481
IamIdentityAssignmentTargetAccountId = os.Getenv("IAM_IDENTITY_ASSIGNMENT_TARGET_ACCOUNT")
472482
IamIdentityEnterpriseAccountId = os.Getenv("IAM_IDENTITY_ENTERPRISE_ACCOUNT")
473483

ibm/provider/provider.go

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,9 @@ func Provider() *schema.Provider {
707707
"ibm_app_config_integration_en": appconfiguration.DataSourceIBMAppConfigIntegrationEn(),
708708
"ibm_app_config_integration_kms": appconfiguration.DataSourceIBMAppConfigIntegrationKms(),
709709

710+
// resource_reclamations
711+
"ibm_resource_reclamations": resourcecontroller.DataSourceIBMResourceReclamations(),
712+
710713
"ibm_resource_quota": resourcecontroller.DataSourceIBMResourceQuota(),
711714
"ibm_resource_group": resourcemanager.DataSourceIBMResourceGroup(),
712715
"ibm_resource_groups": resourcemanager.DataSourceIBMResourceGroups(),
@@ -1463,21 +1466,25 @@ func Provider() *schema.Provider {
14631466
"ibm_kms_kmip_adapter": kms.ResourceIBMKmsKMIPAdapter(),
14641467
"ibm_kms_kmip_client_cert": kms.ResourceIBMKmsKMIPClientCertificate(),
14651468
"ibm_resource_group": resourcemanager.ResourceIBMResourceGroup(),
1466-
"ibm_resource_instance": resourcecontroller.ResourceIBMResourceInstance(),
1467-
"ibm_resource_key": resourcecontroller.ResourceIBMResourceKey(),
1468-
"ibm_security_group": classicinfrastructure.ResourceIBMSecurityGroup(),
1469-
"ibm_security_group_rule": classicinfrastructure.ResourceIBMSecurityGroupRule(),
1470-
"ibm_service_instance": cloudfoundry.ResourceIBMServiceInstance(),
1471-
"ibm_service_key": cloudfoundry.ResourceIBMServiceKey(),
1472-
"ibm_space": cloudfoundry.ResourceIBMSpace(),
1473-
"ibm_storage_evault": classicinfrastructure.ResourceIBMStorageEvault(),
1474-
"ibm_storage_block": classicinfrastructure.ResourceIBMStorageBlock(),
1475-
"ibm_storage_file": classicinfrastructure.ResourceIBMStorageFile(),
1476-
"ibm_subnet": classicinfrastructure.ResourceIBMSubnet(),
1477-
"ibm_dns_reverse_record": classicinfrastructure.ResourceIBMDNSReverseRecord(),
1478-
"ibm_ssl_certificate": classicinfrastructure.ResourceIBMSSLCertificate(),
1479-
"ibm_cdn": classicinfrastructure.ResourceIBMCDN(),
1480-
"ibm_hardware_firewall_shared": classicinfrastructure.ResourceIBMFirewallShared(),
1469+
1470+
// resource_reclamation
1471+
"ibm_resource_reclamation_delete": resourcecontroller.ResourceIBMResourceReclamationDelete(),
1472+
1473+
"ibm_resource_instance": resourcecontroller.ResourceIBMResourceInstance(),
1474+
"ibm_resource_key": resourcecontroller.ResourceIBMResourceKey(),
1475+
"ibm_security_group": classicinfrastructure.ResourceIBMSecurityGroup(),
1476+
"ibm_security_group_rule": classicinfrastructure.ResourceIBMSecurityGroupRule(),
1477+
"ibm_service_instance": cloudfoundry.ResourceIBMServiceInstance(),
1478+
"ibm_service_key": cloudfoundry.ResourceIBMServiceKey(),
1479+
"ibm_space": cloudfoundry.ResourceIBMSpace(),
1480+
"ibm_storage_evault": classicinfrastructure.ResourceIBMStorageEvault(),
1481+
"ibm_storage_block": classicinfrastructure.ResourceIBMStorageBlock(),
1482+
"ibm_storage_file": classicinfrastructure.ResourceIBMStorageFile(),
1483+
"ibm_subnet": classicinfrastructure.ResourceIBMSubnet(),
1484+
"ibm_dns_reverse_record": classicinfrastructure.ResourceIBMDNSReverseRecord(),
1485+
"ibm_ssl_certificate": classicinfrastructure.ResourceIBMSSLCertificate(),
1486+
"ibm_cdn": classicinfrastructure.ResourceIBMCDN(),
1487+
"ibm_hardware_firewall_shared": classicinfrastructure.ResourceIBMFirewallShared(),
14811488

14821489
// Software Defined Storage as a Service
14831490
"ibm_sds_volume": sdsaas.ResourceIBMSdsVolume(),
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
// Copyright IBM Corp. 2024
2+
// Licensed under the Mozilla Public License v2.0
3+
4+
package resourcecontroller
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"log"
10+
"time"
11+
12+
rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2"
13+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
14+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
15+
16+
"github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns"
17+
"github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex"
18+
)
19+
20+
// DataSourceIBMResourceReclamations returns the schema for the ibm_resource_reclamations data source.
21+
//
22+
// Example Terraform usage:
23+
//
24+
// data "ibm_resource_reclamations" "all" {}
25+
// output "reclamation_ids" {
26+
// value = [for r in data.ibm_resource_reclamations.all.reclamations : r.id]
27+
// }
28+
func DataSourceIBMResourceReclamations() *schema.Resource {
29+
return &schema.Resource{
30+
ReadContext: dataSourceIBMResourceReclamationsRead,
31+
Description: "Retrieve the list of all resource reclamations in the account.",
32+
Schema: map[string]*schema.Schema{
33+
"reclamations": {
34+
Type: schema.TypeList,
35+
Computed: true,
36+
Description: "A list of resource reclamations.",
37+
Elem: &schema.Resource{
38+
Schema: map[string]*schema.Schema{
39+
"id": {
40+
Type: schema.TypeString,
41+
Computed: true,
42+
Description: "The ID associated with the reclamation.",
43+
},
44+
"entity_id": {
45+
Type: schema.TypeString,
46+
Computed: true,
47+
Description: "The entity ID for this reclamation.",
48+
},
49+
"entity_type_id": {
50+
Type: schema.TypeString,
51+
Computed: true,
52+
Description: "The entity type ID for this reclamation.",
53+
},
54+
"entity_crn": {
55+
Type: schema.TypeString,
56+
Computed: true,
57+
Description: "The full CRN associated with this reclamation.",
58+
},
59+
"resource_instance_id": {
60+
Type: schema.TypeString,
61+
Computed: true,
62+
Description: "The resource instance ID associated with the reclamation.",
63+
},
64+
"resource_group_id": {
65+
Type: schema.TypeString,
66+
Computed: true,
67+
Description: "The resource group ID.",
68+
},
69+
"account_id": {
70+
Type: schema.TypeString,
71+
Computed: true,
72+
Description: "The account ID.",
73+
},
74+
"policy_id": {
75+
Type: schema.TypeString,
76+
Computed: true,
77+
Description: "The policy ID for the reclamation.",
78+
},
79+
"state": {
80+
Type: schema.TypeString,
81+
Computed: true,
82+
Description: "The state of this reclamation.",
83+
},
84+
"target_time": {
85+
Type: schema.TypeString,
86+
Computed: true,
87+
Description: "When the reclamation retention period ends (RFC3339).",
88+
},
89+
"created_at": {
90+
Type: schema.TypeString,
91+
Computed: true,
92+
Description: "The date/time when created (RFC3339).",
93+
},
94+
"created_by": {
95+
Type: schema.TypeString,
96+
Computed: true,
97+
Description: "The subject who created this reclamation.",
98+
},
99+
"updated_at": {
100+
Type: schema.TypeString,
101+
Computed: true,
102+
Description: "The date/time when last updated (RFC3339).",
103+
},
104+
"updated_by": {
105+
Type: schema.TypeString,
106+
Computed: true,
107+
Description: "The subject who updated this reclamation.",
108+
},
109+
"custom_properties": {
110+
Type: schema.TypeMap,
111+
Computed: true,
112+
Description: "Custom properties set on the reclamation.",
113+
Elem: &schema.Schema{Type: schema.TypeString},
114+
},
115+
},
116+
},
117+
},
118+
},
119+
}
120+
}
121+
122+
// dataSourceIBMResourceReclamationsRead fetches all reclamations using Resource Controller V2
123+
// and sets them into the Terraform state.
124+
// Errors are always reported with flex.DiscriminatedTerraformErrorf and flex.TerraformErrorf to aid in debugging.
125+
func dataSourceIBMResourceReclamationsRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
126+
rsConClient, err := meta.(conns.ClientSession).ResourceControllerV2API()
127+
if err != nil {
128+
tfErr := flex.DiscriminatedTerraformErrorf(
129+
err,
130+
err.Error(),
131+
"(Data) ibm_resource_reclamations",
132+
"read",
133+
"initialize-client",
134+
)
135+
log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage())
136+
return tfErr.GetDiag()
137+
}
138+
139+
opts := &rc.ListReclamationsOptions{}
140+
reclamationsList, _, err := rsConClient.ListReclamationsWithContext(context, opts)
141+
if err != nil {
142+
tfErr := flex.TerraformErrorf(
143+
err,
144+
fmt.Sprintf("ListReclamations failed: %s", err.Error()),
145+
"(Data) ibm_resource_reclamations",
146+
"read",
147+
)
148+
log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage())
149+
return tfErr.GetDiag()
150+
}
151+
152+
var flattened []map[string]interface{}
153+
for _, rec := range reclamationsList.Resources {
154+
flattened = append(flattened, flattenReclamationForDS(&rec))
155+
}
156+
157+
d.SetId(fmt.Sprintf("reclamations-%d", time.Now().Unix()))
158+
if err := d.Set("reclamations", flattened); err != nil {
159+
tfErr := flex.DiscriminatedTerraformErrorf(
160+
err,
161+
fmt.Sprintf("Error setting reclamations: %s", err),
162+
"(Data) ibm_resource_reclamations",
163+
"read",
164+
"set-reclamations",
165+
)
166+
return tfErr.GetDiag()
167+
}
168+
169+
return nil
170+
}
171+
172+
// flattenReclamationForDS transforms rc.Reclamation into a flat map compatible with Terraform schema.
173+
func flattenReclamationForDS(rec *rc.Reclamation) map[string]interface{} {
174+
m := make(map[string]interface{})
175+
if rec.ID != nil {
176+
m["id"] = *rec.ID
177+
}
178+
if rec.EntityID != nil {
179+
m["entity_id"] = *rec.EntityID
180+
}
181+
if rec.EntityTypeID != nil {
182+
m["entity_type_id"] = *rec.EntityTypeID
183+
}
184+
if rec.EntityCRN != nil {
185+
m["entity_crn"] = *rec.EntityCRN
186+
}
187+
if rec.ResourceInstanceID != nil {
188+
m["resource_instance_id"] = *rec.ResourceInstanceID
189+
}
190+
if rec.ResourceGroupID != nil {
191+
m["resource_group_id"] = *rec.ResourceGroupID
192+
}
193+
if rec.AccountID != nil {
194+
m["account_id"] = *rec.AccountID
195+
}
196+
if rec.PolicyID != nil {
197+
m["policy_id"] = *rec.PolicyID
198+
}
199+
if rec.State != nil {
200+
m["state"] = *rec.State
201+
}
202+
if rec.TargetTime != nil {
203+
m["target_time"] = *rec.TargetTime
204+
}
205+
if rec.CreatedAt != nil {
206+
m["created_at"] = rec.CreatedAt.String()
207+
}
208+
if rec.CreatedBy != nil {
209+
m["created_by"] = *rec.CreatedBy
210+
}
211+
if rec.UpdatedAt != nil {
212+
m["updated_at"] = rec.UpdatedAt.String()
213+
}
214+
if rec.UpdatedBy != nil {
215+
m["updated_by"] = *rec.UpdatedBy
216+
}
217+
// Flex.Flatten will safely deal with nil and non-string values
218+
m["custom_properties"] = flex.Flatten(rec.CustomProperties)
219+
return m
220+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright IBM Corp. 2017, 2021 All Rights Reserved.
2+
// Licensed under the Mozilla Public License v2.0
3+
4+
package resourcecontroller_test
5+
6+
import (
7+
"regexp"
8+
"testing"
9+
10+
acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
12+
)
13+
14+
func TestAccIBMResourceReclamationsDataSource_basic(t *testing.T) {
15+
resource.Test(t, resource.TestCase{
16+
PreCheck: func() { acc.TestAccPreCheck(t) },
17+
Providers: acc.TestAccProviders,
18+
Steps: []resource.TestStep{
19+
{
20+
Config: testAccCheckIBMResourceReclamationsDataSourceConfig(),
21+
Check: resource.ComposeTestCheckFunc(
22+
// Basic check to ensure reclamations attribute is present and is a list
23+
resource.TestCheckResourceAttrSet("data.ibm_resource_reclamations.all", "reclamations.#"),
24+
),
25+
},
26+
},
27+
})
28+
}
29+
30+
func TestAccIBMResourceReclamationsDataSource_invalid(t *testing.T) {
31+
// Since reclamations list does not take filters, you might want to add a negative case e.g. empty provider config
32+
resource.Test(t, resource.TestCase{
33+
PreCheck: func() { acc.TestAccPreCheck(t) },
34+
Providers: acc.TestAccProviders,
35+
Steps: []resource.TestStep{
36+
{
37+
Config: `
38+
data "ibm_resource_reclamationss" "all" {
39+
# Intentionally invalid config if any required fields added later, or just test error
40+
}`,
41+
ExpectError: regexp.MustCompile(``),
42+
},
43+
},
44+
})
45+
}
46+
47+
func testAccCheckIBMResourceReclamationsDataSourceConfig() string {
48+
return `
49+
data "ibm_resource_reclamations" "all" {
50+
}
51+
`
52+
}

0 commit comments

Comments
 (0)