Skip to content

feat: Add azure attributes in federated database instance resource #3484

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
4a15649
feat: Azure Support in CloudProviderConfig for mongodbatlas_federated…
marcabreracast Jul 7, 2025
dc626fa
Add flattenAzureCloudProviderConfig function to handle Azure configur…
marcabreracast Jul 8, 2025
4641d4a
test: add Azure cloud provider acceptance test for federated DB instance
marcabreracast Jul 8, 2025
ff374eb
refactor(test): Remove duplicate local implementation to use shared t…
marcabreracast Jul 9, 2025
f1d8e6c
Add changelog
marcabreracast Jul 9, 2025
84b7aa8
Move helper function under test functions for better organization
marcabreracast Jul 10, 2025
1b736b5
Change order of parameters to match formatting options
marcabreracast Jul 10, 2025
c9dc8d8
Remove extra linebreak
marcabreracast Jul 10, 2025
f2dfe08
Add Azure var IDs for Data Federation testing to be used in CI
marcabreracast Jul 10, 2025
a7ba7dd
Remove unnecessary data source for Azure config test reusability
marcabreracast Jul 10, 2025
388f98d
Refactor flattenCloudProviderConfig functions to accept schema.Resour…
marcabreracast Jul 10, 2025
aad20b7
Add data source for azure attribute
marcabreracast Jul 10, 2025
d7da829
Add clarification comments to address change in schema attribute
marcabreracast Jul 10, 2025
4cfc3c5
refactor: Extract schema definition for cloudProviderConfig field int…
marcabreracast Jul 11, 2025
1e9a110
Address PR comment suggestion
marcabreracast Jul 11, 2025
4efdd4e
Add resource_schema file
marcabreracast Jul 11, 2025
ff0e5bd
Modify schema fields to handle test_s3_bucket field on data source
marcabreracast Jul 18, 2025
868111f
Correct cloud provider data source being used for test on azure config
marcabreracast Jul 18, 2025
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
3 changes: 3 additions & 0 deletions .changelog/3484.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets add a changelog entry for both data sources as well

resource/mongodbatlas_federated_database_instance: Adds `azure` attribute to allow the creation of federated databases with Azure cloud provider configuration
```
3 changes: 3 additions & 0 deletions .github/workflows/acceptance-tests-runner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,9 @@ jobs:
MONGODB_ATLAS_FEDERATED_ISSUER_URI: ${{ inputs.mongodb_atlas_federated_issuer_uri }}
MONGODB_ATLAS_FEDERATED_ORG_ID: ${{ inputs.mongodb_atlas_federated_org_id }}
MONGODB_ATLAS_FEDERATED_SETTINGS_ASSOCIATED_DOMAIN: ${{ inputs.mongodb_atlas_federated_settings_associated_domain }}
AZURE_ATLAS_APP_ID: ${{ inputs.azure_atlas_app_id }}
AZURE_SERVICE_PRINCIPAL_ID: ${{ inputs.azure_service_principal_id }}
AZURE_TENANT_ID: ${{ inputs.azure_tenant_id }}
AWS_S3_BUCKET: ${{ secrets.aws_s3_bucket_federation }}
AWS_REGION: ${{ inputs.aws_region_federation }}
AWS_ACCESS_KEY_ID: ${{ secrets.aws_access_key_id }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func DataSourceSetup() *schema.Resource {
"provider_name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{"AWS"}, false),
ValidateFunc: validation.StringInSlice([]string{"AWS", "AZURE"}, false),
},
"role_id": {
Type: schema.TypeString,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ func TestAccCloudProviderAccessSetupAWS_basic(t *testing.T) {
resource.ParallelTest(t, *basicSetupTestCase(t))
}

const (
cloudProviderAzureDataSource = `
data "mongodbatlas_cloud_provider_access_setup" "test" {
project_id = mongodbatlas_cloud_provider_access_setup.test.project_id
provider_name = "AZURE"
role_id = mongodbatlas_cloud_provider_access_setup.test.role_id
}
`
)

func TestAccCloudProviderAccessSetupAzure_basic(t *testing.T) {
var (
resourceName = "mongodbatlas_cloud_provider_access_setup.test"
Expand All @@ -26,13 +36,12 @@ func TestAccCloudProviderAccessSetupAzure_basic(t *testing.T) {
tenantID = os.Getenv("AZURE_TENANT_ID")
projectID = acc.ProjectIDExecution(t)
)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acc.PreCheckCloudProviderAccessAzure(t) },
ProtoV6ProviderFactories: acc.TestAccProviderV6Factories,
Steps: []resource.TestStep{
{
Config: configSetupAzure(projectID, atlasAzureAppID, servicePrincipalID, tenantID),
Config: acc.ConfigSetupAzure(projectID, atlasAzureAppID, servicePrincipalID, tenantID) + cloudProviderAzureDataSource,
Check: resource.ComposeAggregateTestCheckFunc(
checkExists(resourceName),
resource.TestCheckResourceAttrSet(resourceName, "role_id"),
Expand Down Expand Up @@ -104,26 +113,6 @@ func configSetupAWS(projectID string) string {
`, projectID)
}

func configSetupAzure(projectID, atlasAzureAppID, servicePrincipalID, tenantID string) string {
return fmt.Sprintf(`
resource "mongodbatlas_cloud_provider_access_setup" "test" {
project_id = %[1]q
provider_name = "AZURE"
azure_config {
atlas_azure_app_id = %[2]q
service_principal_id = %[3]q
tenant_id = %[4]q
}
}

data "mongodbatlas_cloud_provider_access_setup" "test" {
project_id = mongodbatlas_cloud_provider_access_setup.test.project_id
provider_name = "AWS"
role_id = mongodbatlas_cloud_provider_access_setup.test.role_id
}
`, projectID, atlasAzureAppID, servicePrincipalID, tenantID)
}

func checkExists(resourceName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceName]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,47 +33,7 @@ func DataSource() *schema.Resource {
Type: schema.TypeString,
},
},
"cloud_provider_config": {
Type: schema.TypeList,
MaxItems: 1,
Computed: true,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"aws": {
Type: schema.TypeList,
MaxItems: 1,
Computed: true,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"role_id": {
Type: schema.TypeString,
Computed: true,
},
"test_s3_bucket": {
Type: schema.TypeString,
Computed: true,
Optional: true,
},
"iam_assumed_role_arn": {
Type: schema.TypeString,
Computed: true,
},
"iam_user_arn": {
Type: schema.TypeString,
Computed: true,
},
"external_id": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
},
},
"cloud_provider_config": cloudProviderConfig(true),
"data_process_region": {
Type: schema.TypeList,
Computed: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,47 +45,7 @@ func PluralDataSource() *schema.Resource {
Type: schema.TypeString,
},
},
"cloud_provider_config": {
Type: schema.TypeList,
MaxItems: 1,
Computed: true,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"aws": {
Type: schema.TypeList,
MaxItems: 1,
Computed: true,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"role_id": {
Type: schema.TypeString,
Computed: true,
},
"test_s3_bucket": {
Type: schema.TypeString,
Computed: true,
Optional: true,
},
"iam_assumed_role_arn": {
Type: schema.TypeString,
Computed: true,
},
"iam_user_arn": {
Type: schema.TypeString,
Computed: true,
},
"external_id": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
},
},
"cloud_provider_config": cloudProviderConfig(true),
"data_process_region": {
Type: schema.TypeList,
Computed: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,45 +53,8 @@ func Resource() *schema.Resource {
Type: schema.TypeString,
},
},
"cloud_provider_config": {
Type: schema.TypeList,
MaxItems: 1,
Computed: true,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"aws": {
Type: schema.TypeList,
MaxItems: 1,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"role_id": {
Type: schema.TypeString,
Required: true,
},
"test_s3_bucket": {
Type: schema.TypeString,
Required: true,
},
"iam_assumed_role_arn": {
Type: schema.TypeString,
Computed: true,
},
"iam_user_arn": {
Type: schema.TypeString,
Computed: true,
},
"external_id": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
},
},
// Optional-only behavior from the API, but keeping O+C to avoid behavior changes.
"cloud_provider_config": cloudProviderConfig(false),
"data_process_region": {
Type: schema.TypeList,
MaxItems: 1,
Expand Down Expand Up @@ -708,7 +671,8 @@ func newUrls(urlsFromConfig []any) *[]string {
func newCloudProviderConfig(d *schema.ResourceData) *admin.DataLakeCloudProviderConfig {
if cloudProvider, ok := d.Get("cloud_provider_config").([]any); ok && len(cloudProvider) == 1 {
return &admin.DataLakeCloudProviderConfig{
Aws: newAWSConfig(cloudProvider),
Aws: newAWSConfig(cloudProvider),
Azure: newAzureConfig(cloudProvider),
}
}

Expand All @@ -724,6 +688,14 @@ func newAWSConfig(cloudProvider []any) *admin.DataLakeAWSCloudProviderConfig {
return nil
}

func newAzureConfig(cloudProvider []any) *admin.DataFederationAzureCloudProviderConfig {
if azure, ok := cloudProvider[0].(map[string]any)["azure"].([]any); ok && len(azure) == 1 {
azureSchema := azure[0].(map[string]any)
return admin.NewDataFederationAzureCloudProviderConfig(azureSchema["role_id"].(string))
}
return nil
}

func newDataProcessRegion(d *schema.ResourceData) *admin.DataLakeDataProcessRegion {
if dataProcessRegion, ok := d.Get("data_process_region").([]any); ok && len(dataProcessRegion) == 1 {
return &admin.DataLakeDataProcessRegion{
Expand All @@ -740,8 +712,18 @@ func flattenCloudProviderConfig(d *schema.ResourceData, cloudProviderConfig *adm
return nil
}

aws := cloudProviderConfig.GetAws()
return []map[string]any{
{
"aws": flattenAWSCloudProviderConfig(d, cloudProviderConfig.Aws),
"azure": flattenAzureCloudProviderConfig(cloudProviderConfig.Azure),
},
}
}

func flattenAWSCloudProviderConfig(d *schema.ResourceData, aws *admin.DataLakeAWSCloudProviderConfig) []map[string]any {
if aws == nil {
return nil
}
awsOut := []map[string]any{
{
"role_id": aws.GetRoleId(),
Expand All @@ -751,29 +733,33 @@ func flattenCloudProviderConfig(d *schema.ResourceData, cloudProviderConfig *adm
},
}

currentCloudProviderConfig, ok := d.Get("cloud_provider_config").([]any)
if !ok || len(currentCloudProviderConfig) == 0 {
return []map[string]any{
{
"aws": &awsOut,
},
}
}
// test_s3_bucket is not part of the API response
if currentAWS, ok := currentCloudProviderConfig[0].(map[string]any)["aws"].([]any); ok {
if testS3Bucket, ok := currentAWS[0].(map[string]any)["test_s3_bucket"].(string); ok {
awsOut[0]["test_s3_bucket"] = testS3Bucket
return []map[string]any{
{
"aws": &awsOut,
},
// Optionally add test_s3_bucket if present in the config
if currentCloudProviderConfig, ok := d.Get("cloud_provider_config").([]any); ok && len(currentCloudProviderConfig) > 0 {
if currentAWS, ok := currentCloudProviderConfig[0].(map[string]any)["aws"].([]any); ok && len(currentAWS) > 0 {
if testS3Bucket, ok := currentAWS[0].(map[string]any)["test_s3_bucket"].(string); ok && testS3Bucket != "" {
awsOut[0]["test_s3_bucket"] = testS3Bucket
}
}
}

return awsOut
}

func flattenAzureCloudProviderConfig(azure *admin.DataFederationAzureCloudProviderConfig) []map[string]any {
if azure == nil {
return nil
}

return []map[string]any{
{
"role_id": azure.GetRoleId(),
"atlas_app_id": azure.GetAtlasAppId(),
"service_principal_id": azure.GetServicePrincipalId(),
"tenant_id": azure.GetTenantId(),
},
}
}

func flattenDataProcessRegion(processRegion *admin.DataLakeDataProcessRegion) []map[string]any {
if processRegion == nil || (processRegion.Region == "" && processRegion.CloudProvider == "") {
return nil
Expand Down
Loading
Loading