Skip to content

Commit ed27cba

Browse files
feat: Adds support for service_account_for_atlas and status fields on mongodbatlas_cloud_provider_access_setup resource and data source (#3637)
* Add GCP cloud provider access to mongodbatlas_cloud_provider_access_setup * Fix typo for function name * Add GCP configuration for schema on data source * Change optional field to computed as required per provider * Refactor function to accomodate for Cloud Provider Access - GCP * Add documentation for resource * Add GCP Cloud provider documentation for data source * Add GCP provider for data source validation * Add resource and resouce acceptance test for GCP Cloud Provider Access setup * Fix format * Add changelog * Fix issue where role ID was missing for Azure config * Fix format * Fix issues for refactor on GCP * Address PR comments * Address further PR comments * Refactor setup function to handle different cloud providers, and return error if provider used is not correct Add error handling for cloud provider access * Refactor multiple if/else statements into switch in order to avoid lint errors * Address nit comments * Substitute cloud provider string names with constants
1 parent 3ec1bc6 commit ed27cba

File tree

9 files changed

+172
-43
lines changed

9 files changed

+172
-43
lines changed

.changelog/3637.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
```release-note:enhancement
2+
resource/mongodbatlas_cloud_provider_access_setup: Adds support for GCP as a Cloud Provider.
3+
```
4+
5+
```release-note:enhancement
6+
data-source/mongodbatlas_cloud_provider_access_setup: Adds support for GCP as a Cloud Provider.
7+
```

docs/data-sources/cloud_provider_access_setup.md

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Data Source: mongodbatlas_cloud_provider_access_setup
22

3-
`mongodbatlas_cloud_provider_access_setup` allows you to get a single role for a provider access role setup, currently only AWS and Azure are supported.
3+
`mongodbatlas_cloud_provider_access_setup` allows you to get a single role for a provider access role setup. Supported providers: AWS, AZURE and GCP.
44

55
-> **NOTE:** Groups and projects are synonymous terms. You may find `groupId` in the official documentation.
66

@@ -36,27 +36,43 @@ data "mongodbatlas_cloud_provider_access_setup" "single_setup" {
3636
role_id = mongodbatlas_cloud_provider_access_setup.test_role.role_id
3737
}
3838
```
39+
40+
## Example Usage with GCP
41+
42+
```terraform
43+
resource "mongodbatlas_cloud_provider_access_setup" "test_role" {
44+
project_id = "64259ee860c43338194b0f8e"
45+
provider_name = "GCP"
46+
}
47+
48+
data "mongodbatlas_cloud_provider_access_setup" "single_setup" {
49+
project_id = mongodbatlas_cloud_provider_access_setup.test_role.project_id
50+
provider_name = mongodbatlas_cloud_provider_access_setup.test_role.provider_name
51+
role_id = mongodbatlas_cloud_provider_access_setup.test_role.role_id
52+
}
53+
```
54+
3955
## Argument Reference
4056

4157
* `project_id` - (Required) The unique ID for the project to get all Cloud Provider Access
42-
* `provider_name` - (Required) cloud provider name, currently only AWS is supported
43-
* `role_id` - (Required) unique role id among all the aws roles provided by mongodb atlas
58+
* `provider_name` - (Required) cloud provider name. Supported values: `AWS`, `AZURE`, and `GCP`.
59+
* `role_id` - (Required) unique role id among all the roles provided by MongoDB Atlas.
4460

4561
## Attributes Reference
4662

4763
In addition to all arguments above, the following attributes are exported:
4864

4965
* `id` - Autogenerated Unique ID for this data source.
50-
* `aws` - aws related role information
51-
* `atlas_assumed_role_external_id` - Unique external ID Atlas uses when assuming the IAM role in your AWS account.
52-
* `atlas_aws_account_arn` - ARN associated with the Atlas AWS account used to assume IAM roles in your AWS account.
5366
* `aws_config` - aws related role information
5467
* `atlas_assumed_role_external_id` - Unique external ID Atlas uses when assuming the IAM role in your AWS account.
5568
* `atlas_aws_account_arn` - ARN associated with the Atlas AWS account used to assume IAM roles in your AWS account.
5669
* `azure_config` - azure related configurations
5770
* `atlas_azure_app_id` - Azure Active Directory Application ID of Atlas.
5871
* `service_principal_id`- UUID string that identifies the Azure Service Principal.
5972
* `tenant_id` - UUID String that identifies the Azure Active Directory Tenant ID.
73+
* `gcp_config` - gcp related configurations
74+
* `status` - The status of the GCP cloud provider access setup. See [MongoDB Atlas API](https://www.mongodb.com/docs/api/doc/atlas-admin-api-v2/operation/operation-getgroupcloudprovideraccess#operation-getgroupcloudprovideraccess-200-body-application-vnd-atlas-2023-01-01-json-gcp-object-status).
75+
* `service_account_for_atlas` - The GCP service account email that Atlas uses.
6076
* `created_date` - Date on which this role was created.
6177
* `last_updated_date` - Date and time when this Azure Service Principal was last updated. This parameter expresses its value in the ISO 8601 timestamp format in UTC.
6278

docs/resources/cloud_provider_access.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,21 @@ resource "mongodbatlas_cloud_provider_access_setup" "test_role" {
4444
4545
```
4646

47+
## Example Usage with GCP
48+
49+
```terraform
50+
51+
resource "mongodbatlas_cloud_provider_access_setup" "test_role" {
52+
project_id = "64259ee860c43338194b0f8e"
53+
provider_name = "GCP"
54+
}
55+
56+
```
57+
4758
## Argument Reference
4859

4960
* `project_id` - (Required) The unique ID for the project
50-
* `provider_name` - (Required) The cloud provider for which to create a new role. Currently only AWS and AZURE are supported. **WARNING** Changing the `provider_name` will result in destruction of the existing resource and the creation of a new resource.
61+
* `provider_name` - (Required) The cloud provider for which to create a new role. Currently, AWS, AZURE and GCP are supported. **WARNING** Changing the `provider_name` will result in destruction of the existing resource and the creation of a new resource.
5162
* `azure_config` - azure related configurations
5263
* `atlas_azure_app_id` - Azure Active Directory Application ID of Atlas. This property is required when `provider_name = "AZURE".`
5364
* `service_principal_id`- UUID string that identifies the Azure Service Principal. This property is required when `provider_name = "AZURE".`
@@ -59,6 +70,9 @@ resource "mongodbatlas_cloud_provider_access_setup" "test_role" {
5970
* `aws_config` - aws related arn roles
6071
* `atlas_assumed_role_external_id` - Unique external ID Atlas uses when assuming the IAM role in your AWS account.
6172
* `atlas_aws_account_arn` - ARN associated with the Atlas AWS account used to assume IAM roles in your AWS account.
73+
* `gcp_config` - gcp related configuration
74+
* `status` - The status of the GCP cloud provider access setup. See [MongoDB Atlas API](https://www.mongodb.com/docs/api/doc/atlas-admin-api-v2/operation/operation-getgroupcloudprovideraccess#operation-getgroupcloudprovideraccess-200-body-application-vnd-atlas-2023-01-01-json-gcp-object-status).
75+
* `service_account_for_atlas` - The GCP service account email that Atlas uses.
6276
* `created_date` - Date on which this role was created.
6377
* `last_updated_date` - Date and time when this Azure Service Principal was last updated. This parameter expresses its value in the ISO 8601 timestamp format in UTC.
6478
* `role_id` - Unique ID of this role.

internal/service/cloudprovideraccess/data_source_cloud_provider_access_setup.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
88
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id"
99
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10-
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
1110
"github.com/mongodb/terraform-provider-mongodbatlas/internal/config"
1211
)
1312

@@ -20,9 +19,8 @@ func DataSourceSetup() *schema.Resource {
2019
Required: true,
2120
},
2221
"provider_name": {
23-
Type: schema.TypeString,
24-
Required: true,
25-
ValidateFunc: validation.StringInSlice([]string{"AWS", "AZURE"}, false),
22+
Type: schema.TypeString,
23+
Required: true,
2624
},
2725
"role_id": {
2826
Type: schema.TypeString,
@@ -71,6 +69,22 @@ func DataSourceSetup() *schema.Resource {
7169
},
7270
},
7371
},
72+
"gcp_config": {
73+
Type: schema.TypeList,
74+
Computed: true,
75+
Elem: &schema.Resource{
76+
Schema: map[string]*schema.Schema{
77+
"status": {
78+
Type: schema.TypeString,
79+
Computed: true,
80+
},
81+
"service_account_for_atlas": {
82+
Type: schema.TypeString,
83+
Computed: true,
84+
},
85+
},
86+
},
87+
},
7488
"created_date": {
7589
Type: schema.TypeString,
7690
Computed: true,
@@ -93,7 +107,11 @@ func dataSourceMongoDBAtlasCloudProviderAccessSetupRead(ctx context.Context, d *
93107
return diag.FromErr(fmt.Errorf(ErrorCloudProviderGetRead, err))
94108
}
95109

96-
roleSchema := roleToSchemaSetup(role)
110+
roleSchema, err := roleToSchemaSetup(role)
111+
if err != nil {
112+
return diag.FromErr(fmt.Errorf(ErrorCloudProviderGetRead, err))
113+
}
114+
97115
for key, val := range roleSchema {
98116
if err := d.Set(key, val); err != nil {
99117
return diag.FromErr(fmt.Errorf(ErrorCloudProviderGetRead, err))

internal/service/cloudprovideraccess/resource_cloud_provider_access_setup.go

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99

1010
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1111
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
12-
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
1312
"github.com/mongodb/terraform-provider-mongodbatlas/internal/common/constant"
1413
"github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion"
1514
"github.com/mongodb/terraform-provider-mongodbatlas/internal/common/validate"
@@ -46,10 +45,9 @@ func ResourceSetup() *schema.Resource {
4645
Required: true,
4746
},
4847
"provider_name": {
49-
Type: schema.TypeString,
50-
Required: true,
51-
ValidateFunc: validation.StringInSlice([]string{constant.AWS, constant.AZURE}, false),
52-
ForceNew: true,
48+
Type: schema.TypeString,
49+
Required: true,
50+
ForceNew: true,
5351
},
5452
"aws_config": {
5553
Type: schema.TypeList,
@@ -87,6 +85,22 @@ func ResourceSetup() *schema.Resource {
8785
},
8886
},
8987
},
88+
"gcp_config": {
89+
Type: schema.TypeList,
90+
Computed: true,
91+
Elem: &schema.Resource{
92+
Schema: map[string]*schema.Schema{
93+
"status": {
94+
Type: schema.TypeString,
95+
Computed: true,
96+
},
97+
"service_account_for_atlas": {
98+
Type: schema.TypeString,
99+
Computed: true,
100+
},
101+
},
102+
},
103+
},
90104
"created_date": {
91105
Type: schema.TypeString,
92106
Computed: true,
@@ -119,7 +133,10 @@ func resourceCloudProviderAccessSetupRead(ctx context.Context, d *schema.Resourc
119133
return diag.FromErr(fmt.Errorf(ErrorCloudProviderGetRead, err))
120134
}
121135

122-
roleSchema := roleToSchemaSetup(role)
136+
roleSchema, err := roleToSchemaSetup(role)
137+
if err != nil {
138+
return diag.Errorf(errorCloudProviderAccessCreate, err)
139+
}
123140
for key, val := range roleSchema {
124141
if err := d.Set(key, val); err != nil {
125142
return diag.FromErr(fmt.Errorf(ErrorCloudProviderGetRead, err))
@@ -156,7 +173,10 @@ func resourceCloudProviderAccessSetupCreate(ctx context.Context, d *schema.Resou
156173
}
157174

158175
// once multiple providers enable here do a switch, select for provider type
159-
roleSchema := roleToSchemaSetup(role)
176+
roleSchema, err := roleToSchemaSetup(role)
177+
if err != nil {
178+
return diag.Errorf(errorCloudProviderAccessCreate, err)
179+
}
160180

161181
resourceID := role.GetRoleId()
162182
if role.ProviderName == constant.AZURE {
@@ -197,39 +217,51 @@ func resourceCloudProviderAccessSetupDelete(ctx context.Context, d *schema.Resou
197217
return diag.FromErr(fmt.Errorf(errorCloudProviderAccessDelete, err))
198218
}
199219

200-
d.SetId("")
201220
d.SetId("")
202221
return nil
203222
}
204223

205-
func roleToSchemaSetup(role *admin.CloudProviderAccessRole) map[string]any {
206-
if role.ProviderName == "AWS" {
207-
out := map[string]any{
224+
func roleToSchemaSetup(role *admin.CloudProviderAccessRole) (map[string]any, error) {
225+
switch role.ProviderName {
226+
case constant.AWS:
227+
return map[string]any{
208228
"provider_name": role.GetProviderName(),
209229
"aws_config": []any{map[string]any{
210230
"atlas_aws_account_arn": role.GetAtlasAWSAccountArn(),
211231
"atlas_assumed_role_external_id": role.GetAtlasAssumedRoleExternalId(),
212232
}},
233+
"gcp_config": []any{map[string]any{}},
213234
"created_date": conversion.TimeToString(role.GetCreatedDate()),
214235
"role_id": role.GetRoleId(),
215-
}
216-
return out
217-
}
218-
219-
out := map[string]any{
220-
"provider_name": role.ProviderName,
221-
"azure_config": []any{map[string]any{
222-
"atlas_azure_app_id": role.GetAtlasAzureAppId(),
223-
"service_principal_id": role.GetServicePrincipalId(),
224-
"tenant_id": role.GetTenantId(),
225-
}},
226-
"aws_config": []any{map[string]any{}},
227-
"created_date": conversion.TimeToString(role.GetCreatedDate()),
228-
"last_updated_date": conversion.TimeToString(role.GetLastUpdatedDate()),
229-
"role_id": role.GetId(),
236+
}, nil
237+
case constant.AZURE:
238+
return map[string]any{
239+
"provider_name": role.ProviderName,
240+
"azure_config": []any{map[string]any{
241+
"atlas_azure_app_id": role.GetAtlasAzureAppId(),
242+
"service_principal_id": role.GetServicePrincipalId(),
243+
"tenant_id": role.GetTenantId(),
244+
}},
245+
"aws_config": []any{map[string]any{}},
246+
"gcp_config": []any{map[string]any{}},
247+
"created_date": conversion.TimeToString(role.GetCreatedDate()),
248+
"last_updated_date": conversion.TimeToString(role.GetLastUpdatedDate()),
249+
"role_id": role.GetId(),
250+
}, nil
251+
case constant.GCP:
252+
return map[string]any{
253+
"provider_name": role.GetProviderName(),
254+
"gcp_config": []any{map[string]any{
255+
"status": role.GetStatus(),
256+
"service_account_for_atlas": role.GetGcpServiceAccountForAtlas(),
257+
}},
258+
"aws_config": []any{map[string]any{}},
259+
"role_id": role.GetId(),
260+
"created_date": conversion.TimeToString(role.GetCreatedDate()),
261+
}, nil
262+
default:
263+
return nil, fmt.Errorf("unsupported provider: %s", role.GetProviderName())
230264
}
231-
232-
return out
233265
}
234266

235267
func resourceCloudProviderAccessSetupImportState(ctx context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) {

internal/service/cloudprovideraccess/resource_cloud_provider_access_setup_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,33 @@ func TestAccCloudProviderAccessSetupAzure_basic(t *testing.T) {
6262
},
6363
)
6464
}
65+
func TestAccCloudProviderAccessSetupGCP_basic(t *testing.T) {
66+
acc.SkipTestForCI(t) // Code needs to support long running operations for successful test: CLOUDP-341440
67+
var (
68+
resourceName = "mongodbatlas_cloud_provider_access_setup.test"
69+
dataSourceName = "data.mongodbatlas_cloud_provider_access_setup.test"
70+
projectID = acc.ProjectIDExecution(t)
71+
)
72+
73+
resource.ParallelTest(t, resource.TestCase{
74+
PreCheck: func() { acc.PreCheckGCPEnv(t) },
75+
ProtoV6ProviderFactories: acc.TestAccProviderV6Factories,
76+
Steps: []resource.TestStep{
77+
{
78+
Config: configSetupGCP(projectID),
79+
Check: resource.ComposeAggregateTestCheckFunc(
80+
resource.TestCheckResourceAttrSet(resourceName, "role_id"),
81+
resource.TestCheckResourceAttrSet(resourceName, "gcp_config.0.service_account_for_atlas"),
82+
resource.TestCheckResourceAttr(resourceName, "gcp_config.0.status", "COMPLETE"),
83+
84+
resource.TestCheckResourceAttrSet(dataSourceName, "role_id"),
85+
resource.TestCheckResourceAttrSet(dataSourceName, "gcp_config.0.service_account_for_atlas"),
86+
resource.TestCheckResourceAttr(dataSourceName, "gcp_config.0.status", "COMPLETE"),
87+
),
88+
},
89+
},
90+
})
91+
}
6592

6693
func basicSetupTestCase(tb testing.TB) *resource.TestCase {
6794
tb.Helper()
@@ -113,6 +140,21 @@ func configSetupAWS(projectID string) string {
113140
`, projectID)
114141
}
115142

143+
func configSetupGCP(projectID string) string {
144+
return fmt.Sprintf(`
145+
resource "mongodbatlas_cloud_provider_access_setup" "test" {
146+
project_id = %[1]q
147+
provider_name = "GCP"
148+
}
149+
150+
data "mongodbatlas_cloud_provider_access_setup" "test" {
151+
project_id = mongodbatlas_cloud_provider_access_setup.test.project_id
152+
provider_name = mongodbatlas_cloud_provider_access_setup.test.provider_name
153+
role_id = mongodbatlas_cloud_provider_access_setup.test.role_id
154+
}
155+
`, projectID)
156+
}
157+
116158
func checkExists(resourceName string) resource.TestCheckFunc {
117159
return func(s *terraform.State) error {
118160
rs, ok := s.RootModule().Resources[resourceName]

internal/service/encryptionatrest/resource_migration_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func TestMigEncryptionAtRest_basicGCP(t *testing.T) {
119119
)
120120

121121
resource.Test(t, resource.TestCase{
122-
PreCheck: func() { mig.PreCheck(t); acc.PreCheckGPCEnv(t) },
122+
PreCheck: func() { mig.PreCheck(t); acc.PreCheckGCPEnv(t) },
123123
CheckDestroy: acc.EARDestroy,
124124
Steps: []resource.TestStep{
125125
{

internal/service/encryptionatrest/resource_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func TestAccEncryptionAtRest_basicGCP(t *testing.T) {
169169
)
170170

171171
resource.Test(t, resource.TestCase{
172-
PreCheck: func() { acc.PreCheck(t); acc.PreCheckGPCEnv(t) },
172+
PreCheck: func() { acc.PreCheck(t); acc.PreCheckGCPEnv(t) },
173173
ProtoV6ProviderFactories: acc.TestAccProviderV6Factories,
174174
CheckDestroy: acc.EARDestroy,
175175
Steps: []resource.TestStep{

internal/testutil/acc/pre_check.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func PreCheckPublicKey2(tb testing.TB) {
148148
}
149149
}
150150

151-
func PreCheckGPCEnv(tb testing.TB) {
151+
func PreCheckGCPEnv(tb testing.TB) {
152152
tb.Helper()
153153
if os.Getenv("GCP_SERVICE_ACCOUNT_KEY") == "" || os.Getenv("GCP_KEY_VERSION_RESOURCE_ID") == "" {
154154
tb.Fatal("`GCP_SERVICE_ACCOUNT_KEY` and `GCP_KEY_VERSION_RESOURCE_ID` must be set for acceptance testing")

0 commit comments

Comments
 (0)